版权声明:本文为博主原创文章,转载请注明原文链接 https://blog.csdn.net/qq_36922927/article/details/83957900
环境:windows10+vs2017
音频格式要求:.wav (8位24khz)(这是默认的)
directx只能播放wav格式文件
DirectSound提供了各种音效处理的支持,如:低延迟、3d立体和协调硬件等功能
vs2012开始,vs已经集成directx
步骤:
- 创建DirectSound对象
- 设定协作等级(协调使用硬件的权限)
- 创建主缓存区
- 从音频文件加载音频到次缓冲区
- 播放音频
相关概念:
- 主缓存区: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格式保存即可)
设置参数: