2010-10-14 16 views
0

我有一個應用程序,它可以記錄麥克風的音頻,然後對音頻進行一些後期處理,因此我必須使用AudioRecord類而不是標準MediaRecorder。我的記錄代碼是這樣的:在Android 2.2中錄製麥克風時出現奇怪的失真

DataOutputStream dataOutputStreamInstance = new DataOutputStream(bufferedStreamInstance); 
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); 

int bufferSize = AudioRecord.getMinBufferSize((int)sampleRate, channelConfiguration, DEFAULT_AUDIO_ENCODING) * 2; 
short[] microphoneBuffer = new short[bufferSize]; 
float[] processingBuffer = new float[bufferSize]; 
short[] outputBuffer = new short[bufferSize]; 

AudioRecord microphoneRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); 

microphoneRecorder.startRecording(); 
while(isRecording) { 
    synchronized(mutex) { ... check for pause condition, wait, etc. ... } 
    int numSamplesRead = microphoneRecorder.read(microphoneBuffer, 0, bufferSize); 

    // Convert 16-bit short data to floating point 
    getFloatingPointBufferFromPcmData(microphoneBuffer, processingBuffer, bufferSize); 

    doProcessingStuff(processingBuffer, bufferSize); 

    if(numSamplesRead == AudioRecord.ERROR_INVALID_OPERATION) { 
    throw new IllegalStateException("read() returned AudioRecord.ERROR_INVALID_OPERATION"); 
    } 
    else if(numSamplesRead == AudioRecord.ERROR_BAD_VALUE) { 
    throw new IllegalStateException("read() returned AudioRecord.ERROR_BAD_VALUE"); 
    } 

    try { 
    // Dump the output to the target file in 16-bit short format 
    getShortPcmBufferFromFloatingPointData(processingBuffer, outputBuffer, bufferSize); 
    for(int bufferIndex = 0; bufferIndex < numSamplesRead; bufferIndex++) { 
     dataOutputStreamInstance.writeShort(outputBuffer[bufferIndex]); 
    } 
    } 
    catch(Exception e) { 
    Log.e("MyApp", "Error while writing audio data to file: " + e.getMessage()); 
    e.getStackTrace(); 
    } 
} 

microphoneRecorder.stop(); 

上面的代碼工作正常,我實際上可以從設備錄製音頻,我聽到我的聲音和這樣。問題是,幾秒鐘後,一個非常奇怪的失真模式開始出現,直到整個信號被淹沒。下面是一個沉默的記錄,我通過把一些帶過話筒做的截圖,讓應用程序記錄一分鐘左右:

Screenshot of distortion in wave file

原始波形文件可以是downloaded here

由於我的效果處理代碼,問題肯定是而不是,因爲我試過評論它並在兩種情況下都得到相同的結果。我在網上搜尋了其他可能遇到類似問題的代碼或人員,但沒有發現任何內容。

回答

0

Bah,實際上這個問題並不是Android的錯 - 它是由我用來將原始PCM數據轉換爲WAV格式的軟件引起的。在endian轉換中顯然存在一些錯誤,因爲ARM芯片是big endian,WAV是little endian。當我們嘗試在Audacity中打開原始PCM文件時,他們看起來很好。

+0

我實際上確實建議沿着這些線可能是問題;) – 2010-10-15 14:04:01

+0

是的,這是真的。 :)但是,該錯誤是在轉換軟件,而不是我的Android代碼。不過,我確實讚揚了你的回答,因爲這讓我看到了正確的方向。 – 2010-10-15 14:18:21

1

我根本不知道Android SDK,但getFloatingPointBufferFromPcmDatagetShortPcmBufferFromFloatingPointData看起來不像標準的API函數,儘管可愛的命名約定。 :)

你自己寫了這些嗎?也許他們在循環迭代中使用共享狀態並累積結果?如果這些是您的實施,請分享這些代碼,以便我們幫助您確定實際問題。

您還有可能以錯誤的格式(位數,字節順序)寫出PCM數據,並且您的音頻編輯器正在根據不同的格式解釋數據,從而導致音頻數據錯誤地解碼似乎看起來似乎有一些積累效應發生。

如果這些查詢都不能解決您的問題,那麼我的下一個建議是爲每個循環迭代創建一個新的microphoneBuffer實例,而不是在while循環中使用單個實例。

再一次,我不是Android SDK專家,所以這些只是一般性的建議,這些建議是由多年處理幾乎所有類型的API及其實現細節的經驗所產生的。

希望能幫助診斷您的問題!

+0

感謝您的建議。緩衝區轉換函數都沒有錯,格式轉換也沒有(請參閱我自己的答案)。但是,我添加了一個額外的檢查,以查看從麥克風讀取的字節數與預期相同,令我驚訝的是,Android通常返回的字節數比要求的少,因此我相應地調整了我的代碼。 – 2010-10-15 10:28:41

+0

縮短几個字節我不認爲應該會導致您看到的這種累積效應。您是否嘗試將麥克風緩衝區(重新)分配移到循環中? – 2010-10-15 14:03:21

+0

實際上上面的代碼工作得很好,假設我將'numSamplesRead'而不是'bufferSize'傳遞給緩衝區轉換和處理函數。 – 2010-10-15 14:19:31

0

隨着沉默有可能是在增加輸入增益超出了理性的自動增益控制,試圖找到「東西」爲您記錄(並找到本底噪聲當然)

如果設置,會發生什麼你的個人電腦揚聲器播放一個不錯的音頻正弦曲線 - 噪音是否仍然出現,或者你是否繼續記錄正弦波?