MFC实用技巧之音频播放和录音

目录

音频播放

播放MP3与wav文件

播放音频流

录音

Pcm格式

Wav格式


音频播放

音频播放这里提供两种方式,直接播放音频文件和播放音频流的方式,可以根据实际情况选择使用方法

播放MP3与wav文件

操作步骤包括,装载文件,播放,暂停,恢复,停止

  • 装载文件
int Load(HWND hWnd, CString strFilepath)
{
	m_hWnd = hWnd;
	DWORD dwReturn;
	mciSendCommand(DeviceID, MCI_CLOSE, 0, 0);//在加载文件前先清空上一次播放的设备
	mciopenparms.lpstrElementName = strFilepath;//将音乐文件路径传给设备
	mciopenparms.lpstrDeviceType = _T("mpegvideo");

	if (dwReturn = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, (DWORD_PTR)&mciopenparms))
	{
		//如果打开文件失败,则将出错信息储存在buffer,并显示出错警告
		CString s;
		s.Format(_T("error:%d!"), dwReturn);
		MessageBox(hWnd, s, _T("player"), MB_OKCANCEL);
	}
	DeviceID = mciopenparms.wDeviceID;

	return dwReturn;
}
  • 播放
void play()
{
	MCI_PLAY_PARMS mciplayparms;
	mciplayparms.dwCallback = (DWORD)m_hWnd;
	mciplayparms.dwFrom = 0;//每次播放都是从0开始播放  dwFrom用于设置音乐播放的起始位置
	mciSendCommand(DeviceID, MCI_PLAY, MCI_FROM | MCI_NOTIFY, (DWORD_PTR)&mciplayparms);//dwCallback与MCI_NOTIFY是配对出现的
}
  • 暂停
void pause()
{
	mciSendCommand(DeviceID, MCI_PAUSE, 0, 0);
}
  • 恢复
void resume()
{
	mciSendCommand(DeviceID, MCI_RESUME, 0, 0);
}
  • 停止
void stop()
{
	mciSendCommand(DeviceID, MCI_STOP, 0, 0);//当点击停止按钮时,将所有的信息都清除掉
	mciSendCommand(DeviceID, MCI_CLOSE, 0, 0);//点关闭按钮的时候,清除设备信息,再点播放按钮,就播放不了音乐了

}
  • 设置播放音量
DWORD setvolume(DWORD vol)
{
	MCI_DGV_SETAUDIO_PARMS setvolume;//这是设置音量的参数数据结构
	setvolume.dwCallback = NULL;
	setvolume.dwItem = MCI_DGV_SETAUDIO_VOLUME;//动作是设置音量
	setvolume.dwValue = vol;//音量值是vol
	mciSendCommand(DeviceID, MCI_SETAUDIO, MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE, (DWORD)(LPVOID)&setvolume);
	return 0;
}

DeviceID见装载文件步骤

播放音频流

播放音频流,我已经封装成一个简单的类WaveOut,可直接移植使用,类中包括打开,关闭,push音频数据等,详细见源码

  • 打开一个播放实体

HWAVEOUT hWaveOut;
WAVEHDR wvHeader[2];

int WaveOut::open(DWORD nSamplesPerSec, WORD wBitsPerSample, WORD nChannels)
{
        /*
        ...
        详细见源码
        */

	/* 'waveOutOpen' will call 'SetEvent'. */
	if (waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)hEventPlay, 0, CALLBACK_EVENT))
	{
		return -1;
	}

	waveOutPrepareHeader(hWaveOut, &wvHeader[0], sizeof(WAVEHDR));
	waveOutPrepareHeader(hWaveOut, &wvHeader[1], sizeof(WAVEHDR));

        /*
        ...
        */

	return 0;
}

 

在这个步骤中我们需要将两个buf添加到waveIn中,至于为什么是两个,是因为只有当队列中至少有个buf时才不会有断音的情况,实测属实。

  • 关闭一个播放实体
void WaveOut::close()
{
    waveOutUnprepareHeader(hWaveOut, &wvHeader[0], sizeof(WAVEHDR));
    waveOutUnprepareHeader(hWaveOut, &wvHeader[1], sizeof(WAVEHDR));
    waveOutClose(hWaveOut);
    hWaveOut = NULL;
}
  • Push数据

当队列中的某个buf播放完之后,使用waveOutWrite接口重新加载入数据

录音

播放音频流,我已经封装成一个简单的类WaveIn,可直接移植使用,类中包括打开,关闭,开始录音,暂停,详细见源码

  • 打开一个录音实体

WAVEHDR wvHeader[2];
HWAVEIN hWaveIn;

int WaveIn::open(DWORD nSamplesPerSec, WORD wBitsPerSample, WORD nChannels)
{
        /*
        .
        .详细见源码
        .
        */

	//waveInReset(hWaveIn);
	waveInPrepareHeader(hWaveIn, &wvHeader[0], sizeof(WAVEHDR));
	waveInPrepareHeader(hWaveIn, &wvHeader[1], sizeof(WAVEHDR));

	//将两个wHdr添加到waveIn中去
	waveInAddBuffer(hWaveIn, &wvHeader[0], sizeof(WAVEHDR));
	waveInAddBuffer(hWaveIn, &wvHeader[1], sizeof(WAVEHDR));

	iCurRecording = 0;

	return 0;
}
  • 关闭一个录音实体
void WaveIn::close()
{
    waveInStop(hWaveIn);
    waveInUnprepareHeader(hWaveIn, &wvHeader[0], sizeof(WAVEHDR));
    waveInUnprepareHeader(hWaveIn, &wvHeader[1], sizeof(WAVEHDR));
    waveInClose(hWaveIn);
    hWaveIn = NULL;
}
  • 录音开始
int WaveIn::record_start()
{
	waveInStart(hWaveIn);
	return 0;
}
  • 录音停止
int WaveIn::record_stop()
{
	waveInStop(hWaveIn);
	return 0;
}

Pcm格式

存储pcm格式,直接将录音数据写入文件中即可

Wav格式

typedef struct wav_format_t {
	char riff[4];//"RIFF"
	unsigned int file_len;
	char wav_type[4];//"WAVE"
	char fmt[4];//"fmt "
	unsigned int fmt_len;
	unsigned short wFormatTag;
	unsigned short nChannels;
	unsigned int nSamplesPerSec;
	unsigned int nAvgBytesPerSec;
	unsigned short nBlockAlign;
	unsigned short wBitsPerSample;
	char dataFlag[4];//"data"
	unsigned int data_len;
} wav_format;

存储wav格式时,需要将上述结构体存在文件的头部,其中需要注意的是file_len,其长度为文件大小减4,data_len为文件大小减上诉结构体的大小,即有效音频的大小。这两个都是在录音结束之后才能确定的值

将上诉头存储之后,后面的数据则与pcm存储方式一样

相关资料包括demo代码请到我<MFC实用技巧>篇最下的网盘链接中下载!

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在云巅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值