( 本文对象: DirectMusic 初学者,想快速知道使用 DirectMusic 播放音乐的人 )
原作者ByKylinx, -5-15 ,E-mail:game-diy@
整理:风里有梦
(转载请保证文档的完整性)
在DirectX8~9SDK中,DirectMusic增加了很多新特性,我在这里单单讲用它播放Midi的部分
DirectMusic主要有下面几个部分组成:
IDirectMusicLoader8 IDirectMusicPerformance8 IDirectMusicSegment8 IDirectMusicSegmentState8
你也许会问:为什么没有IDirectMusic8?这个是因为在DirectMusic中,Microsoft把IDirectMusic8“隐藏”起来了,也就是说,我们不需要使用这个接口,
可以通过其他方式轻松实现
IDirectMusic8 IDirectMusicLoader8 IDirectMusicPerformance8 IDirectMusicSegment8 AudioPath IDirectMusicSegmentState8
IDirectMusicLoader8,加载器。用于加载Mid文件等等
IDirectMusicPerformance8用来控制DirectMusic的接口
IDirectMusicSegment8音乐数据段,加载音乐后存放的位置
IDirectMusicSegmentState8音乐段状态
顺便说一下DLS
我们知道,mid文件纪录的只是“乐器”,音调和实践。在播放的时候,声卡对mid文件进行编码,而每种声卡上的“波表”都有差别,所以在编码的时候,播放出来的声音
就与声卡有关。打个比方,你在A机子直接播放和B机子直接播放同一个mid文件,如果A的声卡和B的声卡不同的话,听起来的音质完全不一样(我们耳朵能听到的只能
是模拟的声音而不是数字化的声音数据)。正因为如此,Microsoft在DirectMusic中使用了DLS,很好的解决了这个问题
DLS全称是DownLoadableSounds
MSDN中这样解释:
Astandardforsynthesizingwavesoundsfromdigitalsamplesstoredinsoftware.TheDLSlevel1andlevel2standardsarepublishedbythe
MIDI ManufacturersAssociation.
原理就是在DLS文件中通过使用乐器的单音采样来处理这个问题。所以在DirectMusic中
使用默认的DLS文件,把mid音乐转化为数字化的音乐。数字化的声音就可以通过数字——〉模拟(D/A)转换,随后播放出来的声音听起来都是一样的(因为不需要再声卡上重新编码了啊!)
好了,说了这么多,该开始应用了
IDirectMusicLoader8*g_pDMLoader=NULL;
IDirectMusicPerformance8*g_pDMPerformance=NULL;
IDirectMusicSegment8*g_pSegment=NULL;
首先,初始化COM
(这个东西博大精深,推荐一本:com本质论!看过这本书后,包你对DirectX的认识有新的飞跃!)
========================================================================
HRESULThr = CoInitialize(NULL);
If( FAILED(hr) )
{; //处理错误}
以下为了方便,省了错误处理
//下面创建加载器
CoCreateInstance(CLSID_DirectMusicLoader,//组件的GUID
NULL,//不是创建集合
CLSCTX_INPROC,//创建的环境
IID_IDirectMusicLoader8,//接口的GUID
(void**)&g_pDMLoader);//被创建的接口指针
//创建控制器
CoCreateInstance(CLSID_DirectMusicPerformance,//组件的GUID
NULL,//不是创建集合
CLSCTX_INPROC,//创建的环境
IID_IDirectMusicPerformance8,//接口的GUID
(void**)&g_pDMPerformance);//被创建的接口指针
//初始化声音通道
g_pDMPerformance->InitAudio(
NULL,//DirectMusic对象的指针,因为不需要我们管理,所以让它自动进行
NULL,//DirectSound对象的指针,同上
hWnd,//窗口句柄
DMUS_APATH_SHARED_STEREOPLUSREVERB,//声音通道(AudioPath)类型:立体声+混响
64,//音乐通道数
DMUS_AUDIOF_ALL,//声卡的所有特性
NULL//DMUS_AUDIOPARAMS对象的指针
);
// get current working directory
wchar_t wszDir[MAX_PATH];
if ( NULL == _wgetcwd( wszDir,MAX_PATH) )
return(-1);
//MULTI_TO_WIDE(wszDir, szDir);
// tell the loader were to look for files
hr = g_pDMLoader->SetSearchDirectory( GUID_DirectMusicAllTypes, wszDir, FALSE );
//好了,初始化Dmusic完成
//下面读入mid文件
//g_pDMLoader->LoadObjectFromFile(
CLSID_DirectMusicSegment,//组件的GUID
IID_IDirectMusicSegment8,//接口的GUID
file;//文件名,注意用Unicode
(void**)&g_pSegment//音乐要装到的段
);
//填充结构
DMUS_OBJECTDESCObjDesc;
memset((void*)&ObjDesc, 0, sizeof(DMUS_OBJECTDESC));
ObjDesc.dwSize = sizeof(DMUS_OBJECTDESC);
ObjDesc.guidClass = CLSID_DirectMusicSegment;
wcscpy( ObjDesc.wszFileName, pszFile ); // pszFile是UNICODE MIDI 文件路径
ObjDesc.dwValidData =DMUS_OBJ_CLASS|DMUS_OBJ_FILENAME;
//装入MIDI到g_pSegment对象
hr = g_pDMLoader->GetObject(&ObjDesc,IID_IDirectMusicSegment, (void**) &g_pSegment);
hr = g_pSegment->SetParam(GUID_StandardMIDIFile, -1, 0, 0, (void*)g_pDMPerformance);
hr = g_pSegment->SetParam(GUID_Download, -1, 0, 0, (void*)g_pDMPerformance);
//从ASCII转换到UNICODE的函数有
//MultiByteToWideChar(
CP_ACP,//ASCII码
0,//
asciifile,//要转换的ascii字符串
-1,//要转换的字节数,-1表示以’/ 0’ 结尾的字符串
UnicodeFile,//转换后UNICODE存放的地方
MAX_FILE_LENGTH);
//或Runtime
//下面播放mid音乐
g_pSegment->SetRepeats(looptimes);//重复的次数,如果是DMUS_SEG_REPEAT_INFINITE则为无限
g_pSegment->Download(g_pDMPerformance);//使用DLS,把MID数据转换成数字化的音乐数据
g_pDMPerformance->PlaySegmentEx(g_pSegment,//要播放的段
NULL,//保留,必须为NULL
NULL,//pTransiton
0,//播放的标志
0,//开始的位置
NULL,//用与接收段状态的指针,如果不需要,就为NULL
NULL,//使用默认
NULL//默认的AudioPath
);
//暂停播放
MUSIC_TIMEmtime;//MUSIC_TIME就是一个long类型
g_pDMPerformance->GetTime(NULL,&mtime);//得到暂停的位置
//停止播放
g_pDMPerformance->Stop(NULL,//要停止的段,NULL表示全部段都停止
NULL,//段状态
0,//多少时间后停止,0表示立即
0//标志
);
//从暂停点继续播放
g_pSegment->SetStartPoint(mtime);//播放点
//播放
g_pDMPerformance->PlaySegmentEx(g_pSegment,
NULL,
NULL,
DMUS_SEGF_REFTIME,
0,
NULL,
NULL,
NULL
);
g_pSegment->SetStartPoint(0);
//释放DirectMusic
g_pDMPerformance->CloseDown();
g_pSegment->Release();
g_pDMPerformance->Release();
g_pDMLoader->Release();
CoUninitialize();//停止使用COM
好了,整个过程就是这么简单!当你理解后,可以自行把上面的代码封装为一个类
这样,你就可以在你的游戏中实现MID的播放啦!
当然,播放mid只是DirectMusic功能中很小的一部分
它还能播放wav文件,sgt文件,实现3D声音等等,具体内容自己参考MSSDK中的文档和例子吧!
(参考资料: MSDN的DirectMusic部分)