[轉自:http://blog.csdn.net/zhi_qiu_yi_ye/article/details/6663366]
使用 Wave API 進行Windows音頻編程可以保持很大的自由度,而且與Linux中的OSS編程模式很像。下面我簡單介紹函數的調用順序,具體的用法參見MSDN(VS2008)。
waveInOpen -> waveInPrepareHeader -> waveInAddBuffer -> waveInStart -> waveInStop -> waveInReset ->waveInUnprepareHeader -> waveInClose
錄音的回呼函數只需要處理WIM_DATA訊息,拷貝資料及重新調用waveInAddBuffer將此緩衝排入佇列。
waveOutOpen -> waveOutPrepareHeader -> waveOutWrite -> waveOutReset -> waveOutUnprepareHeader -> waveOutClose
下面是一個Win32控制台程式的源碼,環境VS2008,建立一個空的Win32控制台項目,加入此檔案編譯即可,功能為錄製5秒並回放。注意不要選擇Unicode字元集,不然裝置名稱會出現亂碼。
#include "stdafx.h"////WaveAPI.cpp//// by: 知秋一葉//#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <mmsystem.h>#pragma comment(lib, "winmm.lib")#define BUFFER_SIZE (44100*16*2/8*5)// 錄製聲音長度#define FRAGMENT_SIZE 1024// 緩衝區大小#define FRAGMENT_NUM 4// 緩衝區個數static unsigned char buffer[BUFFER_SIZE] = {0};static int buf_count = 0;// 函數定義void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 );void CALLBACK waveOutProc( HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 );// 入口int main(){/* 錄音 */// Deviceint nReturn = waveInGetNumDevs();printf("輸入裝置數目:%d\n", nReturn);for (int i=0; i<nReturn; i++){WAVEINCAPS wic;waveInGetDevCaps(i, &wic, sizeof(WAVEINCAPS));printf("#%d\t裝置名稱:%s\n", i, wic.szPname);}// openHWAVEIN hWaveIn;WAVEFORMATEX wavform;wavform.wFormatTag = WAVE_FORMAT_PCM;wavform.nChannels = 2;wavform.nSamplesPerSec = 44100;wavform.nAvgBytesPerSec = 44100*16*2/8;wavform.nBlockAlign = 4;wavform.wBitsPerSample = 16;wavform.cbSize = 0;waveInOpen(&hWaveIn, WAVE_MAPPER, &wavform, (DWORD_PTR)waveInProc, 0, CALLBACK_FUNCTION);WAVEINCAPS wic;waveInGetDevCaps((UINT_PTR)hWaveIn, &wic, sizeof(WAVEINCAPS));printf("開啟的輸入裝置:%s\n", wic.szPname);// prepare bufferstatic WAVEHDR wh[FRAGMENT_NUM];for (int i=0; i<FRAGMENT_NUM; i++){wh[i].lpData = new char[FRAGMENT_SIZE];wh[i].dwBufferLength = FRAGMENT_SIZE;wh[i].dwBytesRecorded = 0;wh[i].dwUser = NULL;wh[i].dwFlags = 0;wh[i].dwLoops = 1;wh[i].lpNext = NULL;wh[i].reserved = 0;waveInPrepareHeader(hWaveIn, &wh[i], sizeof(WAVEHDR));waveInAddBuffer(hWaveIn, &wh[i], sizeof(WAVEHDR));}// recordprintf("Start to Record...\n");buf_count = 0;waveInStart(hWaveIn);while (buf_count < BUFFER_SIZE){Sleep(1);}printf("Record Over!\n\n");// cleanwaveInStop(hWaveIn);waveInReset(hWaveIn);for (int i=0; i<FRAGMENT_NUM; i++){waveInUnprepareHeader(hWaveIn, &wh[i], sizeof(WAVEHDR));delete wh[i].lpData;}waveInClose(hWaveIn);system("pause");printf("\n");/* 放音 */// DevicenReturn = waveOutGetNumDevs();printf("\n輸出裝置數目:%d\n", nReturn);for (int i=0; i<nReturn; i++){WAVEOUTCAPS woc;waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS));printf("#%d\t裝置名稱:%s\n", i, wic.szPname);}// openHWAVEOUT hWaveOut;waveOutOpen(&hWaveOut, WAVE_MAPPER, &wavform, (DWORD_PTR)waveOutProc, 0, CALLBACK_FUNCTION);WAVEOUTCAPS woc;waveOutGetDevCaps((UINT_PTR)hWaveOut, &woc, sizeof(WAVEOUTCAPS));printf("開啟的輸出裝置:%s\n", wic.szPname);// prepare bufferWAVEHDR wavhdr;wavhdr.lpData = (LPSTR)buffer;wavhdr.dwBufferLength = BUFFER_SIZE;wavhdr.dwFlags = 0;wavhdr.dwLoops = 0;waveOutPrepareHeader(hWaveOut, &wavhdr, sizeof(WAVEHDR));// playprintf("Start to Play...\n");buf_count = 0;waveOutWrite(hWaveOut, &wavhdr, sizeof(WAVEHDR));while (buf_count < BUFFER_SIZE){Sleep(1);}// cleanwaveOutReset(hWaveOut);waveOutUnprepareHeader(hWaveOut, &wavhdr, sizeof(WAVEHDR));waveOutClose(hWaveOut);printf("Play Over!\n\n");return 0;}// 錄音回呼函數void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ){LPWAVEHDR pwh = (LPWAVEHDR)dwParam1;if ((WIM_DATA==uMsg) && (buf_count<BUFFER_SIZE)){int temp = BUFFER_SIZE - buf_count;temp = (temp>pwh->dwBytesRecorded) ? pwh->dwBytesRecorded : temp;memcpy(buffer+buf_count, pwh->lpData, temp);buf_count += temp;waveInAddBuffer(hwi, pwh, sizeof(WAVEHDR));}}// 放音回呼函數void CALLBACK waveOutProc( HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ){if (WOM_DONE == uMsg){buf_count = BUFFER_SIZE;}}