這篇文章主要介紹了使用WindowsAPI擷取錄音音頻的方法,非常實用的功能,需要的朋友可以參考下
本文執行個體介紹了使用winmm.h進行音頻流的擷取的方法,具體步驟如下:
一、首先需要包含以下引用對象
<a href="http://www.jb51.net/article/53858.htm#">?</a>
1
2
3
<code>#include <Windows.h></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 <stdio.h></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,&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(&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(&phwi,WAVE_MAPPER,&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,&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,&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,&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,&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)->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->wFormatTag = WAVE_FORMAT_PCM;</code>
<code> </code><code>m_WaveFormat->nChannels = nCh;</code>
<code> </code><code>m_WaveFormat->nSamplesPerSec = nSampleRate;</code>
<code> </code><code>m_WaveFormat->nAvgBytesPerSec = nSampleRate * nCh * BitsPerSample/8;</code>
<code> </code><code>m_WaveFormat->nBlockAlign = m_WaveFormat->nChannels * BitsPerSample/8;</code>
<code> </code><code>m_WaveFormat->wBitsPerSample = BitsPerSample;</code>
<code> </code><code>m_WaveFormat->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>