[转自: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() { /* 录音 */ // Device int 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); } // open HWAVEIN 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 buffer static 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)); } // record printf("Start to Record...\n"); buf_count = 0; waveInStart(hWaveIn); while (buf_count < BUFFER_SIZE) { Sleep(1); } printf("Record Over!\n\n"); // clean waveInStop(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"); /* 放音 */ // Device nReturn = 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); } // open HWAVEOUT 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 buffer WAVEHDR wavhdr; wavhdr.lpData = (LPSTR)buffer; wavhdr.dwBufferLength = BUFFER_SIZE; wavhdr.dwFlags = 0; wavhdr.dwLoops = 0; waveOutPrepareHeader(hWaveOut, &wavhdr, sizeof(WAVEHDR)); // play printf("Start to Play...\n"); buf_count = 0; waveOutWrite(hWaveOut, &wavhdr, sizeof(WAVEHDR)); while (buf_count < BUFFER_SIZE) { Sleep(1); } // clean waveOutReset(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; } }