天天看點

使用WindowsAPI擷取錄音音頻的方法

這篇文章主要介紹了使用WindowsAPI擷取錄音音頻的方法,非常實用的功能,需要的朋友可以參考下

本文執行個體介紹了使用winmm.h進行音頻流的擷取的方法,具體步驟如下:

一、首先需要包含以下引用對象

<a href="http://www.jb51.net/article/53858.htm#">?</a>

1

2

3

<code>#include &lt;Windows.h&gt;</code>

<code>#include "mmsystem.h"</code>

<code>#pragma comment(lib, "winmm.lib")</code>

二、音頻的擷取需要調用7個函數

1. waveInGetNumDevs:傳回系統中就緒的波形聲音輸入裝置的數量

<code>UINT</code> <code>waveInGetNumDevs(</code><code>VOID</code><code>);</code>

2. waveInGetDevCaps:檢查指定波形輸入裝置的特性

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<code>MMRESULT waveInGetDevCaps( </code>

<code> </code><code>UINT_PTR</code>   <code>uDeviceID, </code>

<code> </code><code>LPWAVEINCAPS pwic,    </code>

<code> </code><code>UINT</code>     <code>cbwic    </code>

<code>);</code>

<code>//uDeviceID 音頻輸入裝置辨別,也可以為一個打開的音頻輸入裝置的句柄.</code>

<code>//  個人認為如果上一步獲得了多個裝置,可以用索引辨別每一個裝置.</code>

<code>//  </code>

<code>//pwic 對WAVEINCAPS結構體的一個指針,包含裝置的音頻特性.</code>

<code>//</code>

<code>//cbwic WAVEINCAPS結構體的大小,使用sizeof即可.</code>

<code>//MMRESULT 函數執行的結果</code>

<code>//  MMSYSERR_NOERROR 表示執行成功</code>

<code>//  MMSYSERR_BADDEVICEID 索引越界 </code>

<code>//  MMSYSERR_NODRIVER 沒有就緒的裝置 </code>

<code>//  MMSYSERR_NOMEM 不能配置設定或者鎖定記憶體</code>

介紹WAVEINCAPS結構體的含義:

<code>typedef</code> <code>struct</code> <code>{ </code>

<code>  </code><code>WORD</code>   <code>wMid;       </code><code>//音頻裝置制造商定義的驅動程式辨別</code>

<code>  </code><code>WORD</code>   <code>wPid;       </code><code>//音頻輸入裝置的産品辨別</code>

<code>  </code><code>MMVERSION vDriverVersion;   </code><code>//驅動程式版本号</code>

<code>  </code><code>TCHAR</code>   <code>szPname[MAXPNAMELEN];</code><code>//制造商名稱</code>

<code>  </code><code>DWORD</code>   <code>dwFormats;     </code><code>//支援的格式,參見MSDN</code>

<code>  </code><code>WORD</code>   <code>wChannels;     </code><code>//支援的聲道數</code>

<code>  </code><code>WORD</code>   <code>wReserved1;     </code><code>//保留參數</code>

<code>} WAVEINCAPS;</code>

3. waveInOpen:打開指定的音頻輸入裝置,進行錄音

<code>MMRESULT waveInOpen(</code>

<code> </code><code>LPHWAVEIN    phwi,       </code><code>//接收打開的音頻輸入裝置辨別的HWAVEIN結構的指針</code>

<code> </code><code>UINT_PTR</code>    <code>uDeviceID,     </code><code>//指定一個需要打開的裝置辨別.可以使用WAVE_MAPPER選擇一個按指定錄音格式錄音的裝置</code>

<code> </code><code>LPWAVEFORMATEX pwfx,       </code><code>//一個所需的格式進行錄音的WAVEFORMATEX結構的指針 </code>

<code> </code><code>DWORD_PTR</code>   <code>dwCallback,   </code><code>//指向一個回調函數、事件句柄、視窗句柄、線程辨別,對錄音事件進行處理.</code>

<code> </code><code>DWORD_PTR</code>   <code>dwCallbackInstance,</code><code>//傳給回調機制的參數</code>

<code> </code><code>DWORD</code>     <code>fdwOpen     </code><code>//打開裝置的方法辨別,指定回調的類型.參見CSDN</code>

介紹WAVEFORMATEX結構體的含義:

<code>  </code><code>WORD</code> <code>wFormatTag;   </code><code>//波形聲音的格式,單聲道雙聲道使用WAVE_FORMAT_PCM.當包含在WAVEFORMATEXTENSIBLE結構中時,使用WAVE_FORMAT_EXTENSIBLE.</code>

<code>  </code><code>WORD</code> <code>nChannels;   </code><code>//聲道數量</code>

<code>  </code><code>DWORD</code> <code>nSamplesPerSec; </code><code>//采樣率.wFormatTag為WAVE_FORMAT_PCM時,有8.0kHz,11.025kHz,22.05kHz,和44.1kHz.</code>

<code>  </code><code>DWORD</code> <code>nAvgBytesPerSec; </code><code>//每秒的采樣位元組數.通過nSamplesPerSec * nChannels * wBitsPerSample / 8計算</code>

<code>  </code><code>WORD</code> <code>nBlockAlign;   </code><code>//每次采樣的位元組數.通過nChannels * wBitsPerSample / 8計算</code>

<code>  </code><code>WORD</code> <code>wBitsPerSample; </code><code>//采樣位數.wFormatTag為WAVE_FORMAT_PCM時,為8或者16</code>

<code>  </code><code>WORD</code> <code>cbSize;     </code><code>//wFormatTag為WAVE_FORMAT_PCM時,忽略此參數</code>

<code>} WAVEFORMATEX;</code>

介紹dwCallback回調函數格式:

<code>void</code> <code>CALLBACK waveInProc(</code>

<code> </code><code>HWAVEIN hwi,    </code><code>//回調此函數的裝置句柄</code>

<code> </code><code>UINT</code> <code>uMsg,     </code><code>//波形聲音輸入資訊,辨別關閉(WIM_CLOSE)、緩沖區滿(WIM_DATA)、打開(WIM_OPEN).</code>

<code> </code><code>DWORD_PTR</code> <code>dwInstance,</code><code>//使用者在waveInOpen指定的資料</code>

<code> </code><code>DWORD_PTR</code> <code>dwParam1, </code><code>//(LPWAVEHDR)dwParam1,使用者指定的緩沖區</code>

<code> </code><code>DWORD_PTR</code> <code>dwParam2   </code>

4. waveInPrepareHeader:為音頻輸入裝置準備一個緩沖區

<code>MMRESULT waveInPrepareHeader(</code>

<code> </code><code>HWAVEIN hwi, </code><code>//音頻輸入裝置句柄</code>

<code> </code><code>LPWAVEHDR pwh,</code><code>//指向WAVEHDR結構的指針,辨別準備的緩沖區</code>

<code> </code><code>UINT</code> <code>cbwh   </code><code>//WAVEHDR結構的大小,使用sizeof即可</code>

介紹WAVEHDR結構:

<code>typedef</code> <code>struct</code> <code>wavehdr_tag { </code>

<code>  </code><code>LPSTR</code>   <code>lpData;    </code><code>//指向波形格式的緩沖區</code>

<code>  </code><code>DWORD</code>   <code>dwBufferLength;</code><code>//緩沖區的大小</code>

<code>  </code><code>DWORD</code>   <code>dwBytesRecorded;</code><code>//目前存儲了多少資料</code>

<code>  </code><code>DWORD_PTR</code> <code>dwUser;    </code><code>//使用者資料</code>

<code>  </code><code>DWORD</code>   <code>dwFlags;     </code><code>//為緩沖區提供的資訊,在waveInPrepareHeader函數中使用WHDR_PREPARED</code>

<code>  </code><code>DWORD</code>   <code>dwLoops;    </code><code>//輸出時使用,辨別播放次數</code>

<code>  </code><code>struct</code> <code>wavehdr_tag * lpNext;</code><code>//reserved</code>

<code>  </code><code>DWORD_PTR</code> <code>reserved;    </code><code>//reserved</code>

<code>} WAVEHDR, *LPWAVEHDR;</code>

5. waveInAddBuffer:将緩沖區發送給裝置,若緩沖區填滿,則不起作用。(參數同上)

<code>MMRESULT waveInAddBuffer(</code>

<code> </code><code>HWAVEIN hwi, </code>

<code> </code><code>LPWAVEHDR pwh, </code>

<code> </code><code>UINT</code> <code>cbwh </code>

6. waveInStart:開始進行錄制

<code>MMRESULT waveInStart(</code>

<code> </code><code>HWAVEIN hwi</code><code>//裝置句柄</code>

7. waveInClose:關閉裝置

<code>MRESULT waveInClose(</code>

三、完整執行個體代碼如下:

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

<code>//Run.c檔案</code>

<code>#include &lt;stdio.h&gt;</code>

<code>void</code> <code>PlayMusi();</code>

<code>void</code> <code>WaveInitFormat(LPWAVEFORMATEX m_WaveFormat,</code><code>WORD</code> <code>nCh,</code><code>DWORD</code> <code>nSampleRate,</code><code>WORD</code> <code>BitsPerSample);</code>

<code>DWORD</code> <code>CALLBACK MicCallback(HWAVEIN hwavein,</code><code>UINT</code> <code>uMsg,</code><code>DWORD</code> <code>dwInstance,</code><code>DWORD</code> <code>dwParam1,</code><code>DWORD</code> <code>dwParam2);</code>

<code>void</code> <code>RecordWave();</code>

<code> </code> 

<code>void</code> <code>main()</code>

<code>{</code>

<code> </code><code>//PlayMusi();</code>

<code> </code><code>RecordWave();</code>

<code> </code><code>while</code><code>(1);</code>

<code>}</code>

<code>void</code> <code>RecordWave()</code>

<code> </code><code>int</code> <code>count = waveInGetNumDevs();</code><code>//1</code>

<code> </code><code>printf</code><code>(</code><code>"\n音頻輸入數量:%d\n"</code><code>,count);</code>

<code> </code><code>WAVEINCAPS waveIncaps;</code>

<code> </code><code>MMRESULT mmResult = waveInGetDevCaps(0,&amp;waveIncaps,</code><code>sizeof</code><code>(WAVEINCAPS));</code><code>//2</code>

<code> </code><code>printf</code><code>(</code><code>"\n音頻輸入裝置:%s\n"</code><code>,waveIncaps.szPname);</code>

<code> </code><code>if</code><code>(MMSYSERR_NOERROR==mmResult)</code>

<code> </code><code>{</code>

<code> </code><code>HWAVEIN phwi;</code>

<code> </code><code>WAVEFORMATEX pwfx;</code>

<code> </code><code>WaveInitFormat(&amp;pwfx,1,8000,8);</code>

<code> </code><code>printf</code><code>(</code><code>"\n請求打開音頻輸入裝置"</code><code>);</code>

<code> </code><code>printf</code><code>(</code><code>"\n采樣參數:單聲道 8kHz 8bit\n"</code><code>);</code>

<code> </code><code>mmResult=waveInOpen(&amp;phwi,WAVE_MAPPER,&amp;pwfx,(</code><code>DWORD</code><code>)(MicCallback),NULL,CALLBACK_FUNCTION);</code><code>//3</code>

<code>  </code><code>WAVEHDR pwh1;</code>

<code>  </code><code>char</code> <code>buffer1[10240];</code>

<code>  </code><code>pwh1.lpData=buffer1;</code>

<code>  </code><code>pwh1.dwBufferLength=10240;</code>

<code>  </code><code>pwh1.dwUser=1;</code>

<code>  </code><code>pwh1.dwFlags=0;</code>

<code>  </code><code>mmResult=waveInPrepareHeader(phwi,&amp;pwh1,</code><code>sizeof</code><code>(WAVEHDR));</code><code>//4</code>

<code>  </code><code>printf</code><code>(</code><code>"\n準備緩沖區1"</code><code>);</code>

<code>  </code><code>WAVEHDR pwh2;</code>

<code>  </code><code>char</code> <code>buffer2[10240];</code>

<code>  </code><code>pwh2.lpData=buffer2;</code>

<code>  </code><code>pwh2.dwBufferLength=10240;</code>

<code>  </code><code>pwh2.dwUser=2;</code>

<code>  </code><code>pwh2.dwFlags=0;</code>

<code>  </code><code>mmResult=waveInPrepareHeader(phwi,&amp;pwh2,</code><code>sizeof</code><code>(WAVEHDR));</code><code>//4</code>

<code>  </code><code>printf</code><code>(</code><code>"\n準備緩沖區2\n"</code><code>);</code>

<code>  </code><code>if</code><code>(MMSYSERR_NOERROR==mmResult)</code>

<code>  </code><code>{</code>

<code>  </code><code>mmResult=waveInAddBuffer(phwi,&amp;pwh1,</code><code>sizeof</code><code>(WAVEHDR));</code><code>//5</code>

<code>  </code><code>printf</code><code>(</code><code>"\n将緩沖區1加入音頻輸入裝置"</code><code>);</code>

<code>  </code><code>mmResult=waveInAddBuffer(phwi,&amp;pwh2,</code><code>sizeof</code><code>(WAVEHDR));</code><code>//5</code>

<code>  </code><code>printf</code><code>(</code><code>"\n将緩沖區2加入音頻輸入裝置\n"</code><code>);</code>

<code>   </code><code>mmResult=waveInStart(phwi);</code><code>//6</code>

<code>   </code><code>printf</code><code>(</code><code>"\n請求開始錄音\n"</code><code>);</code>

<code>  </code><code>}</code>

<code> </code><code>}</code>

<code>DWORD</code> <code>CALLBACK MicCallback(HWAVEIN hwavein,</code><code>UINT</code> <code>uMsg,</code><code>DWORD</code> <code>dwInstance,</code><code>DWORD</code> <code>dwParam1,</code><code>DWORD</code> <code>dwParam2)</code>

<code> </code><code>switch</code><code>(uMsg) </code>

<code> </code><code>case</code> <code>WIM_OPEN:</code>

<code>  </code><code>printf</code><code>(</code><code>"\n裝置已經打開...\n"</code><code>);</code>

<code>  </code><code>break</code><code>;</code>

<code>  </code> 

<code> </code><code>case</code> <code>WIM_DATA:</code>

<code>  </code><code>printf</code><code>(</code><code>"\n緩沖區%d存滿...\n"</code><code>,((LPWAVEHDR)dwParam1)-&gt;dwUser);</code>

<code>  </code><code>waveInAddBuffer (hwavein, (LPWAVEHDR)dwParam1,</code><code>sizeof</code> <code>(WAVEHDR)) ;</code>

<code> </code><code>case</code> <code>WIM_CLOSE:</code>

<code>  </code><code>printf</code><code>(</code><code>"\n裝置已經關閉...\n"</code><code>);</code>

<code> </code><code>default</code><code>:</code>

<code> </code><code>return</code> <code>0;</code>

<code>void</code> <code>WaveInitFormat(LPWAVEFORMATEX m_WaveFormat,</code><code>WORD</code> <code>nCh,</code><code>DWORD</code> <code>nSampleRate,</code><code>WORD</code> <code>BitsPerSample)</code>

<code> </code><code>m_WaveFormat-&gt;wFormatTag = WAVE_FORMAT_PCM;</code>

<code> </code><code>m_WaveFormat-&gt;nChannels = nCh;</code>

<code> </code><code>m_WaveFormat-&gt;nSamplesPerSec = nSampleRate;</code>

<code> </code><code>m_WaveFormat-&gt;nAvgBytesPerSec = nSampleRate * nCh * BitsPerSample/8;</code>

<code> </code><code>m_WaveFormat-&gt;nBlockAlign = m_WaveFormat-&gt;nChannels * BitsPerSample/8;</code>

<code> </code><code>m_WaveFormat-&gt;wBitsPerSample = BitsPerSample;</code>

<code> </code><code>m_WaveFormat-&gt;cbSize = 0;</code>

<code>void</code> <code>PlayMusi()</code>

<code> </code><code>int</code> <code>error = mciSendString(</code><code>"open C:\\Users\\Angel\\Desktop\\有多少愛可以重來.mp3 alias myDivece"</code><code>, NULL, 0, NULL);</code>

<code> </code><code>if</code> <code>(error == 0)</code>

<code> </code><code>mciSendString(</code><code>"play myDivece"</code><code>, NULL, 0, NULL);</code><code>//播放</code>

繼續閱讀