26.1.1 简单声音录制与播放
Windows API中提供了可以简单地播放声音的函数PlaySound(),它可以播放声音文件、声音资源或系统声音。其函数原型如下:
- BOOL PlaySound( LPCSTR pszSound, // 指定要播放的声音的名称
- HMODULE hmod, // 包含载入资源的可执行文件的句柄
- DWORD fdwSound ); // 指定播放声音的选项
其中fdwSound参数指定播放声音的选项,可以是下列选项的组合。
SND_APPLICATION:播放与应用程序相关的声音。
SND_ALIAS:播放的声音是系统定义的声音。
SND_ALIAS_ID:pszSound参数是预定义的声音标识符。
SND_ASYNC:声音播放是异步的,PlaySound()函数在开始播放声音后立即返回。要终止播放声音,则通过PlaySound()函数传入NULL参数实现。
SND_FILENAME:pszSound参数指定要播放的声音文件名称。
SND_LOOP:重复播放声音,必须与SND_ASYNC选项一起使用。
SND_MEMORY:系统声音文件装载入内存。
SND_NODEFAULT:不适用默认声音事件。如果要播放的声音没有查找到,函数不播放任何声音,直接返回。
SND_NOSTOP:如果正有其他程序在占用资源播放声音,则不会停止当前播放的声音,而直接返回。
SND_NOWAIT:如果设备正忙,则函数立即返回。
SND_PURGE:停止声音播放。
SND_RESOURCE:播放的声音是资源,必须包含在hmod参数中指定模块中。
SND_SYNC:异步播放声音。
播放声音文件成功,返回true;如果播放声音文件失败,则返回false。下面代码显示了如何播放Windows启动声音文件。
- void CSoundSampleDlg::OnButtonPlay()
// 播放声音示例 - {
- if (!PlaySound("C:\\Windows XP 启动.wav",
NULL, SND_SYNC | SND_ - NODEFAULT))
- WriteLog("播放声音文件出现错误");
- }
使用waveIn系列的函数可以录制声音文件。代码如下:
- void CSoundSampleDlg::OnButtonRecord()
// 录制声音示例 - {
- MMRESULT mmResult;
// 定义操作结果变量 - WAVEFORMATEX m_waveformat;
// 定义音频格式 - m_waveformat.wFormatTag=WAVE_FORMAT_PCM;
// 赋值为PCM格式 - m_waveformat.nChannels=1;
// 赋值通道为1 - m_waveformat.nSamplesPerSec=11025;
// 设置每秒采样11025 - m_waveformat.nAvgBytesPerSec=11025;
// 设置每秒平均字节11025 - m_waveformat.nBlockAlign=1;
// 设置对齐方式 - m_waveformat.wBitsPerSample=8;
// 设置每个采样标本中的Bit位数 - m_waveformat.cbSize=0; // 设置结构长度
- // 播放音频
- if ((mmResult = waveInOpen(&m_hWaveIn, 0,
&m_waveformat, - (DWORD)this->m_hWnd, NULL, CALLBACK_
WINDOW))!= MMSYSERR_NOERROR) - {
- if (mmResult == MMSYSERR_ALLOCATED)
WriteLog("音频设备已经被其他设备 - 占用");
- else if (mmResult == MMSYSERR_BADDEVICEID)
- WriteLog("指定的音频设备标识符超出范围");
- else if (mmResult == MMSYSERR_NODRIVER)
- WriteLog("没有准备好音频设备");
- else if (mmResult == MMSYSERR_NOMEM)
WriteLog("没有分配好内存"); - else if (mmResult == WAVERR_BADFORMAT)
WriteLog("错误的音频格式"); - else WriteLog("打开音频输入设备失败");
- return;
- }
- const int MAX_WAVEDATA_LENGTH = 90040;
// 定义音频数据的最大长度 - inbuf = new char[MAX_WAVEDATA_LENGTH];
// 定义音频数据缓冲区 - m_wavehdr.lpData=inbuf;
// 赋值音频句柄数据缓冲区 - m_wavehdr.dwBufferLength=MAX_WAVEDATA_LENGTH;
// 赋值缓冲区长度 - m_wavehdr.dwBytesRecorded=0;
// 赋值字节记录 - m_wavehdr.dwUser=0;
- m_wavehdr.dwFlags=0;
- m_wavehdr.dwLoops=0;
- m_wavehdr.lpNext=NULL;
- m_wavehdr.reserved=0;
- if (waveInPrepareHeader(m_hWaveIn, &m_wavehdr,
sizeof(m_wavehdr)) - != MMSYSERR_NOERROR) // 准备录音
- {
- WriteLog("为录音设备准备缓存函数失败");
- return;
- }
- if (waveInAddBuffer(m_hWaveIn, &m_wavehdr,
sizeof(m_wavehdr)) - != MMSYSERR_NOERROR)
// 为录音设备增加输入缓冲区 - {
- WriteLog("给输入设备增加一个缓存失败");
- return;
- }
- if (waveInStart(m_hWaveIn)!= MMSYSERR_NOERROR)
- {
- WriteLog("开始录音失败");
- return;
- }
- WriteLog("开始录音……");
// 输出提示信息 - }
上面代码中,首先调用waveInOpen()函数打开音频输入设备,然后调用waveInPrepareHeader()函数为录音设备准备缓存空间,调用waveInAddBuffer()函数为录音设备增加缓冲区,最后调用waveInStart()函数启动录音。录音完毕,可以调用waveIn系列函数停止录音,代码如下:
- void CSoundSampleDlg::OnButtonStoprecord()
// 停止录音代码 - {
- if (waveInReset(m_hWaveIn)!= MMSYSERR_NOERROR)
// 停止录音 - {
- WriteLog("停止录音失败");
- return;
- }
- MMRESULT mmResult;
// 定义操作结果 - if ((mmResult = waveInUnprepareHeader(m_hWaveIn,
&m_wavehdr, sizeof - (m_wavehdr)))
- != MMSYSERR_NOERROR)
// 释放输入设备 - {
- if (mmResult == MMSYSERR_INVALHANDLE)
WriteLog("设备句柄无效"); - else if (mmResult == MMSYSERR_NODRIVER)
WriteLog("没有准备好设备驱动"); - else if (mmResult == MMSYSERR_NOMEM)
WriteLog("没有分配或锁定内存"); - else if (mmResult == WAVERR_STILLPLAYING)
WriteLog("正在播放声音"); - else WriteLog("清除缓存失败");
- return;
- }
- if (waveInClose(m_hWaveIn)!= MMSYSERR_NOERROR)
// 关闭录音 - {
- WriteLog("关闭录音设备失败");
- return;
- }
- WriteLog("录制声音完成");
- }
上面代码中,首先调用waveInReset()函数停止录音,然后调用waveInUnprepareHeader()函数清除缓存,最后调用waveInClose()函数关闭录音设备。可以根据需要在调用waveInUnprepareHeader()函数前,保存录制好的声音。