pyaudio高級(jí)玩法3:實(shí)時(shí)聲音處理
? ? ? ? 有了前面兩章的基礎(chǔ),就可以開始實(shí)時(shí)處理聲音啦! 思路很簡(jiǎn)單,pyaudio實(shí)時(shí)錄制聲音,每次錄制一小段,由于錄制過(guò)程是非阻塞的,在錄制聲音的固定時(shí)間內(nèi),電腦就可以同時(shí)對(duì)聲音進(jìn)行處理和播放。 demo程序很簡(jiǎn)單,直接通過(guò)注釋來(lái)看。?
??

import pyaudio
import?struct
import?numpy?as?np
CHUNK?=?882?#需要時(shí)幀率的約數(shù),太長(zhǎng)會(huì)導(dǎo)致明顯的延遲
FORMAT?=?pyaudio.paInt16
CHANNELS?=?1?
RATE?=?176400??#非主流的幀率
pIn?=?pyaudio.PyAudio()
################################################
def?fuc(inData):
????outData?=?inData*1?#這里做原樣輸出,并同步播放。
????#在in?和?out?間做運(yùn)算處理,就可以開始玩啦。但是需要注意
????#1,喇叭和麥之間太近,或喇叭聲音太大會(huì)造成自激,發(fā)出嘯音,
????#2,in比out大可能會(huì)導(dǎo)致超出outData的取值范圍,從而導(dǎo)致程序出錯(cuò)退出。
????#這些都是聲音處理算法上需要注意的。
????return?outData
###########################################################
def?callbackIn(in_data,?frame_count,?time_info,?status):
????#傳入的data參數(shù)即是采樣到的數(shù)據(jù)
????in_data_int?=?np.array(struct.unpack('<882h',?in_data))??#out_data?=?in_data
????out_data_int?=?fuc(in_data_int)
????out_data_byte?=?struct.pack('<882h',?*out_data_int)?
????return?(out_data_byte,?pyaudio.paContinue)?
????#return中的data就是會(huì)輸出的內(nèi)容
streamIn?=?pIn.open(format=FORMAT,
????????channels=CHANNELS,
????????rate=RATE,
????????input=True,??#打開聲音錄制
????????output?=?True,?#打開聲音播放
????????input_device_index=1,?#選擇聲音輸入設(shè)備,課件audioDevice文件
????????output_device_index?=?4,?#這里選擇輸出設(shè)備,這里的參數(shù)是我電腦上的情況??梢圆粚懚际褂媚J(rèn)設(shè)備
????????frames_per_buffer=CHUNK,
????????stream_callback=callbackIn)?#非阻塞情況下使用回調(diào)函數(shù)
streamIn.start_stream()
#?wait?for?stream?to?finish?(5)
while?1:??#壓根就沒(méi)寫退出方法,自己用進(jìn)程管理器去退吧
????if?streamIn.is_active():
????????pass???
#?stop?stream?(6)
streamIn.stop_stream()???#直到運(yùn)行此句錄音終止
streamIn.close()
pIn.terminate()

? ? ? ? 這只是一個(gè)最基礎(chǔ)的程序,在聲音處理時(shí),那門倒可就更多了。 即便是簡(jiǎn)單的線性輸出,也要考慮如何避免自激,如何避免數(shù)值超出范圍等;做頻閾變換時(shí),chunk與chunk之間如何保持連續(xù)性,都會(huì)讓人頭疼??赡軐?duì)聲音削峰變聲之類的小玩意,才是對(duì)聲音最簡(jiǎn)單的處理方法吧。