LilyPond 简谱排版实战:从自动转换到手工 markup 的完整指南 📅 发布时间:2026/9/13 7:50:44 👁 浏览次数: 我第一次想在 LilyPond 里打一份简谱歌谱时几乎把搜索框翻了个底朝天然后得到一个相当打击人的结论LilyPond 默认不支持简谱。这软件打五线谱一绝排出来像印刷品可一到简谱它就像完全没听说过这个物种。 但后来我发现说“不支持”其实不太准确更准确的说法是“没有开箱即用的现成按钮”。LilyPond 是排版引擎简谱所需的基本元素——数字、下划线、高低音点、附点、增时线——它都能做只是需要你把它们组装起来。本文就把我试过的几条路线完整拆开有人写好的自动转换工具、纯手工的 markup 拼装方案以及各种让你当场炸裂的坑。无论你是只想出张简单歌谱还是想把简谱和五线谱对照排印这篇文章应该能帮你省掉不少我当初走过的弯路。1. 简谱和五线谱之间到底差了一层什么1.1 简谱的本质不是“数字谱”而是“唱名时值八度”三层结构很多刚接触简谱的人会觉得简谱就是用 1 到 7 七个数字代替音高比五线谱简单多了。这个印象说对了一半。简谱确实用数字表示音级但它同时要解决另外两个问题这个音比基准高几个八度、这个音持续多长时间。高八度靠数字上方的点来表示低八度靠下方的点时值则靠数字下方的下划线和右侧的短横线。换句话说一个完整的简谱音符其实是“数字 八度标记 时值标记”三层信息叠加在同一个位置上的结果。这和五线谱的信息组织方式非常不一样。五线谱是把音高放在两条线之间的绝对位置时值用符头、符干、符尾来表达简谱则把音高信息“数字化”了但仍然保留了一套独立的符号系统来表达八度与时值。同样是 1 秒钟的时值五线谱上是一个四分音符画一个实心符头加一根符干就行简谱里就是光秃秃一个数字“1”。时值一旦变成八分音符五线谱加一条符尾简谱就要在数字下面画一条下划线。这个差异看起来不复杂但它决定了 LilyPond 不能直接复用五线谱那套字体和排版逻辑。数字本身是字符下划线是线条上下点是定位符号三者在同一个视觉位置叠放本质上是一种“复合排版”不是简单地把音符替换成数字。1.2 LilyPond 的设计目标为什么天然排斥简谱LilyPond 的核心设计目标是把五线谱做到极致精美。它的底层模型建立在音高、时值、谱号、调号这些五线谱概念之上。你在 LilyPond 里写c e g它立刻知道这是三个四分音符并能自动处理符干方向、间距、连音线位置。这套模型对五线谱来说是极大优势但到了简谱就成了“语言不通”。简谱不存在谱号不存在调号这个视觉概念它只有“1C”这样的调名标注它的音高变化不是通过线间位置而是通过数字上下加点的数量来体现的。LilyPond 内部当然知道一个音是中央 C 还是高八度 C但它没有一套现成的“输出成数字并在上方打点”的渲染规则。你让 LilyPond 输出c它默认就画一个五线谱上的音符而不是阿语数字“1”。所以所有要在 LilyPond 里出简谱的方案本质上都是绕开原生的五线谱渲染路径去手动构建一套新的“数字乐谱渲染管线”。这条管线你可以自己写也可以借用别人写好的脚本和模板但无论如何你都得理解上面那层“三层结构”的复合排版逻辑否则出了问题根本不知道去哪找原因。1.3 三条路的对比自动转换、模板拼装、手写 markup目前我在实际操作中验证过的路线有三条各有各的适用场景这里先做个总览免得你看完后面一大段发现自己其实只需要最简单的方案。路线原理适合场景上手难度自动转换脚本先写五线谱 LilyPond 代码再用 Python 脚本解析并重新输出为简谱代码已经会写 LilyPond 五线谱需要批量出简谱中现成简谱模板/宏包加载别人写好的 jianpu.ly直接在代码里用简谱命令写谱不想折腾原理就想快速出一段简谱低纯 markup 手写用 LilyPond 的 markups 手拼数字、下划线、高低音点绝版特殊排版、教学片段、极少量乐谱高我自己最常用的其实是第一条因为我已经习惯用 LilyPond 思维写谱五线谱底稿改起来也方便。但如果你的目标只是做一段独立简谱并且对排版要求没那么高第二条会快得多。第三条属于硬核玩家的地盘它能实现最强的控制力但工作量也线性上涨。2. 主路线实测jianpu-ly 自动转换全流程2.1 jianpu-ly 的原理把五线谱信息“降维”成简谱信息这里先介绍我目前用过最顺手的自动转换工具jianpu-ly。它是一套 Python 脚本加 LilyPond 宏包的组合方案。原理说起来其实不复杂你先用 LilyPond 语法写出一段常规五线谱音符、时值、调号都写完整然后 jianpu-ly 会解析这段谱子里的音乐信息提取出每个音符的唱名、八度位置、时值再按照简谱的记谱规则重新生成一段 LilyPond 代码。听上去像是一个“翻译器”但实际它做了很多细致工作。比如五线谱里的休止符转换后会变成简谱里的 0附点音符会变成数字后面加附点临时升号降号会在数字旁边标记升号降号符号。它生成的代码不是直接渲染成图片而是生成一个新的.ly文件里面会调用\include jianpu.ly由宏包负责最终排版。所以你其实是在五线谱代码里“声明”了音乐内容再由工具把内容重新表达成简谱。这套方案最大的好处在于你不需要手动维护两套谱子。你要改某个音高只改原始五线谱.ly文件再跑一遍转换脚本就行。这非常适合需要把同一首曲子反复修改、同时出五线谱和简谱两个版本的场景。2.2 从零跑通一份《小星星》简谱我直接给你一个完整的可复现流程用《小星星》当测试例。首先安装 jianpu-ly。它是个 Python 包理论上满足 Python 3 环境就能装pip install jianpu-ly安装完成之后先写一个普通的 LilyPond 五线谱文件比如twinkle.ly\version 2.24.0 music { c c g g a a g2 f f e e d d c2 } \score { \new Staff { \music } \layout { } }这个文件本身可以正常编译成五线谱 PDF。接着让 jianpu-ly 把它转成简谱jianpu-ly.py twinkle.ly -o twinkle-jianpu.ly注意不同版本的脚本名可能略有差异有的叫jianpu-ly有的带.py后缀安装后可以直接用jianpu-ly --help看看。转换完成后在twinkle-jianpu.ly文件里你会看到类似这样的结构\include jianpu.ly music { \jianpuMusic { ... } } \score { \new JianpuStaff { \music } \layout { } }最后用 LilyPond 编译这个新文件lilypond twinkle-jianpu.ly顺利的话你会得到一份简谱 PDF。数字 1 到 7 按唱名出现高低音点、时值下划线、附点都由宏包自动处理了。这一步跑通之后你就算是把 LilyPond 和简谱之间的桥打通了后面写任何曲子都是同样套路先写五线谱代码再跑转换再编译。2.3 实测中自动转换的边界在哪工具能跑通基础例子不代表万事大吉。我拿真实曲谱测了很多素材之后发现它的能力边界相当明确。单旋律、节奏规整、没有复杂装饰音的曲子转换效果非常好基本达到可以出版的程度。但如果出现以下情况就要自己动手修了。三连音和五连音简谱里三连音需要在数字上方或下方标一个“3”并夹一条弧线jianpu-ly 对这类内容的处理有时会布局错位数字之间的间距会变得不均衡。跨小节长连线延音线简谱里的延音线通常画在数字上方转换生成的弧线有时角度和长度不够理想尤其是跨行时容易和环境冲突。临时升降号比较密集的乐段简谱里升降号写在数字左侧工具虽然能生成但与高低音点叠在一起时容易显得拥挤需要手动调整间距。反复记号、跳房子简谱习惯的反复记号标记方式和五线谱不完全一样自动转换有时会把五线谱里的反复记号原样搬过来视觉上不符合简谱习惯。遇到这些情况我的做法是把生成好的.ly文件当作草稿手动微调出问题的部分。这比完全手写快得多因为大多数音符和时值都是对的你只需要处理那几处特殊标记。2.4 用参数调整简谱外观jianpu.ly 宏包提供了一些可以设置的参数具体名称会随版本变化但大致方向是统一的。你可以改简谱数字的字体大小、下划线的粗细、高低音点的大小、音符之间的水平间距等。以我常用的版本为例字体大小可以在\layout里覆盖\jianpuNote相关字号设置\layout { \context { \JianpuStaff \override JianpuNoteHead.font-size #1 } }这类配置本质上是在覆盖 LilyPond 的排版属性所以你对 LilyPond 的\override体系越熟悉就越能精细地控制简谱外观。但也要提醒一句不要过度调整。简谱排版有个特点就是数字之间的空白必须均匀读者才容易视奏。手动乱调间距很容易把谱子弄得很“散”。我一般只改字号和整体缩放具体间距交给宏包默认值。3. 纯手工方案用 markup 拼出简谱数字和时值线3.1 一个 10 行的最小手写简谱示例如果你只是要一个两小节的简谱片段比如写进课件、教案或者试卷为它去装 Python 包、跑转换脚本反而显得笨重。这时候可以直接在 LilyPond 的 markup 层手工拼装。markup 是 LilyPond 的文本排版引擎它能做的事情远超“写个标题”这么简单数字、下划线、高低音点都可以作为 markup 对象组合。先看一个最简单的可编译示例\version 2.24.0 \markup { \column { \line { 1C 2/4 } \line { \concat { 1 \hspace #0.5 2 \hspace #0.5 3 \hspace #0.5 4 } } \line { 5 \hspace #0.5 6 \hspace #0.5 5 \hspace #0.5 4 } } }这段代码的输出虽然离真正的简谱还很远但你应该能看懂它的逻辑用字符串“1”“2”“3”表示唱名用\hspace控制水平间距用\column和\line做纵向堆叠。这种方式的优点是全部用文本元素控制完全掌握在自己手里缺点则是所有东西都要自己摆。3.2 在 markup 里做高低音点、下划线、附点简谱的高音点和低音点在 markup 里可以用\raise配合一个圆点字符实现。高音点放在数字上方低音点放在数字下方。举一个高音 do 的例子\markup { \concat { \raise #0.6 \fontsize #-3 . 1 } }\raise的参数单位是全局行距的一半具体数值根据你用的字体大小微调。\fontsize -3是让圆点稍微小一点否则会像个句号一样笨重。低音点思路相同只不过\raise用负值把点放到数字下方。下划线用\underline包裹数字即可\markup { \concat { \underline 5 \hspace #0.3 \underline 3 } }如果要两个八分音符共用一条下划线只能把两个数字放在同一个\underline里中间用空格隔开\markup { \underline \concat { 5 \hspace #0.5 3 } }附点则直接加在数字右边\markup { \concat { 5. \hspace #0.5 3 } }到这里你会发现手工方案的核心其实不是“画数字”而是“控制位置”。每个元素都是一个 markup 对象你要用\concat把它们横向连接、用\raise调整垂直位置、用\hspace控制间距。3.3 封装成自己的 \jianpuNote 函数纯手工 markup 如果要一个个写效率太低。我做教学片段时通常会先定义一个小函数把“数字 高低音点 下划线”封装起来。比如这样#(define (jp-note num octave dur) (let* ((dot (if ( octave 0) (make-concat-markup (list (make-raise-markup 0.6 (make-fontsize-markup -3 .)) (make-number-markup num))) (make-number-markup num)))) (if ( dur 8) (make-underline-markup dot) dot)))这个函数接收音名数字、八度位置、时值三个参数返回一个 markup 对象。你实际使用的时候不需要写这么底层的代码可以直接在.ly文件里用更简单的 Scheme 语法包一层。我自己常用的做法是jianpuNote #(define-music-function (n o d) (integer? integer? integer?) ;; 这里省略具体 markup 组装思路同上 )有了这个函数写一小节简谱就变成了\markup { \jianpuNote 1 1 8 }虽然函数体初次搭建需要花点时间但一旦完成后续的短谱片段基本是填空题效率和可维护性都大幅提升。3.4 哪些场景值得手写简谱手写方案最大的价值不在“绘制”而在“自由度”。我实际使用中发现这几种场景特别适合用手写 markup教学课件里的两三行旋律示例不需要小节线连排只要一个乐句片段。需要在简谱数字旁边额外标注指法、弓法、呼吸记号等内容的乐谱。需要在简谱和文字混排的场合比如校本教材里谱例嵌在段落的中间。想要完全控制每个点的位置比如制作特殊风格的海报、背景图。但反过来超过两行的完整曲目我就不推荐纯手写了。手工方案对跨行、自动换行、小节线对齐这些排版问题的处理几乎是从零开始工作量会随着音符数量几何级增长。那些情况请回到第二部分的自动转换方案或者直接用专门的简谱软件。4. 踩坑实录从下划线乱码到连音线错位4.1 麻烦一下划线、井号、圆点在 LilyPond 里的转义地狱这个坑我猜每个用 markup 拼简谱的人都会踩一次。简谱里的升号是“#”但“#”在 LilyPond 的 markup 字符串里并不总是安全字符。如果你直接写\markup { 1# }偶尔能通过编译但某些版本会把它解释成 Scheme 的颜色标记或别的什么导致编译失败或显示异常。同样低音点如果用英文句点“.”在某些上下文中也会被当成语法符号。解决方案很简单不要直接用裸字符而是用\markup的专用命令。升号推荐用\sharp命令或者先用 Scheme 字符串函数转义\markup { \concat { \fontsize #-2 \sharp 1 } }下划线也有一个隐蔽的坑。\underline是 markup 命令没错但如果你在\concat里混合使用带下划线和不带下划线的数字下划线经常会出现“没对齐”的问题。原因是下划线会改变数字的 baseline 对齐方式。我排查时发现解决方法是把下划线范围内的数字整体放在一个子 markup 里而不是逐个数字单独加下划线这样 LilyPond 才会把它们当成一个整体来对齐下划线的高度。4.2 麻烦二长连音线和跨页折行简谱的延音线是画在数字上方的弧形线表示两个相同音高的音要唱成一个音。LilyPond 在五线谱里画延音线是一键操作一个~就搞定但简谱里的延音线要绕开数字上方的点活着是八度标记位置非常刁钻。自动转换工具生成的延音线有时会出现弧度太大、与高低音点重叠、跨行时飞到页面边缘等问题。这类问题用 markup 手写时更明显你只能通过\shape手动调节控制点或者用\once \override对单个延音线做偏移。这属于排版中最花时间的部分没有通用解法只能一个音一个音调整。我给一个务实的建议如果延音线数量不多、且只在两三个音上直接手动 override 坐标即可如果延音线布满全曲建议不要用 LilyPond 出简谱换工具成本其实更低。这个建议可能让某些完美主义者不舒服但排版工具各有各的擅长领域不硬磕才是高效的做法。4.3 麻烦三多声部混排时上下点对不齐简谱不只用于单旋律合唱谱、二声部器乐谱也要用简谱。但 LilyPond 原本是为五线谱设计的多声部五线谱可以用\voiceOne、\voiceTwo区分符干方向而对简谱来说两个声部的数字可能同时出现在同一列的上下位置如果时值不一样就会出现高低音点相互挤压、下划线重叠的情况。我在实际排合唱简谱时遇到的问题是自动化工具生成多行后每行的间距逻辑继承自五线谱的 Staff那些为五线谱符干预留的空间在简谱里是多余的导致声部间空隙忽大忽小。解决办法是在\layout里调整\JianpuStaff的\override VerticalAxisGroup.default-staff-staff-spacing。简单说就是手动收紧声部间距让数字上下排列更紧凑。4.4 中文歌名和歌词字体的坑简谱歌谱几乎总是伴随中文歌词而 LilyPond 默认使用的 TeX 字体族并不包含中文字形。如果你把中文歌名直接放进\header里编译后大概率出现空白方框或乱码。第一次遇到我还以为是字体文件损坏查了半天才确认是字体配置问题。解决办法是给 LilyPond 指定中文字体最常用的方案是用\paper里的system-system-spacing和fonts变量或者直接在.ly文件顶部引入字体\paper { #(define fonts (set-global-fonts #:roman Noto Serif CJK SC #:sans Noto Sans CJK SC #:factor (/ staff-height pt 20))) }我用的是思源宋体如果你的系统里没有也支持系统里已安装的任何中文字体比如“SimSun”“Source Han Serif SC”。这里有个小技巧字体名称最好用系统fc-list查出来的标准名称别自己猜否则还是乱码。歌词对齐是另一个坑简谱歌词通常要跟数字对齐而 LilyPond 默认的 lyric 对齐机制是按五线谱音符位置来的在简谱里经常偏差半个数字身位。我目前的做法是歌词单独放在\markup行里手动用\hspace对齐虽然不那么智能但结果是可控的。5. 该不该用 LilyPond 做简谱我的取舍标准5.1 适合用 LilyPond 出简谱的三个特征用 LilyPond 出简谱折腾成本不低它不是什么开箱即用的方案。但经过一段时间的实战我总结出三个特征满足其中两个以上就值得继续用。第一你已经熟练掌握了 LilyPond 五线谱语法。这意味着你可以先写五线谱底稿再自动转换或对照修改学习成本大部分已经沉没。第二你的项目要求五线谱和简谱同源维护。比如你要给同一个乐队吹的学员同时发两种谱子用 LilyPond 可以直接从一份源文件派生出两套不同格式改一处两处都更新这是其他方式很难做到的。第三你对排版有特定追求或需要在谱子里混入大量自定义文本、图形元素。LilyPond 的 markup 体系极其强大复杂标记用起来比传统打谱软件更灵活。5.2 不适合的场景整本歌本、出版级简谱、复杂装饰音反过来说如果不符合上面这些特征我不太建议硬用 LilyPond。整本上百首的简谱歌本LilyPond 的排版自动性反而会拖慢你因为每首曲子都可能出现需要手动处理的连音线和间距问题。出版级简谱对符号的精细程度、特殊记谱法的支持度要求很高目前 LilyPond 的简谱生态还达不到这种成熟度。另外如果一首曲子里充斥着滑音、琶音、倚音、波音等各种装饰音自动转换工具通常表现得比较挣扎这些标记在五线谱和简谱中的画法差异非常大自动转换出来的结果基本要大面积重改。这种曲目用专门的简谱打谱软件反而省力得多。5.3 与 MuseScore 等工具的真实对比这个对比我想放在最后不是因为不重要而是因为很多人在搜索“LilyPond 简谱”时其实想要的只是“怎么最快打出一份简谱”。维度LilyPond jianpu-lyMuseScore 简谱插件学习曲线需要熟悉 LilyPond 语法和装 Python 环境可视化界面上手较快五线谱与简谱同源支持得很好一份源文件两种输出插件方案也能同步但需要额外操作复杂记谱法受限于宏包能力插件通常覆盖更多简谱特殊符号排版控制力极强markup 可精细到像素级较弱但大多数场景够用批量处理脚本化非常方便需要手动或二次开发我给一个不负责但真实的口诀要自动化、要批量、要同源用 LilyPond要快速出谱、要复杂的民族记谱法、要团队协作MuseScore 更省心。如果你两个都试一遍大概率会发现不同项目适合不同工具没必要把某一个奉为万能。我自己现在的工作流是教学用的简短谱例直接手写 markup 放在课件里给学生乐队的合奏谱LilyPond 五线谱转简谱自动产出复杂歌本和民歌整理基本还是切回图形界面打谱软件。每个工具都有它不可替代的一天别指望一个方案通吃所有场景。