詳解python的webrtc庫(kù)實(shí)現(xiàn)語(yǔ)音端點(diǎn)檢測(cè)
引言
語(yǔ)音端點(diǎn)檢測(cè)最早應(yīng)用于電話(huà)傳輸和檢測(cè)系統(tǒng)當(dāng)中,用于通信信道的時(shí)間分配,提高傳輸線(xiàn)路的利用效率.端點(diǎn)檢測(cè)屬于語(yǔ)音處理系統(tǒng)的前端操作,在語(yǔ)音檢測(cè)領(lǐng)域意義重大.
但是目前的語(yǔ)音端點(diǎn)檢測(cè),尤其是檢測(cè) 人聲 開(kāi)始和結(jié)束的端點(diǎn)始終是屬于技術(shù)難點(diǎn),各家公司始終處于 能判斷,但是不敢保證 判別準(zhǔn)確性 的階段.
現(xiàn)在基于云端語(yǔ)義庫(kù)的聊天機(jī)器人層出不窮,其中最著名的當(dāng)屬amazon的 Alexa/Echo 智能音箱.
國(guó)內(nèi)如雨后春筍般出現(xiàn)了各種搭載語(yǔ)音聊天的智能音箱(如前幾天在知乎上廣告的若琪機(jī)器人)和各類(lèi)智能機(jī)器人產(chǎn)品.國(guó)內(nèi)語(yǔ)音服務(wù)提供商主要面對(duì)中文語(yǔ)音服務(wù),由于語(yǔ)音不像圖像有分辨率等等較為客觀(guān)的指標(biāo),很多時(shí)候憑主觀(guān)判斷,所以較難判斷各家語(yǔ)音識(shí)別和合成技術(shù)的好壞.但是我個(gè)人認(rèn)為,國(guó)內(nèi)的中文語(yǔ)音服務(wù)和國(guó)外的英文語(yǔ)音服務(wù),在某些方面已經(jīng)有超越的趨勢(shì).
通常搭建機(jī)器人聊天系統(tǒng)主要包括以下三個(gè)方面:
- 語(yǔ)音轉(zhuǎn)文字(ASR/STT)
- 語(yǔ)義內(nèi)容(NLU/NLP)
- 文字轉(zhuǎn)語(yǔ)音(TTS)
語(yǔ)音轉(zhuǎn)文字(ASR/STT)
在將語(yǔ)音傳給云端API之前,是本地前端的語(yǔ)音采集,這部分主要包括如下幾個(gè)方面:
- 麥克風(fēng)降噪
- 聲源定位
- 回聲消除
- 喚醒詞
- 語(yǔ)音端點(diǎn)檢測(cè)
- 音頻格式壓縮
python 端點(diǎn)檢測(cè)
由于實(shí)際應(yīng)用中,單純依靠能量檢測(cè)特征檢測(cè)等方法很難判斷人聲說(shuō)話(huà)的起始點(diǎn),所以市面上大多數(shù)的語(yǔ)音產(chǎn)品都是使用喚醒詞判斷語(yǔ)音起始.另外加上聲音回路,還可以做語(yǔ)音打斷.這樣的交互方式可能有些傻,每次必須喊一下 喚醒詞 才能繼續(xù)聊天.這種方式聊多了,個(gè)人感覺(jué)會(huì)嘴巴疼:-O .現(xiàn)在github上有snowboy喚醒詞的開(kāi)源庫(kù),大家可以登錄snowboy官網(wǎng)訓(xùn)練自己的喚醒詞模型.
考慮到用喚醒詞嘴巴會(huì)累,所以大致調(diào)研了一下,Python擁有豐富的庫(kù),直接import就能食用.這種方式容易受強(qiáng)噪聲干擾,適合一個(gè)人在家玩玩.
- pyaudio: pip install pyaudio 可以從設(shè)備節(jié)點(diǎn)讀取原始音頻流數(shù)據(jù),音頻編碼是PCM格式;
- webrtcvad: pip install webrtcvad 檢測(cè)判斷一組語(yǔ)音數(shù)據(jù)是否為空語(yǔ)音;
當(dāng)檢測(cè)到持續(xù)時(shí)間長(zhǎng)度 T1 vad檢測(cè)都有語(yǔ)音活動(dòng),可以判定為語(yǔ)音起始;
當(dāng)檢測(cè)到持續(xù)時(shí)間長(zhǎng)度 T2 vad檢測(cè)都沒(méi)有有語(yǔ)音活動(dòng),可以判定為語(yǔ)音結(jié)束;
完整程序代碼可以從我的github下載
程序很簡(jiǎn)單,相信看一會(huì)兒就明白了
''' Requirements: + pyaudio - `pip install pyaudio` + py-webrtcvad - `pip install webrtcvad` ''' import webrtcvad import collections import sys import signal import pyaudio from array import array from struct import pack import wave import time FORMAT = pyaudio.paInt16 CHANNELS = 1 RATE = 16000 CHUNK_DURATION_MS = 30 # supports 10, 20 and 30 (ms) PADDING_DURATION_MS = 1500 # 1 sec jugement CHUNK_SIZE = int(RATE CHUNK_DURATION_MS / 1000) # chunk to read CHUNK_BYTES = CHUNK_SIZE 2 # 16bit = 2 bytes, PCM NUM_PADDING_CHUNKS = int(PADDING_DURATION_MS / CHUNK_DURATION_MS) # NUM_WINDOW_CHUNKS = int(240 / CHUNK_DURATION_MS) NUM_WINDOW_CHUNKS = int(400 / CHUNK_DURATION_MS) # 400 ms/ 30ms ge NUM_WINDOW_CHUNKS_END = NUM_WINDOW_CHUNKS 2 START_OFFSET = int(NUM_WINDOW_CHUNKS CHUNK_DURATION_MS 0.5 RATE) vad = webrtcvad.Vad(1) pa = pyaudio.PyAudio() stream = pa.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, start=False, # input_device_index=2, frames_per_buffer=CHUNK_SIZE) got_a_sentence = False leave = False def handle_int(sig, chunk): global leave, got_a_sentence leave = True got_a_sentence = True def record_to_file(path, data, sample_width): "Records from the microphone and outputs the resulting data to 'path'" # sample_width, data = record() data = pack('<' + ('h' len(data)), data) wf = wave.open(path, 'wb') wf.setnchannels(1) wf.setsampwidth(sample_width) wf.setframerate(RATE) wf.writeframes(data) wf.close() def normalize(snd_data): "Average the volume out" MAXIMUM = 32767 # 16384 times = float(MAXIMUM) / max(abs(i) for i in snd_data) r = array('h') for i in snd_data: r.append(int(i times)) return r signal.signal(signal.SIGINT, handle_int) while not leave: ring_buffer = collections.deque(maxlen=NUM_PADDING_CHUNKS) triggered = False voiced_frames = [] ring_buffer_flags = [0] NUM_WINDOW_CHUNKS ring_buffer_index = 0 ring_buffer_flags_end = [0] NUM_WINDOW_CHUNKS_END ring_buffer_index_end = 0 buffer_in = '' # WangS raw_data = array('h') index = 0 start_point = 0 StartTime = time.time() print(" recording: ") stream.start_stream() while not got_a_sentence and not leave: chunk = stream.read(CHUNK_SIZE) # add WangS raw_data.extend(array('h', chunk)) index += CHUNK_SIZE TimeUse = time.time() - StartTime active = vad.is_speech(chunk, RATE) sys.stdout.write('1' if active else '_') ring_buffer_flags[ring_buffer_index] = 1 if active else 0 ring_buffer_index += 1 ring_buffer_index %= NUM_WINDOW_CHUNKS ring_buffer_flags_end[ring_buffer_index_end] = 1 if active else 0 ring_buffer_index_end += 1 ring_buffer_index_end %= NUM_WINDOW_CHUNKS_END # start point detection if not triggered: ring_buffer.append(chunk) num_voiced = sum(ring_buffer_flags) if num_voiced > 0.8 NUM_WINDOW_CHUNKS: sys.stdout.write(' Open ') triggered = True start_point = index - CHUNK_SIZE 20 # start point # voiced_frames.extend(ring_buffer) ring_buffer.clear() # end point detection else: # voiced_frames.append(chunk) ring_buffer.append(chunk) num_unvoiced = NUM_WINDOW_CHUNKS_END - sum(ring_buffer_flags_end) if num_unvoiced > 0.90 NUM_WINDOW_CHUNKS_END or TimeUse > 10: sys.stdout.write(' Close ') triggered = False got_a_sentence = True sys.stdout.flush() sys.stdout.write('\n') # data = b''.join(voiced_frames) stream.stop_stream() print(" done recording") got_a_sentence = False # write to file raw_data.reverse() for index in range(start_point): raw_data.pop() raw_data.reverse() raw_data = normalize(raw_data) record_to_file("recording.wav", raw_data, 2) leave = True stream.close()
程序運(yùn)行方式sudo python vad.py
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Python如何實(shí)現(xiàn)文本轉(zhuǎn)語(yǔ)音
- Python實(shí)現(xiàn)簡(jiǎn)單的語(yǔ)音識(shí)別系統(tǒng)
- Python語(yǔ)言實(shí)現(xiàn)百度語(yǔ)音識(shí)別API的使用實(shí)例
- python在命令行下使用google翻譯(帶語(yǔ)音)
- python實(shí)現(xiàn)百度語(yǔ)音識(shí)別api
- python調(diào)用百度語(yǔ)音識(shí)別實(shí)現(xiàn)大音頻文件語(yǔ)音識(shí)別功能
- python調(diào)用百度REST API實(shí)現(xiàn)語(yǔ)音識(shí)別
- python調(diào)用百度語(yǔ)音REST API
- python調(diào)用百度語(yǔ)音識(shí)別api
- python語(yǔ)音識(shí)別實(shí)踐之百度語(yǔ)音API
相關(guān)文章
pyTorch深入學(xué)習(xí)梯度和Linear Regression實(shí)現(xiàn)
這篇文章主要介紹了pyTorch深入學(xué)習(xí),實(shí)現(xiàn)梯度和Linear Regression,文中呈現(xiàn)了詳細(xì)的示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09Python在終端通過(guò)pip安裝好包以后在Pycharm中依然無(wú)法使用的問(wèn)題(三種解決方案)
這篇文章主要介紹了Python在終端通過(guò)pip安裝好包以后在Pycharm中依然無(wú)法使用的問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03不到20行代碼用Python做一個(gè)智能聊天機(jī)器人
小編先向大家介紹一下本次運(yùn)用到的python庫(kù),本次項(xiàng)目主要運(yùn)用到的庫(kù)有wxpy和chatterbot。對(duì)Python做一個(gè)智能聊天機(jī)器人的相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧2019-04-04Django數(shù)據(jù)結(jié)果集序列化并展示實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了Django數(shù)據(jù)結(jié)果集序列化并展示實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04pycharm配置SSH遠(yuǎn)程連接服務(wù)器詳細(xì)步驟(0基礎(chǔ)詳細(xì)版)
PyCharm是一款流行的Python集成開(kāi)發(fā)環(huán)境(IDE),提供了遠(yuǎn)程連接云服務(wù)器的功能,使得開(kāi)發(fā)者可以更加便捷地進(jìn)行遠(yuǎn)程開(kāi)發(fā)和調(diào)試,這篇文章主要給大家介紹了關(guān)于pycharm配置SSH遠(yuǎn)程連接服務(wù)器的詳細(xì)步驟,需要的朋友可以參考下2024-07-07pandas去除重復(fù)列的實(shí)現(xiàn)方法
這篇文章主要介紹了pandas去除重復(fù)列的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)將多個(gè)映射合并為單個(gè)映射的方法
這篇文章主要介紹了Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)將多個(gè)映射合并為單個(gè)映射的方法,結(jié)合實(shí)例形式分析了Python字典映射合并操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-04-04詳談Python 窗體(tkinter)表格數(shù)據(jù)(Treeview)
今天小編就為大家分享一篇詳談Python 窗體(tkinter)表格數(shù)據(jù)(Treeview),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10pandas中DataFrame排序及分組排序的實(shí)現(xiàn)示例
本文主要介紹了pandas中DataFrame排序及分組排序,pandas中的sort_values()函數(shù)原理類(lèi)似于SQL中的order by,可以將數(shù)據(jù)集依照某個(gè)字段中的數(shù)據(jù)進(jìn)行排序,下面就來(lái)具體介紹一下,感興趣的可以了解一下2024-04-04深度學(xué)習(xí)tensorflow基礎(chǔ)mnist
mnist作為深度學(xué)習(xí)中的HelloWorld,該小工程詳細(xì)描述了如何從零開(kāi)始深度學(xué)習(xí),代碼詳細(xì),解釋全面,需要的朋友可以參考下2021-04-04