TonyChyi

我在那一角落患过抽风

填掉了 LMMS 一个长达两年的大坑
2017年01月20日 文章
LMMS 的代码里其实已经有了一个 MIDI 文件的导出功能。但是代码里的注释告诉我,那个是坏的,而且主界面的代码里把 MIDI 导出的菜单项给注释掉了。 既然 Midi 导入的功能已经改成了 Drumstick,那就更干脆点,直接把导出功能也解决了吧。 原代码功能 原来的 Midi 导出代码是将项目的内容转成 Qt 的 DOM 视图,然后从视图中读取信息,另外再实现一个自己的 Midi 写入的类。 但是这个代码似乎只能导出音符信息,控制器信息却不能导出,这就意味着,像 Pitch bend/Volume/Panning 这些信息要丢掉,也没法导入到其他的软件中。 原代码可以参考这里 新的需求 我的目标是,做一个 GM 兼容的 MIDI 导出功能,不仅导出音符,还要能让导出的 MIDI 文件直接可以拿来听! 接下来就是试验一下 Drumstick 如何写入一个 MIDI 文件。 我们需要这样做1: 首先调用 setFileFormat() 设定文件版本,这里就强制设 1 吧2 然后调用 setDivision() 设定一个四分音符的 Tick 数,同样强制 960 吧。 这样,一个 Header 就完成了,接下来写每个轨道的信息。 扫描整个项目,将使用 Sf2 Player 的轨道记下来,统计数量,调用 setTracks() 设为轨道数 +1s 同样也把 AutomationTrack 也记下来。 Drumstick 按轨写入的方法是,发送一个 signalSMFWriteTrack(int track),然后设置一个 Slot 去接收它。 分配一个 Channel。 track 为 0 时,写入全局事件3,这也是为什么要把轨道数加 1。 从 InstrumentTrack 的 TrackContentObject 中获取音符信息,写入一个事件列表4。 将 Program Change/Control Change/Pitch Bend 事件从 AutomationTrack 取出,写入事件列表,并指定好 Channel。 对事件按时间排序,并计算出事件之间的时间差5。 写入事件到文件。 最后写入一个 EndOfTrack 的事件。 这里分配 Channel 的机制我要单独拿出来说一下。
Tags: #LMMS · #MIDI · #C++ · #Qt

 

TonyChyi © 2018 GPLv2