TTML 从入门到入土
一、入门篇:TTML 基础与 AMLL Editor 快速上手
1.1 什么是 TTML?
TTML(Timed Text Markup Language)是 W3C 定义的时序文本标记语言标准。Apple Music 使用 TTML 作为逐字歌词格式,因此 AMLL 生态也主要采用 TTML 为歌词存储与交换格式。
TTML 的核心能力:
- 逐字时间轴(Word-level timing)
- 对唱/多人演唱者信息(
ttm:agent) - 背景人声(
x-bg) - 翻译与音译(
x-translation/x-roman) - 歌曲分段(
itunes:song-part) - Ruby 注音(日语振假名、拼音等)
1.2 TTML 文件的最小结构
<tt xmlns="http://www.w3.org/ns/ttml"
xmlns:ttm="http://www.w3.org/ns/ttml#metadata"
xmlns:itunes="http://music.apple.com/lyric-ttml-internal"
xmlns:amll="http://www.example.com/ns/amll">
<head>
<metadata>
<!-- 定义演唱者 -->
<ttm:agent type="person" xml:id="v1"/>
<ttm:agent type="other" xml:id="v2"/>
</metadata>
</head>
<body dur="03:12.915">
<div begin="00:02.207" end="03:12.915">
<p begin="00:02.207" end="00:06.042" ttm:agent="v1" itunes:key="L1">
<span begin="00:02.207" end="00:02.967">紧</span>
<span begin="00:02.967" end="00:03.845">握</span>
<!-- ... -->
</p>
</div>
</body>
</tt>
关键要素:
| 元素 | 作用 |
|---|---|
<tt> |
根节点,声明所有命名空间 |
<head><metadata> |
元数据区,定义演唱者(agent) |
<body> |
歌词主体容器,dur 属性标注歌曲总时长 |
<div> |
段落容器,可用 itunes:song-part 标记主歌/副歌 |
<p> |
每一行歌词,带 begin/end 时间码,ttm:agent 指定演唱者 |
<span> |
每一个字/词,带独立的 begin/end 时间码 |
命名空间说明:
xmlns="http://www.w3.org/ns/ttml"— TTML 标准xmlns:ttm="http://www.w3.org/ns/ttml#metadata"— 元数据(agent、role)xmlns:itunes="http://music.apple.com/lyric-ttml-internal"— Apple 扩展(song-part、key)xmlns:amll="http://www.example.com/ns/amll"— AMLL 扩展元数据
时间格式:
- 时钟格式:
MM:SS.fff或HH:MM:SS.fff(小数点后可保留 1~3 位) - 秒值格式:
12.3s
1.3 AMLL Editor 入门操作
AMLL 生态提供两个编辑器:
| 工具 | 技术栈 | 地址 | 特点 |
|---|---|---|---|
| AMLL TTML Tool | React | https://tool.amll.dev/ | 稳定版,功能完整 |
| AMLL Editor | Vue | https://editor.amll.dev/ | 下一代,早期开发,支持查找替换等便利功能 |
基本工作流:
- 导入歌曲与歌词:在编辑器中加载音频文件和纯文本歌词
- 一键分词:工具自动将歌词拆解为逐字/逐词结构
- 打轴(时间标记) :使用快捷键逐字标记时间轴
- F — 标记该行起始时间
- G — 标记每个字的起始时间(逐字打轴)
- H — 标记长空白停顿处
- 配置行属性:标记该行是主唱(v1)、对唱(v2)还是背景和声(x-bg)
- 导出 TTML:生成标准的
.ttml文件
1.4 最简 TTML 模板(可直接复制使用)
<tt xmlns="http://www.w3.org/ns/ttml"
xmlns:ttm="http://www.w3.org/ns/ttml#metadata"
xmlns:itunes="http://music.apple.com/lyric-ttml-internal"
xmlns:amll="http://www.example.com/ns/amll">
<head>
<metadata>
<ttm:agent type="person" xml:id="v1"/>
</metadata>
</head>
<body dur="00:30.000">
<div begin="00:00.000" end="00:30.000">
<p begin="00:00.000" end="00:05.000" ttm:agent="v1" itunes:key="L1">
<span begin="00:00.000" end="00:00.500">你</span>
<span begin="00:00.500" end="00:01.000">好</span>
<span begin="00:01.000" end="00:01.500">世</span>
<span begin="00:01.500" end="00:02.000">界</span>
</p>
</div>
</body>
</tt>
二、进阶篇:时间轴特效与高级技法
以下技法均来自你之前分析的实际歌词文件,是“用时间轴画画”的核心手段。
2.1 多演唱者(对唱/二重唱):ttm:agent
在 <head><metadata> 中定义多个 agent:
<ttm:agent type="person" xml:id="v1"/> <!-- 主唱 -->
<ttm:agent type="person" xml:id="v2"/> <!-- 对唱 -->
在 <p> 或 <span> 中通过 ttm:agent 指定演唱者:
<!-- V1 主唱 -->
<p begin="00:19.919" end="00:22.713" ttm:agent="v1" itunes:key="L7">
<span begin="00:19.919" end="00:20.054">幸</span>
<span begin="00:20.054" end="00:20.313">福</span>
</p>
<!-- V2 对唱 -->
<p begin="00:22.974" end="00:25.708" ttm:agent="v2" itunes:key="L8">
<span begin="00:22.974" end="00:23.070">是</span>
<span begin="00:23.070" end="00:23.323">否</span>
</p>
渲染效果:不同 agent 的歌词行在播放器中以不同颜色显示(如 V1 亮白、V2 淡蓝),实现“声部可视化”。
2.2 背景和声:ttm:role="x-bg"
在 <span> 中嵌套 ttm:role="x-bg" 标记背景人声/和声:
<p begin="00:09.581" end="00:10.294" ttm:agent="v1" itunes:key="L4">
<span begin="00:09.581" end="00:09.914">怯</span>
<span begin="00:09.914" end="00:10.294">懦</span>
<!-- 背景和声:与主唱时间重叠,独立起止 -->
<span ttm:role="x-bg" begin="00:10.059" end="00:13.206">
<span begin="00:10.059" end="00:11.565">Ahhh</span>
<span begin="00:11.885" end="00:13.206">Ahhh</span>
</span>
</p>
关键点:背景和声的 begin/end 可以与主唱歌词完全重叠甚至超出,播放器会将其渲染为更小字号、更低透明度的副歌层。
2.3 翻译与音译:ttm:role="x-translation" / x-roman
在行内嵌入翻译或音译文本:
<p begin="00:11.460" end="00:13.770" ttm:agent="v1" itunes:key="L1">
<span begin="00:11.460" end="00:11.700">Hello</span>
<span ttm:role="x-translation" xml:lang="zh-CN">你好</span>
</p>
2.4 时间轴高级技法(“用时间轴画画”)
技法一:占位拍(Sustain Hold / 长尾占位)
定义:给某个字符分配远超实际发音时长的时间跨度,让这个字“霸占”屏幕直到下一个强拍到来。
实现方式:将某个 <span> 的 end 时间大幅延长:
<!-- “睡”字从 00:58.481 一直拖到 01:00.079,长达 1.6 秒 -->
<p begin="00:55.638" end="01:00.079" ttm:agent="v1" itunes:key="L31">
<span begin="00:58.137" end="00:58.481">沉</span>
<span begin="00:58.481" end="01:00.079">睡</span> <!-- 占位拍! -->
</p>
效果:视觉上这个字“钉”在屏幕上,对应歌手的长高音或尾音颤音,填补主唱换气时的情绪空白。
技法二:幽灵字 / 零时长陷阱(Zero-Duration Ghost)
定义:将某个 <span> 的 begin 和 end 都设为 00:00.000,让该字在渲染时被跳过(“吞字”效果)。
实现方式:
<p begin="01:59.098" end="01:59.221" ttm:agent="v1" itunes:key="L54">
<span begin="01:59.098" end="01:59.177">繁</span>
<span begin="00:00.000" end="00:00.000">茂</span> <!-- 幽灵字!被渲染器跳过 -->
</p>
效果:观众只看到“繁”,紧接着下一句以“繁碌”开头,制造出“词穷而意转”的撕裂感和抢拍效果。
⚠️ 注意:在留声机(Gramophone)中,零时长 span 会被直接跳过不渲染;在 Flamingo 中可能闪一下半透明状态。
技法三:抢拍 / 提前进入(Snap Beat / Negative Gap)
定义:下一句第一个字的 begin 时间早于上一句最后一个字的 end 时间(时间轴重叠)。
实现方式:
<!-- L13 背景和声拖到 00:36.418 -->
<p begin="00:33.200" end="00:35.964" ...>
<span ttm:role="x-bg" begin="00:33.939" end="00:36.418">(言说 描摹 定夺)</span>
</p>
<!-- L14 “盛”在 00:36.248 就开始了,重叠了 170ms -->
<p begin="00:36.248" end="00:36.748" ...>
<span begin="00:36.248" end="00:36.279">盛</span>
</p>
效果:字幕还没结束,下一句的字就“冲”出来了,制造急切、逼迫感。
技法四:负间隙呼吸(Negative Gap)
定义:前后两句之间故意留出 200ms 以上的时间真空(没有高亮字)。
实现方式:
<p begin="00:07.134" end="00:08.531" ...>法</p>
<!-- 420ms 的空白 -->
<p begin="00:08.951" end="00:09.236" ...>和</p>
效果:屏幕突然“黑”了一下,对应歌手的深呼吸/换气口。
技法五:双轨叠录(Dual-Track Overlay)
定义:V1 和 V2 在同一时间段内完全重叠,各自拥有独立的时间轴。
实现方式:
<!-- V1 在唱 -->
<p begin="02:28.065" end="02:30.832" ttm:agent="v1" itunes:key="L62">
<span begin="02:28.065" end="02:28.188">我</span>
<span begin="02:28.188" end="02:28.419">写</span>
<!-- ... -->
</p>
<!-- V2 几乎同时也在唱(仅差 7ms) -->
<p begin="02:28.058" end="02:30.878" ttm:agent="v2" itunes:key="L66">
<span begin="02:28.058" end="02:28.061">再</span>
<span begin="02:28.061" end="02:28.110">次</span>
<!-- ... -->
</p>
⚠️ 这是渲染极限测试:
- 留声机:V1 和 V2 因 agent 不同而独立渲染,但性能开销瞬间拉满
- Flamingo:模糊过渡被放大,形成迷幻叠影效果,但边界精度下降
2.5 AMLL Editor 中实现进阶特效的操作指南
| 特效 | 在 AMLL Editor 中的操作 |
|---|---|
| 多演唱者 | 在元数据侧边栏添加多个 agent,每行歌词选择对应的 ttm:agent |
| 背景和声 | 在歌词行行为设置中勾选“背景歌词”(x-bg) |
| 占位拍 | 手动拖拽该字的结束时间点,向后延长 |
| 幽灵字 | 将该字的 begin 和 end 都设为 00:00.000(需手动编辑或利用零时长快捷键) |
| 抢拍/重叠 | 拖拽下一句第一个字的开始时间点,使其早于上一句的结束时间 |
| 双轨叠录 | 创建两个独立行,分别赋予 v1 和 v2,让它们的时间轴完全重叠 |
2.6 开发工作流建议(基于你的实践验证)
| 阶段 | 工具 | 任务 | 原因 |
|---|---|---|---|
| 精修时间轴(Debug) | 留声机(Gramophone) | 抓虫、规范语法 | 对时间轴重叠/零时长极其敏感,会直接跳过或报错,倒逼语法规范 |
| 最终展示(Polish) | Flamingo | 视觉呈现 | 内置缓动函数和模糊过渡,让干净的时间轴产生高级的呼吸感 |
三、参考资源
- AMLL 官方文档:https://amll.dev/guides/lyric/ttml
- AMLL TTML Tool(在线版) :https://tool.amll.dev/
- AMLL Editor(下一代) :https://editor.amll.dev/
- AMLL TTML 格式规范:https://github.com/amll-dev/amll-ttml-db/wiki/格式规范
- Apple 官方 TTML 歌词指南:https://help.apple.com/itc/videoaudioassetguide/
- AMLL TTML Tool GitHub:https://github.com/amll-dev/amll-ttml-tool

浙公网安备 33010602011771号