本文實例介紹了使用winmm.h進行音頻流的獲取的方法,具體步驟如下:
一、首先需要包含以下引用對象
1
2
3
|
#include <Windows.h>
#include "mmsystem.h"
#pragma comment(lib, "winmm.lib")
|
二、音頻的獲取需要調用7個函數
1. waveInGetNumDevs:返回系統中就緒的波形聲音輸入設備的數量
1
|
UINT
waveInGetNumDevs(
VOID
);
|
2. waveInGetDevCaps:檢查指定波形輸入設備的特性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
MMRESULT waveInGetDevCaps(
UINT_PTR
uDeviceID,
LPWAVEINCAPS pwic,
UINT
cbwic
);
//uDeviceID 音頻輸入設備標識,也可以為一個打開的音頻輸入設備的句柄.
// 個人認為如果上一步獲得了多個設備,可以用索引標識每一個設備.
//
//pwic 對WAVEINCAPS結構體的一個指針,包含設備的音頻特性.
//
//cbwic WAVEINCAPS結構體的大小,使用sizeof即可.
//
//MMRESULT 函數執行的結果
// MMSYSERR_NOERROR 表示執行成功
// MMSYSERR_BADDEVICEID 索引越界
// MMSYSERR_NODRIVER 沒有就緒的設備
// MMSYSERR_NOMEM 不能分配或者鎖定內存
|
介紹WAVEINCAPS結構體的含義:
1
2
3
4
5
6
7
8
9
|
typedef
struct
{
WORD
wMid;
//音頻設備制造商定義的驅動程序標識
WORD
wPid;
//音頻輸入設備的產品標識
MMVERSION vDriverVersion;
//驅動程序版本號
TCHAR
szPname[MAXPNAMELEN];
//制造商名稱
DWORD
dwFormats;
//支持的格式,參見MSDN
WORD
wChannels;
//支持的聲道數
WORD
wReserved1;
//保留參數
} WAVEINCAPS;
|
3. waveInOpen:打開指定的音頻輸入設備,進行錄音
1
2
3
4
5
6
7
8
|
MMRESULT waveInOpen(
LPHWAVEIN phwi,
//接收打開的音頻輸入設備標識的HWAVEIN結構的指針
UINT_PTR
uDeviceID,
//指定一個需要打開的設備標識.可以使用WAVE_MAPPER選擇一個按指定錄音格式錄音的設備
LPWAVEFORMATEX pwfx,
//一個所需的格式進行錄音的WAVEFORMATEX結構的指針
DWORD_PTR
dwCallback,
//指向一個回調函數、事件句柄、窗口句柄、線程標識,對錄音事件進行處理.
DWORD_PTR
dwCallbackInstance,
//傳給回調機制的參數
DWORD
fdwOpen
//打開設備的方法標識,指定回調的類型.參見CSDN
);
|
介紹WAVEFORMATEX結構體的含義:
1
2
3
4
5
6
7
8
9
|
typedef
struct
{
WORD
wFormatTag;
//波形聲音的格式,單聲道雙聲道使用WAVE_FORMAT_PCM.當包含在WAVEFORMATEXTENSIBLE結構中時,使用WAVE_FORMAT_EXTENSIBLE.
WORD
nChannels;
//聲道數量
DWORD
nSamplesPerSec;
//采樣率.wFormatTag為WAVE_FORMAT_PCM時,有8.0kHz,11.025kHz,22.05kHz,和44.1kHz.
DWORD
nAvgBytesPerSec;
//每秒的采樣字節數.通過nSamplesPerSec * nChannels * wBitsPerSample / 8計算
WORD
nBlockAlign;
//每次采樣的字節數.通過nChannels * wBitsPerSample / 8計算
WORD
wBitsPerSample;
//采樣位數.wFormatTag為WAVE_FORMAT_PCM時,為8或者16
WORD
cbSize;
//wFormatTag為WAVE_FORMAT_PCM時,忽略此參數
} WAVEFORMATEX;
|
介紹dwCallback回調函數格式:
1
2
3
4
5
6
7
|
void
CALLBACK waveInProc(
HWAVEIN hwi,
//回調此函數的設備句柄
UINT
uMsg,
//波形聲音輸入信息,標識關閉(WIM_CLOSE)、緩沖區滿(WIM_DATA)、打開(WIM_OPEN).
DWORD_PTR
dwInstance,
//用戶在waveInOpen指定的數據
DWORD_PTR
dwParam1,
//(LPWAVEHDR)dwParam1,用戶指定的緩沖區
DWORD_PTR
dwParam2
);
|
4. waveInPrepareHeader:為音頻輸入設備准備一個緩沖區
1
2
3
4
5
|
MMRESULT waveInPrepareHeader(
HWAVEIN hwi,
//音頻輸入設備句柄
LPWAVEHDR pwh,
//指向WAVEHDR結構的指針,標識准備的緩沖區
UINT
cbwh
//WAVEHDR結構的大小,使用sizeof即可
);
|
介紹WAVEHDR結構:
1
2
3
4
5
6
7
8
9
10
|
typedef
struct
wavehdr_tag {
LPSTR
lpData;
//指向波形格式的緩沖區
DWORD
dwBufferLength;
//緩沖區的大小
DWORD
dwBytesRecorded;
//當前存儲了多少數據
DWORD_PTR
dwUser;
//用戶數據
DWORD
dwFlags;
//為緩沖區提供的信息,在waveInPrepareHeader函數中使用WHDR_PREPARED
DWORD
dwLoops;
//輸出時使用,標識播放次數
struct
wavehdr_tag * lpNext;
//reserved
DWORD_PTR
reserved;
//reserved
} WAVEHDR, *LPWAVEHDR;
|
5. waveInAddBuffer:將緩沖區發送給設備,若緩沖區填滿,則不起作用。(參數同上)
1
2
3
4
5
|
MMRESULT waveInAddBuffer(
HWAVEIN hwi,
LPWAVEHDR pwh,
UINT
cbwh
);
|
6. waveInStart:開始進行錄制
1
2
3
|
MMRESULT waveInStart(
HWAVEIN hwi
//設備句柄
);
|
7. waveInClose:關閉設備
1
2
3
|
MRESULT waveInClose(
HWAVEIN hwi
//設備句柄
);
|
三、完整實例代碼如下:
//Run.c文件 #include <Windows.h> #include <stdio.h> #include "mmsystem.h" #pragma comment(lib, "winmm.lib") void PlayMusi(); void WaveInitFormat(LPWAVEFORMATEX m_WaveFormat, WORD nCh,DWORD nSampleRate,WORD BitsPerSample); DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2); void RecordWave(); void main() { //PlayMusi(); RecordWave(); while(1); } void RecordWave() { int count = waveInGetNumDevs();//1 printf("\n音頻輸入數量:%d\n",count); WAVEINCAPS waveIncaps; MMRESULT mmResult = waveInGetDevCaps(0,&waveIncaps,sizeof(WAVEINCAPS));//2 printf("\n音頻輸入設備:%s\n",waveIncaps.szPname); if(MMSYSERR_NOERROR==mmResult) { HWAVEIN phwi; WAVEFORMATEX pwfx; WaveInitFormat(&pwfx,1,8000,8); printf("\n請求打開音頻輸入設備"); printf("\n采樣參數:單聲道 8kHz 8bit\n"); mmResult=waveInOpen(&phwi,WAVE_MAPPER,&pwfx,(DWORD)(MicCallback),NULL,CALLBACK_FUNCTION);//3 if(MMSYSERR_NOERROR==mmResult) { WAVEHDR pwh1; char buffer1[10240]; pwh1.lpData=buffer1; pwh1.dwBufferLength=10240; pwh1.dwUser=1; pwh1.dwFlags=0; mmResult=waveInPrepareHeader(phwi,&pwh1,sizeof(WAVEHDR));//4 printf("\n准備緩沖區1"); WAVEHDR pwh2; char buffer2[10240]; pwh2.lpData=buffer2; pwh2.dwBufferLength=10240; pwh2.dwUser=2; pwh2.dwFlags=0; mmResult=waveInPrepareHeader(phwi,&pwh2,sizeof(WAVEHDR));//4 printf("\n准備緩沖區2\n"); if(MMSYSERR_NOERROR==mmResult) { mmResult=waveInAddBuffer(phwi,&pwh1,sizeof(WAVEHDR));//5 printf("\n將緩沖區1加入音頻輸入設備"); mmResult=waveInAddBuffer(phwi,&pwh2,sizeof(WAVEHDR));//5 printf("\n將緩沖區2加入音頻輸入設備\n"); if(MMSYSERR_NOERROR==mmResult) { mmResult=waveInStart(phwi);//6 printf("\n請求開始錄音\n"); } } } } } DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { switch(uMsg) { case WIM_OPEN: printf("\n設備已經打開...\n"); break; case WIM_DATA: printf("\n緩沖區%d存滿...\n",((LPWAVEHDR)dwParam1)->dwUser); waveInAddBuffer (hwavein, (LPWAVEHDR)dwParam1, sizeof (WAVEHDR)) ; break; case WIM_CLOSE: printf("\n設備已經關閉...\n"); break; default: break; } return 0; } void WaveInitFormat(LPWAVEFORMATEX m_WaveFormat, WORD nCh,DWORD nSampleRate,WORD BitsPerSample) { m_WaveFormat->wFormatTag = WAVE_FORMAT_PCM; m_WaveFormat->nChannels = nCh; m_WaveFormat->nSamplesPerSec = nSampleRate; m_WaveFormat->nAvgBytesPerSec = nSampleRate * nCh * BitsPerSample/8; m_WaveFormat->nBlockAlign = m_WaveFormat->nChannels * BitsPerSample/8; m_WaveFormat->wBitsPerSample = BitsPerSample; m_WaveFormat->cbSize = 0; } void PlayMusi() { int error = mciSendString("open C:\\Users\\Angel\\Desktop\\有多少愛可以重來.mp3 alias myDivece", NULL, 0, NULL); if (error == 0) { mciSendString("play myDivece", NULL, 0, NULL); //播放 } }