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
把 LMMS 的 Midi 导入功能改用 drumstick 实现了
2017年01月08日 文章
啊,更好的方法就是,用他妈的什么 portsmf 用 drumstick 啦 ——@liushuyu 终于折腾好了 带着对 drumstick 的撞憧憬,我终于还是给自己挖了个大坑,把原来 LMMS 在 Midi 文件导入时用到的 portsmf 库换成了 drumstick。 然而这并不是一个有趣的过程。 portsmf 是按顺序返回 Midi 事件,而 drumstick 是基于 Qt 的 Signal/Slot 机制。 于是我先花费了一点时间搞明白 drumstick 是如何工作的。 然后对整个的 MidiImport 插件进行了大拆解——将混乱不堪的代码按照 class 分成了几个文件。 接着写了一个 midiReader 类,用来接收 Midi 事件,并添加到 LMMS 的轨道中。 那么接下来的工作就是实现 midiReader 的 Slot。 在 lmms 的导入过程中,用到了以下 Signal: signalSMFTimeSig(int,int,int,int) “以四分音符为一拍,每小节四拍” signalSMFTempo(int) 节奏,单位是 ms/quarter_note signalSMFError(QString) 错误处理信息 signalSMFCtlChange(int,int,int) 控制器信息 signalSMFPitchBend(int,int) 弯音信息1 signalSMFNoteOn(int,int,int) 音符开始,但最后一个参数为 0 时等同于音符结束 signalSMFNoteOff(int,int,int) 音符结束 signalSMFProgram(int,int) 音色改变2 signalSMFHeader(int,int,int) Midi 文件头信息 这样就完全不用考虑导入的 Midi 文件是格式 0 还是格式 1 了,忽略掉 signalSMFTrackStart() 和 signalSMFTrackEnd() 就可以。
Tags: #LMMS · #MIDI · #drumstick · #C++
修复了 LMMS Pitch Bend Bug
2017年01月04日 文章
@leo_song 对我说,搞报表平台的代码不如研究 LMMS LMMS 有一个存在了很长时间的 BUG:导入 Midi 文件的时候,对 Pitch Bend 不能很好的处理导致走音。 定位 在 Cakewalk 中测试,如果是单纯调整 Pitch Bend,最大范围是 ±2 个半音,而我这里有个文件1甚至可以达到 1 个八度。 经过一番测试,发现是 RPN(0, 12) 这个参数在起作用: 0, 0, Header, 1, 7, 960 1, 0, Start_track 1, 0, Control_c, 0, 101, 0 1, 0, Control_c, 0, 100, 0 1, 0, Control_c, 0, 6, 12 1, 0, Control_c, 0, 38, 0 …… 也就是上面的 Contol_c 事件,先以 101 和 100 控制器发送值 02,然后再用 6 控制器发送 123,最后以 38 控制器发送 0。
Tags: #LMMS · #MIDI

 

TonyChyi © 2018 GPLv2