詳解python的webrtc庫實現(xiàn)語音端點檢測
引言
語音端點檢測最早應(yīng)用于電話傳輸和檢測系統(tǒng)當(dāng)中,用于通信信道的時間分配,提高傳輸線路的利用效率.端點檢測屬于語音處理系統(tǒng)的前端操作,在語音檢測領(lǐng)域意義重大.
但是目前的語音端點檢測,尤其是檢測 人聲 開始和結(jié)束的端點始終是屬于技術(shù)難點,各家公司始終處于 能判斷,但是不敢保證 判別準(zhǔn)確性 的階段.
現(xiàn)在基于云端語義庫的聊天機器人層出不窮,其中最著名的當(dāng)屬amazon的 Alexa/Echo 智能音箱.

國內(nèi)如雨后春筍般出現(xiàn)了各種搭載語音聊天的智能音箱(如前幾天在知乎上廣告的若琪機器人)和各類智能機器人產(chǎn)品.國內(nèi)語音服務(wù)提供商主要面對中文語音服務(wù),由于語音不像圖像有分辨率等等較為客觀的指標(biāo),很多時候憑主觀判斷,所以較難判斷各家語音識別和合成技術(shù)的好壞.但是我個人認為,國內(nèi)的中文語音服務(wù)和國外的英文語音服務(wù),在某些方面已經(jīng)有超越的趨勢.

通常搭建機器人聊天系統(tǒng)主要包括以下三個方面:
- 語音轉(zhuǎn)文字(ASR/STT)
- 語義內(nèi)容(NLU/NLP)
- 文字轉(zhuǎn)語音(TTS)
語音轉(zhuǎn)文字(ASR/STT)
在將語音傳給云端API之前,是本地前端的語音采集,這部分主要包括如下幾個方面:
- 麥克風(fēng)降噪
- 聲源定位
- 回聲消除
- 喚醒詞
- 語音端點檢測
- 音頻格式壓縮
python 端點檢測
由于實際應(yīng)用中,單純依靠能量檢測特征檢測等方法很難判斷人聲說話的起始點,所以市面上大多數(shù)的語音產(chǎn)品都是使用喚醒詞判斷語音起始.另外加上聲音回路,還可以做語音打斷.這樣的交互方式可能有些傻,每次必須喊一下 喚醒詞 才能繼續(xù)聊天.這種方式聊多了,個人感覺會嘴巴疼:-O .現(xiàn)在github上有snowboy喚醒詞的開源庫,大家可以登錄snowboy官網(wǎng)訓(xùn)練自己的喚醒詞模型.
考慮到用喚醒詞嘴巴會累,所以大致調(diào)研了一下,Python擁有豐富的庫,直接import就能食用.這種方式容易受強噪聲干擾,適合一個人在家玩玩.
- pyaudio: pip install pyaudio 可以從設(shè)備節(jié)點讀取原始音頻流數(shù)據(jù),音頻編碼是PCM格式;
- webrtcvad: pip install webrtcvad 檢測判斷一組語音數(shù)據(jù)是否為空語音;
當(dāng)檢測到持續(xù)時間長度 T1 vad檢測都有語音活動,可以判定為語音起始;
當(dāng)檢測到持續(xù)時間長度 T2 vad檢測都沒有有語音活動,可以判定為語音結(jié)束;
完整程序代碼可以從我的github下載
程序很簡單,相信看一會兒就明白了
'''
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()
程序運行方式sudo python vad.py
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
pyTorch深入學(xué)習(xí)梯度和Linear Regression實現(xiàn)
這篇文章主要介紹了pyTorch深入學(xué)習(xí),實現(xiàn)梯度和Linear Regression,文中呈現(xiàn)了詳細的示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09
Python在終端通過pip安裝好包以后在Pycharm中依然無法使用的問題(三種解決方案)
這篇文章主要介紹了Python在終端通過pip安裝好包以后在Pycharm中依然無法使用的問題及解決方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03
Django數(shù)據(jù)結(jié)果集序列化并展示實現(xiàn)過程
這篇文章主要介紹了Django數(shù)據(jù)結(jié)果集序列化并展示實現(xiàn)過程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-04-04
pycharm配置SSH遠程連接服務(wù)器詳細步驟(0基礎(chǔ)詳細版)
PyCharm是一款流行的Python集成開發(fā)環(huán)境(IDE),提供了遠程連接云服務(wù)器的功能,使得開發(fā)者可以更加便捷地進行遠程開發(fā)和調(diào)試,這篇文章主要給大家介紹了關(guān)于pycharm配置SSH遠程連接服務(wù)器的詳細步驟,需要的朋友可以參考下2024-07-07
Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)將多個映射合并為單個映射的方法
這篇文章主要介紹了Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)將多個映射合并為單個映射的方法,結(jié)合實例形式分析了Python字典映射合并操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2018-04-04
詳談Python 窗體(tkinter)表格數(shù)據(jù)(Treeview)
今天小編就為大家分享一篇詳談Python 窗體(tkinter)表格數(shù)據(jù)(Treeview),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10
pandas中DataFrame排序及分組排序的實現(xiàn)示例
本文主要介紹了pandas中DataFrame排序及分組排序,pandas中的sort_values()函數(shù)原理類似于SQL中的order by,可以將數(shù)據(jù)集依照某個字段中的數(shù)據(jù)進行排序,下面就來具體介紹一下,感興趣的可以了解一下2024-04-04
深度學(xué)習(xí)tensorflow基礎(chǔ)mnist
mnist作為深度學(xué)習(xí)中的HelloWorld,該小工程詳細描述了如何從零開始深度學(xué)習(xí),代碼詳細,解釋全面,需要的朋友可以參考下2021-04-04

