呼叫API實現錄音

freshairpeng發表於2009-03-08

應一個朋友委託,做一個錄音程式.
我原本以為要用direct來做,先是在google上搜尋了一把,收穫不大。後來在codeproject上發現一篇文章A full-duplex audio player in C# using the waveIn/waveOut APIs ,原來可以很簡單。在System32下原來有一個多媒體處理的API,winmm.dll,發現之非常興奮,哈哈。
原來微軟已經提供了一系列的wavein 和waveout方法,參考了裡面一些東西做法。做了一些修改。由於我以前對音訊並不怎麼了解,特地查了一下音訊的有關知識,不瞭解的朋友也可以瞭解一下,呵呵,知識共享拉。
其中音訊取樣率(位/bit),取樣率包括32000Hz,44100Hz,48000Hz3種,取樣大小分為16位和8位,聲道通常就是2(立體聲)和1(單聲道)了。其中有一個重要的資料叫取樣速率,計算公式為取樣速率=取樣率×取樣大小×聲道。我們通常比較熟悉的128K的MP3就是44100×16×2=1411.2Kb/s,這樣的音訊很大,通常10秒種就有1M多。而如果使用模擬訊號的話並非取樣率越高越好,只會盲目的增加我們檔案的大小,只有數字訊號的時候才會提高我們的效果。
對於音訊這一塊,希望其他朋友能提供給一些更多的知識與技術。特別是音訊對比和頻譜圖等等。
那麼我們往下看。

呼叫API實現錄音//wav頭
呼叫API實現錄音
                long chunksize = fs.Length + 36;
呼叫API實現錄音                WriteChars(bw, 
"RIFF");//格式
呼叫API實現錄音
                bw.Write((int)chunksize);//檔案長度(要加上頭的36位元組)
呼叫API實現錄音
                WriteChars(bw, "WAVE");//標示
呼叫API實現錄音
                WriteChars(bw, "fmt ");//fmt
呼叫API實現錄音
                bw.Write((int)16);//fmt長度
呼叫API實現錄音
                bw.Write(m_Format.wFormatTag);//壓縮模式
呼叫API實現錄音
                bw.Write(m_Format.nChannels);//聲道
呼叫API實現錄音
                bw.Write(m_Format.nSamplesPerSec);//取樣率包含:32000Hz,44100Hz,48000Hz.
呼叫API實現錄音
                bw.Write(m_Format.nAvgBytesPerSec);//每秒播放位元組
呼叫API實現錄音
                bw.Write(m_Format.nBlockAlign);//位速
呼叫API實現錄音
                bw.Write(m_Format.wBitsPerSample);//取樣大小
呼叫API實現錄音
                WriteChars(bw,"data");//data標誌
呼叫API實現錄音
                bw.Write(fs.Length);//音訊長度

這就是我們需要給wave檔案寫上的頭。
大家查一下winmm.dll就會發現,裡面提供了很多有用的API,非常的棒。
呼叫API實現錄音// WaveIn calls
呼叫API實現錄音
        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInGetNumDevs();
呼叫API實現錄音        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInAddBuffer(IntPtr hwi, ref WaveHdr pwh, int cbwh);
呼叫API實現錄音        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInClose(IntPtr hwi);
呼叫API實現錄音        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInOpen(out IntPtr phwi, int uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, int dwInstance, int dwFlags);
呼叫API實現錄音        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInPrepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, int uSize);
呼叫API實現錄音        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInUnprepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, int uSize);
呼叫API實現錄音        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInReset(IntPtr hwi);
呼叫API實現錄音        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInStart(IntPtr hwi);
呼叫API實現錄音        [DllImport(mmdll)]
呼叫API實現錄音        
public static extern int waveInStop(IntPtr hwi);
其中DataArrived方法是委託的方法,它將我們接收到的資料拷貝到m_RecBuffer中,再寫入到檔案裡。在這裡我並沒有使用MenmoyStream,看到windows錄音限制1分鐘,我估計它(我並沒有認真看過)是講資料寫入記憶體,再統一儲存的,為了沒有限制,所以直接用了FileStream,寫到檔案裡了。
呼叫API實現錄音private void DataArrived(IntPtr data, int size)
呼叫API實現錄音        
{
呼叫API實現錄音            
try
呼叫API實現錄音            
{
呼叫API實現錄音                
if (m_RecBuffer == null || m_RecBuffer.Length < size)
呼叫API實現錄音                
{
呼叫API實現錄音                    m_RecBuffer 
= new byte[size];
呼叫API實現錄音                }

呼叫API實現錄音                System.Runtime.InteropServices.Marshal.Copy(data, m_RecBuffer, 
0, size);
呼叫API實現錄音
呼叫API實現錄音                bw_tmp.Write(m_RecBuffer);
呼叫API實現錄音                _recordSize
+=m_RecBuffer.Length;
呼叫API實現錄音            }

呼叫API實現錄音            
catch(Exception e)
呼叫API實現錄音            
{
呼叫API實現錄音                
return;
呼叫API實現錄音            }

呼叫API實現錄音        }

裡面我加入了一些功能,包括開始,停止,暫停,繼續等等。

在此,我想問一下其他朋友,音訊的頻譜圖是基於怎樣的演算法呢?如何畫的?這個我很想了解,有這方面知識的朋友望能告知,給點參考。在此謝過。

Source
參考:
A full-duplex audio player in C# using the waveIn/waveOut APIs
PCM編碼及其技術

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14766526/viewspace-563282/,如需轉載,請註明出處,否則將追究法律責任。

相關文章