Python+pyaudio實(shí)現(xiàn)音頻控制示例詳解
簡(jiǎn)介
PyAudio是一個(gè)跨平臺(tái)的音頻處理工具包,使用該工具包可以在Python程序中播放和錄制音頻,也可以產(chǎn)生wav文件等
安裝
pip install PyAudio
注意:使用該命令安裝時(shí)可能會(huì)報(bào)錯(cuò),報(bào)錯(cuò)內(nèi)容如下:
針對(duì)該問(wèn)題,我們使用whl文件進(jìn)行安裝,首先在網(wǎng)址下面找到以下文件并下載,根據(jù)自己的python版本及計(jì)算機(jī)系統(tǒng)下載相應(yīng)文件即可。
下載完成后,切換到文件所在目錄,使用如下命令安裝即可
pip3 install PyAudio-0.2.11-cp38-cp38-win_amd64.whl
pyaudio控制指定設(shè)備,錄制音頻/采集音頻流/播放音頻
#!/usr/bin/env python3 #-*- coding:utf-8 -*- #------------- 音頻設(shè)備操作模塊 ------------------- # # 功能: 錄制/獲取音頻流/播放音頻 # 時(shí)間: 2021-09-13 # #-------------------------------------------------- import sys ,pyaudio, wave from tqdm import tqdm class UacAudioInAndOut: def __init__(self): """ 功能: 錄音參數(shù)初始化 創(chuàng)建vad檢測(cè)模塊對(duì)象 參數(shù): / 返回值: / """ self.input_format_dict = {"S8_LE":16, "S16_LE":8, "S24_LE":4, "S32_LE":2} self.framerate_list = [8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000] def _inforPrintf(self, infor_content): """ 功能: 檢測(cè)操作系統(tǒng),使用正確編碼 輸出打印信息 參數(shù): infor_content: 信息內(nèi)容 返回值: / """ if sys.platform != "linux" and sys.platform != "darwin": infor_content = str(infor_content).encode("gbk","ignore").decode("gbk") print(infor_content) def GetAllDevInfor(self): """ 功能: 顯示支持設(shè)備信息 參數(shù): / 返回值: / """ PA = pyaudio.PyAudio() self._inforPrintf("----------------------< 本機(jī)支持設(shè)備 >------------------------------") for dev_index in range(PA.get_device_count()): self._inforPrintf("\n-------------------------------------------------------") for key in PA.get_device_info_by_index(dev_index): self._inforPrintf("%s:%s"%(key, str(PA.get_device_info_by_index(dev_index)[key]))) self._inforPrintf("========================================================") def GetUacDevInfor(self, devKeywordOrIndex=None): """ 功能: 獲取UAC設(shè)備信息 參數(shù): devKeywordOrIndex: 設(shè)備名稱(chēng)關(guān)鍵字或索引 返回值: dic 設(shè)備信息字典 False 設(shè)備信息獲取失敗 """ PA = pyaudio.PyAudio() if devKeywordOrIndex == None: self._inforPrintf("\033[0;36;31m[UacAudioInAndOut] 未設(shè)設(shè)備, 當(dāng)前使用默認(rèn)設(shè)備\033[0m") return PA.get_default_input_device_info() if str(devKeywordOrIndex).isdigit(): devKeywordOrIndex = int(devKeywordOrIndex) return PA.get_device_info_by_index(devKeywordOrIndex) uac_infor_list = [] for uac_index in range(PA.get_device_count()): if PA.get_device_info_by_index(uac_index).get("name").find(str(devKeywordOrIndex)) >= 0: uac_infor_list.append(PA.get_device_info_by_index(uac_index)) if len(uac_infor_list) > 1: self._inforPrintf("\033[0;36;33m[UacAudioInAndOut] UAC 設(shè)備有多個(gè),\ 請(qǐng)修正關(guān)鍵字, 當(dāng)前設(shè)備如下: %s\033[0m"%str(uac_infor_list)) return False else: return uac_infor_list.pop() def is_framerate_supported(self, setFramerate, UacAudioInHandle, load_parame_dict, input_or_output="input"): """ 功能: 判斷當(dāng)配置在指定設(shè)備中是否支持 參數(shù): setFramerate: 設(shè)置采樣率 UacAudioInHandle: 設(shè)備句柄 load_parame_dict: 加載字典 input_or_output: 輸入/輸出功能 返回值: bool True/False """ try: if input_or_output == "input": UacAudioInHandle.is_format_supported(rate=float(setFramerate), input_device=load_parame_dict['index'], input_channels=load_parame_dict['setInputChannels'], input_format=load_parame_dict['_setInputFormat']) else: UacAudioInHandle.is_format_supported(rate=float(setFramerate), output_device=load_parame_dict['index'], output_channels=load_parame_dict['maxOutputChannels'], output_format=UacAudioInHandle.get_format_from_width(load_parame_dict['setOutputFormat'])) return True except: return False def LoadUacAudioInDevice(self, maxStreamDuration=1000, setInputChannels=None, setInputFormat=None, devKeywordOrIndex=None): """ 功能: 加載音頻獲取設(shè)備 參數(shù): maxStreamDuration=1000 默認(rèn)一段流時(shí)長(zhǎng) setInputChannels: 通道數(shù) setInputFormat: 位寬 devKeywordOrIndex: 錄音設(shè)備關(guān)鍵字/索引 返回值: 成功: UacAudioInHandle, StreamHandle, load_parame_dict 失敗: False """ try: load_parame_dict = {} uac_infor_dict = self.GetUacDevInfor(devKeywordOrIndex) if not setInputFormat: _Format = "S16_LE" self._inforPrintf("\033[0;36;33m[UacAudioInAndOut] 未設(shè)置位寬,使用默認(rèn) S16_LE \033[0m") else: _Format = setInputFormat setInputFormat = self.input_format_dict[_Format] if not setInputChannels or int(setInputChannels) > uac_infor_dict["maxInputChannels"]: setInputChannels = uac_infor_dict["maxInputChannels"] self._inforPrintf("\033[0;36;33m[UacAudioInAndOut] 輸入通道未設(shè)置/超出當(dāng)前設(shè)備最大值,使用默認(rèn)最大通道 %s\ \033[0m"%setInputChannels) else: setInputChannels = int(setInputChannels) dev_index = uac_infor_dict["index"] load_parame_dict["index"]=dev_index load_parame_dict["setInputFormat"] = _Format load_parame_dict["_setInputFormat"] = setInputFormat load_parame_dict["setInputChannels"] = setInputChannels UacAudioInHandle = pyaudio.PyAudio() for setInputFramerate in self.framerate_list: if self.is_framerate_supported(setInputFramerate, UacAudioInHandle, load_parame_dict): load_parame_dict["setInputFramerate"] = setInputFramerate break #計(jì)算數(shù)據(jù)大小一段 CHUNK_SIZE = int(setInputFramerate * maxStreamDuration / 1000) load_parame_dict["CHUNK_SIZE"] = CHUNK_SIZE self._inforPrintf("\033[0;36;38m[UacAudioInAndOut] 加載參數(shù): %s\033[0m"%str(load_parame_dict)) #加載設(shè)備 StreamHandle = UacAudioInHandle.open( format=load_parame_dict['_setInputFormat'], channels=load_parame_dict['setInputChannels'], rate=load_parame_dict['setInputFramerate'], input=True, input_device_index=load_parame_dict['index'], start=False, frames_per_buffer=int(CHUNK_SIZE)) #開(kāi)始流獲取 StreamHandle.start_stream() return UacAudioInHandle, StreamHandle, load_parame_dict except: self._inforPrintf("\033[0;36;31m[UacAudioInAndOut] Uac AudioIn 加載失敗\033[0m") return False, False, False def LoadUacAudioOutDevice(self, devKeywordOrIndex): """ 功能: 加載音頻輸出設(shè)備 參數(shù): / 返回值: UacAudioInHandle 或 False """ try: uac_infor_dict = self.GetUacDevInfor(devKeywordOrIndex) UacAudioInHandle = pyaudio.PyAudio() return UacAudioInHandle, uac_infor_dict except: return False def GetUacAudioInStream(self, StreamHandle, CHUNK_SIZE): """ 功能: 開(kāi)始采集聲卡音頻 生成音頻流 參數(shù): UacAudioInHandle: 設(shè)備句柄 StreamHandle: 流句柄 返回值 chunk_data 流數(shù)據(jù) """ return StreamHandle.read(CHUNK_SIZE, exception_on_overflow=False) #防止溢出 def UacAudioOutPlay(self, playWavFile, Repeat=None, Pdict=None, devKeywordOrIndex=None,): """ 功能: 可以循環(huán)播放指定文件 參數(shù): playWavFile: 播放文件路徑 Repeat: 循環(huán)播放次數(shù) CustomizeAudioParam: 自定義播放參數(shù) 返回值: / """ UacAudioInHandle, uac_infor_dict = self.LoadUacAudioOutDevice(devKeywordOrIndex) self._inforPrintf(str(uac_infor_dict).encode("gbk","ignore").decode("gbk")) self._inforPrintf("\033[1;36;34m[UacAudioInAndOut] 指定設(shè)備: %s\t播放文件: %s\t循環(huán)總數(shù): %s\ \033[0m"%(devKeywordOrIndex, playWavFile,Repeat)) try: chunk=1024 pfb = wave.open(playWavFile, 'rb') setOutputFormat = pfb.getsampwidth() setOutputChannels = pfb.getnchannels() setOutputFramerate = pfb.getframerate() uac_infor_dict['setOutputFormat'] = setOutputFormat if setOutputChannels > uac_infor_dict["maxOutputChannels"]: self._inforPrintf("\033[0;36;31m[UacAudioInAndOut] 當(dāng)前通道數(shù),在該設(shè)備上不支持, \ 設(shè)備最大通道數(shù): %s\033[0m"%uac_infor_dict["maxOutputChannels"]) return False if not self.is_framerate_supported(setOutputFramerate, UacAudioInHandle, uac_infor_dict, "output"): self._inforPrintf("\033[0;36;31m[UacAudioInAndOut] 當(dāng)前文件采樣率,在該設(shè)備上不支持,\ 設(shè)備默認(rèn)采樣率: %s\033[0m"%uac_infor_dict["defaultSampleRate"]) return False else: uac_infor_dict["defaultSampleRate"] = setOutputFramerate stream = UacAudioInHandle.open( output_device_index=uac_infor_dict['index'], format=UacAudioInHandle.get_format_from_width(setOutputFormat), channels=setOutputChannels, rate=setOutputFramerate, output=True) if Repeat == "Dead_cycle": self._inforPrintf("\033[1;36;33m[UacAudioInAndOut] Dead cycle play !!! \033[0m") while True: if type(Pdict) == dict and Pdict["play status"] == "stop": break pfb = wave.open(playWavFile, 'rb') while True: data = pfb.readframes(chunk) if not data: break stream.write(data) else: for index in tqdm(range(int(Repeat))): if type(Pdict) == dict and Pdict["play status"] == "stop": break pfb = wave.open(playWavFile, 'rb') while True: data = pfb.readframes(chunk) if not data: break stream.write(data) stream.stop_stream() stream.close() self.CloseAudioDevice(UacAudioInHandle) return True except: stream.stop_stream() stream.close() return False def UacAudioInRecord(self, saveWavFile, recordTime, #單位秒 setInputChannels=None, setInputFormat=None, devKeywordOrIndex=None): """ 功能: 錄制音頻文件 參數(shù): recordTime: 錄音時(shí)長(zhǎng), 單位(s) setInputFramerate: 采樣率 setInputChannels: 通道數(shù) setInputFormat: 位寬 devKeywordOrIndex: 錄音設(shè)備索引 返回值: / """ maxStreamDuration=1000 load_parame_dict = {} UacAudioInHandle, StreamHandle, load_parame_dict = self.LoadUacAudioInDevice( maxStreamDuration, setInputChannels, setInputFormat, devKeywordOrIndex) if not UacAudioInHandle or not StreamHandle: self._inforPrintf("\033[0;36;31m[UacAudioInAndOut] 錄音失敗\033[0m") return False self._inforPrintf("\033[1;36;34m[UacAudioInAndOut] 錄音 -> 文件名: %s 時(shí)長(zhǎng): %s\ \033[0m"%(saveWavFile,recordTime)) self._inforPrintf(load_parame_dict["CHUNK_SIZE"]) data_list = [] for recordTime_index in range(int(recordTime)): data = None data = StreamHandle.read(load_parame_dict["CHUNK_SIZE"], exception_on_overflow=False) data_list.append(data) StreamHandle.stop_stream() StreamHandle.close() self.CloseAudioDevice(UacAudioInHandle) with wave.open(saveWavFile, "wb") as wavfb: wavfb.setnchannels(load_parame_dict["setInputChannels"]) wavfb.setsampwidth(UacAudioInHandle.get_sample_size(load_parame_dict["_setInputFormat"])) wavfb.setframerate(load_parame_dict["setInputFramerate"]) wavfb.writeframes(b''.join(data_list)) """ 功能: 關(guān)閉音頻流設(shè)備 參數(shù): UacAudioInHandle 返回值: bool True/False """ try: StreamHandle.stop_stream() StreamHandle.close() self.CloseAudioDevice() return True except: return False def CloseAudioDevice(self, UacAudioDeviceHandle): """ 功能: 釋放 Audio 設(shè)備 參數(shù): UacAudioDeviceHandle 返回值: bool True/False """ try: UacAudioDeviceHandle.terminate() return True except: return False if __name__=="__main__": asv = UacAudioInAndOut() asv.GetAllDevInfor() #asv.UacAudioOutPlay(sys.argv[1], int(sys.argv[2]), None, sys.argv[3]) asv.UacAudioInRecord(sys.argv[1], sys.argv[2])
以上就是Python+pyaudio實(shí)現(xiàn)音頻控制示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Python pyaudio音頻控制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python 讀寫(xiě)excel文件操作示例【附源碼下載】
這篇文章主要介紹了python 讀寫(xiě)excel文件操作,結(jié)合實(shí)例形式分析了Python基于xlutils導(dǎo)入xlrd,xlwt庫(kù)操作Excel相關(guān)實(shí)現(xiàn)技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2019-06-06Python入門(mén)之使用pandas分析excel數(shù)據(jù)
這篇文章主要給大家介紹了關(guān)于Python入門(mén)學(xué)習(xí)之使用pandas分析excel數(shù)據(jù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用python具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05python數(shù)據(jù)類(lèi)型之間怎么轉(zhuǎn)換技巧分享
在本篇文章里小編給大家分享的是關(guān)于python數(shù)據(jù)類(lèi)型之間怎么轉(zhuǎn)換實(shí)例以及小技巧內(nèi)容,有興趣的朋友們參考下。2019-08-08python下的opencv畫(huà)矩形和文字注釋的實(shí)現(xiàn)方法
今天小編就為大家分享一篇python下的opencv畫(huà)矩形和文字注釋的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07使用Python中的reduce()函數(shù)求積的實(shí)例
今天小編就為大家分享一篇使用Python中的reduce()函數(shù)求積的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-06-06Python第三方庫(kù)h5py_讀取mat文件并顯示值的方法
今天小編就為大家分享一篇Python第三方庫(kù)h5py_讀取mat文件并顯示值的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-02-02Python發(fā)送郵件封裝實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了Python發(fā)送郵件封裝實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05