技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 185|回复: 4
收起左侧

【DirectX】用 DirectMusic 实现可更换音色库和多轨的 midiOut

[复制链接]

2

主题

14

帖子

180

积分

用户组: 小·技术宅

UID
4293
精华
2
威望
9 点
宅币
113 个
贡献
25 次
宅之契约
0 份
在线时间
12 小时
注册时间
2018-9-19
发表于 2019-8-28 01:13:09 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有帐号?立即注册→加入我们

x
本帖最后由 系统消息 于 2019-8-28 20:52 编辑

原帖来源:【DirectX】用 DirectMusic 实现可更换音色库和多轨的 midiOuthttps://www.0xaa55.com/forum.php ... 59&fromuid=4293(出处: 技术宅的结界,转载请保留出处。)
参考来源:【C语言】Midi文件播放器(可跨平台)https://www.0xaa55.com/forum.php ... 89&fromuid=4293(出处: 技术宅的结界)

之前看过A5大神写的midi文件解析,并用winmm.dll的midiOut函数输出实现播放midi音乐,我在研究的过程发现了一些不太理想的问题:
1.midiOut 设备不能打开多个实例(也就基本上告别了同时播放多个文件),软件设备一个进程只能打开1个实例,硬件设备整个系统只能打开1个实例。
2.midiOut 设备没有多轨支持,A5大神的代码是忽略了音轨序号,这样做对于一些比较大的midi文件会出现冲突。
3.midiOut 设备没有精确时间控制,A5大神的代码是每Sleep1毫秒,更新一次midi进度,这样只能做到毫秒级精度控制,但是Sleep本身又不稳定。
4.midiOut 设备无法更换音色库,只能局限于midiOut设备驱动提供的音色。
5.midiOut API只能选择用哪个midi设备来合成声音,不能选择最终合成的声音输出到哪张声卡。

我在之前接触过DirectMusic,知道DirectMusic支持在应用层自行midi合成,再通过DirectSound做最终输出,因此以上问题在它这里都不是问题。
不过网上的DirectMusic资料全部是老掉牙的,只有上层接口的相关API调用代码(加载、解析midi文件都封装好了,完全不用接触底层),但是我想要的不是这些,而是像winmm.dll的midiOut,自己输出原始midi命令的功能,而且微软在很多年已经放弃了对DirectMusic的上层接口支持(x86下还在兼容,但新版DXSDK里面不再提供头文件了,x64下直接连dll都没有了),只有DirectMusic的底层接口微软一直提供支持(SDK一直在提供头文件,x64也有对于的dll),可是微软从来没有给过这方面的例子,只有接口描述文档,网上也找不到有人给过这方面的例子。于是我就自己慢慢研究DirectMusic的底层接口,最后终于成功自己实现midiOut的功能,再与A5大神的midi文件解析代码结合,不仅完美解决所有问题,还可以结合DirectSound实现音量、音高、平衡、3D空间音效以及DX8的声音特效。现在是时候来分享技术了:

DX MIDI 播放器

DX MIDI 播放器

从上图可以看到,基于DirectMusic实现的MIDI播放器,我们除了可以更换midi文件外,还可以自由更换音色库文件,可以随时调节音量、音高、平衡,中间的输出内容就是A5大神的midi文件解析库的输出内容(A5大神原版是输出到控制台)。
提示:DirectMusic每个合成器实例最大支持1000个音轨,每个音轨又各自有16个独立通道(每个通道9都是架子鼓),但是这16000个通道都是在同一个DirectSoundBuffer上输出的,因此单独调整DirectSoundBuffer属性,请分别创建多个DirectMusicPort实例(并为它们各自己绑定一个DirectSoundBuffer)。
推荐用法:在一个游戏进程内同时播放多个midi文件时,只需要创建一个DirectSound+DirectMusic,给每个midi文件创建一个DirectSoundBuffer+DirectMusicPort,而同一个midi文件的多个音轨分配在同一个DirectMusicPort的不同通道组即可。

在附件中提供了,DXMIDIOut(用DX模拟的midiOut)、midiPlayer(MIDI播放器,不带GUI)、midiPiano(MIDI电钢琴)等源码,以及MIDI播放器和MIDI电钢琴的二进制文件(需要VC2013运行库)。
MIDI 电钢琴是模仿当年4399上的flash键盘钢琴做的,只不过我没有做界面(只有一个空白对话框,方便让你拖拽dls文件去更换音色库,不然我就直接做成控制台了)。
附件中的压缩包密码是没有密码的拼音,其中 ReadMe.txt 提供压缩包内文件描述,MusicScore.txt 是MIDI电钢琴的乐谱(从flash键盘钢琴上继承,少部分是我自己添加)。
提示:由于附件资源的大小有限,无法上传Demo中测试用的音色库文件(一百多兆),如有学习需要请QQ联系我,或者自己去网上找找。(如需商用请自己注意版权问题)。
免责声明:Demo中的资源文件全部来源网络,仅供学习参考,未避免版权纠纷问题,请勿用于商业。

dxmidilib_src.rar

16.68 KB, 阅读权限: 20, 下载次数: 1

售价: 1 个宅币  [记录]  [购买]

DXMIDI库源码

dxmidilib_bin.rar

195.57 KB, 下载次数: 1

DXMIDI库测试Demo

评分

参与人数 2威望 +2 宅币 +20 贡献 +2 收起 理由
watermelon + 1 + 10 + 1 纽币!
0xAA55 + 1 + 10 + 1 屌!

查看全部评分

1043

主题

2335

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
217
威望
294 点
宅币
18229 个
贡献
36857 次
宅之契约
0 份
在线时间
1738 小时
注册时间
2014-1-26
发表于 2019-8-28 10:17:44 | 显示全部楼层
我记得我似乎没有忽略多音轨的问题

17

主题

183

帖子

1279

积分

用户组: 上·技术宅

UID
3808
精华
5
威望
31 点
宅币
949 个
贡献
60 次
宅之契约
0 份
在线时间
187 小时
注册时间
2018-5-6
发表于 2019-8-28 12:01:31 | 显示全部楼层
支持系统消息大佬。
菜鸟一枚,直接指正,不必留情

2

主题

14

帖子

180

积分

用户组: 小·技术宅

UID
4293
精华
2
威望
9 点
宅币
113 个
贡献
25 次
宅之契约
0 份
在线时间
12 小时
注册时间
2018-9-19
 楼主| 发表于 2019-8-28 19:32:05 | 显示全部楼层
本帖最后由 系统消息 于 2019-8-28 19:42 编辑
0xAA55 发表于 2019-8-28 10:17
我记得我似乎没有忽略多音轨的问题


你的是解析多轨的确是对的,我是说最后用midiOutShortMsg输出的时候,你忽略了音轨参数,直接把所有音轨往同一个音轨上输出的。
举个例子,假如说音轨1和音轨2在同时在使用通道1,它们就会发生冲突,比如音轨1把通道1设成钢琴,音轨2把通道1设成小提琴,谁执行的晚一步就会覆盖上一个音轨内容,还有就是两个音轨互相开关冲突问题。
DirectMusic的多轨机制是每个音轨各自都有独立的16个通道,音轨1的通道1和音轨2的通道1是两个单独的通道实例。
我帖子截图里面那个梁祝.mid就存在这个现象(好像有三十多个音轨),从截图上的输出内容可以看出20、21、22三个音轨在同时使用D(13)通道,改用DirectMusic的多轨机制后就正常了。

1043

主题

2335

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
217
威望
294 点
宅币
18229 个
贡献
36857 次
宅之契约
0 份
在线时间
1738 小时
注册时间
2014-1-26
发表于 2019-8-28 22:05:00 | 显示全部楼层
系统消息 发表于 2019-8-28 19:32
你的是解析多轨的确是对的,我是说最后用midiOutShortMsg输出的时候,你忽略了音轨参数,直接把所有音轨 ...


与其说我忽略了多音轨的问题,不如说,我把音轨和通道概念搞混了。

图片是多年前写的VB6播放midi时解析midi字节的逻辑
20190828225538.png

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号|网站地图

GMT+8, 2019-9-20 11:29 , Processed in 0.107483 second(s), 45 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表