前一段时间看到有人发布XM音乐的播放方法,主要用于在注册机加一个小巧的背景音乐.
但由于XM音乐比较少,比较小巧的就更少了,况且还依赖minifmod库.
所以考虑到以下因素,同样推荐在注册机加入MIDI音乐:
1.MIDI音乐文件使用更广泛,更容易获得,制作和编辑.
2.DirectMusic附带4MB音色库的Roland软波表,音质也不比XM差。
3.MIDI数据比XM数据更容易被压缩(MIDI文件压缩比在1:8左右).
4.不需要外部编程库,系统自带播放内核,添加的代码量极少.
这里给出一个最简单的MIDI音乐的播放方法,即使用DirectMusic高层库.
虽然利用MCI的高层也可以播放,但它似乎不支持内存载入,
而且无法避免与其他MIDI音乐的同时播放的冲突.
估计都有装了DirectX吧,播放的通用性应该没有问题.
但编译这个程序还需要装上DirectX SDK.
代码:
// Tiny MIDI player [By Dwing]
#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(linker,"/ENTRY:Entry")
#include<dmusici.h>
unsigned char mididata[]={0x4D,0x54,0x68,0x64,......}; // 这里加入mid文件的数据.
IDirectMusicPerformance* performance=0;
IDirectMusicSegment* segment =0;
IDirectMusicLoader* loader =0;
bool PlayMIDI(unsigned char* data,unsigned int size)
{
DMUS_OBJECTDESC desc={0};
desc.dwSize =sizeof(desc);
desc.guidClass =CLSID_DirectMusicSegment;
desc.pbMemData =data;
desc.llMemLength=size;
desc.dwValidData=DMUS_OBJ_CLASS|DMUS_OBJ_MEMORY;
if(FAILED(CoInitialize(0))) return false;
if(FAILED(CoCreateInstance(CLSID_DirectMusicPerformance,0,CLSCTX_INPROC,
IID_IDirectMusicPerformance,(void**)&performance))) return false;
if(FAILED(CoCreateInstance(CLSID_DirectMusicLoader,0,CLSCTX_INPROC,
IID_IDirectMusicLoader,(void**)&loader))) return false;
if(FAILED(loader->GetObject(&desc,IID_IDirectMusicSegment,(void**)&segment))) return false;
if(FAILED(performance->Init(0,0,0))) return false;
if(FAILED(performance->AddPort(0))) return false;
if(FAILED(segment->SetParam(GUID_StandardMIDIFile,-1,0,0,performance))) return false;
if(FAILED(segment->SetParam(GUID_Download,-1,0,0,performance))) return false;
if(FAILED(segment->SetRepeats(DMUS_SEG_REPEAT_INFINITE))) return false;
if(FAILED(performance->PlaySegment(segment,0,0,0))) return false;
return true;
}
void StopMIDI()
{
if(segment)
{
if(performance)
{
performance->Stop(segment,0,0,0);
segment->SetParam(GUID_Unload,-1,0,0,(void**)performance);
}
segment->Release();
segment=0;
}
if(loader)
{
loader->Release();
loader=0;
}
if(performance)
{
performance->CloseDown();
performance->Release();
performance=0;
}
CoUninitialize();
}
void Entry()
{
if(PlayMIDI(mididata,sizeof(mididata)))
{
MessageBox(0,"Playing...","MIDI",0);
StopMIDI();
}
else
MessageBox(0,"Error!","MIDI",0);
ExitProcess(0);
}
mid文件的数据可用一个小工具自己导出成数组格式.
执行PlayMIDI()后音乐的播放会有约1~2秒的延迟,估计不会有太大影响的.
如果在程序退出前不需要停止播放音乐,可以不调用StopMIDI(),程序会更小.
PlayMIDI()函数用VC的最小代码编译,只有200多字节!