WPLRC 文件格式规范
前言
WPLRC 是 WpfMusicPlayer 使用的中间歌词格式。它是一种采用 UTF-8 编码的 JSON 格式,用于在传统 LRC 输入完成规范化之后,保留歌词文本、翻译、罗马化行以及可选的词级时间控制节点之间的语义顺序。
该格式旨在作为传统 LRC 的后继格式。传统 LRC 缺乏明确的 schema 和统一标准,也无法保留歌词节点之间的语义信息。
当前格式版本为 2。
状态
本文档描述 WPLRC 格式版本 2。该格式由 LrcFileControllerNative::to_intermediate_json 生成,并由 WpfMusicPlayer 中的托管歌词处理流水线读取。
版本 2 将罗马化 schema 信息移动到文档根级。旧版版本 1 文档可能包含行级 schema 或 scheme 属性;WpfMusicPlayer 会通过推断占主导地位的根级 romanization_schema,并移除行级 schema 字段,将这些文档升级到版本 2。
文件格式
一个 WPLRC 文件:
- 必须是有效的标准 JSON。不允许使用 JSON 注释。
- 应该采用 UTF-8 编码。WpfMusicPlayer 导出不带 BOM 的 UTF-8。
- 应该使用
.wplrc文件扩展名。 - 必须包含一个顶层 JSON 对象。
所有时间值均为以毫秒为单位的整数。
顶层对象
| 属性 | 类型 | v2 生成器是否必需 | 说明 |
|---|---|---|---|
format_version | integer | 是 | 格式版本。当前值为 2。 |
romanization_schema | string | 否 | 全局罗马化记法 schema。有效值为 romaji 和 jyutping。未启用罗马化 schema 时应省略。 |
offset | integer | 是 | 全局歌词偏移量,单位为毫秒。正值会延后歌词;负值会提前歌词。为兼容性考虑,消费者应该将缺失的偏移量默认视为 0。 |
metadata | object | 是 | 从 LRC 标签转换而来的元数据。可以是空对象。 |
lyric_lines | array | 是 | 按顺序排列的歌词行节点数组。 |
消费者应该拒绝 format_version 不受支持的文档。WpfMusicPlayer 当前接受版本 1 用于升级,并将版本 2 作为当前格式。
Metadata 对象
metadata 对象包含可选的字符串字段。生成器应该省略空的元数据字段。
| 属性 | 来源 LRC 标签 | 说明 |
|---|---|---|
artist | ar, artist | 艺术家名称。 |
album | al, album | 专辑名称。 |
author | au, author | 歌词作者。 |
by | by | LRC 文件创建者或上传者字段。 |
title | ti, title | 歌曲标题。 |
LRC 的 [offset:...] 标签由顶层 offset 属性表示,而不是放在 metadata 内部。
歌词行对象
lyric_lines 中的每一项都表示一个带时间的歌词组。
| 属性 | 类型 | 必需 | 说明 |
|---|---|---|---|
time_start_ms | integer | 是 | 该歌词组的开始时间。 |
time_end_ms | integer | 是 | 该歌词组的结束时间。 |
lines | array | 是 | 属于该带时间歌词组的语义行节点。 |
lyric_lines 应该按 time_start_ms 升序排序。生成器应该确保 time_end_ms > time_start_ms;如果消费者正在处理的节点满足 time_start_ms > time_end_ms,则应该立即失败。如果某个 LRC 行没有显式结束时间,WpfMusicPlayer 会从下一行开始时间、词级控制器时间、可用的歌曲时长,或一个最小的非零回退时长中推导该结束时间。
行节点对象
歌词行的 lines 数组中的每一项都表示一个语义文本行。
| 属性 | 类型 | 必需 | 说明 |
|---|---|---|---|
role | string | 是 | 语义角色。有效值为 lyric、translation、romanization 和 ignored。 |
language | string | 推荐 | 检测到的语言分类器输出。有效值见下文。 |
text | string | sync 缺失时必需;当 sync 存在时,该字段会被静默丢弃。 | 该语义行的纯文本。 |
sync | string | 否 | 同步类型。使用 controller_nodes 表示词级时间。 |
controller_nodes | array | 当 sync 为 controller_nodes 时必需 | 词级或片段级时间控制节点。 |
WpfMusicPlayer 当前生成的有效 language 值如下:
zh: 简体中文/繁体中文latin: 英语/法语/意大利语/西班牙语,以及/或其他基于拉丁字母的语言jp: 日语,包含平假名、片假名和汉字kr: 韩语,包含谚文字母和汉字ru: 俄语/蒙古语,以及/或其他基于西里尔字母的语言jyut: 粤语粤拼和汉语拼音roma: 日语和韩语的罗马化onomatopoeia: 没有实际语义的拟声词,或其他未识别语言
消费者应该保守处理未知的 role、language 或 sync 值。WpfMusicPlayer 以大小写不敏感的方式读取 role,并使用第一个 lyric role 作为主显示行。如果不存在 lyric role,则回退到该组中的第一个行节点。
控制器节点
当某个行节点包含 "sync": "controller_nodes" 时,该行使用带时间的控制器节点,而不是普通文本时间。
| 属性 | 类型 | 必需 | 说明 |
|---|---|---|---|
time_start_ms | integer | 是 | 该控制器片段的开始时间。 |
time_end_ms | integer | 是 | 该控制器片段的结束时间。 |
text | string | 是 | 该控制器片段期间显示的文本。 |
控制器节点时间是文档中的绝对时间,单位为毫秒,而不是相对于父行的偏移量。
控制器同步行应该忽略 text;消费者可以通过按顺序拼接 controller_nodes[*].text 来重构显示文本,并静默丢弃 text 属性。WpfMusicPlayer 会在 text 缺失时执行这种重构。
在高亮进度方面,WpfMusicPlayer 会在每个控制器节点内部进行线性插值,并将当前活动节点索引加上节点内局部进度映射为整行进度。空的控制器节点文本会被托管显示流水线忽略。
出于旧版兼容性考虑,WpfMusicPlayer 也会将 sync: "controller_node" 识别为等价于 sync: "controller_nodes",但版本 2 生成器应该只写入 controller_nodes。
Romanization Schema
romanization_schema 是版本 2 中的文档级属性。它描述 role 为 romanization 的行所使用的记法系统。
有效值:
romaji: 由 WpfMusicPlayer 歌词引擎分类出的日语罗马字,或韩语风格的罗马化。jyutping: 粤语粤拼,以及/或汉语拼音。
如果 romanization_schema 缺失或未知,消费者应该仅在存在 romanization role 行时将罗马化视为存在,但不应该假定具体的记法系统。
版本 2 行节点不得使用 schema 或 scheme。消费者可以在规范化过程中移除这些字段。
示例
下面是一个完整的 WPLRC 版本 2 文档。该示例是有效 JSON,且不包含注释。
{
"format_version": 2,
"romanization_schema": "romaji",
"offset": 0,
"metadata": {
"artist": "sample",
"album": "sample",
"author": "sample",
"by": "sample",
"title": "sample"
},
"lyric_lines": [
{
"time_start_ms": 12060,
"time_end_ms": 13843,
"lines": [
{
"role": "romanization",
"sync": "controller_nodes",
"language": "roma",
"controller_nodes": [
{
"time_start_ms": 12060,
"time_end_ms": 12215,
"text": "ba "
},
{
"time_start_ms": 12216,
"time_end_ms": 12371,
"text": "'d "
},
{
"time_start_ms": 12371,
"time_end_ms": 12507,
"text": "do "
},
{
"time_start_ms": 12508,
"time_end_ms": 12655,
"text": "ra "
},
{
"time_start_ms": 12656,
"time_end_ms": 12803,
"text": "n "
},
{
"time_start_ms": 12803,
"time_end_ms": 12955,
"text": "do "
},
{
"time_start_ms": 12956,
"time_end_ms": 13123,
"text": "ni "
},
{
"time_start_ms": 13123,
"time_end_ms": 13275,
"text": "u "
},
{
"time_start_ms": 13276,
"time_end_ms": 13428,
"text": "ma "
},
{
"time_start_ms": 13428,
"time_end_ms": 13556,
"text": "re "
},
{
"time_start_ms": 13557,
"time_end_ms": 13843,
"text": "ta "
}
]
},
{
"role": "lyric",
"language": "jp",
"text": "バッドランドに生まれた"
},
{
"role": "translation",
"language": "zh",
"text": "只因诞生于劣地"
}
]
},
{
"time_start_ms": 13843,
"time_end_ms": 16267,
"lines": [
{
"role": "romanization",
"sync": "controller_nodes",
"language": "roma",
"controller_nodes": [
{
"time_start_ms": 13843,
"time_end_ms": 13987,
"text": "da "
},
{
"time_start_ms": 13987,
"time_end_ms": 14154,
"text": "ke "
},
{
"time_start_ms": 14154,
"time_end_ms": 14313,
"text": "de "
},
{
"time_start_ms": 14314,
"time_end_ms": 14474,
"text": "ba "
},
{
"time_start_ms": 14474,
"time_end_ms": 14634,
"text": "'d "
},
{
"time_start_ms": 14635,
"time_end_ms": 14786,
"text": "do "
},
{
"time_start_ms": 14786,
"time_end_ms": 14938,
"text": "ra "
},
{
"time_start_ms": 14939,
"time_end_ms": 15116,
"text": "i "
},
{
"time_start_ms": 15116,
"time_end_ms": 15258,
"text": "fu "
},
{
"time_start_ms": 15258,
"time_end_ms": 15417,
"text": "ga "
},
{
"time_start_ms": 15418,
"time_end_ms": 15554,
"text": "de "
},
{
"time_start_ms": 15555,
"time_end_ms": 15630,
"text": "fo "
},
{
"time_start_ms": 15706,
"time_end_ms": 15842,
"text": "to "
},
{
"time_start_ms": 15843,
"time_end_ms": 16266,
"text": "ka "
}
]
},
{
"role": "lyric",
"language": "jp",
"text": "だけでバッドライフがデフォとか"
},
{
"role": "translation",
"language": "zh",
"text": "就默认会拥有糟糕的人生吗"
}
]
}
]
}
最小示例
{
"format_version": 2,
"offset": 0,
"metadata": {},
"lyric_lines": [
{
"time_start_ms": 1000,
"time_end_ms": 5500,
"lines": [
{
"role": "lyric",
"language": "latin",
"text": "First line"
}
]
}
]
}
版本兼容性
WPLRC 版本 1 是旧版中间格式。它的已知差异是:罗马化 schema 可能以 schema 或 scheme 的形式出现在各个行节点上。
当将版本 1 升级到版本 2,且当前 WPLRC 版本 1 文档包含罗马化行节点时,WpfMusicPlayer 会:
- 统计可识别的行级 schema 值。
- 如果
jyutping出现次数多于romaji,则选择jyutping;否则,只要存在任何可识别的罗马化 schema,就选择romaji。 - 将所选值写入根级
romanization_schema。 - 将
format_version设置为2。 - 移除所有行级
scheme(以及schemea,如存在)属性。
否则,它不会生成根级 romanization_schema 属性。
版本 2 生成器不应该输出版本 1 字段。
生成器说明
WpfMusicPlayer 的 LRC 转换器当前会将若干 LRC 模式规范化为 WPLRC:
- 普通的逐行定时 LRC。
- 一个 LRC 行中包含多个时间标签。
- 时间戳顺序错乱的 LRC,按时间进行稳定排序。
- 交错或同步的翻译行。
- 受支持模式中的行内翻译。
- 使用
<mm:ss.xxx>或[mm:ss.xxx]风格控制器标记的扩展 LRC 或词级时间节点。
这些针对源 LRC 的启发式规则属于生成器行为,不是额外的 WPLRC 语法。WPLRC 读取器只需要实现上文描述的 JSON 格式。