from http://www.vckbase.com/index.php/wv/434

平时,你在多媒体软件的设计中是怎样处理声音文件的呢?使用Windows 提供的API函数 sndPlaySound来实现WAV文件的播放?但是,你有没有遇到过这种情况呢:当WAV文件大于可用内存时,sndPlaySound 函数就不能进行播放!!!那么,如何利用MCI播放大型音频文件呢?

本文将介绍一种方法。

Windows支持两种RIFF(resource interchange file format,“资源交互文件格式”)音 频文件:MIDI的RMID文件和波形音频文件格式WAV文件,本文将介绍如何用MCI命令播放大型W AV文件。用sndPlaySound播放音频文件只需要一行代码。比如实现异步播放的方法为 sndPlaySound("c:\windows\ding.wav",SND_ASYNC);

由此可以看到,sndPlaySound 的使用是很简单的。但是用sndPlaySound播放音频文件有 一个限制,即整个音频文件必须全部调入可用的物理内存。因此应用sndPlaySound播放的音频 文件相对较小,最大约100K。要播放大一些的音频文件(在多媒体设计中是经常要遇到的情况 )需要使用MCI的功能。这里创建了一个Cwave类,可以处理播放音频的MCI命令,因为该类能够 执行很多的MCI命令和建立了数据结构,所以只需要简单的成员函数(如OpenDevice, CloseDe vice, Play和Stop)。在CWave类中抽象了特定的MCI命令和数据结构,只含几个简单的成员函
数OpenDevice, CloseDevice, Play和Stop。波形音频设备是一个复合设备,如果打开波形设 备,然后打开并关闭每个波形元素,最后关闭波形设备,这样可以使得播放性能更好。调用C wave::OpenDevice就可以打开波形设备,OpenDevice将MCI_OPEN命令传递给mciSendCommand函 数,如果调用成功,就用数据结构MCI_OPEN_PARMS的wDeviceID成员返回波形设备的标识符, 该标识符保存在一个供以后使用的私有数据成员中。一旦打开了Cwace对象,通过Cwace::Pla
y播放WAV文件就就绪了,WAV文件名和一个窗口指针被传递给Play方法以便将MCI通知消息发送 到制定的窗口。

WAV文件的播放首先要通过分配一个MCI_OPEN_PARMS结构并给所要播放的WAV文件设置

lpstrElementName成员打开WAV文件。将该结构和MCI_OPEN传递给mciSendCommand,打开WAV文件 并用MCI_OPEN_PARMS结构的wDeviceID成员返回元素标识符。第二步是命令波形音频设备播放 WAV文件。分配了MCI_PLAY_PARMS结构并将dwCallback成员设置为窗口句柄。如果要同步播放 音频波形文件,就增加MCI_WAIT标志并跳过窗口句柄。这样做会使应用程序在mciSendComman d函数返回之前等待WAV文件播放完毕。最可能的情况是异步播放大型WAV文件,可以象下面那
样指定MCI_NOTIFY标志并设置dwCallback成员做到这一点。

  1. MCI_PLAY_PARMS mciPlayParms;
  2. MciPlayParms.dwCallback=(DWORD)pWnd->m_hWnd;
  3. DwResult=mciSendCommand(m_nDevice,
  4. MCI_PLAY,
  5. MCI_NOTIFY,
  6. (DWORD)(LPVOID)&mciPlayParms);

这样就开始了WAV文件的播放,并且在播放完毕后,MM_MCINOTIFY消息会发送到指定的窗口。一个WAV文件播放所发生的事件序列为:(1)命令播放WAV文件并立即返回;(2)播放WAV文 件;(3)完成后发送通知消息。

完成播放后关闭WAV文件元素是程序员的责任,简单的调用Cwave类的Stop成员函数就可以了。Stop成员函数将WAV文件标识符和MCI_CLOSE命令传递给mciSendCommand函数,不必为该命令分配一个MCI结构,下述代码关闭了WAV文件:

  1. mciSendCommand(m_nElement,MCI_CLOSE,NULL,NULL);

播放完所有的WAV文件后必须关闭波形音频设备,Cwave类的析构函数调用Cwave::Close Device自动完成。 将本文中介绍的CWave类加入到自己的程序中,就可以方便的应用它播放音频文件了。

//建立Cwave类,放在Wave.h文件中:

  1. class CWave:public CObject
  2. {
  3. //Construction
  4. public:
  5. CWave();
  6. virtual ~CWave();
  7.  
  8. //Operations
  9. public:
  10. DWORD OpenDevice();
  11. DWORD CloseDevice();
  12. DWORD Play(CWnd *pParentWnd,LPCSTR pFileName);
  13. DWORD Stop();
  14.  
  15. //Implementation
  16. protected:
  17. void DisplayErrorMsg(DWORD dwError);
  18.  
  19. //Members
  20. protected:
  21. MCIDEVICEID m_nDeviceID;
  22. MCIDEVICEID m_nElementID;
  23. };
  24.  
  25. //Cwave类的实现代码,Cwave.cpp
  26. #include <stdafx.h>
  27. #include "cwave.h"
  28.  
  29. CWave::CWave()
  30. {
  31. m_nDeviceID=0;
  32. m_nElementID=0;
  33. }
  34.  
  35. CWave::~CWave()
  36. {
  37. if(m_nElementID)
  38. Stop();
  39. if(m_nDeviceID)
  40. CloseDevice();
  41. }
  42.  
  43. DWORD CWave::OpenDevice()
  44. {
  45. DWORD dwResult=0;
  46.  
  47. if (m_nDeviceID)
  48. {
  49. MCI_OPEN_PARMS mciOpenParms;
  50.  
  51. mciOpenParms.lpstrDeviceType=(LPSTR)MCI_DEVTYPE_WAVEFORM_AUDIO;
  52.  
  53. //open the wave device
  54. dwResult = mciSendCommand(NULL,
  55. MCI_OPEN,
  56. MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_WAIT,
  57. (DWORD)(LPVOID)&mciOpenParms);
  58.  
  59. //save device identifier,will use eith other MCI commands
  60. m_nDeviceID = mciOpenParms.wDeviceID;
  61.  
  62. //display error message if failed
  63. if(dwResult)
  64. DisplayErrorMsg(dwResult);
  65. }
  66. //return result of MCI operation
  67. return dwResult;
  68. }
  69.  
  70. DWORD CWave::CloseDevice()
  71. {
  72. DWORD dwResult=0;
  73.  
  74. //close if currently open
  75. if(m_nDeviceID)
  76. {
  77. //close the MCI device
  78. dwResult=mciSendCommand(m_nDeviceID,MCI_CLOSE,NULL,NULL);
  79.  
  80. //display error message if failed
  81. if(dwResult)
  82. DisplayErrorMsg(dwResult);
  83.  
  84. //set identifier to close state
  85. else
  86. m_nDeviceID=0;
  87. }
  88.  
  89. //return result of MCI operation
  90. return dwResult;
  91. }
  92.  
  93. DWORD CWave::Play(CWnd* pWnd,LPCSTR pFileName)
  94. {
  95. MCI_OPEN_PARMS mciOpenParms;
  96. //initialize structure
  97. memset(&mciOpenParms,0,sizeof(MCI_OPEN_PARMS));
  98.  
  99. //set the WAV file name to be played
  100. mciOpenParms.lpstrElementName=pFileName;
  101.  
  102. //first open the device
  103. DWORD dwResult=mciSendCommand(m_nDeviceID,MCI_OPEN,
  104. MCI_OPEN_ELEMENT,(DWORD)(LPVOID)&mciOpenParms);
  105.  
  106. //display error message if failed
  107. if(dwResult)
  108. DisplayErrorMsg(dwResult);
  109.  
  110. //if successful,instruct the device to play the WAV file
  111. else
  112. {
  113. //save element indentifier
  114. m_nElementID=mciOpenParms.wDeviceID;
  115.  
  116. MCI_PLAY_PARMS mciPlayParms;
  117.  
  118. //set the window that will receive notification message
  119. mciPlayParms.dwCallback=(DWORD)pWnd->m_hWnd;
  120.  
  121. //instruct device to play file
  122. dwResult=mciSendCommand(m_nElementID,MCI_PLAY,
  123. MCI_NOTIFY,(DWORD)(LPVOID)&mciPlayParms);
  124.  
  125. //display error and close element if failed
  126. if(dwResult)
  127. {
  128. DisplayErrorMsg(dwResult);
  129. Stop();
  130. }
  131. }
  132.  
  133. //return result of MCI operation
  134. return dwResult;
  135. }
  136.  
  137. DWORD CWave::Stop()
  138. {
  139. DWORD dwResult=0;
  140.  
  141. //close if element is currently open
  142. if(m_nElementID)
  143. {
  144. dwResult=mciSendCommand(m_nElementID,MCI_CLOSE,NULL,NULL);
  145.  
  146. //display error message if failed
  147. if(dwResult)
  148. DisplayErrorMsg(dwResult);
  149. //set identifier to closed state
  150. else
  151. m_nElementID=0;
  152. }
  153. return dwResult;
  154. }
  155.  
  156. void CWave::DisplayErrorMsg(DWORD dwError)
  157. {
  158. //check if there was an error
  159. if(dwError)
  160. {
  161. //character string that contains error message
  162. char szErrorMsg[MAXERRORLENGTH];
  163.  
  164. //retrieve string associated error message
  165. if(!mciGetErrorString(dwError,szErrorMsg,sizeof(szErrorMsg)))
  166. strcpy(szErrorMsg,"Unknown Error");
  167. //display error string in message box
  168. AfxMessageBox(szErrorMsg);
  169. }
  170. }

如何播放 WAV 文件?的更多相关文章

  1. C#播放wav文件

    C#使用HWQPlayer类播放wav文件 类的代码: using System.IO; using System.Runtime.InteropServices; namespace HoverTr ...

  2. python 播放 wav 文件

    未使用其他库, 只是使用 pywin32 调用系统底层 API 播放 wav 文件. # Our raison d'etre - playing sounds import pywintypes im ...

  3. WinAPI: sndPlaySound - 播放 wav 文件

    WinAPI: sndPlaySound - 播放 wav 文件 //声明: sndPlaySound(   lpszSoundName: PChar; {声音文件}   uFlags: UINT{播 ...

  4. 8086汇编语言 调用声卡播放wav文件(sound blaster)

    开更 大概最后做了一个能播放无损音乐(无压缩.不需解码)的播放器 原理是基于dosbox的模拟声卡,通过硬件之间的相互通讯做到的 关于详细内容接下来再讲. 一.从dosbox入手 我们知道cpu可以直 ...

  5. Linux音频编程--使用ALSA库播放wav文件

    在UBUNTU系统上使用alsa库完成了对外播放的wav文件的案例. 案例代码: /** *test.c * *注意:这个例子在Ubuntu 12.04.1环境下编译运行成功. * */ #inclu ...

  6. c++(qt)播放wav文件的四种方式

    //方法一(要符合RIFF规范) 1 QSound::play("E:/Projects/报警声1-1.wav"); //方法二(要符合RIFF规范) 1 QSoundEffect ...

  7. windows下使用waveout函数族播放wav文件

    要使用waveout函数组,族,首先要知道几个数据结构,首先是这个 typedef struct tWAVEFORMATEX { WORD wFormatTag; /* 格式的类型 */ WORD n ...

  8. 【C#学习笔记】播放wav文件

    using System; using System.Media; namespace ConsoleApplication { class Program { static void Main(st ...

  9. java播放wav文件

    import java.io.File; import java.io.IOException; import javax.sound.sampled.AudioFormat; import java ...

随机推荐

  1. 腾讯自研万亿级消息中间件TubeMQ为什么要捐赠给Apache?

    导语 | 近日,云+社区技术沙龙“腾讯开源技术”圆满落幕.本次沙龙邀请了多位腾讯技术专家围绕腾讯开源与各位开发者进行探讨,深度揭秘了腾讯开源项目TencentOS tiny.TubeMQ.Kona J ...

  2. PHP 对接 饿了么开放平台 接单

    <?php # 一开始使用的是API方式对接,所以我这里是API的方式+SDK的结合 (除了获取token之外都是使用SDK方式,所以看到的朋友还是直接使用纯SDK方式对接最好),因为我这里使用 ...

  3. 日志冲突解决方案(基于gradle)

    日志冲突解决方案 前提:我使用gradle管理项目 最近在项目中需要用curator客户端操作zookeeper,在maven仓库拉取的jar包导致日志冲突,会报以下的错误: 经常会有如上图2处红色框 ...

  4. asp.net core系列 74 Exceptionless服务端安装

    一.   Docker安装 Docker   要求版本Docker 18.09.0+以上 安装地址:https://www.runoob.com/docker/windows-docker-insta ...

  5. 《C++Primer》第五版习题解答--第四章【学习笔记】

    [C++Primer]第五版习题解答--第四章[学习笔记] ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2020/1/11 第四章:表达式 练习4. ...

  6. FUTABA舵机参数大全

    S9150 Digital servo 尺寸:47.5X27X25.3mm 重量:53g 速度:0.18sec/60"(4.8V) 扭力:5.8kg:cm(4.8V) ——————————— ...

  7. 基于springboot+thymeleaf+springDataJpa自带的分页插件实现完整的动态分页

    实现百度搜索使用的前五后四原则,效果如下. 下面贴出代码,复制到前端即可,只需要域中放置page对象就可以.(springdatajpa自带的page 注意:第一页是按0开始算的) <div c ...

  8. Go的内存对齐和指针运算详解和实践

    uintptr 和 unsafe普及 uintptr 在Go的源码中uintptr的定义如下: /* uintptr is an integer type that is large enough t ...

  9. 【5min+】闪电光速拳? .NetCore 中的Span

    系列介绍 简介 [五分钟的DotNet]是一个利用您的碎片化时间来学习和丰富.net知识的博文系列.它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的. ...

  10. cogs 3008. 朋友圈

    3008. 朋友圈 ★★   输入文件:friendscircle.in   输出文件:friendscircle.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] NO ...