日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

【VS开发】【智能语音处理】Windows下麦克风语音采集

發(fā)布時(shí)間:2023/11/27 生活经验 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【VS开发】【智能语音处理】Windows下麦克风语音采集 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡介

?? 這是我很早以前的大學(xué)畢業(yè)設(shè)計(jì),忽然間找到貼出來以紀(jì)念自己的純真年代...但是因?yàn)镃SDN不給面子所以導(dǎo)致短短的一篇文章貼了足足7次..他老提時(shí)說文章超過了64K,老大,拜托,那是算上了里面的圖片大小吧...:-(

?? 本文簡單介紹了聲卡的工作原理?,?錄音的原理以及數(shù)字音頻的基本知識并且利用?Windows?提供的?Waveform Aduio APIs?以及?Multimedia File I/O APIs?實(shí)現(xiàn)一個(gè)?Windows?環(huán)境下的麥克風(fēng)錄音以及將錄音文件保存成?.wav?文件的簡單系統(tǒng)?.

?

關(guān)鍵字

??Waveform Aduio APIs, Multimedia File I/O APIs,waveInXXX,

mmioXXX,?麥克風(fēng)?,?錄音?,?波形文件?,VC6++

?

??要深入的了解麥克風(fēng)錄音的實(shí)現(xiàn)我們必須了解聲卡的工作原理?,麥克風(fēng)錄音的原理以及了解相關(guān)的編程接口,下面我們將慢慢道來…

?

1.?聲卡的工作原理

?

聲卡的工作原理其實(shí)很簡單?,我們知道,麥克風(fēng)和喇叭所用的都是模擬信號,而電腦所能處理的都是數(shù)字信號,兩者不能混用,聲卡的作用就是實(shí)現(xiàn)兩者的轉(zhuǎn)換。從結(jié)構(gòu)上分,聲卡可分為模數(shù)轉(zhuǎn)換電路和數(shù)模轉(zhuǎn)換電路兩部分,模數(shù)轉(zhuǎn)換電路負(fù)責(zé)將麥克風(fēng)等聲音輸入設(shè)備采到的模擬聲音信號轉(zhuǎn)換為電腦能處理的數(shù)字信號,而數(shù)模轉(zhuǎn)換電路負(fù)責(zé)將電腦使用的數(shù)字聲音信號轉(zhuǎn)換為喇叭等設(shè)備能使用的模擬信號,就這么簡單?。
?
上圖就是一塊典型的聲卡?,?Mic?插口?用于連接麥克風(fēng)?,?通過它可以錄制外界的聲音

2.?數(shù)字音頻基礎(chǔ)知識

??麥克風(fēng)錄音的過程其實(shí)就是將模擬信號轉(zhuǎn)化成數(shù)字信號的過程?,?其中涉及的一些概念如下?:

?1.?采樣率?(Sampling Rate)

????采樣率指聲卡在一秒之中對聲音?(?波形?)?作記錄的次數(shù)?,?根據(jù)研究聲音播出時(shí)的質(zhì)量常常只能達(dá)到采樣率的一半?,?因此必須采取雙倍的采樣率才能將聲音標(biāo)準(zhǔn)重現(xiàn)?.?也就是只要采樣率大于原始信號頻率的兩倍以上即可減低錯(cuò)誤?,?達(dá)到和原始聲音差不多的質(zhì)量?.?人的聽力大概是?20KHZ,?所以高品質(zhì)的采樣率應(yīng)為其兩倍以上?.

????當(dāng)聲音來源為音樂時(shí)?,?因?yàn)樗鶛M跨的頻率變化極為寬廣?,?通常以?44.1KHZ?的頻率為?CD?音樂采樣率的標(biāo)準(zhǔn)?.?但是若以語言為主由于人說話的語音大概是?10KHZ,?因此加倍采樣?,?只取?22KHZ?即可?,?采樣率越高所記錄下來的音質(zhì)就越清晰?,?當(dāng)然?,?越高的采樣所記錄下的文件就越大?.

??2.?采樣位

????解析度決定了采樣的音波是否能保持原來的形狀?,?越接近原型則需解析度越高?,?若以?8?位來采樣的話其能表達(dá)的組合種類是?2?的?8?次方?,?即?256,?表示用?8?位的采樣大小能分辨出?256?個(gè)層次的聲音?,?若用?16?位來采樣?,?則能分辨的差異將高達(dá)?2?的?16?次方?,?為?65536,?其精度自然大為提高?.16?位?,8?位采樣的差別在于動態(tài)范圍的寬窄?,?動態(tài)范圍寬廣?,?音量起伏的大小變化就能夠更精細(xì)的被記錄下來?,?如此一來不論是細(xì)微的聲音或是強(qiáng)烈的動感震撼?,?都可以表現(xiàn)的淋漓盡致?,?而?CD?音質(zhì)的采樣規(guī)格正式?16?位采樣的規(guī)格?.

??3.?量化誤差?(Quantization error)

???????在采樣的過程中?,?不斷連續(xù)變化的模擬信號要用數(shù)字化的數(shù)值來表示?,?這樣的過程就會發(fā)生所謂的量化誤差?(Quantization error).?所謂的量化誤差指的是實(shí)際的信號的振幅?(smplitude)?和數(shù)字化之后所的數(shù)字之間的差異?.?如果用將數(shù)字信號還原成模擬信號的角度看?,?量化誤差就是失真?(Distortion).?我們可以用增加采樣大小的方式來降低量化誤差?,?也就是更多的位?(bits)?來表示一個(gè)采樣信號?,?這樣可以提高精度?.

?4.?量化?(Quantization),?線性量化法?(Linear quantization)?和非線性量化法?(Nonlinear quantization)

???????所謂的量化?(Quantization)?就是將模擬信號所代表的連續(xù)范圍分成一段一段的區(qū)間?(Interval),?每一段區(qū)間我們定義一個(gè)數(shù)字化的值?.?區(qū)間的數(shù)目是跟采樣大小有關(guān)?,?舉例來說?,?有一種最簡單的量化法稱為?”?線性量化法?”(Linear quantization),?這種量化法采用等距離的間隔空間?,?架設(shè)一個(gè)訊號它的最大值是?5.0,?采樣大小為?3?位?,?則每個(gè)量化區(qū)間就時(shí)?5.0/2^3,?也就是?0.625?單位?.?另外一種相反的量化方法就是?”?非線性量化法?”(Nonlinear quantization),?這種量化法采用不同的間隔空間?.?以?”?對數(shù)量化法?”(Logarithm quantization)?為例?.?低振幅范圍的量化區(qū)間就比高振幅的范圍的區(qū)間較為接近?,?用這種量化的法產(chǎn)生的結(jié)果就是在低振幅時(shí)我們會得到佳好的效果?.?通常如果使用同樣的采樣大小?,?非線性量化法會比線性量化法得到更好的聲音品質(zhì)?.?但是如果是要對聲音做濾波?(filtered)?或一些運(yùn)算的時(shí)候?,?使用線性量化法會比較容易處理?.

?5.?聲音強(qiáng)度

?????????波形振幅的平方.兩個(gè)聲音強(qiáng)度上的差常以分貝?(db)?為單位來度量?,計(jì)算公式如下:

????20*log(A1/A2)?分貝?,?A1,A2?為兩個(gè)聲音的振幅?.

a.?如果采樣大小為?8?位?,則采樣的動態(tài)范圍為?20*log(256)?分貝?=48db;

b.?如果樣本大小為?16?位?,則采樣動態(tài)范圍為?20*log(65536)?大約是?96?分貝?,接近了人聽覺極限和痛苦極限,是再線音樂的理想范圍,?windows?同時(shí)支持8?位和?16?位的采樣大小?.

?

?6.?音頻編碼方法

??????目前已經(jīng)發(fā)展了許多音頻編碼的方法用以減少存儲量或是傳輸?shù)臅r(shí)間?,?以下所列為兩種較普遍的編碼方法?:

???a.PCM(Pulse code modulation);

脈沖編碼調(diào)制?,即對波形按照固定周期頻率采樣。為了保證采樣后數(shù)據(jù)質(zhì)量,采樣頻率必須是樣本聲音最高頻率的兩倍,這就是?Nyquist?頻率?.

???b.ADPCM(Adaptive delta pulse modulation).

3.?RIFF?文件結(jié)構(gòu)和?WAVE?文件格式?

  ?Windows?支持兩種?RIFF(Resource Interchange File Format,"?資源交互文件格式?")?格式的音頻文件:?MIDI?的?RMID?文件和波形音頻文件格式WAVE?文件,其中在計(jì)算機(jī)領(lǐng)域最常用的數(shù)字化聲音文件格式是后者,它是微軟專門為?Windows?系統(tǒng)定義的波形文件格式(?Waveform Audio?),由于其擴(kuò)展名為?"*.wav"?,因而該類文件也被稱為?WAVE?文件。?為了突出重點(diǎn),有的放矢,本文涉及到的聲音文件所指的就是?WAVE?文件。常見的?WAVE?語音文件主要有兩種,分別對應(yīng)于單聲道(?11.025KHz?采樣率、?8Bit?的采樣值)和雙聲道(?44.1KHz?采樣率、?16Bit?的采樣值)。這里的采樣率是指聲音信號在進(jìn)行?"?模→數(shù)?"?轉(zhuǎn)換過程中單位時(shí)間內(nèi)采樣的次數(shù)。采樣值是指每一次采樣周期內(nèi)聲音模擬信號的積分值。對于單聲道聲音文件,采樣數(shù)據(jù)為八位的短整數(shù)(short int 00H-FFH?);而對于雙聲道立體聲聲音文件,每次采樣數(shù)據(jù)為一個(gè)?16?位的整數(shù)(?int?),高八位和低八位分別代表左右兩個(gè)聲道。?WAVE?文件數(shù)據(jù)塊包含以脈沖編碼調(diào)制(?PCM?)格式表示的樣本。在進(jìn)行聲音編程處理以前,首先讓我們來了解一下?RIFF?文件和?WAVE?文件格式。?

  ?RIFF?文件結(jié)構(gòu)可以看作是樹狀結(jié)構(gòu),其基本構(gòu)成是稱為?"?塊?"?(?Chunk?)的單元,每個(gè)塊有?"?標(biāo)志符?"?、?"?數(shù)據(jù)大小?"?及?"?數(shù)據(jù)?"?所組成,塊的結(jié)構(gòu)如圖?2?所示:

?

塊的標(biāo)志符(?4BYTES?)

數(shù)據(jù)大小?(?4BYTES?)

數(shù)據(jù)

????????????? ????????????????????????????????????????圖?2?

  從上圖可以看出,其中?"?標(biāo)志符?"?為?4?個(gè)字符所組成的代碼,如?"RIFF"?,?"LIST"?等,指定塊的標(biāo)志?ID?;數(shù)據(jù)大小用來指定塊的數(shù)據(jù)域大小,它的尺寸也為?4?個(gè)字符;數(shù)據(jù)用來描述具體的聲音信號,它可以由若干個(gè)子塊構(gòu)成,一般情況下塊與塊是平行的,不能相互嵌套,但是有兩種類型的塊可以嵌套子塊,他們是?"RIFF"?或?"LIST"?標(biāo)志的塊,其中?RIFF?塊的級別最高,它可以包括?LIST?塊。另外,?RIFF?塊和?LIST?塊與其他塊不同,?RIFF?塊的數(shù)據(jù)總是以一個(gè)指定文件中數(shù)據(jù)存儲格式的四個(gè)字符碼(稱為格式類型)開始,如?WAVE?文件有一個(gè)?"WAVE"?的格式類型。?LIST?塊的數(shù)據(jù)總是以一個(gè)指定列表內(nèi)容的?4?個(gè)字符碼(稱為列表類型)開始,例如擴(kuò)展名為?".AVI"?的視頻文件就有一個(gè)?"strl"?的列表類型。?RIFF?和?LIST?的塊結(jié)構(gòu)如下:

RIFF/LIST?標(biāo)志符

數(shù)據(jù)?1?大小

數(shù)據(jù)?1

格式?/?列表類型

數(shù)據(jù)

????????????????????????????????????????????????圖?3?

  ?WAVE?文件是非常簡單的一種?RIFF?文件,它的格式類型為?"WAVE"?。?RIFF?塊包含兩個(gè)子塊,這兩個(gè)子塊的?ID?分別是?"fmt"?和?"data",?其中?"fmt"?子塊由結(jié)構(gòu)?PCMWAVEFORMAT?所組成,其子塊的大小就是?sizeofof(PCMWAVEFORMAT),?數(shù)據(jù)組成就是?PCMWAVEFORMAT?結(jié)構(gòu)中的數(shù)據(jù)。?WAVE?文件的結(jié)構(gòu)如下圖?4?所示:

標(biāo)志符(?RIFF?)

數(shù)據(jù)大小

格式類型(?"WAVE"?)

"fmt"

Sizeof(PCMWAVEFORMAT)

PCMWAVEFORMAT

"data"

聲音數(shù)據(jù)大小

聲音數(shù)據(jù)

????????????????????????????????????????????????????圖?4?

  ?PCMWAVEFORMAT?結(jié)構(gòu)定義如下:

typedef struct
{
?????WAVEFORMAT wf;?????????//?波形格式?,?前面已經(jīng)提過了?;?
?????WORD wBitsPerSample;// WAVE?文件的采樣大小;?
}PCMWAVEFORMAT
?"data"子塊包含WAVE文件的數(shù)字化波形聲音數(shù)據(jù),其存放格式依賴于"fmt"子塊中wFormatTag成員指定的格式種類,在多聲道WAVE文件中,樣本是交替出現(xiàn)的。如16bit的單聲道WAVE文件和雙聲道WAVE文件的數(shù)據(jù)采樣格式分別如圖5所示:

  16位單聲道:

采樣一

采樣二

……

低字節(jié)

高字節(jié)

低字節(jié)

高字節(jié)

……


  ?16?位雙聲道:

采樣一?……

左聲道

右聲道

……

低字節(jié)

高字節(jié)

低字節(jié)

高字節(jié)

……


???????????????             ?圖?5

?

4.?硬件抽象層?(?HAL,?Hardware Abstraction?Layer?)

?????HAL?是一個(gè)可加載的核心模塊?(HAL.dll)?,它為運(yùn)行在?Windows NT?架構(gòu)?(?包括?WindowsNT4.0,Windows2000,WindowsXP)?上?的硬件平臺提供低級接口?,?HAL?隱藏各種與硬件有關(guān)的細(xì)節(jié)?,例如:?I/O?接口?,中斷控制器,聲卡…這樣的話如果用戶需要訪問聲卡硬件的話只能通過該聲卡的驅(qū)動程序來實(shí)現(xiàn),聲卡驅(qū)動程序再調(diào)用?HAL?中的相應(yīng)例程來實(shí)現(xiàn)?,下圖顯示了?HAL?,聲卡驅(qū)動程序,?Waveform Audio APIs?,我們的麥克錄音程序之間的關(guān)系:

5.?Waveform Audio

?????Waveform Audio APIs?是?Microsoft?提供給廣大?Win32?程序員用來給自己的應(yīng)用程序添加聲音支持的一套強(qiáng)大的?API,?它提供的功能如下:

?????????1.?打開?/?關(guān)閉?/?查詢聲音設(shè)備?;

????????2.?播放波形文件?;

????????3.?設(shè)置播放速度?;

?????????4.?播放進(jìn)度控制?;

?????????5.?錄音?;

?????????6.?得到當(dāng)前的播放位置?;

????????7.?調(diào)節(jié)音量?.

?

下面簡單介紹一下這套?API?提供的主要函數(shù)?:

  • 打開錄音設(shè)備函數(shù)

????????????MMRESULT waveInOpen(

??????????? LPHWAVEIN phwi,?????????????????//?輸入設(shè)備句柄

????????????UINT uDeviceID,?????????????????? //?輸入設(shè)備?ID

????????????LPWAVEFORMATEX pwfx,?????? //?錄音格式指針

????????????DWORD dwCallback,??????????????//?處理?MM_WIM_***?消息的回調(diào)函數(shù)或窗??

???????????????????????????????????????????????????????//?口句柄,線程?ID

??????????? DWORD dwCallbackInstance,?

??????????? DWORD fdwOpen????????????????? //?處理消息方式的符號位

??????????);

?

  • 為錄音設(shè)備準(zhǔn)備緩存函數(shù)

??????????????MMRESULT waveInPrepareHeader(? HWAVEIN hwi,?

??????????????????????????????????????????????????????????????????LPWAVEHDR pwh,

??????????????????????????????????????????????????????????????????UINT bwh );?

?

  • 給輸入設(shè)備增加一個(gè)緩存

??????????????MMRESULT waveInAddBuffer(? HWAVEIN hwi,

???????????????????????????????????????????????????????????LPWAVEHDR pwh,

???????????????????????????????????????????????????????????UINT cbwh );?

?

  • 開始錄音

??????????????MMRESULT waveInStart(? HWAVEIN hwi? );?

?

  • 清除緩存

??????????????MMRESULT waveInUnprepareHeader( HWAVEIN hwi,

?????????????????????????????????????????????????????????????????????LPWAVEHDR pwh,

?????????????????????????????????????????????????????????????????????UINT cbwh);?

?

  • 停止錄音

??????????????MMRESULT waveInReset( HWAVEIN hwi );?

?

  • 關(guān)閉錄音設(shè)備

??????????????MMRESULT waveInClose( HWAVEIN hwi );?

?

  • Wave_audio?數(shù)據(jù)格式

??????????????typedef struct {

???????????????????WORD? wFormatTag; //?數(shù)據(jù)格式,一般為?WAVE_FORMAT_PCM?即

???????????????????????????????????????????????????//?脈沖編碼

?????????????????? WORD? nChannels;?????//?聲道

?????????????????? DWORD nSamplesPerSec;???//?采樣頻率

?????????????????? DWORD nAvgBytesPerSec;??//?每秒數(shù)據(jù)量

?????????????????? WORD? nBlockAlign;

?????????????????? WORD? wBitsPerSample;?????//?樣本大小

?????????????????? WORD? cbSize;

????????????} WAVEFORMATEX;?

  • waveform-audio?緩存格式 

?????????????typedef struct {

?????????????????? LPSTR? lpData;????????????????????//?內(nèi)存指針

???????????????????DWORD? dwBufferLength;????//?長度

???????????????????DWORD? dwBytesRecorded; //?已錄音的字節(jié)長度

???????????????????DWORD? dwUser;

???????????????????DWORD? dwFlags;

???????????????????DWORD? dwLoops;??????????????//?循環(huán)次數(shù)

???????????????????struct wavehdr_tag * lpNext;

???????????????????DWORD? reserved;

?????????????} WAVEHDR;?

?

  • 相關(guān)消息 

?????????????MM_WIM_OPEN:?打開設(shè)備時(shí)消息,在此期間我們可以進(jìn)行一些初始化工作

?????????????MM_WIM_DATA:?當(dāng)緩存已滿或者停止錄音時(shí)的消息,處理這個(gè)消息可以對

?????????????????????????????????????緩存進(jìn)行重新分配,實(shí)現(xiàn)不限長度錄音

?????????????MM_WIM_CLOSE?:關(guān)閉錄音設(shè)備時(shí)的消息。

?

?

5. Multimedia File I/O

???????Multimedia File I/O APIs?是?Microsoft?提供的另外一套強(qiáng)大的針對媒體文件?I/O?的?API,?我們知道許多像?MediaPlay,RealOne?這樣的多媒體程序?qū)γ襟w文件的讀寫性能要求很高?,?它們幾乎要求實(shí)時(shí)的將磁盤上的媒體文件以流的形式讀入?,?但是對于一般的文件?I/O?形式如圖?1:

1.文件從磁盤上被讀入操作系統(tǒng)的File I/O的buffer;

????2.?然后拷貝到應(yīng)用程序自己的?buffer?中?;

????3.?應(yīng)用程序這時(shí)候才能讀取文件內(nèi)容?.

????????上述的過程對于多媒體應(yīng)用程序來說是低效的而且浪費(fèi)寶貴的內(nèi)存資源,如果文件和大的話勢必還要采取分段讀取等機(jī)制,?Multimedia File I/O?采取了一種直接存取機(jī)制?(?如圖?2),?使得應(yīng)用程序可以直接讀取操作系統(tǒng)的?File I/O buffer,?大大提高了效率?.?后面我們會利用此套?API實(shí)現(xiàn)錄音文件的存儲?.
?
?

6.?麥克錄音系統(tǒng)簡介

???本文實(shí)現(xiàn)的麥克錄音系統(tǒng)將具備以下功能?:

??????1.?錄制用戶通過麥克風(fēng)發(fā)出的聲音?;

????????????????這將利用到?Waveform APIs,?流程如下?:

?????????????????????a.?打開錄音設(shè)備?waveInOpen;

?????????????????????b.?準(zhǔn)備?wave?數(shù)據(jù)頭?waveInPrepareHeader;

?????????????????????c.?準(zhǔn)備數(shù)據(jù)塊?waveInAddBuffer;

?????????????????????d.?開始錄音?waveInStart;

?????????????????????e.?停止錄音?(waveInReset);

?????????????????????f.?關(guān)閉錄音設(shè)備?(waveInClose);

?????????????????????g.?當(dāng)開始錄音后當(dāng)?buffer?已滿時(shí)?,?將收到?MM_WIM_DATA?消息?,?處理該

????????????????????????消息可以保存已錄好數(shù)據(jù)?.

?

???????2.?根據(jù)用戶的聲音強(qiáng)弱動態(tài)顯示聲音波形?;

????????????這主要通過?GDI?函數(shù)來實(shí)現(xiàn)?.

??

??????3.?將用戶通過麥克風(fēng)發(fā)出的聲音錄制成?wav?文件保存?.

????????????這將利用到?Multimedia file I/O APIs.

?????????????????a?.調(diào)用?mminoOpen?函數(shù)來打開?WAVE?文件?,?獲取?HMMIO?類型的文件句柄?;?
  ????????????b?.根據(jù)?WAVE?文件的結(jié)構(gòu)?,?調(diào)用?mmioRead?、?mmioWrite?和?mmioSeek?函數(shù)實(shí)現(xiàn)文件的讀、寫和定位操作?;?
??  ???????????c?.調(diào)用?mmioClose?函數(shù)來關(guān)閉?WAVE?文件?.??

?

7.?麥克錄音系統(tǒng)的實(shí)現(xiàn)?(MicDemo)???

?

下面是該系統(tǒng)的界面?:
?

?對于錄音來說最重要的就是CSoundIn類,下面就是該類的定義:

?namespace??perdubug??{???//??prevent?the?name-space?pollution??
?

?class??CSoundIn??

?{

?public?:????

????????????????BOOL?????__initMic();??//??get?the?best?wave?format?supported?by?your?sound?card

????????????????????????????????????????????????????
?//??and?then?i?will?use?the?format?to?capture?sound.?
?

?

?????????????????void??????__closeMic();

?

????????????????

????????????????BOOL?????__openMic();??//??open?device?and?begin?to?capture?with?the?best?format(when?

???????????????????????????????????????????????????????
?//??invoke?__initMic?function?then?you?will?get?the?best?format

???????????????????????????????????????????????????????
?//??supported?by?host's?sound?card

????????????????

????????????????
?//?
?
????????????????
?//??if?your?want?to?capture?sound?and?export?into?a?wav?file?please?invoke?this?function

????????????????
?//??to?tell?me?the?full?path?then?i?will?create?the?wav?file.

????????????????
?//
?
?????????????????void??????__createOutputWaveFile(?const??TCHAR??*??lpszFileName);

????????????????

?????????????????//??if?you?invoke?any?member?function?return?error/false?please

????????????????
?//??use?this?function?to?get?the?result?
?

????????????????DWORD????__getLastError();

?

?????????????????//?
?
????????????????
?//??when?the?capture?buffer?is?filled?please?invoke?this?function?to?'add?buffer'(Actually

????????????????
?//??you?should?create?two-circular?buffers,when?1st?buffer?is?filled?then?switch?to?2st,1st

????????????????
?//??buffer?will?be?wrote?into?wav?file.

????????????????
?//
?
?????????????????void??AddBuffer();

????????????????

?????????????????virtual???~?CSoundIn();

????????????????

????????????????friend?CSoundIn??&??theSoundCapture();

?private?:

?

????????????????BOOL??GetBestWaveFormat(WAVEFORMATEX??&??waveFormatEx);

????????????????

?????????????????//??because?sound?card?is?one?and?only?so?i?must?limit?the?number?of?CSoundIn?object,

????????????????
?//??but?how?to?limit?the?class?object?nums?maybe?put?constructor?into?private?scope?is

????????????????
?//??a?good?idea,:-)?
?

????????????????CSoundIn();??????????

?

?private?:

????????????????WAVEINCAPS????????????????????m_WaveInDevCaps;

????????????????HWAVEIN????????????????????????????m_WaveIn;

????????????????WAVEHDR???????????????????????????m_WaveHeader;

????????????????WAVEFORMATEX????????????m_WaveFormat;??

????????????????

????????????????UINT????m_WaveInSampleRate;

?????????????????int??????????m_NbMaxSamples;

????????????????UINT????m_SizeRecord;

?

????????????????DWORD???m_dwLastError;

?

?????????????????enum???{?MAX_SIZE_INPUT_BUFFER??=???1???*???2???*???1024??}?;??//??samples?*?voie?*?size_samples?
?

?

?public?:

????????????????SHORT??InputBuffer[MAX_SIZE_INPUT_BUFFER];????//??used?for?int?FFT,many?GUI?application?

??????????????????????????????????????????????????????????????????????????????????????????????????????????
?//??want?to?display?sound?peak?so..?
?

????????????????BOOL???m_bTerminateThread;????????????????????//???to?'kill'?waveCallback?function?
?

????????????????BOOL???m_bImportToWaveFile;

????????????????

????????????????CWaveFile???????m_waveFile;

}?
;

?

}?
??//??end?namespace?perdubug?
?

?

對于將錄音保存在WAV文件的工作主要是由CwaveFile類來完成.下面是該類的定義:

?//?
?
?
//??Encapsulates?reading?or?writing?sound?data?to?or?from?a?wave?file

?//?-----------------------------------------------------------------------------?
?

?class??CWaveFile

?{

?public?:

????WAVEFORMATEX?*??m_pwfx;?????????//??Pointer?to?WAVEFORMATEX?structure?
?

????HMMIO??????????????m_hmmio;???????????????//??MM?I/O?handle?for?the?WAVE?
?

????MMCKINFO??????m_ck;???????????????????????//??Multimedia?RIFF?chunk?
?

????MMCKINFO??????m_ckRiff;????????????????//??Use?in?opening?a?WAVE?file?
?

????DWORD?????????????m_dwSize;??????????????//??The?size?of?the?wave?file?
?

????MMIOINFO???????m_mmioinfoOut;

????DWORD?????????????m_dwFlags;

????BOOL?????????????????m_bIsReadingFromMemory;

????BYTE?*????????????????m_pbData;

????BYTE?*????????????????m_pbDataCur;

????ULONG??????????????m_ulDataSize;

????CHAR?*???????????????m_pResourceBuffer;????

?protected?:

????HRESULT?ReadMMIO();

????HRESULT?WriteMMIO(?WAVEFORMATEX??*?pwfxDest?);

?

?public?:

????CWaveFile();

?????~?CWaveFile();

?

????HRESULT?Open(?LPCTSTR?strFileName,?WAVEFORMATEX?*??pwfx,?DWORD?dwFlags?);

????HRESULT?OpenFromMemory(?BYTE?*??pbData,?ULONG?ulDataSize,?

????????????????????????????????????????????????????????WAVEFORMATEX?*??pwfx,?DWORD?dwFlags?);

????HRESULT?Close();

?

????HRESULT?Read(?BYTE?*??pBuffer,?DWORD?dwSizeToRead,?DWORD?*??pdwSizeRead?);

????HRESULT?Write(?UINT?nSizeToWrite,?BYTE?*??pbData,?UINT?*??pnSizeWrote?);

?

????DWORD???GetSize();

????HRESULT?ResetFile();

????WAVEFORMATEX?*??GetFormat()??{??return??m_pwfx;?}?;

}?
;

?
?我們有了這兩個(gè)強(qiáng)有力的類的支持就可以開始我們的編程工作了….

????1?.用VC6?++?建立一個(gè)MFC基于對話框的工程:MicDemo;

????2?.添加我們的兩個(gè)類CSoundIn,CwaveFile;????????

????3?.當(dāng)我們點(diǎn)擊開始(Start)按鈕的時(shí)候我們就要開始錄音了…

?

??????????void??CMicDemoDlg::OnStart()?

?????????{

????????????????m_btnStart.EnableWindow(FALSE);????????????????

?????????????????if?(theSoundCapture().__initMic())

?????????????????{

??????????????????????m_filePath.SetWindowText(_T(?"?yangchen.wav.?"?));?????????

??????????????????????theSoundCapture().__createOutputWaveFile(_T(?"?yangchen.wav?"?));?????????????????????

??????????????????????if?(?!?theSoundCapture().__openMic())

???????????????????????{

????????????????????????::MessageBox(?this?->?m_hWnd,_T(?"?Can?not?open?microphone!?"?),?_T(?"?Error?"?),MB_OK?|?MB_ICONERROR);

??????????????????????????return?;

??????????????????????}?

?
????????????????}?

?
????????????????

????????????????m_btnStop.EnableWindow(TRUE);

??????????????

???????????????//??設(shè)置定時(shí)器是為了畫波形用的???????
?

?????????????????SetTimer(?1?,??200???/*?start?slow?*/?,?NULL);

???????????}?

?
??

?????4?.在定時(shí)器的回調(diào)函數(shù)中畫波形.

????????????void??CMicDemoDlg::OnTimer(UINT?nIDEvent)?

?????????????{

?????????????????????if?(nIDEvent??==???1?)

????????????????????{???????????

?????????????????????????????????static???const???int??xCon??=???13?;

?????????????????????????????????static???const???int??yCon??=???13?;

?????????????????????????????????static???const???int??wCon??=???623?;

?????????????????????????????????static???const???int??hCon??=???80?;

????????????????????????????????

????????????????????????????????CClientDC?dc(?this?);

????????????????????????????????

????????????????????????????????CBitmap???Bitmap;

????????????????????????????????CBitmap??*??pbmOld??=??NULL;??????????????????????????????

????????????????????????????????CDC?????????dcMem;

????????????????????????????????

????????????????????????????????dcMem.CreateCompatibleDC(?&?dc);?????????????????

????????????????????????????????Bitmap.CreateCompatibleBitmap(?&?dc,wCon,hCon);

????????????????????????????????

????????????????????????????????pbmOld??=??dcMem.SelectObject(?&?Bitmap);

????????????????????????????????

????????????????????????????????dcMem.PatBlt(?0?,?0?,wCon,hCon,?WHITENESS);??????????????????????????????

????????????????????????????????dcMem.MoveTo(?0?,hCon?/?2?);

????????????????????????????????

?????????????????????????????????//?
?
????????????????????????????????
?//??display?incomming?signal--key?idea!

????????????????????????????????
?//
?
?????????????????????????????????for?(?int??x??=?0??;?x??<??wCon;?x?++?)???//??display?Input?
?

??????????????????????????????????{

??????????????????????????????????????????dcMem.LineTo(x,(hCon??>>???1?)??-??(theSoundCapture().InputBuffer[x]??>>???7?));

????????????????????????????????}?

?
????????????????????????????????

????????????????????????????????dc.BitBlt(xCon,yCon,wCon,hCon,?&?dcMem,??0?,??0?,?SRCCOPY);

????????????????????????????????

????????????????????????????????dcMem.SelectObject(pbmOld);

????????????????????????????????dcMem.DeleteDC();?????????????

??????????????????}?

?
???????????????????else?
?
?????????????????????????CDialog::OnTimer(nIDEvent);

????????????}?

?
???????

???????5?.點(diǎn)擊停止(Stop)按鈕的時(shí)候停止錄音和寫WAV文件

???????????????????void??CMicDemoDlg::OnStop()?

??????????????????{

????????????????????????m_btnStop.EnableWindow(FALSE);?

????????????????????????theSoundCapture().__closeMic();?

????????????????????????m_btnStart.EnableWindow(TRUE);

?????????????????}?

?
看完整段代碼你可能會很奇怪怎么在CmicDemoDlg中居然都沒有定義一個(gè)CSoundIn對象????呵呵,原因很簡單,因?yàn)樵O(shè)備的獨(dú)占性所以在一個(gè)時(shí)刻只能有一個(gè)CSoundIn對象存在(因?yàn)镃SoundIn對象需要占據(jù)錄音設(shè)備),所以我們必須限制程序員生成CSoundIn對象的數(shù)量,怎么限制呢???那就是把CSoundIn的構(gòu)造函數(shù)放在private區(qū)域里面:

???

??????private?:

????????????????BOOL??GetBestWaveFormat(WAVEFORMATEX??&??waveFormatEx);

????????????????

?????????????????//??because?sound?card?is?one?and?only?so?i?must?limit?the?number?of?CSoundIn?object,

????????????????
?//??but?how?to?limit?the?class?object?nums?maybe?put?constructor?into?private?scope?is

????????????????
?//??a?good?idea,:-)?
?

????????CSoundIn();??????????

?

這樣的話就根本無法聲明一個(gè)CSoundIn對象,不信你試一下在你的代碼中寫上:

?????CSoundIn??soundInObj;

?能編譯通過嗎???肯定是不能,那如何調(diào)用CSoundIn的成員函數(shù)呢???答案是通過一個(gè)全局函數(shù):

?

???????????????//??global?function,:-(

??????????????
?//??client?can?only?through?this?function?to?use?CSoundIn?object?
?

??????????????CSoundIn??&??theSoundCapture()

???????????????{

??????????????????????static??CSoundIn?p;

??????????????????????return??p;

???????????????}?

?
?

??這時(shí)候你應(yīng)該明白了為什么上面的代碼中調(diào)用CSoundIn的成員函數(shù)的時(shí)候都是用theSoundCapture來做的原因了吧.?

轉(zhuǎn)載于:https://www.cnblogs.com/huty/p/8518458.html

總結(jié)

以上是生活随笔為你收集整理的【VS开发】【智能语音处理】Windows下麦克风语音采集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。