(四)MFC学习之使用directSound播放音频文件

版权声明:本文为博主原创文章,转载请注明原文链接 https://blog.csdn.net/qq_36922927/article/details/83957900

环境:windows10+vs2017

音频格式要求:.wav  (8位24khz)(这是默认的)

directx只能播放wav格式文件

DirectSound提供了各种音效处理的支持,如:低延迟、3d立体和协调硬件等功能

vs2012开始,vs已经集成directx

步骤:

  1. 创建DirectSound对象
  2. 设定协作等级(协调使用硬件的权限)
  3. 创建主缓存区
  4. 从音频文件加载音频到次缓冲区
  5. 播放音频

相关概念:

  • 主缓存区:DiectSound播放声音、产生混音效果的区域。默认播放格式是(8bit,22kHz)如果不需要播放其他格式(指的是不同位,不同频率的音频,但是都是wav格式),就不需要手动创建主缓存区,否则需要先创建主缓冲区(16bit,44kHz),对其格式进行设定。(相当于舞台)
  • 次缓冲区:主要用于存储要播放的音频数据及播放格式,可以建立数个次缓冲区来存放多个要播放的声音(相当于舞台幕后)

示意图:

WAVE音频文件格式:

是RIFF文件(Resource InterChange File Format ),DirectSound只接受“.wav”文件

使用到的类:

窗体程序基本就用到CMyApp,CMyWnd

其余就是:

LPDIRECTSOUND;

 LPDIRECTSOUNDBUFFER ;

   HRESULT

代码:

#include <afxwin.h>
#include <mmsystem.h>
#include <dsound.h>


//常量定义
//#define SOUND_FILE_NAME "SOUND.WAV";
//线程部分
	HANDLE threadHandle;
	DWORD threadId;
	DWORD  funcRun(LPVOID lParam);




class CMyWnd :public CFrameWnd {
private:
	CDC *mdc;
	CBitmap* bmp[2];
	//优先级最高  []
	//优先级最低  ,
//	CRect rect;
	CRect * rect;
	int mFrameNo;
	int x;
	//声音部分
	LPDIRECTSOUND pDs;

	LPDIRECTSOUNDBUFFER pDSB_BK, pDSB_MG;
	HRESULT result;
	
	
public:
	CMyWnd();
	LPDIRECTSOUNDBUFFER CreateSecondBuffer(LPSTR filename);

	DECLARE_MESSAGE_MAP()
	afx_msg void OnPaint();


};
CMyWnd::CMyWnd() {
	Create(NULL, "TestThread");
	mdc = new CDC;
	CClientDC dc(this);
	mFrameNo = 0;
	//客户区大小
	rect = new CRect;
	GetClientRect(rect);
	x = 63;
	//创建线程
	threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)funcRun, this, 0, &threadId);

	mdc->CreateCompatibleDC(&dc);
	for (int i = 0; i < 2; i++) {
		bmp[i] = new CBitmap;

	}
	//springf_s;
	bmp[0]->m_hObject = LoadImage(NULL, "bground.bmp",
		IMAGE_BITMAP, rect->right, rect->bottom, LR_LOADFROMFILE);
	bmp[1]->m_hObject = LoadImage(NULL, "crimer1.bmp",
		IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

	//1,创建directSound
	//音频设备指针,  第三个必须为NULL,
	result = DirectSoundCreate(NULL, &pDs, NULL);
	if (result != DS_OK) {
		MessageBox(_T("建立DirectSound失败!"));
	}
	//2,设定程序协作等级
	result = pDs->SetCooperativeLevel(m_hWnd, DSSCL_PRIORITY);
	if (result != DS_OK) {
		MessageBox(_T("设定程序协调等级失败"));
	}
	//加载背景音乐

	char szMusicName[40];
	sprintf_s(szMusicName, "wavs/jump.wav");
	/*CString fileName = "wavs/bgm.wav";*/
	pDSB_BK = CreateSecondBuffer(szMusicName);
	pDSB_BK->Play(0, 0, 1);
	
}
//创建次缓冲区
LPDIRECTSOUNDBUFFER CMyWnd:: CreateSecondBuffer(LPSTR filename) {

	//声音部分
	HMMIO hmmio;
	MMRESULT mmresult;//函数返回值
	
	//1,打开音频文件

	hmmio = mmioOpen(filename, NULL, MMIO_ALLOCBUF | MMIO_READ);
	if (NULL == hmmio) {
		MessageBox(_T("文件打开失败"));

	}



     // 2,确认是否为riff文件
	MMCKINFO ckriff;//WAVE文件信息结构
	ckriff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
	mmresult = mmioDescend(hmmio, &ckriff, NULL, MMIO_FINDRIFF);//最后一个常量是查找类型
      
	if (MMSYSERR_NOERROR != mmresult) {
		MessageBox(_T("文件类型不是wave"));
	}


      //3,进入fmt区块,读取音频格式,然后退出fmt区块
	MMCKINFO ckinfo;
	ckinfo.ckid = mmioFOURCC('f', 'm', 't', ' ');//设定区块类型
	mmresult = mmioDescend(hmmio, &ckinfo, &ckriff, MMIO_FINDCHUNK);//此方法退出区块
	if (MMSYSERR_NOERROR != mmresult) {
		MessageBox(_T("进入fmt区域错误"));
	}
	WAVEFORMATEX swfmt;
	//读取音频格式
	if (-1 == mmioRead(hmmio, (HPSTR)&swfmt, sizeof(swfmt))) {
		MessageBox("读取音频文件格式失败");
	}

      //4,进入data区块,读取音频长度

	mmioAscend(hmmio, &ckinfo, 0);
	ckinfo.ckid = mmioFOURCC('d','a','t', 'a');
	mmresult = mmioDescend(hmmio, &ckinfo, &ckriff, MMIO_FINDCHUNK);
	if (MMSYSERR_NOERROR != mmresult) {
		MessageBox("进入data区域失败");
	}


         //5,创建音频次缓冲区
	LPDIRECTSOUNDBUFFER pTempBuf ;
	DSBUFFERDESC desc;//用以描述缓冲区结构
	memset(&desc, 0, sizeof(desc));
	desc.dwSize = sizeof(desc);
	desc.lpwfxFormat = &swfmt;
	desc.dwFlags = DSBCAPS_STATIC;//static表示可多次播放,当然还可以指定其他的使用| 连接
	desc.dwBufferBytes = ckinfo.cksize;
	result = pDs->CreateSoundBuffer(&desc, &pTempBuf, NULL);

	if (DS_OK != result) {
		MessageBox("创建次缓冲失败");
		return NULL;
	}
        // 6,从文件读取音频数据存入次缓冲区
	LPVOID pAudio;
	DWORD BytesAudio;
	pTempBuf->Lock(0, ckinfo.cksize, &pAudio, &BytesAudio, NULL, NULL, NULL);
	if (-1 == mmioRead(hmmio, (HPSTR)pAudio, BytesAudio)) {
		MessageBox("读取音频数据失败");
	}

	pTempBuf->Unlock(pAudio, BytesAudio, NULL, NULL);
        //7,关闭文件
	mmioClose(hmmio, 0);
	return pTempBuf;
}
class CMyApp :public CWinApp
{

	BOOL InitInstance();

};
BOOL CMyApp::InitInstance() {

	CMyWnd * pf = new CMyWnd;
//	pf->Create(0,"hello");

	pf->ShowWindow(m_nCmdShow);
	pf->UpdateWindow();
	this->m_pMainWnd = pf;
	
	return TRUE;
}

BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()


void CMyWnd::OnPaint()
{
	//这里只能使用CPaintDc
	CPaintDC dc(this); // device context for painting
					   // TODO: 在此处添加消息处理程序代码
					   // 不为绘图消息调用 CFrameWnd::OnPaint()
	mdc->SelectObject(bmp[0]);

	dc.BitBlt(0, 0, rect->right, rect->bottom, mdc, 0, 0, SRCCOPY);
	mdc->SelectObject(bmp[1]);
	switch (mFrameNo)
	{
	case 0:

		dc.BitBlt(x, rect->bottom/2-70,49, 154, mdc,49, 0, SRCAND);
		dc.BitBlt(x, rect->bottom/2-70, 49, 154, mdc, 0, 0, SRCPAINT);
		mFrameNo = 1;
		break;
	case 1:
		dc.BitBlt(x, rect->bottom /2-70, 49, 154, mdc, 49, 154, SRCAND);
		dc.BitBlt(x, rect->bottom /2-70, 49, 154, mdc, 0, 154, SRCPAINT);
		mFrameNo =0;
		break;
	default:
		break;
	}
	x += 63;
	if (x > rect->right) {
		x = 63;
	}

	
}
//线程方法实现
DWORD  funcRun(LPVOID lParam) {

	CMyWnd*  wnd = (CMyWnd*)lParam;
	while (1) {
		wnd->Invalidate();
		Sleep(500);
	}
	
	return 0;

}

CMyApp TheApp;

注意使用directsound需要注意依赖库:

  • 头文件:“mmsystem.h”和“sdound.h”
  • 项目->属性->链接器->附加依赖项中添加:“dxguid.lib”、“dsound.lib”、"winmm.lib"库

此代码可以直接运行!

需要注意音频文件位置。

wav声音制作:

使用软件:Cool Edit pro 即可,使用方便(附上网盘链接 )


链接:https://pan.baidu.com/s/1DgLTYgSBwgq-T0HP-1dxCw
提取码:l886

以将mp3转为 8位,22khz的wav文件为例:

file-》open(选择mp3文件-》edit-》convert  ...->设置一些参数-》等待几秒即可完成转换-》file->save as(选择wav格式保存即可)

设置参数:

猜你喜欢

转载自blog.csdn.net/qq_36922927/article/details/83957900