zoukankan      html  css  js  c++  java
  • windows下使用waveout函数族播放wav文件

      要使用waveout函数组,族,首先要知道几个数据结构,首先是这个

    typedef struct tWAVEFORMATEX
    {
        WORD        wFormatTag;         /* 格式的类型 */
        WORD        nChannels;          /* 通道数 */
        DWORD       nSamplesPerSec;     /* 采样频率 */
        DWORD       nAvgBytesPerSec;    /* 比特率 采样率*声道数*采样位数/8 */
        WORD        nBlockAlign;        /* 一次采样的宽度 通道数*采样位数/8 */
        WORD        wBitsPerSample;     /* 采样位数 */
        WORD        cbSize;             /* 外部附加信息,不用设置为0 */
                                        /* extra information (after cbSize) */
    } WAVEFORMATEX, 

    这个结构体在打开音频设备准备播放声音的时候是必须的,打开音频设备的时候需要使用的函数为

    if(!(waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,(LPWAVEFORMATEX)&pFormat,(DWORD)this, 0, 0) == MMSYSERR_NOERROR))

    第一个参数是音频设备的句柄,定义如下

    LPHWAVEOUT hWaveOut;

    实际上也就是一个设备指针

    第二个参数为设备类型,其中选择WAVE_MAPPER能选一个能够播放给定格式的波形音频输出装置

    第三个参数为音频数据的格式信息

    第四个参数是一个回调函数

    第五个是回调函数的资源句柄

    第六个是打开装置的标识,具体的描述可以去看msdn成功后返回MMSYSERR_NOERROR ,否则返回以下值:

    值描述
    MMSYSERR_ALLOCATED   表示资源已存在
    MMSYSERR_BADDEVICEID   装置ID超出范围
    MMSYSERR_NODRIVER   没有驱动
    MMSYSERR_NOMEM    不能分配内存
    WAVERR_BADFORMAT   企图打开一个不被支持的格式
    WAVERR_SYNC 装置是可同步的,但waveOutOpen没用有WAVE_ALLOWSYNC

     

    打开音频设备之后就需要准备音频的格式信息了,这里需要第二个结构体

    /* wave data block header */
    typedef struct wavehdr_tag {
        LPSTR       lpData;                 /*指向锁定数据缓冲区的指针 */
        DWORD       dwBufferLength;         /*数据缓冲区长度 */
        DWORD       dwBytesRecorded;        /* used for input only */
        DWORD_PTR   dwUser;                 /* for client's use */
        DWORD       dwFlags;                /* assorted flags (see defines) */
        DWORD       dwLoops;                /* loop control counter */
        struct wavehdr_tag FAR *lpNext;     /* reserved for driver */
        DWORD_PTR   reserved;               /* reserved for driver */
    } WAVEHDR

    使用方式如下

    hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)sizeof(WAVEHDR));
            if(hWaveHdr == NULL)
            {
                MessageBox("Not enough memory for header","error",MB_OK);//打开设备失败
                return;
            }
            lpWaveHdr = (LPWAVEHDR)GlobalLock(hWaveHdr);
            if(lpWaveHdr == NULL)
            {
                MessageBox("Failed to lock memory for header","error",MB_OK);
                return;
            }
    
            // 初始化音频结构After allocation, set up and prepare header.
            lpWaveHdr->lpData = (char *)pVoiceBuffer;
            lpWaveHdr->dwBufferLength = lFileSize;
            lpWaveHdr->dwFlags = 0L;                 //WHDR_BEGINLOOP | WHDR_ENDLOOP;
            lpWaveHdr->dwLoops = 0L;
    
            if(waveOutPrepareHeader((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)

    缓冲区可以设置为我们读取进来的数据的内存地址,另外,该缓冲区需要锁定

    接下来就可以写入数据了

    wResult = waveOutWrite((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR));

    写入数据失败的话要把之前锁定的缓冲区解除掉,使用这个函数

    waveOutUnprepareHeader((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
                GlobalUnlock(lpWaveHdr);
                GlobalFree(hWaveHdr);

    如果成功就可以进入循环一直播放知道数据播放完成,如下

    while(waveOutUnprepareHeader((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR))!= MMSYSERR_NOERROR)
            {
                //循环清除缓冲区,如果成功表示播放完毕
                //如果没有播放完毕则循环下面语句
                if(bExit)
                    break;//让循环也可以响应消息
                MSG message; 
                if(::PeekMessage (&message,NULL,0,0,PM_REMOVE)) 
                { 
                    ::TranslateMessage (&message); 
                    ::DispatchMessage (&message); 
                } 
            }

    数据播放完成之后需要先复位播放器在关闭音频设备,如下

    //播放完毕
            if(waveOutReset((HWAVEOUT)hWaveOut) != MMSYSERR_NOERROR)
            {
                MessageBox("WaveOutReset Error!","error",MB_OK);
                return;
            }
            if(waveOutClose((HWAVEOUT)hWaveOut)!= MMSYSERR_NOERROR)
            {
                MessageBox("WaveOutClose Error!","error",MB_OK);
                return;
            }

    通过这些就能完成一个基本的wav播放器了,同时mp3的播放器只需要mp3解码也能做了

    界面如下

    工程代码链接如下

    http://download.csdn.net/detail/dengrengong/8639579
  • 相关阅读:
    Ubuntu安装deepin wine版QQ
    解决anaconda安装cvxpy失败的方法
    1006
    一种不用参数交换两变量值的方法
    输入三位数,翻转输出
    一个简单的问题
    1006ac(转)
    1007(转)
    杭电oj1004 自写成功代码
    1004
  • 原文地址:https://www.cnblogs.com/dengxiaojun/p/4461880.html
Copyright © 2011-2022 走看看