ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MIDI 转 ABC:从二进制事件到文本乐谱的转换指南

MIDI 转 ABC:从二进制事件到文本乐谱的转换指南 简介这是一款基于Haskell的MIDI转ABC表示法工具面向需要对传统曲调进行数字乐谱转换的音乐爱好者和开发者。项目当前重点支持Scandi风格等节奏规整的单音旋律可将MIDI文件转换为格式正确的ABC文件后续阶段计划处理真实钢琴演奏的MIDI输入通过启发式方法修正音符时值与条线偏差为乐谱生成与识别提供了分段实现思路。资源包共41个文件包含11个Haskell源码、17个MIDI示例文件、10个Shell脚本以及说明文档整体仅43KB结构紧凑便于快速阅读和编译测试。项目演示了从MIDI解析到ABC输出的完整流程并附有多首传统舞曲样本适合对函数式编程与音乐信息处理感兴趣的读者研究。目前已有781人浏览学习。1. 为什么传统音乐需要 MidiToAbc1.1 MIDI 和 ABC 是两种“语言”做过传统音乐采集、记谱或者乐器教学的朋友应该都遇到过这种场景从现场录了一段音频想转成方便印刷和分享的简谱/五线谱结果要么手动一个个音符扒谱扒到眼瞎要么找到一段 MIDI 文件却不知道怎么变成能编辑的文本谱。这个时候MidiToAbc 这种工具就能派上大用场。简单说它做的事情就是把计算机、合成器、编曲软件里常见的 MIDI 文件转成用纯文本表达的 ABC 表示法——一种用字母、数字和符号记录旋律的轻量记谱格式。MidiToAbc 解决了从“机器能认的 MIDI”到“人容易读写的 ABC”之间的最后一公里问题。MIDI 本身不承载任何声音波形它记录的只是演奏指令哪个音符在什么时间按下、力度多大、持续多久。这跟 ABC 记谱法有本质上的相似之处因为 ABC 也是符号化地记录音高、时值、拍号而不是记录实际音频。所以从理论上讲MIDI 转 ABC 是一个“符号到符号”的映射过程不涉及音频识别也不涉及复杂的机器学习纯粹靠规则就能完成。这也是 MidiToAbc 这类工具通常体积小、运行快、离线可用的原因。1.2 谁需要这种转换如果你玩传统音乐、民乐、古典室内乐或者经常在论坛上跟人分享曲谱你多半见过 ABC 谱。它只有一个纯文本文件几百字节就能存下一整首曲子在任何设备上都能打开甚至可以直接嵌在网页里用 JS 渲染成五线谱。相比导出 PDF 或图片ABC 更适合做版本对比、片段复用和自动化处理。而 MIDI 文件是现代音乐制作里最通用的中间格式键盘上弹一段旋律保存成 MIDI再丢给 MidiToAbc马上就能得到可读的 ABC 谱子这个工作流对我来说已经是顺手得不能再顺手的日常。需要这类转换的群体很明确一是只懂音乐不想碰底层的爱好者他们手上有一堆别人给的 MIDI 文件想快速变成自己能看懂的谱子二是做软件开发的工程师想在程序里批量处理乐谱比如把一个在线曲库的 MIDI 全部转成 ABC 做数据集三是做电子乐器 DIY 的玩家从 ESP32、Arduino Mega 这类板子里输入 MIDI 信号再输出 ABC 谱存成文档。甚至有人用在线照片转 MIDI 的工具把简谱照片变成 MIDI再用 MidiToAbc 变成 ABC 做进一步编辑相当于给传统曲谱打通了一条数字化的快速通道。2. 转换的核心思路从二进制事件到字母乐谱2.1 MIDI 文件里到底装了什么想要正确转换先得明白 MIDI 文件的内在结构。标准 MIDI 文件SMF由两个 chunk 组成一个是文件头 MThd另一个或几个是音轨数据 MTrk。文件头里最关键的是 division也就是一拍被分成了多少个 tick。常见的值是 480也有 120、960这个值直接决定了音符时值的精度。音轨数据里是一个一个的事件每个事件都有一个 delta-time表示距离上一个事件过去了多少个 tick。最核心的事件是 Note On 和 Note Off分别代表按下和抬起一个键音高用 0~127 的数字表示中央 CC4在 MIDI 里通常是 60往下到 C3 是 48往上到 C5 是 72。在很多人的想象里MIDI 转 ABC 无非是读个音符然后换行写字母。真做起来远没那么简单因为 MIDI 允许同一时刻多个音符发声允许同一个音轨里混着多个通道的不同乐器还允许音符在 tick 精度上出现“不齐整”的时间偏移。比如人工弹键盘时同一个和弦的几个音往往不是绝对同时按下有的早了几个 tick有的晚了几个 tick。如果转换时不做量化处理ABC 谱里就会冒出一堆乱七八糟的三十二分音符和休止符谱面根本没法看。2.2 ABC 表示法的关键规则ABC 记谱法用字母 A 到 G 表示音名大小写代表八度的变化。默认情况下小写字母 c 是中央 C 下方的 C或者说 C4而大写 C 反而比小写 c 高一个八度。这个规则刚接触时容易懵但习惯了就好。八度的升降用撇号和逗号表示c 表示高一个八度c,, 表示低两个八度。时值则用数字 1、2、4、8、16 等跟在音名后面比如 A2 表示二分音符 AD4 表示四分音符 D数字是几分音符就是几。如果不写数字默认是四分音符。小节线用竖线 |拍号写 M:4/4调号写 K:C这些字段放在曲子的开头。更复杂一点的是和弦。ABC 用方括号 [CEG] 表示三音同时发声也就是和弦。装饰音、连音线、三连音等也有对应的符号。MIDI 转 ABC 时需要把纵向重叠的音符合成和弦把横向先后出现的音符合成旋律再根据各音符的 tick 差值推算出时值。听起来不复杂但碰到被延音踏板拉长的音符、力度变化带来的假音符以及未按要求关闭的 Note Off 事件时规则稍不严谨就会出错。2.3 音符映射逻辑与时值换算MIDI 音高转 ABC 音名的公式是这样的用 MIDI 音高数字减去 60得到相对中央 C 的半音数。如果差值在 -2 到 11 之间会落在小写 c 到大写 B 的范围内超出这个区间就用撇号或逗号调整八度。具体映射可以用查表法也可以用模运算处理。举个例子MIDI 67 是 G4对应 ABC 里的 gMIDI 74 是 D5对应 d。实际实现时我更喜欢把 MIDI 数字转成类似科学音高记号再转成 ABC 字符串因为中间多一步更方便处理移调。时值换算更核心。假设 PPQPPQ Pulses Per Quarter Note即每四分音符的 tick 数是 480一个音符从 Note On 到 Note Off 持续了 960 个 tick那它就是一个二分音符因为 960 ÷ 480 2 个四分音符长度。如果持续了 240 个 tick就是半拍对应八分音符用数字 8 表示。ABC 里 4 是四分音符8 是八分音符16 是十六分音符换算表几乎是线性的。不过现实里音符长度很少正好是整数倍会有轻微的人为误差所以转换工具需要提供量化参数比如“把误差小于 30 tick 的音符吸附到最近的八分音符网格上”。这个参数在 MidiToAbc 里通常写成 -q 或 --quantize。3. 实操一次完整的 MidiToAbc 转换3.1 准备输入文件我平时用得最多的场景是把 MuseScore、Logic Pro 导出的 MIDI 文件转成 ABC。先确保 MIDI 文件本身是干净的如果是从复杂编曲工程里导出的最好只保留一条旋律轨或者至少把节奏轨、和弦伴奏轨分开存成不同的 MIDI 文件。因为 MidiToAbc 虽然支持多轨但多轨转出来会默认生成多个声部谱面会非常拥挤反而不利于查看旋律。如果手头只有一张简谱照片可以先用在线简谱转 MIDI 工具把照片里的音符识别成 MIDI再拖进 MidiToAbc。这类照片识别工具偶尔会有音高识别错误建议转完 ABC 后对着原谱逐句校对。我之前处理过一首笛子曲的简谱照片识别出来的 MIDI 里把高音 1 认成了低音 5如果不查原稿整套谱子的调就全偏了。3.2 命令行转换与参数说明MidiToAbc 的典型用法特别简单打开终端输入miditoabc input.mid -o output.abc默认情况下它会读入 input.mid 的所有音轨把每一条音轨作为一个声部输出声部名用 V:1、V:2 区分。如果只想取第一轨的旋律可以加个轨道选择参数miditoabc input.mid -t 1 -o output.abc我最常用的参数是量化阈值和休止符处理。量化阈值默认是 30 tick但你最好根据自己的 MIDI 文件 PPQ 调整。PPQ 是 480 时8 分音符长度是 240 tick一个 30 tick 的误差只有 1/8 拍影响不大但如果 PPQ 是 968 分音符只有 48 tick30 tick 的量化阈值就会把本来正常的八分音符扭曲成十六分音符。所以每次转换前先确认文件头的 PPQ或者用 MidiToAbc 自带的-i参数查看文件信息miditoabc -i input.mid它会输出文件包含多少个音轨、每个音轨的通道、PPQ、音符数量等信息方便你决定怎么转。3.3 校验 ABC 结果转出来的 ABC 文件看起来像这样X:1 T:Untitled M:4/4 L:1/8 K:C | c2 d e | g4 f2 e2 | d c a2- a g | c4 z2 |这里面有几个值得注意的点。M:4/4是拍号如果 MidiToAbc 没有从 MIDI 文件里正确读出来就可能是默认的 4/4跟原曲不符需要手动改正。L:1/8是最短音符时值这是影响频率长度的一个重要参数MidiToAbc 一般会自动选择但也允许手动指定。谱子里出现了z2这是 ABC 里的休止符表示两拍的空缺。想要快速验证转换结果对不对我会把 ABC 文本直接粘贴到在线 abcjs 渲染器里它会实时显示五线谱还能播放试听。如果听着哪里不对再看是音高、时值还是调号的问题。另一个更硬核的校验办法是用命令行工具 abc2xml 把 ABC 转回 MIDI如果转回去的音乐跟原始 MIDI 几乎一致那至少说明没有丢关键信息。4. 常见问题与避坑指南4.1 多轨 MIDI 混在一起怎么办这是新手最容易踩的坑。MIDI 文件里一条音轨可能同时包含旋律和伴奏甚至一条旋律被拆到左右手两个通道里。如果不加处理直接转ABC 会变成两个声部在同一小节里上下叠加读起来非常费劲。解决思路有两个一是转之前用 DAW 或 MIDI 编辑器把人声轨、钢琴轨分离开各存成一个文件二是用 MidiToAbc 的通道过滤功能比如-c 0只转换通道 0 的数据。如果你的目标是传统音乐的单旋律谱建议直接过滤掉低音区和打击乐通道只保留主旋律所在的高音区效率会高很多。另外MIDI 的打击乐通常在通道 10索引 9这一通道里的音符对应的是各种打击乐器如果你要的是旋律谱务必把这一通道排除掉。我见过有人转出来一堆 b 和 d 的乱码音符结果发现是踩镲的开闭事件跟旋律一点关系都没有。4.2 调号和拍号还原不准怎么办MidiToAbc 的调号推断逻辑通常是统计音阶中出现率最高的音符然后推测可能是哪个大调或小调。但这套逻辑对传统音乐有点水土不服。很多中国民歌是五声音阶不带 Fa 和 SiMIDI 文件里压根没有足够信息判断调号所以工具会默认给 C 调。这种情况下我建议先看原谱或听试听确定调号然后在 ABC 文件里手动改K:字段。比如原曲是 G 调笛子曲就把K:C改成K:G。拍号也是类似问题。MIDI 文件里的拍号元事件放在第一个音轨的特定位置如果原文件是 DAW 里随便录制的可能没有写入拍号信息导致 MidiToAbc 默认输出 4/4。所以转换完第一件事就是检查M:和K:两行别让调号拍号这种基础信息错了带偏整首曲谱。4.3 常见故障快查表症状可能原因处理方法输出全是超长音符没有休止符某些 MIDI 音符只发 Note On 没发 Note Off或者工具没识别到 Note Off用 MIDI 编辑器修复文件或调整工具对“悬挂音符”的处理策略音符时值忽长忽短谱面很难看量化参数设置不合理根据 PPQ 重新设置量化阈值或开启自动量化多轨同时响谱面重叠混乱没有分轨或过滤通道使用 -t 选择音轨或用 -c 过滤通道转出来没有调号字段MIDI 文件缺少调号元事件手动在 ABC 开头添加 K: 字段和弦处只显示一个音符工具简化了重叠音符确认工具的和弦模式或手动用 [ ] 补充和弦4.4 休止符和延音线怎么处理MIDI 没有休止符的概念它只记录“此刻没有琴键按下”。MidiToAbc 把同一音轨里两个相邻音符之间的时间缝隙识别成休止符这在原理上没问题但遇到延音踏板时就会出现误判。踩下延音踏板后钢琴音符的 Note Off 会被延迟但人耳听到的其实还是同一个音符这就会导致转换时出现大量不该有的休止符或长音符。处理办法是转换前在 MIDI 编辑器里把延音信息清除或者用 MidiToAbc 自带的“忽略 controller 事件”参数。我一般直接删掉 CC64延音踏板事件再转出来的谱面干净得多。延音线在 ABC 里用-表示。如果一个音符跨小节并在下一个音符重复同一个音高工具通常能自动识别成延音线。但如果中间有一个很小的 gap比如 5 个 tick 的缝隙它就可能被拆成两个音。这时候我会把量化阈值调大一点让缝隙被忽略再重新转换。5. 从电脑到硬件MidiToAbc 的扩展玩法5.1 串口、蓝牙 MIDI 采集后直接转谱最近玩 ESP32 和 Arduino 这类板子的朋友越来越多大家常问一个问题Arduino Mega 支持 USB MIDI 吗实际上Arduino Mega 本身没有原生 USB MIDI 能力通常需要外接 USB Host Shield 或者用 ATmega16U2 做二次开发。不过 ESP32 倒是天生支持蓝牙 MIDI可以接收蓝牙 MIDI 键盘的输入。如果你在弹 MIDI 键盘数据通过蓝牙传到电脑上的 MidiToAbc就能秒转成 ABC 谱这对现场采风、即兴录音特别有用。我自己试过把 ESP32 作为 USB MIDI 转串口的桥接设备板子收到 MIDI 事件后通过串口发到 PCPC 上跑一个监听脚本实时把事件喂给 MidiToAbc弹完一段立刻就有 ABC 谱出来。这样做最大的好处是省略了把 MIDI 存成文件的步骤适合需要快速记录灵感的人。要注意的是串口传输有延迟但 MIDI 事件本身只有几十字节实测下来 115200 波特率完全不会丢数据。5.2 在线工具打辅助的完整工作流网上常看到“在线简谱转成 MIDI”或“在线把简谱照片转成 MIDI”的工具这些工具跟 MidiToAbc 配合使用基本能拼出一条全自动的曲谱数字化流水线。我的常用流程是手机拍简谱照片 → 在线识别成 MIDI → 用 MidiToAbc 转成 ABC → 在编辑器里修正调号和装饰音 → 导出成 PDF 或嵌入网页。这套流程对没有专业扒谱基础的人非常友好唯一要留意的是照片识别的准确率参差不齐五线谱还好一些简谱里的高音点、低音点经常被漏掉所以转完必须逐句核对。如果你是开发音教类 App 的工程师还可以把 MidiToAbc 编译成 WebAssembly 或作为后端服务做成“上传 MIDI 返回 ABC 文本”的 API。整个转换逻辑不依赖任何重型框架拆出来也就几百行代码很适合塞进服务器。我认识一个做在线乐谱库的朋友就是靠这个思路把几万份老旧 MIDI 资源全部转成了 ABC体积小了不说还能直接在网页端实时渲染用户体验提升了好几个量级。说到这回到 MidiToAbc 本身。折腾过这么多轮之后我最大的感受是工具再自动化最终还是要靠人判断音乐语境。调号、装饰音、声部层次这些信息MIDI 文件里藏着很多但怎么解读、怎么取舍取决于你想得到一份“能看”的谱子还是一份“能练”的谱子。我自己的习惯是先用默认参数转一版然后拷到 abcjs 里播放对比再手动修掉那些机器判断不出来的味道。一次转换可能花不了两分钟但手工修正能看出你对这首歌的理解有多深。下次你从旧 MIDI 里翻出一首快要遗忘的旋律不妨试试这个流程或许能重新找回手写谱子时的亲切感。本文还有配套的精品资源点击获取
返回列表