使用WindowsAPI獲取錄音音頻


本文實例介紹了使用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); //播放
 }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM