如何把原谱制作成网页吉他谱
以《偏爱》指弹和《老男孩》弹唱伴奏为例,记录读取截图与网页原图、逐小节识谱、生成独立 HTML、校核音符和检查打印的实际过程。
01 · 本次完成了什么
原始材料是按小节编号命名的截图,以及说明分段和重复关系的《小节信息.txt》。先完成前奏 1–4 小节,请用户比对;再依次制作 A、B、C 段,最后补齐 D–G 段。最终得到 《偏爱》指弹完整曲谱。
制作过程由 AI 视觉识读、独立复核、用户反馈和脚本生成共同完成。当前没有一键自动识谱流程,也没有部署 OCR / OMR(光学乐谱识别)模型;音符先被整理为结构化数据,再由制谱库重新绘制成 SVG。
成品共 61 小节、16 行,最后一行只有结尾小节;在本项目浏览器检查环境中,A4 横向打印为 4 页。页面包含段定位、小字小节范围、缩放、打印、谱前技法说明和逐小节转录明细。标题、品牌“小k吉他练习”和说明换行都依据用户反馈调整。
02 · 使用了哪些工具
| 工具 / 技术 | 本次的实际用途 |
|---|---|
| AI 图像查看与视觉识读 | 查看原始截图和放大预览,识别六根弦上的品位、符干、连梁、弧线、装饰音及其他符号;对模糊处再次放大并独立复核。 |
| 网页读取工具、Python urllib | 从用户给出的网页查找正文和图片地址;读取工具未能取到图片时,再以带浏览器标识和来源页的普通 HTTP 请求验证原图是否可访问。用于已查看的《老男孩》页面。 |
@coderline/alphatab 1.8.4 | 实际制谱引擎。解析 AlphaTex,布局六线谱、节奏和技法,并输出 SVG。版本固定在项目依赖中。 |
| 原生 SVG 伴奏绘制 | 《老男孩》在构建时直接绘制和弦图、扫弦箭头、连梁、过门与跳转提示,保持伴奏的箭头记法。无需额外运行时或字体,禁用脚本也可阅读。 |
| AlphaTex | 制谱库读取的文本格式。构建脚本将 JSON 中的音符和技巧转换为该格式,便于检查渲染前的乐谱内容。 |
| Node.js、npm | 运行构建脚本和测试;管理项目内依赖;将库、字体、数据和模板组合为独立 HTML。 |
| HTML / CSS / SVG、Bravura 字体 | 完成页面和矢量谱面显示;字体以数据 URL 内嵌,避免离线时缺字或依赖外部 CDN。 |
Playwright 1.58.2、Chromium | 放大查看原图,打开本地 HTML,模拟离线、手机和打印,生成浏览器截图与 PDF,并检查交互。 |
| Node 内置测试框架 | 检查小节编号、四拍时值、弦品和技法关系;把 AlphaTex 再解析回模型,确认没有丢音或误改语义。 |
pdfinfo、pdftoppm | 查看 PDF 页数、纸张大小,将每一页转换为预览图,检查跨页重叠与裁切。 |
| 独立审谱代理 | 对同一批截图独立识读,再与主转录结果逐项对照,重点检查难辨的时值和技法。 |
项目内 skill:lit-sheet-music | 参考了使用 Lit + OpenSheetMusicDisplay 渲染 MusicXML 的方案。当前实现采用 alphaTab,未引入 Lit 或 OSMD 运行时。该 skill 保存在 项目目录中。 |
需要区分:skill 提供工作方法和参考资料。《偏爱》使用 alphaTab;《老男孩》伴奏采用原生 SVG 构建脚本,未引入新的制谱库。依赖和额外 skill 均安装在项目内。
03 · 如何读取原谱
按小节命名的截图
先读取小节信息,列清分段、已有图片和重复来源,再对照实际小节线查看整小节。红色虚线框经用户确认只是练习标记,所以框外属于该小节的音符同样转录。小图通过浏览器放大后查看;预览保存在 artifacts/,不会嵌入成品曲谱。
识读时先固定弦号:最上方为 1 弦,最下方为 6 弦;再按横向时间位置,分清同时发音的一组音符与先后出现的音符。读取品位后,还必须检查下方的符干和连梁,才能判断时值。
用户提供的网页链接
链接输入先检查正文和原图,而不能只凭文章标题判断已经看到了谱子。本次查看的 《老男孩》页面有一张封面图和三张谱图;成功读取原图后,确认是含和弦图、扫弦节奏、演唱简谱、歌词和反复跳转的弹唱伴奏谱。现已整理其伴奏声部,生成 《老男孩》弹唱伴奏,演唱部分通过原谱链接对照。
04 · 分段制作流程
- 确认交付方式。独立 HTML 展示重新绘制的谱面,保留可维护的乐谱数据。先选择小范围样稿,确定整体效果。
- 制作前奏样稿。先转录 1–4 小节,让用户对照原图。用户提出每行由 2 小节改为 4 小节,随后确认音符无误。
- 逐段追加。沿用已确认的格式,识读下一段,记录疑点,独立复核后加入数据。已确认段落通过回归检查保持一致。
- 核对相似与重复。明确重复的小节使用来源引用;仅旋律相似的段落仍逐音检查,避免将不同的尾音或滑音一起复制。
- 生成网页。JSON 转为 AlphaTex,模板嵌入脚本、字体、乐谱与许可证,输出到
sheet_music/。 - 交叉验证。检查数据时值、解析后语义、屏幕排版、交互与逐页打印,再向用户提供可查看的文件。
- 吸收反馈。将用户确认同步写入曲谱、结构化说明和文档。例如星号表示“打板”,D 段实际为 29–36。
05 · 音符如何记录
每首谱按小节保存,每小节有按时间排列的 beats。这里的一个 beat 是一次谱面事件,并不一定等于一拍;它可能是八分音符、同时发音的和弦,或装饰音。
{
"duration": 8,
"notes": [
{ "string": 1, "fret": 3 },
{ "string": 2, "fret": 0 },
{ "string": 6, "fret": 0 }
],
"text": "*"
}
上例表示一个八分音符事件,同时弹响 1 弦 3 品、2 弦空弦、6 弦空弦,并在对应位置保留打板标记。数据中的 text: "*"用于显示打板,不额外占用标称时值。
| 数据项 | 含义与当前转换 |
|---|---|
duration | 4、8、16、32 分别代表四分、八分、十六分、三十二分音符;以四分音符为一拍时,普通事件拍数为 4 / duration。 |
dotted: true | 单附点,时值乘 1.5;转换为 AlphaTex d。 |
tuplet: [3, 2] | 三连音,时值乘 2/3;转换为 tu 3 2,本谱三个八分三连音合为一拍。 |
grace: true | 装饰音,不另占标称拍数;转换为 gr beforeBeat。装饰音的显示时值要与制谱库解析结果一致。 |
legato: true | 标在击弦或勾弦的起音上,转换为 h;结合后续同弦目标音生成 H / P 关系。 |
tie: true | 标在延音的后续事件上,转换为 t。同音继续发声,不是再拨一次。 |
slide: "legato" | 标在滑音起音上,转换为 sl;必须核对具体目标音。 |
harmonic: true | 自然泛音,转换为 nh。 |
arpeggio: "up" | 记录原图向上的琶音箭头;本项目转换为 ad,已按实际 SVG 箭头方向核对,不能仅凭英文命名推断。 |
fret: "x" | 原谱标示的闷音。它与星号“打板”是不同符号,分别保存。 |
repeatOf | 引用明确重复的小节,例如 {"number":41,"repeatOf":17}。构建时复制音符并改为目标编号。 |
AlphaTex 用 品位.弦号表达音符;同一事件的音符放在括号中。与本项目采用的弦号约定相比,alphaTab 解析模型的弦索引方向相反,测试通过 7 - string 对照。
四拍检查使用标称时值:普通时值 × 附点系数 × 连音系数,装饰音计零。解析后的 displayDuration也应合计为 3840 ticks。这个规则针对本次 4/4 完整小节;以后遇到弱起、不完全小节或变拍号,应按实际拍号和谱面定义调整。
06 · 遇到的问题与处理
空白位置可能仍然有音符事件
延音终点在原图中可能只有弧线和符干,没有重复印出品位。第 20 小节第二拍连续三处都延续 2 弦空弦,其中首尾叠加 6 弦闷音。必须把这些时值和同时发音关系写入数据,不能把空白处直接跳过。
括号品号要保持延音语义
第 16 小节三弦的 (2)同时是延音终点和滑音起点。alphaTab 默认省略这类小节中间的延音品号,因此在 显示调整脚本中,只扩展了 NoteNumberGlyph的显示条件,使它显示括号品号;延音和滑音关系仍由原模型保留,没有用“幽灵音”属性来伪造括号。
这项调整依赖固定版本源码,并检查替换位置是否唯一。若升级 alphaTab 后匹配条件改变,构建会报错,必须重新审查。调整后的可读源码与许可一同嵌入成品。
装饰音会影响相邻小节的播放时间
加入第 17 小节的拍前装饰音后,解析模型从第 16 小节末音借走了 120 ticks。第 16 小节书写时值仍是四拍,但其播放时值合计变为 3720。测试因此改用 displayDuration核对书写拍数,避免为了让播放总量通过而错误修改原谱。
相似段落不能整段盲目复制
第 24 小节一弦 3→5→3 是连续滑音;第 48 小节只有 3→5 带滑音,随后 3 需要重新拨弦。第 49 小节与第 17 小节的正式事件一致,但没有开头的装饰击弦。第 39 小节末尾也与第 15 小节不同。
未知符号先保留,确认后统一命名
星号最初被记录为含义未明的原谱标记,用户随后说明它代表打板。已同步修正图例、逐小节说明及文档,保留其原始位置。显示上使用制谱库的 beat text,在固定版本中将 TextEffectInfo的 effect band 设为谱下的 SharedBottom = 3,由原生布局计算间距。此处也使用了内部接口,升级库时需要复核。
文字信息与图中分段冲突
《小节信息.txt》曾将 D 段写为 26–36,与 C 段 17–28 重叠;第 29 小节截图实际标有 D 段。向用户核实后,确定 D 段为 29–36。最终小节编号连续,26–28 没有重复插入。
屏幕正确不代表分页正确
整谱变长后,第一次 PDF 预览出现跨页谱行重叠。原因是制谱库的行容器采用绝对定位。打印样式将行容器放回正常文档流,并禁止行内分页,才让后续页按顺序排版。
@media print {
.at-surface {
height: auto !important;
overflow: visible !important;
}
.at-surface > div {
position: static !important;
display: block !important;
break-inside: avoid;
}
}
分页修复后,逐页查看 PDF,而不是只依据 DOM 检查“没有重叠”。最后一行不足四小节时不强制拉满整行,保留自然的结尾宽度。
07 · 如何验证结果
| 验证层次 | 检查内容 | 能说明什么 |
|---|---|---|
| 原图对照与独立识读 | 弦品、符干连梁、同时发音、H/P、滑音、延音、装饰音、打板及小节线。 | 用于发现最初转录的识读错误;用户对照审谱也是这一层的依据。 |
| 数据检查 | 编号连续、弦品有效、拍数、重复关系与来源。 | 发现漏拍、错拍和错误的重复编号。 |
| 解析回读 | 将生成的 AlphaTex 读回 alphaTab 模型,逐项比对 JSON;检查延音起点、滑音目标、击勾弦连接和结尾四拍延音。 | 发现格式转换导致的丢音、错义或技法丢失。 |
| 浏览器检查 | 本地文件离线打开、无远程请求和脚本错误、61 小节、16 行、90 处打板、段导航、缩放、手机内部横向滚动。 | 验证成品能独立使用且主要交互有效。 |
| 视觉与打印复核 | 桌面和手机截图;四页 PDF;密集音符、括号、三十二分连梁、结尾以及页边界。 | 发现模型正确但谱面拥挤、重叠、裁切的问题。 |
当前两首曲谱都有 Node 数据测试与浏览器检查。原图与放大图供识读使用,生成曲谱依赖的是已经转录的数据;从当前提交重新构建不需要读取原始截图。
08 · 文件与重建方法
guitar/
├── index.html # 曲谱库首页,支持搜索、分类和下载
├── assets/ # 首页样式、脚本及独立曲谱清单
├── sheet_music/
│ ├── 偏爱指弹.html # 指弹成品
│ └── 老男孩弹唱伴奏.html # 伴奏成品
├── score/ # 两首曲谱的结构化数据;偏爱另含 AlphaTex
├── src/template.html # 曲谱页面模板、交互和打印样式
├── scripts/build.mjs # 合并数据、展开重复、生成 HTML
├── scripts/build-laonanhai.mjs # 老男孩独立构建入口
├── scripts/accompaniment-svg.mjs # 伴奏矢量绘制
├── src/accompaniment.html # 伴奏页面模板
├── scripts/alphatab-display.mjs
├── tests/ # 数据、解析和浏览器验证
├── docs/制谱.html # 本文
└── .agents/skills/lit-sheet-music/
修改音符时编辑 score/中的 JSON;修改谱面页面时编辑模板;修改输出过程时编辑构建脚本。然后重新生成成品,避免直接修改会被构建覆盖的 HTML 或 AlphaTex。
# 在仓库根目录执行
npm ci
npm run build
npm test
npx playwright install chromium
npm run test:browser
若已有 Chromium,可用 PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH指定其可执行文件。PDF 辅助检查使用本地 Poppler 工具:
pdfinfo artifacts/score-print.pdf
pdftoppm -scale-to 1600 -png artifacts/score-print.pdf artifacts/preview
构建时读取本地 alphaTab 脚本、Bravura 字体和许可证,连同数据一起写入 HTML。用户打开成品无需安装 Node.js,也无需启动服务器。node_modules/、artifacts/及其他临时文件由 .gitignore排除;成品、数据、模板、脚本、依赖锁文件和项目 skill 可纳入版本管理。
早期兼容入口 前奏.html已按用户要求删除,构建不会重新生成它。npm run build依次生成《偏爱》和《老男孩》;npm run build:laonanhai仅重建伴奏谱。首页清单在 assets/catalog.js登记,不自动扫描目录。
09 · 后续如何复用
下一首曲谱的制作顺序
- 收集原图或网页原图,记录曲名、来源、页序、分段和已知参数;明确哪些只是练习标记。
- 区分指弹独奏与弹唱伴奏的表达需求,先转录一小段,让用户审查音符和显示方式。
- 逐小节录入并核对节奏与技法;明确重复的来源,单独识读相似段落的变化。
- 确认特殊符号、段落冲突和看不清的内容,将结论写回数据说明。
- 生成 HTML,做数据回读、浏览器和逐页打印检查,最后放入
sheet_music/。
《老男孩》伴奏声部的实践
三页原谱分别有20、24、11个书写小节,共55小节。先建立小节编号,再记录和弦变换拍点与节奏模式。普通半小节为“下扫四分、下扫八分、下扫十六分、上扫十六分”;另行记录密集C和弦、三和弦、过门、琶音与延续,不把相似小节全部套成同一节奏。
score/laonanhai.json中的 patterns保存节奏事件,bars引用模式并指定和弦起拍。品位事件仍采用1弦在上、6弦在下的约定;过门为4弦0击到2,再弹3弦空弦。和弦图的数组则按6弦至1弦读取,两种方向需要明确区分。
独立识读发现第18、43小节只写了两拍,因此保留 beats: 2并附原谱说明。校验要求事件时值合计与该值一致,非四拍小节必须有说明;不通过补音来凑满四拍。Dm7、A7、G7按图保留 x00211、002223、300001;G/B原图没有指法图,补充常用 x20003并用†明确标为参考。
反复保持书写顺序:第1房子28–29,第2房子30。完整演奏路线为 1–29 → 7–27 → 30–45 → 21–26 → 46–47 → 21–27 → 48–55。两次D.S.均回21,分别在27之前跳到46、28之前跳到48。页面同时提供路线导航和小节内文字提示,避免把跳尾入口当成需要先演奏的小节。
为保留箭头扫弦记法,构建脚本直接绘制SVG和弦图、六根弦、方向箭头、节奏连梁与小节线。生成文件没有远程资源请求,也不依赖JavaScript绘制;脚本仅处理缩放、定位和打印。SVG逐行进入正常文档流并禁止行内分页,打印忽略屏幕缩放值。
仓库逐步整理的方向
根目录 index.html现已实现曲谱目录,元信息独立保存在 assets/catalog.js,支持搜索、分类、排序、打开及下载,并适配 GitHub Pages。新增成品放入 sheet_music/后登记清单即可展示。后续可为每首曲谱分开保存来源和结构化数据,再扩展按曲谱选择生成的构建流程。