2017-09-05 36 views
0

我正在使用pyaudio來錄製我想然後以塊(例如,每5秒)處理的音頻。我在回調模式下使用pyaudio,並且每調用一次錄製的1500個音頻樣本就會調用一個回調函數,並在該函數內將這些樣本添加到隊列中。我還將樣本保存到一個wav文件中,以便驗證它們是否符合預期。在回調模式下使用python與pyaudio的線程問題

q = Queue.Queue() 
flag = False 
waveFile = wave.open('recording.wav', 'wb') 
waveFile.setnchannels(1) 
waveFile.setsampwidth(2) 
waveFile.setframerate(RATE) 


def callback(in_data, frame_count, time_info, status): 
    silent = is_silent(in_data) 
    if silent == False: 
     numpydata = np.fromstring(in_data, dtype=np.int16) 
     waveFile.writeframes(in_data) 
     q.put(numpydata) 
     callback_flag = pyaudio.paContinue 

    elif silent == True and flag == True: 
     numpydata = np.fromstring(in_data, dtype=np.int16) 
     if len(numpydata) != 0: 
      waveFile.writeframes(in_data) 
      q.put(numpydata) 
     waveFile.close() 
     callback_flag = pyaudio.paComplete 
    else: 
     callback_flag = pyaudio.paContinue 

    return (in_data, callback_flag) 

p=pyaudio.PyAudio() # start the PyAudio class 
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,frames_per_buffer=1500, stream_callback = callback) #uses default input device 

一旦隊列不再是空的,我進入while循環,其從該隊列,以一個單獨的緩衝器添加數據,然後每當已添加音頻5秒處理在該緩衝器中的數據。

while q.empty() == True: 
if q.empty() == False: 
    break 

buf = [] 

while 1: 
    flag = True 
    try: 
     snd_data = q.get(True,timeout = 4) 
     buf.extend(snd_data) 
     if len(buf) >= 220500: 

      process audio... 


    except Queue.Empty: 

我的問題是,我在音頻信號中注意到奇怪的意想不到的毛刺,彷彿節目短暫停止錄製了幾樣,然後再次啓動備份。我可以通過在Audacity中打開錄製的wav文件並放大信號來看到這一點。我認爲這是因爲pyaudio每1500個樣本在一個單獨的線程中調用回調函數,有時它可能會嘗試調用回調函數,但前一個回調函數的線程仍處於打開狀態,並且此回調函數尚未完成,數據是仍然被添加到隊列等(道歉,如果這是一個不連貫的解釋,我不太確定使用什麼術語)。

有誰知道我該如何解決這個問題?是否有一種同步方法,以便每個回調函數只有在前一個回調函數完成處理後纔會調用?

回答

0

你應該非常小心你的回調函數。最值得注意的是,你不應該從那裏讀取或寫入文件。 您提到您只是爲了調試而編寫文件,但這可能實際上會導致毛刺。

此外,您應該始終檢查您的回調函數的status參數。這告訴你是否有超限或欠載。 如果您遇到超限或欠載,您可以嘗試增加塊大小(和延遲),直到它們消失。

這是一個腳本示例,我將這些記錄製作成了一個聲音文件:rec_unlimited.py。 下面是一個繪製輸入信號的示例:plot_input.py。您可以調整它來執行任何其他處理而不是繪圖。

是否有一種同步它的方法,以便每個回調函數只會在前一個回調函數完成處理後調用?

這實際上已經是這種情況,對回調函數的調用將永遠不會重疊。但是,如果調用回調函數的時間過長,則將生成的輸出數據發送到聲卡並且不得不丟棄該音頻數據,從而導致可聽見的中斷。這被稱爲「輸出欠載」。 如果先前調用回調函數的時間過長,則會有太多的音頻輸入數據可用,其中一些將不得不被丟棄,從而導致丟失。這被稱爲「輸入超限」。

+0

感謝您提供的內容豐富的回覆,我似乎通過處理回調函數中的音頻來擺脫問題(無論如何我都這樣認爲),但我會看看您的腳本,並嘗試將其適用於我的目的。 – CJF