大型WAV文件的播放

在多媒体软件的设计中经常要处理声音文件,用Windows提供的API函数sndPlaySound可以实现小型WAV文件的播放。但是当WAV文件大于可用内存时,sndPlaySound函数就不能进行播放,那么如何利用MCI播放大型音频文件呢?本文将介绍一种方法。

Windows支持两种RIFF(resource interchange file format,“资源交互文件格式”)音频文件:MIDI的RMID文件和波形音频文件格式WAV文件,本文将介绍如何用MCI命令播放大型WAV文件。

用sndPlaySound播放音频文件只需要一行代码。比如实现异步播放的方法为
sndPlaySound("c:/windows/ding.wav",SND_ASYNC);

由此可以看到,sndPlaySound的使用是很简单的。但是用sndPlaySound播放音频文件有一个限制,即整个音频文件必须全部调入可用的物理内存。因此应用sndPlaySound播放的音频文件相对较小,最大约100K。要播放大一些的音频文件(在多媒体设计中是经常要遇到的情况)需要使用MCI的功能。

本文创建了一个Cwave类,可以处理播放音频的MCI命令,因为该类能够执行很多的MCI命令和建立了数据结构,所以只需要简单的成员函数(如OpenDevice, CloseDevice, Play和Stop)。在CWave类中抽象了特定的MCI命令和数据结构,只含几个简单的成员函数OpenDevice, CloseDevice, Play和Stop。波形音频设备是一个复合设备,如果打开波形设备,然后打开并关闭每个波形元素,最后关闭波形设备,这样可以使得播放性能更好。调用Cwave::OpenDevice就可以打开波形设备,OpenDevice将MCI_OPEN命令传递给mciSendCommand函数,如果调用成功,就用数据结构MCI_OPEN_PARMS的wDeviceID成员返回波形设备的标识符,该标识符保存在一个供以后使用的私有数据成员中。

一旦打开了Cwace对象,通过Cwace::Play播放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标志并跳过窗口句柄。这样做会使应用程序在mciSendCommand函数返回之前等待WAV文件播放完毕。最可能的情况是异步播放大型WAV文件,可以象下面那样指定MCI_NOTIFY标志并设置dwCallback成员做到这一点。
    MCI_PLAY_PARMS mciPlayParms;
    MciPlayParms.dwCallback=(DWORD)pWnd->m_hWnd;
    DwResult=mciSendCommand(m_nDevice,MCI_PLAY,MCI_NOTIFY,
(DWORD)(LPVOID)&mciPlayParms);

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

图1 播放WAV文件
    完成播放后关闭WAV文件元素是程序员的责任,简单的调用Cwave类的Stop成员函数就可以了。Stop成员函数将WAV文件标识符和MCI_CLOSE命令传递给mciSendCommand函数,不必为该命令分配一个MCI结构,下述代码关闭了WAV文件
mciSendCommand(m)nElement,MCI_CLOSE,NULL,NULL);
    播放完所有的WAV文件后必须关闭波形音频设备,Cwave类的析构函数调用Cwave::CloseDevice自动完成。
    将本文中介绍的CWave类加入到自己的程序中,就可以方便的应用它播放音频文件了。
//建立Cwave类,放在Wave.h文件中
class CWave:public CObject
{
    //Construction
    public:
        CWave();
        virtual ~CWave();

//Operations
public:
        DWORD OpenDevice();
        DWORD CloseDevice();
        DWORD Play(CWnd *pParentWnd,LPCSTR pFileName);
        DWORD Stop();

//Implementation
    protected:
        void DisplayErrorMsg(DWORD dwError);

//Members
    protected:
        MCIDEVICEID m_nDeviceID;
        MCIDEVICEID m_nElementID;
};

//Cwave类的实现代码,Cwave.cpp
#include <stdafx.h>
#include "cwave.h"

CWave::CWave()
{
    m_nDeviceID=0;
    m_nElementID=0;
}

CWave::~CWave()
{
    if(m_nElementID)
        Stop();
    if(m_nDeviceID)
        CloseDevice();
}

DWORD CWave::OpenDevice()
{
    DWORD dwResult=0;
    if (m_nDeviceID)

MCI_OPEN_PARMS mciOpenParms;
    mciOpenParms.lpstrDeviceType=(LPSTR)MCI_DEVTYPE_WAVEFORM_AUDIO;
        //open the wave device
dwResult=mciSendCommand(NULL,MCI_OPEN,
            MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_WAIT,
            (DWORD)(LPVOID)&mciOpenParms);
        //save device identifier,will use eith other MCI commands
        m_nDeviceID=mciOpenParms.wDeviceID;
        //display error message if failed
        if(dwResult)
            DisplayErrorMsg(dwResult);
    }
            //return result of MCI operation
            return dwResult;
}

DWORD CWave::CloseDevice()
{
    DWORD dwResult=0;

//close if currently open
    if(m_nDeviceID)
    {

//close the MCI device
        dwResult=mciSendCommand(m_nDeviceID,MCI_CLOSE,NULL,NULL);

//display error message if failed
        if(dwResult)
            DisplayErrorMsg(dwResult);

//set identifier to close state
        else
            m_nDeviceID=0;
    }

//return result of MCI operation
    return dwResult;
}

DWORD CWave::Play(CWnd* pWnd,LPCSTR pFileName)
{
    MCI_OPEN_PARMS mciOpenParms;
    //initialize structure
    memset(&mciOpenParms,0,sizeof(MCI_OPEN_PARMS));

//set the WAV file name to be played
    mciOpenParms.lpstrElementName=pFileName;

//first open the device
    DWORD dwResult=mciSendCommand(m_nDeviceID,MCI_OPEN,
        MCI_OPEN_ELEMENT,(DWORD)(LPVOID)&mciOpenParms);

//display error message if failed
    if(dwResult)
        DisplayErrorMsg(dwResult);

//if successful,instruct the device to play the WAV file
    else
    {

//save element indentifier
        m_nElementID=mciOpenParms.wDeviceID;

MCI_PLAY_PARMS mciPlayParms;

//set the window that will receive notification message
        mciPlayParms.dwCallback=(DWORD)pWnd->m_hWnd;

//instruct device to play file
        dwResult=mciSendCommand(m_nElementID,MCI_PLAY,
            MCI_NOTIFY,(DWORD)(LPVOID)&mciPlayParms);

//display error and close element if failed
        if(dwResult)
        {
            DisplayErrorMsg(dwResult);
            Stop();
        }
    }

//return result of MCI operation
    return dwResult;
}

DWORD CWave::Stop()
{

DWORD dwResult=0;

//close if element is currently open
    if(m_nElementID)
    {
        dwResult=mciSendCommand(m_nElementID,MCI_CLOSE,NULL,NULL);

//display error message if failed
        if(dwResult)
            DisplayErrorMsg(dwResult);

//set identifier to closed state
        else
            m_nElementID=0;
    }
    return dwResult;
}

void CWave::DisplayErrorMsg(DWORD dwError)
{
    //check if there was an error
    if(dwError)
    {
        //character string that contains error message
        char szErrorMsg[MAXERRORLENGTH];

//retrieve string associated error message
        if(!mciGetErrorString(dwError,szErrorMsg,sizeof(szErrorMsg)))
            strcpy(szErrorMsg,"Unknown Error");
        //display error string in message box
        AfxMessageBox(szErrorMsg);
    }
}

大型WAV文件的播放相关推荐

  1. java wav文件_java播放wav文件

    STM32播放WAV程序_计算机软件及应用_IT/计算机_专业资料.此程序配置的采样率为16k,PWM频率144k; 此代码可以实现16位单声道的WAV文件解码,通过PWM 或者DAC输出音频.... ...

  2. 使用opensl 的BufferQueueAudioPlayer对wav文件的播放

    创建音频引擎之后,读取wav文件到内存,然后使用BufferQueueAudioPlayer进行播放. 这里在读取wav文件的时候需要对wav文件的前44个类似头信息进行解析,然后在进行播放的时候,在 ...

  3. 下载的php播放不了,php – 下载的WAV文件无法播放

    我正在从我的远程服务器(Centos 5.8)下载WAV文件.使用以下 PHP脚本: header('Content-Description: File Transfer'); header('Con ...

  4. 测试Animation大型动画文件拆分播放的可行性

    最近遇到一个问题,cutscene剧情动画文件大了复杂了之后,每次修改输出很麻烦,导出fbx就需要20分钟. 所以我想到了一个比较好的解决方法,在unity这边解决.把动画文件拆分成若干份,然后赋予不 ...

  5. java wav 时间,Java-调整WAV文件的播放速度

    I'm likely dense but I cannot seem to find a solution to my issue (NOTE: I CAN find lots of people r ...

  6. 用API函数播放wav文件声音不连续的解决方法

    作为一个多媒体技术方面的初学者,我从wav文件的播放开始了解媒体播放的流程. 于是从建立两个线程开始,线程1用来将文件中的数据读到Buffer中去,以后称为读线程,线程2用来将Buffer中的数据送到 ...

  7. IE 播放wav文件

    IE9下载wav文件总是播放的解决办法 最近写代码遇到问题,音频wav格式的文件总是下载不了,谷歌可以 .但IE浏览器总是直接打开,自己在网上找到方法解决后  在这里整理给大家. 以下是代码: HTM ...

  8. .wav文件详解,PCM数据格式,.wav生成C语言数组

    .WAV文件,PCM数据 1. 音频简介 经常见到这样的描述: 44100HZ 16bit stereo 或者 22050HZ 8bit mono 等等.44100HZ 16bit stereo: 每 ...

  9. C#文字转语音,实时播放以及mp3,wav文件保存

    源码下载地址:https://download.csdn.net/download/horseroll/10500847 无积分付费下载地址:https://download.csdn.net/dow ...

最新文章

  1. activity使用dialog主题
  2. 项目管理中常用到的简便工具
  3. javascript获取系统时间时区_5个JavaScript技巧让你成为更好的开发者
  4. socket.io.js的disconnect事件
  5. 启动mysql会遇到的问题_MySQL学习(一)——启动和登录MySql遇到的问题及解决
  6. 如何导出SQL Azure脚本?
  7. cpio -H newc参数详解
  8. 本机web开发环境的搭建--nginx篇
  9. JS规则 是非颠倒(逻辑非操作符)!是逻辑非操作符,也就是不是的意思,非真即假,非假即真...
  10. ECMAScript——(二)
  11. ubuntu下QQ无法登录解决。
  12. 推荐系统--MovieLens数据集
  13. Assigning Pods to Nodes(将Pod分配到Node)
  14. 【毕业设计】基于微信小程序的奶茶店奶茶点单系统
  15. 多地政府提及元宇宙发展 | 产业区块链发展周报
  16. 基于GPS经纬度和当地时间计算日落日出时间实现
  17. 界面开发(3)--- PyQt5用户登录界面连接数据库
  18. 第十章 初识面向对象
  19. 计算机网络技能鉴定三级,计算机网络管理员(三级)技能鉴定试题A
  20. html在线录音并上传,一种网页版在线录制wav音频的方法与流程

热门文章

  1. 连接已失效_Win 10 蓝牙bug,无法删除蓝牙设备导致键盘无法连接,如何解决?...
  2. 有喜无惊 2013苹果秋季发布会6亮点4遗憾
  3. 2021小白Python学习记录Day7 面向对象基础(上) (定义类和对象、__init__传参、self、魔术方法)
  4. java 多线程 安全 源码,纯干货,从源码解析多线程与高并发,再说不会,我再也不踏足IT圈...
  5. SpringBoot+Zookeeper+Seata实现Dubbo分布式事务管理
  6. mtb检出_Xpert MTB/RIF在儿童肺结核肺泡灌洗液检测中的应用
  7. python中怎么表示lnx_python – 如何在matplotlib中绘制一个带有代表原始数据的颜色标记的日志归一化图形图...
  8. 银行核心系统软件开发 转
  9. 移动端身份证识别技术:手机上进行身份验证
  10. 计算机毕业设计Node.js+Vue特色网红小吃网站(程序+源码+LW+部署)