基于C#實(shí)現(xiàn)語音預(yù)處理
無論是在音視頻錄制系統(tǒng),還是音視頻通話系統(tǒng)、或視頻會(huì)議系統(tǒng)中,對從麥克風(fēng)采集到的說話的聲音數(shù)據(jù)進(jìn)行預(yù)處理,都是是非常必要的。
語音數(shù)據(jù)預(yù)處理主要包括:??降噪(Noise Reduction)、靜音檢測(Silence Detection/VAD)、自動(dòng)增益(Automatic Gain Control, AGC)?? 。
一. 語音預(yù)處理的作用
我們先解釋一下,降噪、靜音檢測、自動(dòng)增益,這些語音預(yù)處理分別起什么作用。
(1)降噪
降噪,用于消除背景噪聲,比如馬路車流聲、環(huán)境雜音等,以保留清晰的說話人聲。
更高級的,結(jié)合AI模型訓(xùn)練,還可以消除電腦的風(fēng)扇聲、鍵盤敲擊聲等等。
(2)靜音檢測
靜音檢測,又稱為語音活動(dòng)檢測,用于識(shí)別音頻流中的靜音片段(沒有講話人聲),這樣可以簡化后續(xù)的編碼等環(huán)節(jié),并可以節(jié)省傳遞所需要的帶寬。
(3)自動(dòng)增益
自動(dòng)增益,用于動(dòng)態(tài)調(diào)整說話聲音的音量,使輸出電平保持穩(wěn)定,以避免講話的聲音忽大忽小。
二. 實(shí)現(xiàn)語音預(yù)處理
接下來,我們使用C#實(shí)現(xiàn)一個(gè)Demo,這個(gè)Demo將從麥克風(fēng)采集聲音數(shù)據(jù),然后進(jìn)行語音預(yù)處理,并且將處理后的聲音數(shù)據(jù)實(shí)時(shí)播放出來。Demo的運(yùn)行效果如下圖所示:

Demo 功能很簡單,那我們來具體看看代碼是如何實(shí)現(xiàn)的。
1. 創(chuàng)建采集器、預(yù)處理器、播放器
麥克風(fēng)聲音數(shù)據(jù)采樣率我們選擇16K、單聲道。
WaveSampleRate sr = WaveSampleRate.S16k; int channelCount = 1; //創(chuàng)建語音預(yù)處理器,開啟降噪、自動(dòng)增益、靜音檢測 this.voicePreprocessor = CapturerFactory.CreateVoicePreprocessor(sr, channelCount, true ,true); //創(chuàng)建麥克風(fēng)采集器 this.microphoneCapturer = CapturerFactory.CreateMicrophoneCapturer(int.Parse(this.textBox_mic.Text), sr); this.microphoneCapturer.AudioCaptured += new ESBasic.CbGeneric<byte[]>(microphoneCapturer_AudioCaptured); //創(chuàng)建聲音播放器 this.audioPlayer = PlayerFactory.CreateAudioPlayer(int.Parse(this.textBox_speaker.Text), (int)sr, channelCount, 16, 2); this.microphoneCapturer.Start();
CreateVoicePreprocessor 方法的最后兩個(gè)參數(shù)可以指定在降噪的同時(shí),是否開啟靜音檢測和自動(dòng)增益功能。
2. 預(yù)處理語音數(shù)據(jù)
語音預(yù)處理器每次處理10ms的聲音數(shù)據(jù),而現(xiàn)在的麥克風(fēng)采集器每次采集的是20ms的PCM數(shù)據(jù),所以,我們將其拆成兩個(gè)10ms數(shù)據(jù),再提交給預(yù)處理器處理。
void microphoneCapturer_AudioCaptured(byte[] audioData)
{
if (this.checkBox_enabled.Checked)
{
//麥克風(fēng)每次采集20ms數(shù)據(jù),降噪器每次處理10ms數(shù)據(jù)。
byte[] frame10ms1 = new byte[audioData.Length / 2];
byte[] frame10ms2 = new byte[audioData.Length / 2];
Buffer.BlockCopy(audioData, 0, frame10ms1, 0, frame10ms1.Length);
Buffer.BlockCopy(audioData, frame10ms1.Length, frame10ms2, 0, frame10ms2.Length);
this.HandleData(frame10ms1);
this.HandleData(frame10ms2);
return;
}
this.audioPlayer.Play(audioData);
}(1)通過一個(gè)CheckBox勾選框來實(shí)時(shí)控制是否啟用語音預(yù)處理,這樣在測試時(shí),就可以很方便的對比體驗(yàn)開啟了語音預(yù)處理的效果。
(2)調(diào)用IVoicePreprocessor 的 Process 方法,就可以完成一幀語音數(shù)據(jù)(10ms)的預(yù)處理。如下所示:
private void HandleData(byte[] frame10ms)
{
byte[] res = this.voicePreprocessor.Process(frame10ms);
if (res == null) //靜音幀
{
++this.silenceFrameCountTotal;
this.audioPlayer.Play(this.voicePreprocessor.SlienceFrame);
}
else
{
this.audioPlayer.Play(res);
}
}如果Process 方法返回的是null,表示檢測到該幀是靜音幀,于是,將內(nèi)置的10ms靜音幀 SlienceFrame 提交給播放器去播放。
3. 統(tǒng)計(jì)靜音幀數(shù)量
一個(gè)語音幀是10ms,那么1秒鐘就有100個(gè)語音幀,程序中,我們統(tǒng)計(jì)了上一秒出現(xiàn)了多少個(gè)靜音幀,并在UI左下方顯示出來。
private volatile int silenceFrameCountTotal = 0;
private volatile int silenceFrameCountPre = 0;
private void timer1_Tick(object sender, EventArgs e)
{
int delt = this.silenceFrameCountTotal - this.silenceFrameCountPre;
this.silenceFrameCountPre = this.silenceFrameCountTotal;
//顯示上一秒靜音幀數(shù)量。
this.label_silenceFrameCount.Text = delt.ToString();
}實(shí)際測試時(shí)可以發(fā)現(xiàn),當(dāng)不說話時(shí),UI實(shí)時(shí)顯示1秒鐘出現(xiàn)的靜音幀是100個(gè)。
到此這篇關(guān)于基于C#實(shí)現(xiàn)語音預(yù)處理的文章就介紹到這了,更多相關(guān)C#語音預(yù)處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#程序提示“正由另一進(jìn)程使用,因此該進(jìn)程無法訪問該文件”的解決辦法
這篇文章主要介紹了C#程序提示“正由另一進(jìn)程使用,因此該進(jìn)程無法訪問該文件”的解決辦法,本文通過改寫程序代碼實(shí)現(xiàn)解決這個(gè)問題,需要的朋友可以參考下2015-06-06
C#中結(jié)構(gòu)(struct)的部分初始化和完全初始化實(shí)例分析
這篇文章主要介紹了C#中結(jié)構(gòu)(struct)的部分初始化和完全初始化,通過實(shí)例分析了結(jié)構(gòu)初始化中常見的錯(cuò)誤及技巧,有助于加深對C#結(jié)構(gòu)(struct)的認(rèn)識(shí),需要的朋友可以參考下2014-09-09
c# 實(shí)現(xiàn)圓形的進(jìn)度條(ProgressBar)
這篇文章主要介紹了c# 如何實(shí)現(xiàn)圓形的進(jìn)度條(ProgressBar),幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03
C#將圖片和字節(jié)流互相轉(zhuǎn)換并顯示到頁面上
本文主要介紹用C#實(shí)現(xiàn)圖片轉(zhuǎn)換成字節(jié)流,字節(jié)流轉(zhuǎn)換成圖片,并根據(jù)圖片路徑返回圖片的字節(jié)流,有需要的朋友可以參考下2015-08-08

