windows下使用waveout函数族播放wav文件
要使用waveout函数组,族,首先要知道几个数据结构,首先是这个
typedef struct tWAVEFORMATEX { WORD wFormatTag; /* 格式的类型 */ WORD nChannels; /* 通道数 */ DWORD nSamplesPerSec; /* 采样频率 */ DWORD nAvgBytesPerSec; /* 比特率 采样率*声道数*采样位数/8 */ WORD nBlockAlign; /* 一次采样的宽度 通道数*采样位数/8 */ WORD wBitsPerSample; /* 采样位数 */ WORD cbSize; /* 外部附加信息,不用设置为0 */ /* extra information (after cbSize) */ } WAVEFORMATEX,
这个结构体在打开音频设备准备播放声音的时候是必须的,打开音频设备的时候需要使用的函数为
if(!(waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,(LPWAVEFORMATEX)&pFormat,(DWORD)this, 0, 0) == MMSYSERR_NOERROR))
第一个参数是音频设备的句柄,定义如下
LPHWAVEOUT hWaveOut;
实际上也就是一个设备指针
第二个参数为设备类型,其中选择WAVE_MAPPER能选一个能够播放给定格式的波形音频输出装置
第三个参数为音频数据的格式信息
第四个参数是一个回调函数
第五个是回调函数的资源句柄
第六个是打开装置的标识,具体的描述可以去看msdn成功后返回MMSYSERR_NOERROR ,否则返回以下值:
值描述
MMSYSERR_ALLOCATED 表示资源已存在
MMSYSERR_BADDEVICEID 装置ID超出范围
MMSYSERR_NODRIVER 没有驱动
MMSYSERR_NOMEM 不能分配内存
WAVERR_BADFORMAT 企图打开一个不被支持的格式
WAVERR_SYNC 装置是可同步的,但waveOutOpen没用有WAVE_ALLOWSYNC
打开音频设备之后就需要准备音频的格式信息了,这里需要第二个结构体
/* wave data block header */ typedef struct wavehdr_tag { LPSTR lpData; /*指向锁定数据缓冲区的指针 */ DWORD dwBufferLength; /*数据缓冲区长度 */ DWORD dwBytesRecorded; /* used for input only */ DWORD_PTR dwUser; /* for client's use */ DWORD dwFlags; /* assorted flags (see defines) */ DWORD dwLoops; /* loop control counter */ struct wavehdr_tag FAR *lpNext; /* reserved for driver */ DWORD_PTR reserved; /* reserved for driver */ } WAVEHDR
使用方式如下
hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)sizeof(WAVEHDR)); if(hWaveHdr == NULL) { MessageBox("Not enough memory for header","error",MB_OK);//打开设备失败 return; } lpWaveHdr = (LPWAVEHDR)GlobalLock(hWaveHdr); if(lpWaveHdr == NULL) { MessageBox("Failed to lock memory for header","error",MB_OK); return; } // 初始化音频结构After allocation, set up and prepare header. lpWaveHdr->lpData = (char *)pVoiceBuffer; lpWaveHdr->dwBufferLength = lFileSize; lpWaveHdr->dwFlags = 0L; //WHDR_BEGINLOOP | WHDR_ENDLOOP; lpWaveHdr->dwLoops = 0L; if(waveOutPrepareHeader((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
缓冲区可以设置为我们读取进来的数据的内存地址,另外,该缓冲区需要锁定
接下来就可以写入数据了
wResult = waveOutWrite((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
写入数据失败的话要把之前锁定的缓冲区解除掉,使用这个函数
waveOutUnprepareHeader((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); GlobalUnlock(lpWaveHdr); GlobalFree(hWaveHdr);
如果成功就可以进入循环一直播放知道数据播放完成,如下
while(waveOutUnprepareHeader((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR))!= MMSYSERR_NOERROR) { //循环清除缓冲区,如果成功表示播放完毕 //如果没有播放完毕则循环下面语句 if(bExit) break;//让循环也可以响应消息 MSG message; if(::PeekMessage (&message,NULL,0,0,PM_REMOVE)) { ::TranslateMessage (&message); ::DispatchMessage (&message); } }
数据播放完成之后需要先复位播放器在关闭音频设备,如下
//播放完毕 if(waveOutReset((HWAVEOUT)hWaveOut) != MMSYSERR_NOERROR) { MessageBox("WaveOutReset Error!","error",MB_OK); return; } if(waveOutClose((HWAVEOUT)hWaveOut)!= MMSYSERR_NOERROR) { MessageBox("WaveOutClose Error!","error",MB_OK); return; }
通过这些就能完成一个基本的wav播放器了,同时mp3的播放器只需要mp3解码也能做了
界面如下
工程代码链接如下
http://download.csdn.net/detail/dengrengong/8639579