|
基於API的錄音機程式
作者/欒義明
一、數字音頻基礎知識
任何周期的波形可以分解成多個正弦波,這些正弦波的頻率都是整數倍。級數中其他正線波的頻率是基礎頻率的整數倍。基礎頻率稱為一級諧波。
pulse code modulation,脈衝編碼調製,即對波形按照固定周期頻率採樣。為了保證採樣後資料品質,採樣頻率必須是樣本聲音最高頻率的兩倍,這就是Nyquist頻率。
樣本大小:採樣後用於儲存振幅級的位元,實際就是脈衝編碼的階梯數,位元越大表明精度越高,這一點學過數字邏輯電路的應該清楚。
波形振幅的平方。兩個聲音強度上的差常以分貝(db)為單位來度量,
20*log(A1/A2)分貝。A1,A2為兩個聲音的振幅。如果採樣大小為8位,則採樣的動態範圍為20*log(256)分貝=48db。如果樣本大小為16位,則採樣動態範圍為20*log(65536)大約是96分貝,接近了人聽覺極限和痛苦極限,是再線音樂的理想範圍。windows同時支援8位和16位的採樣大小。
二、相關API函數,結構,訊息
對於錄音裝置來說,windows 提供了一組wave***的函數,比較重要的有以下幾個:
MMRESULT waveInOpen( LPHWAVEIN phwi, //輸入裝置控制代碼 UINT uDeviceID, //輸入裝置ID LPWAVEFORMATEX pwfx, //錄音格式指標 DWORD dwCallback, //處理MM_WIM_***訊息的回呼函數或視窗控制代碼,線程ID DWORD dwCallbackInstance, DWORD fdwOpen //處理訊息方式的符號位);
MMRESULT waveInPrepareHeader( HWAVEIN hwi, LPWAVEHDR pwh, UINT bwh );
MMRESULT waveInAddBuffer( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh );
MMRESULT waveInStart( HWAVEIN hwi );
MMRESULT waveInUnprepareHeader( HWAVEIN hwi,LPWAVEHDR pwh, UINT cbwh);
MMRESULT waveInReset( HWAVEIN hwi );
MMRESULT waveInClose( HWAVEIN hwi );
typedef struct { WORD wFormatTag; //資料格式,一般為WAVE_FORMAT_PCM即脈衝編碼 WORD nChannels; //聲道 DWORD nSamplesPerSec; //採樣頻率 DWORD nAvgBytesPerSec; //每秒資料量 WORD nBlockAlign; WORD wBitsPerSample;//樣本大小 WORD cbSize; } WAVEFORMATEX;
typedef struct { LPSTR lpData; //記憶體指標 DWORD dwBufferLength;//長度 DWORD dwBytesRecorded; //已錄音的位元組長度 DWORD dwUser; DWORD dwFlags; DWORD dwLoops; //迴圈次數 struct wavehdr_tag * lpNext; DWORD reserved; } WAVEHDR;
MM_WIM_OPEN:開啟裝置時訊息,在此期間我們可以進行一些初始化工作MM_WIM_DATA:當緩衝已滿或者停止錄音時的訊息,處理這個訊息可以對緩衝進行重新分配,實現不限長度錄音MM_WIM_CLOSE:關閉錄音裝置時的訊息。
相對於錄音來說,回放就簡單的多了,用到的函數主要有以下幾個:
MMRESULT waveOutOpen( LPHWAVEOUT phwo, UINT uDeviceID, LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwCallbackInstance, DWORD fdwOpen );
MMRESULT waveOutPrepareHeader( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh );
MMRESULT waveOutWrite( HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh );
相應的也有三個訊息,用法跟錄音的類似:
三、程式設計
一個錄音程式的簡單流程:
開啟錄音裝置waveInOpen===>準備wave資料頭waveInPrepareHeader===>準備資料區塊waveInAddBuffer===>開始錄音waveInStart===>停止錄音(waveInReset) ===>關閉錄音裝置(waveInClose)
當開始錄音後當buffer已滿時,將收到MM_WIM_DATA訊息,處理該訊息可以儲存已錄好資料。
回放程式比這個要簡單的多:
開啟回放裝置waveOutOpen===>準備wave資料頭waveOutPrepareHeader===>寫wave資料waveOutWrite===>停止放音(waveOutRest) ===>關閉回放裝置(waveOutClose)
如何處理MM訊息:
MSDN告訴我們主要有 CALLBACK_FUNCTION、CALL_BACKTHREAD、CALLBACK_WINDOW 三種方式,常用的是Thread,window方式。
線程模式
waveInOpen(&hWaveIn,WAVE_MAPPER,&waveform,m_ThreadID,NULL,CALLBACK_THREAD),我們可以繼承MFC的CwinThread類,只要相應的處理線程訊息即可。
MFC線程訊息的宏為:
ON_THREAD_MESSAGE,
可以這樣添加訊息映射:
ON_THREAD_MESSAGE(MM_WIM_CLOSE, OnMM_WIM_CLOSE)
視窗模式
類似於線程模式,參見來源程式即可。 |