使用WaveOut接口播放WAV文件
来源:互联网 发布:深圳福永美工招聘 编辑:程序博客网 时间:2024/05/22 03:29
我需要在插件中实现一边接收数据,一边展示媒体文件的功能,因此从最简单的音频文件来开始研究,绝大多数API如:playSound等都是根据完整文件来播放音频的,即便是内存模式也是需要将整个文件全部读入一片内容,然后将内存指针传递给playSound。最后逐渐寻找到WaveOut接口。
要一边接收数据一边播放,首先需要得到头信息,然后使用多个缓存在WaveOutWrite中交替为音频设备填充数据。
这里有几个我觉得不错的参考资料:
http://apps.hi.baidu.com/share/detail/59300070
http://blog.csdn.net/jinlking/article/details/3864259
我在做的过程中,遇到的比较棘手的问题是:1:在WaveOutOpen函数中的回调函数的处理。2、多个缓存交替播放时声音一卡一卡的。
第一个问题:因为我使用了一个WavePlayer类来实现我的功能,在这个类的构造函数中做了一些准备工作,根据文件头数据音乐信息。然后,最后play函数中指定回调函数,准备最开始的数据填充接受三个参数:最后每当播放完毕就会调用回调函数,在回调函数中填充当前数据。
回调函数必须是全局函数,在类中只能以static函数存在,但是静态成员函数无法访问类的非静态成员变量,因此这里很久才搞定,最后解决方案是在WaveOutOpen中奖第五个参数设置为this。利用this指针来将对象传递到静态回调函数中,在回调函数中将这个指针强制转换成wavePlayer*。这样就可以访问该对象的非静态成员了。
- bool WavePlayer::wavePlay(HPSTR wavData,long dataSize,int numOfBuf/* =1 */)
- {
- //多缓存交替播放
- DWORD rs=0;
- //检查音频设备,返回音频输出设备的性能
- if (MMSYSERR_NOERROR != (rs = waveOutGetDevCaps(WAVE_MAPPER, &pwoc, sizeof(WAVEOUTCAPS))))
- {
- ErrHandler(_T("waveOutGetDevCaps()"),rs);
- return false;
- }
- if (MMSYSERR_NOERROR != (rs =waveOutOpen(&hWaveOut, WAVE_MAPPER, &wvformat, (DWORD)waveOutCallBack, (DWORD_PTR)this, CALLBACK_FUNCTION)))
- {
- ErrHandler(_T("waveOutOpen()"),rs);
- return false;
- }
- HPSTR dataBlocks=new char[dataSize*numOfBuf];
- memcpy(dataBlocks,wavData,dataSize*numOfBuf);
- lpWavhdr = new WAVEHDR[numOfBuf];
- for (int i=0;i<numOfBuf;++i)
- {
- //准备播放数据
- lpWavhdr[i].lpData = (HPSTR)(dataBlocks+i*dataSize);
- lpWavhdr[i].dwBufferLength = dataSize;
- lpWavhdr[i].dwFlags = 0;
- if (MMSYSERR_NOERROR != (rs =waveOutPrepareHeader(hWaveOut, (LPWAVEHDR)(&lpWavhdr[i]), sizeof(WAVEHDR))))
- {
- ErrHandler(_T("waveOutPrepareHeader()"),rs);
- return false;
- }
- //将数据写入设备并开始播放
- if (MMSYSERR_NOERROR != (rs =waveOutWrite(hWaveOut,(LPWAVEHDR)(&lpWavhdr[i]) , sizeof(WAVEHDR))))
- {
- ErrHandler(_T("waveOutWrite()"),rs);
- return false;
- }
- }
- *pIsLoop=true;
- *pIsBufNull=true;
- lpData=new char[dataSize];
- return true;
- }
- void CALLBACK WavePlayer::waveOutCallBack(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
- {
- WavePlayer* pPlayer=(WavePlayer*)dwInstance;
- if(uMsg == WOM_DONE)
- {
- if (!*(pPlayer->pIsLoop))
- {
- return;//不在交替播放循环,直接返回
- }
- if (*(pPlayer->pIsBufNull)&&!*(pPlayer->pIsEod))
- {
- return;//缓存为空,但不是文件尾部,返回
- }
- LPWAVEHDR pWaveHeader = (LPWAVEHDR)dwParam1;//系统自动识别是哪一个WAVEHDR播放完毕
- pWaveHeader->dwFlags=0;
- waveOutUnprepareHeader( hwo, pWaveHeader, sizeof(WAVEHDR) );//播放完后须调用此函数
- if (*(pPlayer->pIsEod)&&*(pPlayer->pIsBufNull))
- {
- return;//数据已经读取完毕,且缓存为空。Unprepare之后再返回
- }
- //此处填充WAVEHDR的lpdate缓冲
- pWaveHeader->lpData=pPlayer->lpData;
- pWaveHeader->dwBufferLength=pPlayer->mBufSize;
- pWaveHeader->dwFlags=0;
- waveOutPrepareHeader( hwo, pWaveHeader, sizeof(WAVEHDR));
- waveOutWrite( hwo, pWaveHeader, sizeof(WAVEHDR) );
- *(pPlayer->pIsBufNull)=true;
- }
- return;
- }
- /************************************************************************/
- /* 双缓存交替播放 */
- /************************************************************************/
- long bufSize=8*1024;
- int bufNum=2;
- long curPos=44+bufSize*bufNum;
- HPSTR lpPreData=new char[bufSize*bufNum];
- SetFilePointer(hFile,44,NULL,FILE_BEGIN);
- ReadFile(hFile,lpPreData,bufSize*bufNum,&dwRead,NULL);
- *wavPlayer.pIsBufNull=false;
- wavPlayer.mBufSize=bufSize;
- while(1)
- {
- if (!*(wavPlayer.pIsLoop))
- {
- wavPlayer.wavePlay(lpPreData,bufSize,bufNum);
- }
- if (*wavPlayer.pIsLoop)
- {
- if (lpPreData!=NULL)
- {
- delete[] lpPreData;
- lpPreData=NULL;
- }
- }
- if (*wavPlayer.pIsBufNull && !(*wavPlayer.pIsEod))
- {
- SetFilePointer(hFile,curPos,NULL,FILE_BEGIN);
- ReadFile(hFile,wavPlayer.lpData,bufSize,&dwRead,NULL);
- if (0==dwRead||ERROR_HANDLE_EOF==GetLastError())
- {
- *wavPlayer.pIsEod=true;
- *wavPlayer.pIsBufNull=false;
- break;
- }
- curPos+=bufSize;
- *wavPlayer.pIsBufNull=false;
- }
- Sleep(bufSize/0xb110);
- }
第二个问题比较小:就是声音卡顿的现象。但是找了很久才找到;就是在回调函数中填充数据的时候处理得不合理:
- pWaveHeader->lpData=pPlayer->lpData;
- memcpy(pWaveHeader->lpData,pPlayer->lpData,pPlayer->mBufSize);
关于实现双缓冲连续播放大文件的最好参考资料是前面给出的第一个链接。不过我是在作完这些之后才看到。否则我的程序应该会更漂亮一点。
- 使用WaveOut接口播放WAV文件
- 使用WaveOut接口播放WAV文件
- 使用waveOut接口在Windows中播放声音
- 使用waveOut接口在Windows中播放声音
- 使用waveOut接口在Windows中播放声音
- 使用waveOut接口在Windows中播放声音
- 使用waveOut接口在Windows中播放声音
- 使用waveOut接口在Windows中播放声音
- 使用waveOut接口在Windows中播放声音
- 使用 windows waveOut 接口
- 使用libao播放wav文件
- waveout播放pcm文件总结
- android:使用audiotrack 类播放wav文件
- 使用Audio Player来播放wav文件
- android:使用audiotrack 类播放wav文件
- 播放wav文件
- 播放WAV文件
- 播放WAV文件
- org/objectweb/asm/Type异常解决办法
- bridge来说明下hooks参数
- 给人打工的人工的人阿达瓦大
- spring中加载properties文件
- 10个不错的面试问题
- 使用WaveOut接口播放WAV文件
- UISearchBar 改变背景色
- 【思维导图】
- 【BZOJ】【P2748】【HAOI2012】【音量调节】【题解】【dp】
- 查看Linux系统的平均负载
- JavaScript(8) BOM
- iptables四个表与五个链间的处理关系
- First Missing Positive
- net中 css 控制 GridView 样式