如何播放大型 WAV 文件?

原创 2011年10月18日 09:36:36
 平时,你在多媒体软件的设计中是怎样处理声音文件的呢?使用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成员做到这一点。
    MCI_PLAY_PARMS mciPlayParms;
    MciPlayParms.dwCallback=(DWORD)pWnd->m_hWnd;
    DwResult=mciSendCommand(m_nDevice,
                            MCI_PLAY,
                            MCI_NOTIFY,
                            (DWORD)(LPVOID)&mciPlayParms);

这样就开始了WAV文件的播放,并且在播放完毕后,MM_MCINOTIFY消息会发送到指定的窗口。一个WAV文件播放所发生的事件序列为:(1)命令播放WAV文件并立即返回;(2)播放WAV文 件;(3)完成后发送通知消息。
完成播放后关闭WAV文件元素是程序员的责任,简单的调用Cwave类的Stop成员函数就可以了。Stop成员函数将WAV文件标识符和MCI_CLOSE命令传递给mciSendCommand函数,不必为该命令分配一个MCI结构,下述代码关闭了WAV文件:
mciSendCommand(m_nElement,MCI_CLOSE,NULL,NULL);

播放完所有的WAV文件后必须关闭波形音频设备,Cwave类的析构函数调用Cwave::Close Device自动完成。 将本文中介绍的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);
    }
} 

【C】借助DirectSound进行流的形式无缝播放的例子

DirectSound是DirectX的一个组件。用于播放声音、BGM等。和DirectMusic不一样,DirectSound用于播放波形声音(WAV无损等),而不是midi音乐。通常大家使用Dir...
  • imxiangzi
  • imxiangzi
  • 2018-02-11 21:32:08
  • 90

FPGA开发之SD卡数据包的封装和命令

1 .sd卡指令数据包: sd卡的指令被封装成48位的数据包,每次传送这48位的数据包。数据包的内容包括起始位、结束位、传输位、命令索引、传输参数和7位CRC校验码。其具体格式分布如下图: 其中...
  • c602273091
  • c602273091
  • 2014-11-29 11:41:47
  • 619

linux 播放wav文件

from : http://blog.chinaunix.net/uid-9672747-id-3309602.html #include #include #include #incl...
  • yan420523
  • yan420523
  • 2013-05-10 17:09:42
  • 1841

python 实现播放wav文件

  • 2017年06月17日 15:35
  • 562B
  • 下载

如何得到WAV文件播放的总时间

 如何得到WAV文件播放的总时间?  1、直接读取wav文件头信息,从文件起始地址偏移28个字节长度为4个字节保存的是每秒钟播放的字节数,从文件起始地址偏移40个字节长度为4个字节保存的是声音数据的总...
  • 91program
  • 91program
  • 2008-06-12 14:15:00
  • 4860

linux下编程实现wav文件播放注意的小问题

1.在linux的声卡驱动中存在两种架构,一种是OSS(开放声音系统),一种是ALSA(先进Linux声音架构),对于两种驱动我们都可以编程实现wav文件的播放,但是由于OSS没有得到积极维护,并且落...
  • dingjianfeng2014
  • dingjianfeng2014
  • 2016-10-18 11:53:15
  • 273

Python--pyAudio播放wav格式声音

1、下载并安装pyaudio pyaudio下载地址 : http://people.csail.mit.edu/hubert/pyaudio/packages/ 2、pyaudio AP...
  • xsc_c
  • xsc_c
  • 2013-05-18 16:25:36
  • 9224

java 播放 wav 声音文件

import java.io.FileInputStream; import sun.audio.AudioPlayer; import sun.audio.AudioStream; public...
  • grpideas
  • grpideas
  • 2014-08-02 21:45:25
  • 8152

Java实现播放wav格式的音乐文件

import java.applet.Applet; import java.applet.AudioClip; import java.awt.GridLayout; import java....
  • hephec
  • hephec
  • 2014-07-19 11:34:30
  • 2390
收藏助手
不良信息举报
您举报文章:如何播放大型 WAV 文件?
举报原因:
原因补充:

(最多只允许输入30个字)