Skip to content

Repository files navigation

669 首简谱谱面:记谱方言普查、统一与三层验证

2026-09-03 · 对 669 首古风简谱歌(raw_jianpu_669)的记谱方法做全量普查、归一化到主流写法, 并以"双渲染对比 + SVG 逐字节对比"完成验证闭环。

一、研究动机

669 首谱面({song_id}_原始简谱.json)虽然都是同一套简谱 DSL 语法,但每首歌的写法选择不同, 导致下游(渲染、对齐、统计)处处踩坑。本研究回答三个问题:

  1. 669 个谱的记谱方法到底有几种?(普查)
  2. 能不能统一成一种写法,且不改变任何音乐语义?(归一化)
  3. 怎么证明"没改变"?(验证闭环)

二、核心发现

2.1 记谱方言:同一语法,205 种组合

三大正交方言轴(全量实测):

方言轴 变体分布(歌数)
减时线(8 变体) x 396 / _ 87 / _= 75 / x= 62 / x_= 31 / x_ 17 / = 1 / 无 1
低八度点(8 变体) g+d 213 / g 144 / g+, 129 / d 93 / , 56 / …
段落结构(8 变体) {play:}+段名行 248 / 跳房[1: 187 / 无结构 132 / {{}} 18 / …
  • DSL 语义词表(实测确认):数字 1-7 音阶、0 休止、- 延一拍、_/x 各=一条减时线(八分)、 __/xx/= 两条(十六分)、. 附点、g 高八度点、d/, 低八度点、b/# 升降、 ( ) 连音/倚音、[1,2: 跳房、{!拼音!} 歌词槽、{{ }} 段结构、{play:}{bpm:}{cn:}{f:} 等 20 种标签
  • 411 首(61%)无 {bpm:} 标记 → 渲染器一律填默认 72(必须区分 explicit/default)
  • keynote 26 种写法(1=A4 带八度、1=F G 双调、1=B 全角等号、37 首为空)

2.2 歌词记录:9 种形态、两套体系

  • raw songdata.lyric = 字符串里套 JSON 数组;/ 分组(567 首)、// 空行(386 首)、 _ 延音填充(39 首)、多空格对齐、中文标点 669 首全混排、日语歌词(群青)
  • 拼音槽体系 {!c.an_gq_ia.n_g!} 与汉字体系并存(69 首)
  • 歌词段数与谱面段落结构基本不对应(93% 的 {play:} 歌不匹配)→ 歌词数组无结构语义
  • 多段词机制(227 首两段词):同一旋律按遍展开,每遍挂一段词;词段缺句回落挂段 1(实证:某段播 3 遍挂同一句词,该句只在段 1 存在)

2.3 同一旋律的 9 种记谱表示

原始 DSL(紧缩)/ 渲染 DSL(playback)/ 行内 jianpu+中文拍注 / MIDI 数组(谱面域)/ MIDI(演唱域)/ 42 字段事件 / c-t-dur 结构化 / MIDI 文件两套(PPQ480 秒轴、PPQ3360 拍轴)/ f0 Hz。

三、统一方案

统一目标 = 众数写法:减时线一律 x 系列(x/xx/xxx),低音点一律 d(高音点 g 本已统一); 标签、段落、歌词槽、调号等非音符记号原样保留

5 条改写规则(顺序敏感!):

___ → xxx    (三条线)
__  → xx     (两条线)
,   → d      (低音点, 必须先于 =→xx, 否则 "7,=" 的 = 漏转)
=   → xx     (等号=两条线)
_   → x      (一条线; 正文内全部)

保护机制:{…} 标签、{!…!} 歌词槽、{{ }} 段边界、[1,2: 跳房头内部不转换; 含未证实记号 =}(15 首)整首跳过、原文照存。

四、验证闭环(三层)

方法 结果
events 语义 原版与统一版各过官方渲染器,逐事件 diff 音高/拍轴/秒轴/歌词槽/定位 654/654 全等
SVG 视觉 各渲染 SVG,剥除嵌入源数据 payload 与溯源列坐标后逐字节对比 654/654 全等
残留自检 统一版正文逐段扫描旧方言记号(渲染对比抓不到漏转——两边一致地"没转"也 PASS) 0 残留
歌词守恒 音符级字槽 vs raw 原文字数对账 0 缺失

结果:654/669 统一并验证通过,15 首含 =} 原文照存(标记 skip),0 失败。 实际改写 287 首,规则命中 5.8 万处(_x 31142、=xx 20878、,d 6050、___xxx 90)。

SVG 仅有的差异 = 嵌入的源数据 payload(notation 字段原文 vs 统一文)与 溯源列坐标 firstColumn/lastColumn(=xx 加长导致 +1 平移)——都是"源文本不同"的记录, 画出来的图形逐字节相同。

五、两层统一 JSON 与"按句拆段单独渲染"

研究确认存在两层统一 JSON,分工如下:

第一层:songdata 统一(统一简谱/) 第二层:cell 统一(0830/songs_unified/)
形态 {songdata:{notation, notation_raw, lyric, lyric_layer}} {notes:[{content,octave,underBarCount,dotCount,noteNumber}], raw}
统一层面 文本层(方言 → x-d 规范,可逆) 结构层(减时线/附点/音高全部字段化,方言在字段层天然归一)
角色 渲染器输入(喂 json2svg / render.py) 渲染结果对照表:notes[i] ↔ SVG 第 i 个音符(noteCount = svg_note_count,牵丝戏 200=200)

反向获取:随便一两句 LRC → 单独渲染一段

一两句 LRC
   ↓ 词序匹配(⚠️不能用 LRC 时间戳: LRC=实际音频时间轴, 谱面=bpm 合成时间轴)
播放展开流 → 字槽 loc={(line,col,occ)} → 这两句占的谱面位置
   ↓ 按 loc 切第一层 songdata
组装"子段 songdata json"(谱面文本切片 + 歌词切片)
   ↓ render.py / json2svg
单独渲染的一段 SVG ✓

基建先例(已跑通):0830/ 的 6141_十年人间拆段版(原始简谱_子段版.json → 每段独立页面+MIDI)、 render.py 通用渲染器、分段铁律(房子不单独成段、|:/{DS}/|| 清理、{{}} 过滤、 词块按遍整挂、; 延音占位)。

拆段判定三连续:词序连续(句 i+1 紧跟句 i)、版面连续(谱面行差≤1,SVG 连续流水排版)、 播放连续(前句末音 offset = 后句首音 onset,零间隔);间奏行 = 天然段界。 兜底:重复段句按第 n 遍匹配(occ)、谱面缺词段挂最近音符标记补挂。 牵丝戏 33 句实测:17 句对三连续全满足、1 断点=间奏、失败句全部分类可兜底(详见 拆段方案.md)。

第二层(songs_unified)用作切完后的校验:切段渲染出的音符数/音高应等于 notes[i..j] 切片。

六、文件结构

├── README.md               本文档
├── schema.md               统一数据模型设计(bai-ma-unified-v1)
├── 验证报告.md             结果总表+方言分布+跳过清单
├── 拆段方案.md             LRC 句 → 段级 json+SVG 的拆段研究
├── 统一简谱/               ★ 669 首统一版(每首含 notation / notation_raw / notation_dialect / lyric_layer)
├── lib/
│   ├── dialect.py          方言归一化器(5 规则 + 保护段 + 未证实记号检测)
│   └── lyric_slots.py      歌词字槽提取(音符级 0..n 字 + 守恒检查)
├── run_normalize.py        批量归一化 + 双渲染验证 + 残留自检
├── verify_svg.py           全量 SVG 逐字节验证
├── integrate_lyric_layer.py 字槽集成
└── logs/                   逐歌验证明细(json)

统一版每首歌的 json 字段:

{"songdata": {
  "notation":         "…0x5dx1x7dx…",   // 统一写法(x-d 规范)
  "notation_raw":     "…0_5,_1_7,_…",   // 原文一字不动(可逆锚)
  "notation_dialect": {"line_x":, "oct_comma":}, // 转换前方言指纹
  "lyric_layer": {                      // 歌词层
     "raw_lyric": "原样", "slots": [{line,col,occ,chars}], "conservation": {"missing":[]}
  }
}}

七、复现

python3 run_normalize.py          # 归一化 + 双渲染验证 + 残留自检(669 首, ~8min)
python3 integrate_lyric_layer.py  # 歌词字槽集成
python3 verify_svg.py             # SVG 全量逐字节验证

依赖:Node.js(苍强渲染器 export_playback_full.js / json2svg.py)。

About

669 首简谱谱面记谱方言普查、统一(x-d 规范)与三层验证: 双渲染 events 全等 + SVG 逐字节全等 654/654

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages