簡體   English   中英

Android Studio App 在運行線程時崩潰

[英]Android Studio App crash when running a thread

我想首先聲明我對 Android Studio 和 Java 腳本非常陌生,而且編程甚至不是我的強項。 但是,我正在嘗試開發一個音頻合成器應用程序,雖然我可以讓一切正常工作,但我無法將音頻傳輸到 stream。 本質上,我可以在 static 模式下使用 AudioTrack 來播放計算出的聲音波形長達 10 秒,但是,我無法動態播放多個按鍵(我在應用程序上設置了 2 個八度音階 25 鍵鍵盤),我無法按住長按一個鍵也不行。 我有一個長度 slider 可以將音符的持續時間從 0.1 調整到 10 秒。 我希望能夠同時按下多個鍵,以及長時間按住一個鍵,並讓應用程序連續發出 output 聲音。 我做了一些研究,似乎實現這一目標的最佳方法是使用 AudioTrack 庫的“流”模式,並使用線程? 我對庫、線程甚至語言都非常陌生。

我正在關注此處提供的音頻流教程,但我嘗試了一種稍微不同的方法,我相信這種方法在我的情況下會更好。 我在下面發布了我的測試代碼(請注意,這不是我播放不同聲音等的所有代碼,而是只有一個鍵設置(c4)的最低限度,我試圖讓它連續播放聲音。當我第一次按下鍵時,只要按住鍵,它就會播放聲音。但是,當我松開鍵並再次按下它后,應用程序就崩潰了。我不太清楚為什么會這樣正在發生。我嘗試了不同的方法,例如只調用一次“audioThread.start()”function,或者嘗試停止線程,但我沒有成功。如果我只調用一次“audioThread.start()”function,則當我再次按下鍵時應用程序不會崩潰,但它也不會播放聲音。當它播放聲音時,如果我再次按下鍵它會崩潰應用程序。

我還給出了上述問題的完整 scope,因為我不確定使用線程是否是解決 go 的最佳方法。 理想情況下,我希望它可以按鍵盤上的 25 個鍵中的任何一個,並且音頻庫將 stream 同時按下的鍵的聲音,而不是 output 任何東西如果沒有按下。 我不喜歡運行 25 個不同線程的想法,因為我的音頻緩沖區是在每個線程中設置的,我認為如果我一次播放多個音符會覆蓋以前的緩沖區? 如果您認為我的目標是使用線程,請告訴我。 我認為線程會更好,因為我必須在流式傳輸音頻之前進行大量計算(最大,25 x 6 x 3 = 450 次觸發操作來計算我的波形的一個樣本),所以我認為以某種方式流水線化計算會會更好?

無論哪種方式,請告訴我為什么當我第二次按下該鍵時我無法獲得下面的測試設置來播放聲音? 如果這是相關信息,我也在使用聯想 tabM10 FHD Plus。 這也是我第一次使用stackOverflow,所以如果我在格式化我的帖子時做得很糟糕,我深表歉意。 如果您認為我應該編輯我的帖子以更簡潔/清楚地說明我的問題,請告訴我,我會解決它。 對於給您帶來的任何不便,我深表歉意。

我的測試代碼:

 package com.example.ece496_simplesynth; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.core.view.MotionEventCompat; import android.graphics.Color; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; import android.os.Build; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; public class MainActivity extends AppCompatActivity { private AudioTrack audioTrack; private int intBufferSize; private short[] shortAudioData; private boolean isActive = false; private Thread audioThread; private boolean keyPress = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final View c4 = (View) findViewById(R.id.c4); c4.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { int action = motionEvent.getAction();//.getActionMasked(motionEvent); if (action == MotionEvent.ACTION_DOWN) { c4.setBackgroundColor(Color.parseColor("#ed1b24")); //"#81DAF5" keyPress = true; audioThread.start(); } else if (action == MotionEvent.ACTION_UP) { c4.setBackgroundColor(Color.parseColor("#FFFFFF")); keyPress = false; //audioThread.stop(); } return true; } }); audioThread = new Thread(new Runnable() { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public void run() { threadLoop(); } }); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void threadLoop(){ int intSampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); intBufferSize = AudioTrack.getMinBufferSize(intSampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); shortAudioData = new short[intBufferSize]; audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, intSampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, intBufferSize, AudioTrack.MODE_STREAM); audioTrack.setPlaybackRate(intSampleRate); int n = 0; float x; float TS = 1.0f/intSampleRate; float freq = 440.0f; float PI = 3.14159f; float omega = 2.0f*PI*freq*TS; if(keyPress){ audioTrack.play(); } while(keyPress){ for(int i = 0; i < shortAudioData.length; ++i){ if(n == Integer.MAX_VALUE | n < 0){ n = 0; } x = (float)(Math.sin((float)(omega*n))); ++n; shortAudioData[i] = (short)(x * Short.MAX_VALUE); } audioTrack.write(shortAudioData, 0, shortAudioData.length); } audioTrack.stop(); } }

我使用純 Java 編寫了與您的項目類似的內容。 我認為有一些可行的計划。 我采取的方法是讓鍵盤觸發(按鍵/按鍵釋放動作)采用松散耦合到預先分配的合成器庫。 產生 PCM 的合成器方法以及將 output 的合成器組合在一起的混音器駐留在一個專用的“音頻線程”上。 對於 Java,我使用SourceDataLine為 output。 使用 Android,您可以使用AudioTrack的 stream 原始 PCM。

您可以支持的並發音符的數量可能會受到合成算法所采用的計算復雜性的限制。 我認為一個常見的計划是在小塊中完成工作,例如幾毫秒的長度。 在“音頻線程”中,計算每個合成器中當前使用音符激活的下一個 PCM 數組,然后“音頻混合”步驟將每個數組的內容添加到通過AudioTrack寫入的單個數組中。 我咨詢過的一個人建議使用 256 幀 PCM 的緩沖區大小,作為以最小延遲獲得高吞吐量的最佳選擇,但我無法確定這是否屬實,或者它是否適用於 Android 環境。

跟蹤單個鍵的按鍵的代碼還必須跟蹤哪個合成器已被分配產生音符的任務,以便它可以在鍵釋放發生時向正確的合成器發送“釋放”命令。

作為提醒,我發現許多鍵盤不支持真正獨立的鍵。 例如,如果按下了一些相鄰的鍵,我的系統將不會注冊新的按鍵,例如:如果您已經關閉 QWR,您的鍵盤可能無法注冊 E 的附加按鍵。我沒有研究這個虧空的細節,只是讓自己甘心到了一定程度的不可預測性。

我還沒試過用觸摸屏來做這件事。 我制作的鍵盤“按鈕”響應鼠標點擊,但觸摸屏上只有一個鼠標,而不是多個手指。

這是一個有趣的項目,您將學到很多關於管理線程和資源的知識。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM