原作者By Kylinx,
整理:风里有梦
(转载请保证文档的完整性)
在DirectX8~9 SDK 中,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全称是DownLoadable Sounds
MSDN中这样解释:
A standard for synthesizing wave sounds from digital samples stored in software. The DLS level 1 and level 2 standards are published by the
原理就是在DLS文件中通过使用乐器的单音采样来处理这个问题。所以在DirectMusic中
使用默认的DLS文件,把mid音乐转化为数字化的音乐。数字化的声音就可以通过 数字——〉模拟(D/A)转换,随后播放出来的声音听起来都是一样的(因为不需要再声卡上重新编码了啊!)
好了,说了这么多,该开始应用了
IDirectMusicLoader8* g_pDMLoader=NULL;
IDirectMusicPerformance8* g_pDMPerformance=NULL;
IDirectMusicSegment8* g_pSegment=NULL;
首先,初始化COM
(这个东西博大精深,推荐一本:com本质论!看过这本书后,包你对DirectX的认识有新的飞跃!)
========================================================================
HRESULT hr = 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_OBJECTDESC ObjDesc;
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表示以’/
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_TIME mtime;//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中的文档和例子吧!
(参考资料: MSDN2005的DirectMusic部分)