科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC中用低级音频函数WaveX播放声音

VC中用低级音频函数WaveX播放声音

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

Windows通过高级音频函数、媒体控制接口MCI设备驱动程序;

作者:王结太 来源:CSDN 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
2.4 主要程序清单

  2.4.1 播放部分

void CPlayWaveDlg::OnPlay()
{
LPSTR szFileName;//声音文件名
LPSTR szPathName;
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 = (CEdit*) 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.GetBuffer(0);

//打开波形文件
if (!(m_hmmio = mmioOpen(szPathName, NULL, MMIO_READ | MMIO_ALLOCBUF)))
{
/*-------------------------------------------------------------------------------
信息显示函数ShowMsg():
void CPlayWaveDlg::ShowMsg(char* szMsg, ...)
{
va_list vl;
char szBuf[256];

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);
return;
}

//进入块,检查打开文件是否是wave文件
mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
if (mmioDescend(m_hmmio, (LPMMCKINFO) & mmckinfoParent, NULL,
MMIO_FINDRIFF))
{
ShowMsg("%s is an invalid wave file!", szFileName);
mmioClose(m_hmmio, NULL);
return;
}

//寻找 'fmt' 块
mmckinfoSubChunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
if (mmioDescend(m_hmmio, &mmckinfoSubChunk, &mmckinfoParent,
MMIO_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));
if (!m_hFormat)
{
ShowMsg("Alloc memory failed!");
return;
}

lpFormat = (WAVEFORMATEX *) LocalLock(m_hFormat);
if (!lpFormat)
{
ShowMsg("Lock memory failed!");
OnStop();
return;
}

if ((unsigned long) mmioRead(m_hmmio, (HPSTR) lpFormat, dwFmtSize) !=
dwFmtSize)
{
ShowMsg("Read format chunk of %s failed!", szFileName);
OnStop();
return;
}
//离开 fmt 块
mmioAscend(m_hmmio, &mmckinfoSubChunk, 0);
//寻找 'data' 块
mmckinfoSubChunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
if (mmioDescend(m_hmmio, &mmckinfoSubChunk, &mmckinfoParent,
MMIO_FINDCHUNK))
{
ShowMsg("Cannot find data chunk in: %s", szFileName);
OnStop();
return;
}
//获得 'data'块的大小
m_dwDataSize = mmckinfoSubChunk.cksize ;
m_dwDataOffset = mmckinfoSubChunk.dwDataOffset ;
if (m_dwDataSize == 0L)
{
ShowMsg("%s has no data!", szFileName);
OnStop();
return;
}

//为音频数据分配内存
lpData = new char[m_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 < 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 failed!", szFileName);
OnStop();
return;
}
//检查音频设备,返回音频输出设备的性能
if (waveOutGetDevCaps(WAVE_MAPPER, &pwoc, sizeof(WAVEOUTCAPS)) != 0)
{
ShowMsg("waveOutGetDevCaps() failed!");
OnStop();
return;
}

//检查音频输出设备是否能播放指定的音频文件
/*----------------------------------------------------------------------------------------------
  waveOutOpen函数最后三个参数的设置对消息处理方式起决定性作用,需要特别注意,通常我们用下列处理方法:

  1. 使用窗口作为消息的接收者,则第四个参数设置为该窗口的句柄,则和这次播放有关的消息都将进入该窗口的消息队列,这时 第五个参数为NULL,第六个参数为CALLBACK_WINDOW,表明由窗口的过程来处理消息。

  2. 直接使用回调函数来处理消息,则第四个参数设置为该回调函数的指针,则和这次播放有关的消息都将由该函数处理,这时第 五个参数为传入该函数的参数,第六个参数为CALLBACK_FUNCTION,表明由指定函数来处理消息。

  3. 使用新的线程来处理消息,则第四个参数设置为该线程函数的指针,和这次播放有关的消息都将由该线程处理,这时第五个参 数为传入该函数的参数,第六个参数为CALLBACK_THREAD,表明由线程来处理消息。

  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;
}

//准备待播放的数据
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 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_hmmio != NULL)
{
mmioClose(m_hmmio, NULL);
}
//停止播放并重置管理器
waveOutReset(hWaveOut);
//关闭播放设备
waveOutClose(hWaveOut);
//清理用WaveOutPrepareHeader准备的Wave。
waveOutUnprepareHeader(hWaveOut, &pWaveOutHdr, sizeof(WAVEHDR));

//释放内存
if (m_hFormat != NULL)
{
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 lParam)
{
// ShowMsg("Play finished!");
OnStop();
}

  2.4.4 相关头文件

/*------------------------------------------------------
说明:本文介绍的操作函数的声明包含在mmsystem.h头文件中,因此在程序中必须用#include "mmsystem.h"语句加入头文件。同时在编译时要加入动态连接导入库winmm.lib,具体实现方法有两种:
1. 从Developer Studio的Project菜单中选择Settings,然后在Link选项卡上的Object/Library Modules控制中加入winmm.lib
2. 如下所示在代码中加入#pragma comment(lib, "winmm.lib")
-------------------------------------------------------------------------------*/
#include "mmsystem.h"
#pragma comment(lib, "winmm.lib")

class CPlayWaveDlg : public CDialog
{

//省略与播放无关部分
//................

protected:

HANDLE m_hData;
HWAVEOUT hWaveOut;
WAVEHDR pWaveOutHdr;
HANDLE m_hFormat;
HPSTR lpData;//音频数据
HMMIO m_hmmio;//音频文件句柄

CString m_strPathName;
CString m_strFileName;

void ShowMsg(char *szMsg, ...);

afx_msg void OnPlay();
afx_msg void OnStop();

afx_msg void OnMMWomDone(UINT wParam, LONG lParam);
DECLARE_MESSAGE_MAP()
};

  以上代码在Visual C++ 6.0 + windows 2000 pro 上通过。

  3. 应用

  低级音频函数能够具体的在内存中对各个声音数据块进行细节控制,比如可以通过检测声音的振幅强度进行声音采集的筛选,或者进行声音文件的剪切合并等,这就为声音文件的灵活操作提供了很好的方法;因为它能够操作声音数据块,从而也能为声音的实时传输提供有效的途径。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章