




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、VC中使用低级音频函数WaveX播放声音文件
2、160; 王结太 2004.08.08-文章摘要: 本文讨论并实现了在VC+中使用低级音频函数WaveX播放声音文件的方法。- Windows通过高级音频函数、媒体控制接口MCI设备驱动程序;低级音频函数MIDI Mapper、低级音频设备驱动;以及DirectSound提供了音频服务,可以从声卡获取音频流。1. 播放声音文件的其它方法 在介绍wavex系列之前,我先来介绍之外的其它几种方法:1.1 MCI方法简介
3、 用MCI方法是很方便的,它对媒体设备控制主要通过命令接口函数mciSendCommand()或者字符串接口函数mciSendString()来完成的,这两个函数的作用相同。命令接口函数比命令字符串使用起来要复杂,但它为MCI提供了更为强大的控制能力,两个接口函数的原型:MCIERROR mciSendCommand(MCIDEVICEID IDDevice,UINT uMsg,DWORD fdwCommand,DWORD dwParam);MCIERROR mciSendString(LPCTSTR lpszCommand, LPTSTR lpszReturnStri
4、ng, UINT cchReturn, HANDLE hwndCallback);比如要使用mciSendCommand方法,我们先在MCI_OPEN_PARMS中设置要播放的文件并发送MCI_OPEN命令打开声音设备,发送MCI_PLAY命令消息播放,结束后发送MCI_STOP命令关闭设备。关于它们的具体使用方法可以参考MSDN。1.2 PlaySound方法 BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound ); BOOL PlayS
5、ound(LPCSTR pszSound,HMODULE hmod, DWORD fdwSound); 其中参数lpszSound是需要播放声音的.WAV文件的路径和文件名,hmod在这里为NULL,fuSound是播放声音的标志,详细说明请参考VC+中的帮助。 例如播放C:soundmusic.wav可以用sndPlaySound ("c:soundmusic.wav",SND_ASYNC);或PlaySound("c:soundmusic.wav",NULL, SND_ASYNC|SND_NODEFAULT );如
6、果没有找到music.wav文件,第一种格式将播放系统默认的声音,第二种格式不会播放系统默认的声音1,这是SND_NODEFAULT标志的作用。 当然我们也可以将声音文件作为用户自定义资源加入程序资源文件中,经过编译连接生成EXE文件,这样就可以实现无.WAV文件的声音播放。利用上面的函数也很简单,如下,其中IDR_YOUR_WAVE是加入的wave文件资源标识符: PlaySound(MAKEINTRESOURCE(IDR_YOUR_WAVE),GetModuleHandle(NULL), SND_RESOURCE);2
7、. 使用低级音频函数WaveX 下面将进入文章的主题。2.1 概述 低层音频服务及重要的数据结构低级音频服务控制着不同的音频设备,这些设备包括WAVE、MIDI和辅助音频设备2。低级音频服务包括如下内容:(1)查询音频设备;(2)打开和关闭设备驱动程序;(3)分配和准备音频数据块;(4)管理音频数据块;(5)应用结构;(6)处理错误。 2.2 重要消息及数据结构 使用低级音频函
8、数之所以能够对各个声音数据块操作,要归功于Windows的消息映射,Windows在采集、播放完一个数据块之后就会发送有关的消息。播放声音涉及到的重要消息及触发条件如下: MM_WOM_CLOSE:在一个波形声音输出设备关闭时发出,之后该设备句柄不再有效 MM_WOM_DONE:当给定的输出缓存播放完毕返回给应用程序,或者直接调用waveOutReset函数停止播放并重置管理器 MM_WOM_OPEN:当给定的波形声音输出设备被打开时
9、160; MOM_CLOSE:当MIDI输出设备关闭时 WOM_DONE:当留缓冲播放完毕并正被返回程序时发到MIDI输出回调函数 WOM_OPEN:当MIDI输出设备打开时 重要的数据结构: 波形数据格式 WAVEFORMAT/WAVEFORMATEX 波形数据缓冲区格式 WAVEHDR 音频输出设备性能 WAVEOUTCAPS &
10、#160; 这些内容都定义在mmsystem.h头文件中,更为具体的信息请参阅MSDN。 2.3 wavex播放声音波形文件方法的大致流程 常用mmio函数: mmioOpen( ) 打开一个RIFF文件 mmioDescend ( ) 进入块 mmioRead( ); 该取RIFF文件 mmioAscend ( ); 跳出块
11、 mmioClose( ); 关闭PIFF文件 对于块来说,进入块和跳出块是配对的。 读取WAV文件的读取过程: mmioOpen( ) 打开文件 mmioDescend ("WAVE") 进入"fmt"块 mmioRead( ) 读取WAVE文件格式信息
12、 mmioAscend ( ) 跳出"fmt"块 mmioDescend ("data") 进入"data"块 mmioRead( ) 读取WAVE数据信息 mmioClose( ) 关闭文件。 &
13、#160; 输出WAV文件的过程: WaveOutOpen () 打开一个输出设备 WaveOutPrepareHeader() 准备WAVE数据头。 WaveOutWrite() 将数据写入设备并开始播放 WaveOutReset() 停止播放并重置管理器
14、 WaveOutClose() 并闭播放设备 WaveOutUnpareHeader() 清理用WaveOutPrepareHeader准备的Wave 2.4 主要程序清单2.4.1 播放部分void CPlayWaveDlg:OnPlay() LPSTR szFileName;/声音文件名 LPSTR szPathName
15、; MMCKINFO mmckinfoParent; MMCKINFO mmckinfoSubChunk; DWORD dwFmtSize; DWORD m_WaveLong; WAVEFORMATEX* lpFormat; DWORD m_dwDataOffset; DWORD m_dwDataSize; WAVEOUTCAPS pwoc; LONG lSoundOffset; LONG lSoundLong; CEdit* pEdit = (CE
16、dit*) GetDlgItem(IDC_FILE); pEdit->GetWindowText(m_strFileName); if (m_strFileName = "") ShowMsg("Please select a wave file to play!"); return; szPathName = m_strPathName.GetBuffer(0); szFileName = m_strFileName.GetB
17、uffer(0); /打开波形文件 if (!(m_hmmio = mmioOpen(szPathName, NULL, MMIO_READ | MMIO_ALLOCBUF) /*- 信息显示函数ShowMsg(): void CPlayWaveDlg:ShowMsg(char* szMsg, .) va_list vl; char szBuf256;
18、0;va_start(vl, szMsg); vsprintf(szBuf, szMsg, vl); va_end(vl); :MessageBox(NULL, szBuf, "WavePlayer", MB_OK | MB_ICONEXCLAMATION); -*/ ShowMsg("Failed to open file: %s", szFileName);&
19、#160; return; /进入块,检查打开文件是否是wave文件 mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); if (mmioDescend(m_hmmio, (LPMMCKINFO) & mmckinfoParent, NULL, MMIO_FINDRIFF) ShowMsg("%s is an invalid wave
20、 file!", szFileName); mmioClose(m_hmmio, NULL); return; /寻找 'fmt' 块 mmckinfoSubChunk.ckid = mmioFOURCC('f', 'm', 't', ' '); if (mmioDescend(m_hmmio, &mmckinfoSubChunk, &mmckinfoParent, MM
21、IO_FINDCHUNK) ShowMsg("Cannot find fmt chunk in %s!", szFileName); mmioClose(m_hmmio, NULL); return; /获得 'fmt '块的大小,申请内存 dwFmtSize = mmckinfoSubChunk.cksize ; m_hFormat = LocalAlloc(LMEM_MOVEABLE, LOWORD(dwFmtSize); i
22、f (!m_hFormat) ShowMsg("Alloc memory failed!"); return; lpFormat = (WAVEFORMATEX *) LocalLock(m_hFormat); if (!lpFormat) ShowMsg("Lock memory failed!"); OnStop(); return; if (unsigned lo
23、ng) mmioRead(m_hmmio, (HPSTR) lpFormat, dwFmtSize) != dwFmtSize) ShowMsg("Read format chunk of %s failed!", szFileName); OnStop(); return; /离开 fmt 块 mmioAscend(m_hmmio, &mmckinfoSubChunk, 0); /寻找 'data' 块
24、60;mmckinfoSubChunk.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (mmioDescend(m_hmmio, &mmckinfoSubChunk, &mmckinfoParent, MMIO_FINDCHUNK) ShowMsg("Cannot find data chunk in: %s", szFileName); OnStop();&
25、#160; return; /获得 'data'块的大小 m_dwDataSize = mmckinfoSubChunk.cksize ; m_dwDataOffset = mmckinfoSubChunk.dwDataOffset ; if (m_dwDataSize = 0L) ShowMsg("%s has no data!", szFileName); OnStop(); return; /
26、为音频数据分配内存 lpData = new charm_dwDataSize; if (!lpData) ShowMsg("Alloc memory for wave data failed!"); OnStop(); return; lSoundOffset = m_dwDataOffset; LONG lSize = mmioSeek(m_hmmio, lSoundOffset, SEEK_SET); if (lSize <
27、 0) ShowMsg("Seek data chunk of %s failed!", szFileName); OnStop(); return; lSoundLong = m_dwDataSize; m_WaveLong = mmioRead(m_hmmio, lpData, lSoundLong); if (m_WaveLong < 0) ShowMsg("Read data chunk of %s
28、 failed!", szFileName); OnStop(); return; /检查音频设备,返回音频输出设备的性能 if (waveOutGetDevCaps(WAVE_MAPPER, &pwoc, sizeof(WAVEOUTCAPS) != 0) ShowMsg("waveOutGetDevCaps() failed!"); OnStop(); return;
29、;/检查音频输出设备是否能播放指定的音频文件 /*- waveOutOpen函数最后三个参数的设置对消息处理方式起决定性作用,需要特别注意,通常我们用下列处理方法: 1. 使用窗口作为消息的接收者,则第四个参数设置为该窗口的句柄,则和这次播放有关的消息都将进入该窗口的消息队列,这时 第五个参数为NULL,第六个参数为CALLBACK_WINDOW,表明由窗口的过程来处理消息。 2. 直接使用回调函数来处理消息,则第四个参数设置为该回调函
30、数的指针,则和这次播放有关的消息都将由该函数处理,这时第 五个参数为传入该函数的参数,第六个参数为CALLBACK_FUNCTION,表明由指定函数来处理消息。 3. 使用新的线程来处理消息,则第四个参数设置为该线程函数的指针,和这次播放有关的消息都将由该线程处理,这时第五个参 数为传入该函数的参数,第六个参数为CALLBACK_THREAD,表明
31、由线程来处理消息。 4. 如果你不需要处理消息,这后面三个参数分别为NULL,NULL,CALLBACK_NULL -*/ if (waveOutOpen(&hWaveOut, WAVE_MAPPER, lpFormat, (ULONG)m_hWnd, NULL, CALLBACK_WINDOW) != 0) ShowMsg("Open the wave out devices failed!"); OnStop(); return;
32、160; /准备待播放的数据 pWaveOutHdr.lpData = (HPSTR) lpData; pWaveOutHdr.dwBufferLength = m_WaveLong; pWaveOutHdr.dwFlags = 0; pWaveOutHdr.dwLoops = 5; if (waveOutPrepareHeader(hWaveOut, &pWaveOutHdr, sizeof(WAVEHDR) != 0) ShowMsg("Failed to prepare the
33、 wave data buffer!"); OnStop(); /将数据写入设备并开始播放 if (waveOutWrite(hWaveOut, &pWaveOutHdr, sizeof(WAVEHDR) != 0) ShowMsg("Failed to write the wave data buffer"); OnStop(); 2.4.2 停止播放部分void CPlayWaveDlg:OnStop() if (m_h
34、mmio != NULL) mmioClose(m_hmmio, NULL); /停止播放并重置管理器 waveOutReset(hWaveOut); /关闭播放设备 waveOutClose(hWaveOut); /清理用WaveOutPrepareHeader准备的Wave。 waveOutUnprepareHeader(hWaveOut, &pWaveOutHdr, sizeof(WAVEHDR); /释放内存 if (m_hFormat != NU
35、LL) LocalUnlock(m_hFormat); m_hFormat = NULL; if (m_hFormat != NULL) LocalFree(m_hFormat); m_hFormat = NULL; if (lpData != NULL) delete lpData; lpData = NULL; 2.4.3 处理消息部分:添加消息映射:ON_MESSAGE(MM_WOM_DONE,OnMMWomDone)void CPlayWaveDlg:OnMMWomDone(UINT wParam, LONG lPara
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年项目管理重要考点复习试题及答案
- 小吃店经营数据分析与应用考核试卷
- 游乐设施施工中的合同履行考核试卷
- 玩具行业的跨境电商机遇考核试卷
- 新手村2024年农艺师考试试题及答案
- 学习网络2025年证券从业资格证考试试题及答案
- 资产配置与证券投资的关系试题及答案
- 2023年中国电信蚌埠分公司客户经理招聘笔试参考题库附带答案详解
- 福建事业单位考试信息技术试题及答案
- 微生物检验有效性试题及答案盘点
- 二次函数压轴题(二)【图像与取值范围】
- 儿科学课件:化脓性脑膜炎、病毒性脑炎、脑膜炎
- 安全事故隐患举报、奖励制度
- 《智能系统》第7章 自主无人系统
- 树木栽植检查记录表
- Q∕SY 1670.1-2014 投产方案编制导则 第1部分:原油、成品油管道
- WS377.4-2013 妇女保健基本数据集 第4部分:孕产期保健服务与高危管理
- 刺激性气体中毒课件
- 作文素材----片段式作文
- 巧用Mapinfo软件SQL查询功能--肖2017
- ID2016 200V三相驱动芯片-电荷泵mos管驱动芯片-骊微电子
评论
0/150
提交评论