系统消息 发表于 2022-3-25 17:19:19

【DirectX】基于XAudio2的midi合成器——XAMIDI

本帖最后由 系统消息 于 2022-3-25 17:53 编辑

原帖来源:【DirectX】基于XAudio2的midi合成器——XAMIDI https://www.0xaa55.com/thread-26601-1-1.html(出处:技术宅的结界,转载请保留出处。)
参考来源:【C语言】Midi文件播放器(可跨平台)https://www.0xaa55.com/thread-1489-1-1.html(出处:技术宅的结界)
**** Hidden Message *****

在学习 DirectX 的道路上学完了图形接下来就是音频,早期 DX 的音频是用的 DSound,并且微软同时还给我们提供了基于 DSound 实现 midi 合成的 DMusic,两者结合就可以实现很强大的音乐音效系统。可是后来微软放弃了 DSound,并开发的了一下新的音频组件叫 XAudio(有两个大版本 XAudio1 和 XAudio2,原来的 DSound 则仅支持 Windows,而 XAudio1 仅支持 XBox,XAudio2 同时支持 Windows 和 XBox),XAudio2 比原来的 DSound 和 XAudio1 强大很多,可是当我们从 DSound 切换到 XAudio2 后却发现一个相当严重的问题,就是 XAudio2 没有提供对应的 midi 合成器,而 DMusic 又只能和 DSound 对接。这时如果开发新的游戏,我们想在游戏中使用 midi 功能怎么办呢?
1.退回到midiOut(功能很弱、延迟又高、还只能打开一个实例)。
2.继续用DMusic来合成 midi(这样 midi 只能走 DSound 输出,不能对接到 XAudio2)
3.用 Win10 的新 API Windows.Devices.Midi.h 的 MidiSynthesizer 对象(系统版本要求太高,而且还需要WinRT或UWP才能使用,最重要的是功能还不如 DMusic)
4.用 XAudio2 来模拟一个假的 DSound 来跟 DMusic 对接(咦,好像这个方案比较可行)
5.直接调用 dmsynth.dll 的底层API(这个比方案4更好,但是这里面都是非公开的 API)
6.调用第三方和 midi 合成器,再将合成结果流式写入到 XAudio2 中(这个方案好不好不好说,毕竟还要考虑版权等问题,还有就是可能第三方合成器太大,对小游戏开发者来说有点不划算)
目前 XAMIDI 采样的是方案4,如果将来我把 dmsynth.dll 研究透了,可能会更换为更好的方案5。我们先来看一下参考示例的运行截图吧:


在正式编程使用之前,再来看看 XAMIDI 的工作流程结构:

从上图可以看到有个比较有意思的地方,就是 XAudio2 的回调就是去调用对应的 XAMIDI 方法,而 XAMIDI 的回调又是去调用 XAudio2 的相关方法。它们之间的相互调用才实现了实时的 midi 合成工作,最后再由 XAudio2 将合成的音频流输出到声卡设备上。
User MIDI Player:代表用户自己编程实现的midi播放器
IXAMIDISynthesizer:为XAMIDI的合成器对象接口
IXAMIDISynthCallback:为XAMIDI的合成器回调接口
IXAudio2SourceVoice:为XAudio2的源语音对象接口
IXAudio2VoiceCallback:为XAudio2的源语音回调接口
IXAudio2SubmixVoice:为XAudio2的子语音对象接口
IXAudio2MasteringVoice:为XAudio2的主语音对象接口
System Audio Devices:代表最终的音频输出设备

XAMIDI 是一个基于 XAudio2 的 midi1.0 合成器,其接口同大多数DX组件采样了相同的工厂模式:组件自身只有一个创建工厂对象的全局函数,其它对象接口均是通过该工厂对象创建。

DSound、DMusicXAudio2、XAMIDI
WaveDirectSoundCreate→IDirectSound→IDirectSoundBufferXAudio2Create→IXAudio2→IXAudio2Voice
MIDICLSID_DirectMusic→IDirectMusic→IDirectMusicPortXAMIDICreate→IXAMIDI→IXAMIDISynthesizer
DSound 与 XAudio2 接口对应关系:
根对象缓冲区主缓冲区副缓冲区事件通知
IDirectSoundIDirectSoundBufferIDirectSoundBuffer+DSBCAPS_PRIMARYBUFFERIDirectSoundBuffer+其它IDirectSoundNotify
IXAudio2IXAudio2VoiceIXAudio2MasteringVoiceIXAudio2SourceVoiceIXAudio2VoiceCallback
DMusic 与 XAMIDI 接口对应关系:

根对象(工厂)合成器(端口)音色库(波表)音色(乐器)已下载音色
IDirectMusicIDirectMusicPortIDirectMusicCollectionIDirectMusicInstrumentIDirectMusicDownloadedInstrument
IXAMIDIIXAMIDISynthesizerIXAMIDITimbreBanksHXAMIDITimbreIXAMIDITimbreDownloaded

XAMIDI 接口描述:

接口描述
IXAMIDIXAMIDI的工厂接口,用于创建和管理其它的对象。
IXAMIDISynthesizerXAMIDI的合成器接口,用于将midi1.0消息合成波形音频流并输出到XAudio2上。
IXAMIDITimbreBanksXAMIDI的音色库接口,用于从波形文件中加载音色集合。
HXAMIDITimbreXAMIDI的音色接口,表示单个音色对象,用于下载到合成器对象中。
IXAMIDITimbreDownloadedXAMIDI的已下载音色接口,用于在不再需要使用时卸载。

对 XAMIDI 的工作流程及相关接口都已经了解的差不多了,现在可以来看看用法示例了:
**** Hidden Message *****
以上代码就是用 XAMIDI 在 XAudio2 上合成的经典菊花残音乐。顺便一提,其实 XAMIDI 不仅仅是支持输出到 XAudio2,只要自己实现相应的调用和回调处理,输出到别的音频 API 上也是可以的。
附件密码:XAMIDI-0000

王者 发表于 2022-5-6 11:59:42

最近也在学directx,参考借鉴

小冰 发表于 2022-4-15 03:50:25

系统消息太棒了:$

nzxiansheng 发表于 2022-3-28 11:02:14

6666666666666666666666666666666666666666666

BIG5 发表于 2022-4-20 15:03:03

感谢分享!!

退行了的倒影 发表于 2022-6-24 23:58:19

看看老板的东西

viwooo 发表于 2024-7-24 09:26:28

ᕙ(•̤᷆ ॒ ູ॒•̤᷇)ᕘ

工具人 发表于 2024-7-24 09:41:43

🤣🤣🤣
页: [1]
查看完整版本: 【DirectX】基于XAudio2的midi合成器——XAMIDI