post: generating subtitles for songs that ship without timestamps
Deploy / build (push) Successful in 30s

Tutorial on turning untimed AI-generated audio into LRC + SRT: align ASR word
timestamps against the KNOWN lyrics (SequenceMatcher) instead of trusting a
transcript, then a governor that rejects impossible anchors, refills runs by
unit-proportional duration, and enforces a 1.2 s minimum line gap.

Ships 18 English songs (342 subtitle lines, mean anchor coverage 0.96, 9/18
fully anchored) with synced lyrics plus downloadable .srt per track. Documents
both player bugs and the headless-Chrome numeric probe that finally caught them.
This commit is contained in:
hoelee committed 2026-10-20 22:09:34 +08:00
1 parent cf327211df
commit 92f38184fb
20 files changed
+2737

No files matched your search

@@ -0,0 +1,664 @@
---
title: "给没有时间戳的歌曲自动生成字幕"
description: "AI 音乐工具只给你音频 —— 没有逐行时间,没有卡拉 OK。这是我给 18 首歌生成 LRC 与 SRT 字幕的完整流程,为什么单纯转写不行,以及让歌词框滚到底的两个 bug。"
pubDate: 2026-10-20
category: tutorials
tags: ["subtitles", "lrc", "srt", "whisper", "forced-alignment", "ai-music", "python"]
draft: false
---
我试过的每一个 AI 音乐工具,交出来的东西形状都一样:一个音频文件。没有一个会告诉你**每一句是什么时候唱的**。只想听的话没问题,但只要你想把歌词放到屏幕上 —— 卡拉 OK 的那一行、视频字幕、播放器下面的滚动框 —— 就完全不够用。
时间轴才是全部难点。音频反而是简单的部分。
这是我最后跑通的一套流程,用在本地生成的 18 首英文歌上,外加它在浏览器里崩掉的两个地方。下面全部可复现:它唯一需要你提供的东西,是**你已经写好的歌词**。
## 你真正需要的两样东西
两种字幕格式,共用同一份数据结构:
| 格式 | 用在哪 | 长什么样 |
|---|---|---|
| **LRC** | 音乐播放器、卡拉 OK 块、`<audio>` 歌词层 | `[mm:ss.xx]歌词行` |
| **SRT** | VLC、YouTube、Premiere、ffmpeg 烧字 | 序号 / `hh:mm:ss,mmm --> hh:mm:ss,mmm` / 文本 |
两者本质都是「**行 → 起始时间**」(SRT 多一个结束时间)。所以真正的任务是:
**给定一串歌词行和一个音频文件,找出每一行从哪儿开始。**
## 为什么「直接转写」行不通
最直觉的做法:跑一次语音识别,把它的分段结果写出去。它会因为两个原因失败。
**1. 唱腔的识别率远低于说话。** 模型要同时对付乐器、混响和拉长的元音。我这一批里,中文唱词的词错率大约 25–35%,电子混音密集的更差。
**2. 它会整段丢掉。** 有一首 140 BPM 的燃曲,整段第一段主歌压根没出现在转写结果里 —— 人声被埋住了,模型直接跳过去。另外两首丢了尾奏。
有洞的转写,变不出没洞的字幕。但换个框法就全通了:
> 你不是在**转写**,你是在**对齐**。你早就知道确切的字 —— 那就是你的歌词。音频只是用来提供**锚点**。
## 让它成立的思路反转
让识别器给出词级时间戳,然后拿它的输出跟你已知的歌词做最长公共子序列 diff。你根本不在乎它有没有听对 —— 你在乎的是它听出来的那些词**顺序对不对**,因为每一个匹配都是一个时间锚点。
```python
import difflib
ref = [u for line in lines for u in units(line)] # 你的歌词
hyp = [w[0] for w in asr_words] # 它听到的
sm = difflib.SequenceMatcher(a=ref, b=hyp, autojunk=False)
for tag, i1, i2, j1, j2 in sm.get_opcodes():
if tag != "equal":
continue # 不匹配的地方只是空洞,不是错误
for k in range(i2 - i1):
matched[ref_index[i1 + k]] = asr_words[j1 + k][1:] # (起, 止)
```
然后每一行歌词取它**第一个匹配单位**的时间戳。这种做法的稳健性是转写给不了的:60–70% 的词准确率就完全够用,因为每一个位置正确的词都钉住了它所属的那一行。
这批实测的锚定覆盖率 —— 也就是「拿到了至少一个真实锚点」的行占比:
| 语言 | 单位 | 平均锚定覆盖率 | 全行锚定的歌 |
|---|---|---:|---|
| 英文 | 词 | **0.96** | 9/18 首 |
| 中文 | 字 | 0.70 | 11/11 首 |
英文对齐更好,原因很无聊:词之间用空格隔开,所以每个 ASR token 能干净地对应一个歌词 token。中文则必须把每个字平摊到 token 的时间跨度上:
```python
span = w.end - w.start
for i, ch in enumerate(hanzi_in_word):
chars.append((ch, w.start + span * i / n, w.start + span * (i + 1) / n))
```
## 修正器:三条规则,挡住荒唐的时间
锚点能带你走完大半程。但如果放着不管,锚点之间的空隙会产出物理上不可能的时间 —— 其中两个是真的咬到我了:
**故障 A —— 一行落在 0.0 秒。** 有一首歌的第一句歌词正好落在零点,前奏都还没结束,因为锚点搜索在开头的喊麦里匹配到了一个零散的字。
**故障 B —— 四行挤在 0.6 秒里。** 有一首歌的尾奏被识别器整段漏掉,剩下的行被压到相隔 0.18 秒。12 个字不可能在 0.18 秒里唱完。
所以对齐之后,跑三条规则:
1. **估计这首歌自己的速率** —— 用相邻两行都已锚定的样本(单位数 ÷ 秒数,取中位数)。每行的期望时长 = `单位数 ÷ 速率`,下限约 1.8 秒。同一批里英文是 0.96 到 2.33 词/秒,中文是 2.3 到 4.1 字/秒,**不能用全局常数**。
2. **按比例填充没锚定的段**,而不是固定行距。一段夹在两个锚点之间,就按期望时长分摊;空间不够就等比压缩。
3. **剔除不可能的锚点 + 强制最小行距。** 起始时间早于「5 秒 + 它前面所有内容可能占用的时间」的锚点一定是假匹配 —— 降级重算。然后正向扫一遍,保证任意两行起始间隔不小于 1.2 秒;若尾部被推出音频,再从末尾倒推收回。
最后那趟扫描,才是把「看起来合理」变成「不可能闪烁」的关键。
## 同时输出两种格式
同一份时间数组,两个写出函数:
```python
def lrc(ts, lines): # [mm:ss.xx]
return "\n".join(f"[{m:02d}:{s:05.2f}]{l}" for (m, s), l in zip(ts, lines))
def srt(spans, lines): # hh:mm:ss,mmm
out = []
for i, (line, (a, b)) in enumerate(zip(lines, spans), 1):
out.append(f"{i}\n{stamp(a)} --> {stamp(b)}\n{line}\n")
return "\n".join(out)
```
LRC 只要起点;SRT 要起点**和**终点,所以用**下一行**的起点当作当前行的结束(这正是最小行距规则重要的原因 —— 没有它,SRT 块会变成零时长,有些播放器会整块跳过)。
## 验证:我错了两次的地方
字幕早在显示之前就是对的。两个 bug 都在那 20 行播放器脚本里,而且都是**读代码看不出来**的。
**Bug 1 —— 一开播就在末尾。** 找当前行我写的是 `lines.findIndex(l => l.t > now) - 1`。第一句之前 `findIndex` 返回 `0`,于是 `i` 变成 `-1`,而那句 `if (i < 0) i = lines.length - 1` 把「还没开始」翻译成了「最后一行」。播放器一打开就停在尾奏。
**Bug 2 —— 然后第一个和弦就滚到底。** 修完 bug 1,我用 `p.offsetTop` 来做居中。`offsetTop` 是相对**最近的定位祖先**量的 —— 而歌词框没有 `position: relative`,所以它返回的是这一行到**页面顶部**的距离,上千像素。`scrollTop` 被夹到 `maxScroll`:直接到底,字全看不见。
正确写法根本不关心定位上下文:
```js
const br = box.getBoundingClientRect(), pr = p.getBoundingClientRect();
box.scrollTop += (pr.top - br.top) - (box.clientHeight - pr.height) / 2;
```
**关于「怎么测」的教训比修复本身更重要。** 我在 Node 里单测过索引逻辑 —— 通过了。我看过截图 —— 我把高亮的那一行看错了。两者都看不见布局 bug。真正有效的是在 headless Chrome 里打数值探针:stub 掉 `currentTime`,派发 `timeupdate`,然后把真实 DOM 读回来。
```bash
chrome --headless=new --dump-dom --virtual-time-budget=8000 \
--window-size=760,520 "file:///probe.html"
```
```js
Object.defineProperty(a, 'currentTime', { get: () => 100, configurable: true });
a.dispatchEvent(new Event('timeupdate'));
// 然后输出:当前行索引、它在框内的偏移、scrollTop、maxScroll
```
通过条件是**数字**,不是观点:当前行在框内的偏移应当约为框高的一半(我得到的 274 px 框里是 124 px);t = 0 时 `scrollTop = 0` 且没有任何行高亮;只有最后几句时 `scrollTop = maxScroll`。
## 结果
18 首歌,没有一首自带时间戳。现在每一首都有逐行的 LRC 和 SRT —— 只靠歌词加音频生成。
| | |
|---|---:|
| 歌曲 | 18 |
| 字幕行数 | 342 |
| 平均锚定覆盖率 | 0.96 |
| 全行锚定的歌 | 9 / 18(每行都有时间) |
| 处理耗时 | 每首 63–90 秒,纯 CPU |
| 占用显卡 | 无 |
下面每个播放器都会滚动歌词、把当前句保持在中间,旁边还有 **.srt 下载** —— 想烧字进视频或在 VLC 里打开都行。
<style>
.subs-track{margin:2.4rem 0}
.subs-track figcaption{font-weight:600;margin-bottom:.35rem}
.subs-meta{font-weight:400;opacity:.6;font-size:.9em}
.subs-dl{float:right;font-size:.8em;font-weight:600;text-decoration:none;border:1px solid var(--accent,#22c55e);border-radius:6px;padding:.16rem .55rem;color:var(--accent,#22c55e);background:transparent}
.subs-dl:hover{background:rgba(34,197,94,.14)}
.subs-dl::before{content:"930"}
.subs-track audio{width:100%;max-width:560px}
.subs-box{position:relative;max-height:250px;overflow-y:auto;border:1px solid var(--border,#3a3f47);border-radius:8px;padding:.7rem 1rem;margin-top:.6rem;font-size:.95em;line-height:1.6}
.subs-box p{margin:.18rem 0;opacity:.55}
.subs-box p.on{opacity:1;font-weight:600;color:var(--accent,#22c55e)}
</style>
<figure class="subs-track">
<figcaption>Tiny Borrowed Shoes <span class="subs-meta">· Celtic folk · 21 lines · 139 s</span><a class="subs-dl" href="/subs/tiny-borrowed-shoes.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-1" src="https://content.hoelee.com/file/hoelee/music/Tiny-Borrowed-Shoes-Mr-Hoelee.mp3"></audio>
<pre id="subs-1" hidden>[ti:Tiny Borrowed Shoes]
[ar:Mr Hoelee]
[00:11.56]Underneath the floorboards where the shadows play
[00:14.60]I tied a little ribbon at the break of day
[00:18.32]A button for a table, a thimble for a cup
[00:22.02]I climbs the ivy ladder when the sun comes up
[00:27.76]Sugar on the windowsill, a feather in my hand
[00:31.42]The garden is a jungle and a wonderland
[00:35.22]Careful not to wake the cat sleeping by the door
[00:40.00]Tip-toe in my borrowed shoes across the wooden floor
[00:44.46]Fly away, little breeze, carry me along
[00:48.10]Through the clover and the leaves, singing my own song
[00:51.90]Though the world is wide and tall, and I am very small
[00:57.58]In the secret morning light, I can have it all
[01:09.62]Dewdrops on the dandelion shining like a crown
[01:12.24]I catch a floating parachute and spin around and down
[01:15.98]If you hear a tiny laugh hiding in the wall
[01:19.62]That is just my secret song, answering your call
[01:27.26]Fly away, little breeze, carry me along
[01:30.72]Through the clover and the leaves, singing my own song
[01:34.58]Though the world is wide and tall, and I am very small
[01:40.32]In the secret morning light, I can have it all
[01:51.98]La-la-la, in the morning light...</pre>
</figure>
<figure class="subs-track">
<figcaption>Mist Over Skellig <span class="subs-meta">· Celtic folk · 18 lines · 194 s</span><a class="subs-dl" href="/subs/mist-over-skellig.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-2" src="https://content.hoelee.com/file/hoelee/music/Mist-Over-Skellig-Mr-Hoelee.mp3"></audio>
<pre id="subs-2" hidden>[ti:Mist Over Skellig]
[ar:Mr Hoelee]
[00:21.73]Where the gray Atlantic meets the abbey stone
[00:28.56]White birds circle high above the cliff alone
[00:33.56]Carved into the stairway of a thousand years
[00:42.16]Every drop of ocean rain whispers in my ears
[00:49.16]Sail into the silver mist, beyond the western sea
[00:57.96]Where the ancient lanterns glow for you and me
[01:06.32]Hush now, hear the harp strings ring across the foam
[01:14.74]Through the fog and falling stars, the tide will bring us home
[01:25.36]Candles in the chapel window flicker in the gale
[01:33.04]Ink upon the parchment tells a forgotten tale
[01:57.48]Little hands upon the rock, looking at the sky
[02:05.18]Watching all the centuries gently passing by
[02:16.98]Sail into the silver mist, beyond the western sea
[02:22.94]Where the ancient lanterns glow for you and me
[02:30.46]Hush now, hear the harp strings ring across the foam
[02:38.98]Through the fog and falling stars, the tide will bring us home
[02:57.02]Oceans rise and oceans fall...
[03:04.34]The tide will bring us home.</pre>
</figure>
<figure class="subs-track">
<figcaption>Willow by the Silver Stream <span class="subs-meta">· Celtic folk · 19 lines · 198 s</span><a class="subs-dl" href="/subs/willow-by-the-silver-stream.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-3" src="https://content.hoelee.com/file/hoelee/music/Willow-by-the-Silver-Stream-Mr-Hoelee.mp3"></audio>
<pre id="subs-3" hidden>[ti:Willow by the Silver Stream]
[ar:Mr Hoelee]
[00:23.83]Mmm-mmm, ahh-ahh...
[00:26.70]Silver runs the quiet stream beneath the willow tree
[00:33.64]Golden is the evening star shining down on me
[00:40.54]All the little meadow flowers fold their petals tight
[00:46.36]Waiting for the moon to weave a blanket of the night
[00:53.02]May the wind be gentle on your weary wings
[00:59.76]May you hear the lullaby the river softly sings
[01:06.28]Close your eyes and drift away where the shadows gleam
[01:13.52]Peace will walk beside you in the valley of a dream
[01:27.32]Fireflies are dancing slow among the reeds and moss
[01:33.14]Showing every wandering heart the stepping stones to cross
[01:39.46]Nothing in the dark can harm the light inside your chest
[01:46.66]Lay your head upon the grass and let the world rest
[01:53.62]May the wind be gentle on your weary wings
[01:59.76]May you hear the lullaby the river softly sings
[02:06.30]Close your eyes and drift away where the shadows gleam
[02:13.42]Peace will walk beside you in the valley of a dream
[02:50.86]In the valley of a dream...
[02:56.54]Sleep in peace tonight.</pre>
</figure>
<figure class="subs-track">
<figcaption>Clockwork Starlight <span class="subs-meta">· Japanese healing · 21 lines · 161 s</span><a class="subs-dl" href="/subs/clockwork-starlight.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-4" src="https://content.hoelee.com/file/hoelee/music/Clockwork-Starlight-Mr-Hoelee.mp3"></audio>
<pre id="subs-4" hidden>[ti:Clockwork Starlight]
[ar:Mr Hoelee]
[00:19.30]Ticking in the quiet tower made of porcelain and glass
[00:23.44]I can see the painted clouds and paper swallows pass
[00:32.36]Every gear is turning slow beneath the velvet sky
[00:36.72]Counting all the shooting stars that never say goodbye
[00:46.12]Someone left a silver key beside the windowpane
[00:50.52]Unlocking all the memories hidden in the rain
[00:59.86]Sing for the dawn across the endless night
[01:04.66]Spinning the threads of shadow into light
[01:09.20]Even if the clock should stop and time fades away
[01:13.70]I will keep this little wish until the break of day
[01:22.28]La-la-lu-la, hear the distant bell
[01:31.34]Breaking the silent spell
[01:38.14]Pages of an ancient book are fluttering like wings
[01:42.50]Telling me of emerald seas and forgotten kings
[01:52.16]With my small and trembling hands I open up the door
[01:56.38]Stepping out into a world I've never seen before
[02:05.70]Sing for the dawn across the endless night
[02:10.56]Spinning the threads of shadow into light
[02:15.02]Even if the clock should stop and time fades away
[02:21.12]I will keep this little wish until the break of day
[02:33.64]Until the break of day...</pre>
</figure>
<figure class="subs-track">
<figcaption>Waltz of the Dandelion <span class="subs-meta">· Japanese healing · 18 lines · 180 s</span><a class="subs-dl" href="/subs/waltz-of-the-dandelion.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-5" src="https://content.hoelee.com/file/hoelee/music/Waltz-of-the-Dandelion-Mr-Hoelee.mp3"></audio>
<pre id="subs-5" hidden>[ti:Waltz of the Dandelion]
[ar:Mr Hoelee]
[00:17.62]One, two, three, the summer breeze is knocking at my door
[00:22.56]Dancing with the sunlit dust upon the wooden floor
[00:30.62]Out across the grassy hill the dandelions grow
[00:38.40]Waiting for a little breath to tell them where to go
[00:48.08]La-la-la, wherever you may fly
[00:53.28]Underneath the big and gentle sky
[00:57.28]Even when the seasons change and winter turns to spring
[01:06.06]I will still remember every little song we sing
[01:27.36]Drops of rain upon a leaf are rolling into one
[01:34.62]Shining like a diamond in the afternoon sun
[01:42.46]If you ever lose your way or feel a little sad
[01:50.26]Think about the quiet days and all the smiles we had
[02:00.18]La-la-la, wherever you may fly
[02:05.28]Underneath the big and gentle sky
[02:09.14]Even when the seasons change and winter turns to spring
[02:17.90]I will still remember every little song we sing
[02:25.96]La-la-la, la-la-la...
[02:29.46]See you again someday.</pre>
</figure>
<figure class="subs-track">
<figcaption>Whale in the Milky Way <span class="subs-meta">· Japanese healing · 20 lines · 165 s</span><a class="subs-dl" href="/subs/whale-in-the-milky-way.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-6" src="https://content.hoelee.com/file/hoelee/music/Whale-in-the-Milky-Way-Mr-Hoelee.mp3"></audio>
<pre id="subs-6" hidden>[ti:Whale in the Milky Way]
[ar:Mr Hoelee]
[00:12.10]Ah-ah-ah, ooh-ooh...
[00:15.70]Up above the sleeping town where all the rooftops end
[00:21.86]Swims a giant silver whale that wants to be my friend
[00:27.94]Ripples in the Milky Way are washing on the shore
[00:34.34]Leaving little seashells by my bedroom door
[00:40.98]Can you hear the quiet song echoing in space?
[00:47.28]Every lonely little star has found a hiding place
[00:59.60]Float away, float away, into the velvet blue
[01:06.26]I am sending all my gentle lullabies to you
[01:12.74]Through the clouds of stardust and the galaxies afar
[01:19.59]You are never lost because I see how bright you are
[01:38.82]Paper boats upon the sea of infinite delight
[01:44.56]Carrying our tiny dreams across the quiet night
[01:51.08]Hold my hand and do not fear the deep and silent sky
[01:57.42]We can ride the silver whale and watch the world go by
[02:04.14]Float away, float away, into the velvet blue
[02:10.26]I am sending all my gentle lullabies to you
[02:16.74]Through the clouds of stardust and the galaxies afar
[02:23.52]You are never lost because I see how bright you are
[02:32.74]Goodnight, little star...</pre>
</figure>
<figure class="subs-track">
<figcaption>Puddle Jumping Parade <span class="subs-meta">· Japanese cute · 21 lines · 106 s</span><a class="subs-dl" href="/subs/puddle-jumping-parade.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-7" src="https://content.hoelee.com/file/hoelee/music/Puddle-Jumping-Parade-Mr-Hoelee.mp3"></audio>
<pre id="subs-7" hidden>[ti:Puddle Jumping Parade]
[ar:Mr Hoelee]
[00:06.76]One, two! Ready, go!
[00:08.68]Put on my yellow boots and grab my red umbrella too
[00:12.30]The rain has stopped and left the sky a shiny, happy blue!
[00:16.08]A giant puddle in the street is looking back at me
[00:20.08]I take a giant running leap—one, two, and three!
[00:23.86]Splash! Goes the water, jumping to the sky
[00:27.66]Even little sparrows stop to watch us marching by!
[00:32.66]Hooray, hooray! Join the happy parade!
[00:36.20]Dancing in the sunshine that the morning made!
[00:40.16]Clap your hands together, stomp your little feet
[00:44.44]Every single puddle makes the melody complete!
[00:49.30]La-la-la, step in time, smiling ear to ear!
[00:56.42]A snail upon the garden wall is waving with its horn
[01:00.10]The brightest, biggest rainbow in the neighborhood is born!
[01:03.90]We'll share a pocketful of sweets and sing a silly tune
[01:07.72]And march around the playground till we reach the afternoon!
[01:13.06]Hooray, hooray! Join the happy parade!
[01:16.24]Dancing in the sunshine that the morning made!
[01:20.12]Clap your hands together, stomp your little feet
[01:23.90]Every single puddle makes the melody complete!
[01:29.20]Jump! Splash! Hooray!</pre>
</figure>
<figure class="subs-track">
<figcaption>Strawberry Cloud Bakery <span class="subs-meta">· Japanese cute · 19 lines · 101 s</span><a class="subs-dl" href="/subs/strawberry-cloud-bakery.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-8" src="https://content.hoelee.com/file/hoelee/music/Strawberry-Cloud-Bakery-Mr-Hoelee.mp3"></audio>
<pre id="subs-8" hidden>[ti:Strawberry Cloud Bakery]
[ar:Mr Hoelee]
[00:08.32]Ding-dong rings the little bell above the bakery door
[00:13.48]Flour on the apron and confetti on the floor
[00:16.54]Butter in the mixing bowl and sugar in the pan
[00:20.34]Baking up the fluffiest creations that I can!
[00:24.20]Wait a little minute as the oven starts to glow
[00:29.12]Watch the little loaves of bread begin to rise and grow!
[00:34.04]Welcome to the bakery upon the strawberry cloud!
[00:39.24]Where singing in the kitchen is definitely allowed!
[00:42.76]A croissant for the puppy and a muffin for the cat
[00:46.20]With a dollop of vanilla cream upon a beret hat!
[00:57.82]Pour a cup of warm milk tea and sit beside the window
[01:01.68]Wave hello to everyone walking down below
[01:05.98]If your day is sour like a lemon on a tree
[01:09.78]Take a bite of honey toast and share a smile with me!
[01:13.90]Welcome to the bakery upon the strawberry cloud!
[01:19.26]Where singing in the kitchen is definitely allowed!
[01:22.48]A croissant for the puppy and a muffin for the cat
[01:26.20]With a dollop of vanilla cream upon a beret hat!
[01:33.58]Fresh out of the oven! Yum, yum!</pre>
</figure>
<figure class="subs-track">
<figcaption>Captain Marshmallow <span class="subs-meta">· Japanese cute · 22 lines · 95 s</span><a class="subs-dl" href="/subs/captain-marshmallow.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-9" src="https://content.hoelee.com/file/hoelee/music/Captain-Marshmallow-Mr-Hoelee.mp3"></audio>
<pre id="subs-9" hidden>[ti:Captain Marshmallow]
[ar:Mr Hoelee]
[00:08.06]Attention please! Captain on the deck!
[00:10.64]Sofa is my pirate ship, the carpet is the sea
[00:13.92]Pillow fort is waiting there for teddy bear and me
[00:17.52]Put a paper triangle upon my curly head
[00:20.96]No one has to take a nap or go to sleep in bed!
[00:25.68]Left turn! Right turn! Watch out for the shark!
[00:31.08]Wait—that's just the fluffy dog barking in the dark!
[00:36.78]Aye, aye, Captain Marshmallow!
[00:38.42]Sailing where the candy breezes blow!
[00:42.04]Cookies in the treasure chest, chocolate on the map
[00:45.56]Give a little salute and a double-double clap! (Clap-clap!)
[00:50.74]We rule the living room today!
[00:56.34]Homework is forbidden by the royal pirate law
[00:59.60]Every single citizen must draw a dinosaur!
[01:03.12]More pudding for the afternoon, and juice inside the cup
[01:07.28]When the clock strikes dinner time, we'll eat the treasure up!
[01:13.80]Aye, aye, Captain Marshmallow!
[01:15.28]Sailing where the candy breezes blow!
[01:19.00]Cookies in the treasure chest, chocolate on the map
[01:22.46]Give a little salute and a double-double clap! (Clap-clap!)
[01:26.82]We rule the living room today!
[01:33.00]Mission accomplished! Yay!</pre>
</figure>
<figure class="subs-track">
<figcaption>Lanterns on the Lotus Pond <span class="subs-meta">· Guofeng fusion · 19 lines · 132 s</span><a class="subs-dl" href="/subs/lanterns-on-the-lotus-pond.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-10" src="https://content.hoelee.com/file/hoelee/music/Lanterns-on-the-Lotus-Pond-Mr-Hoelee.mp3"></audio>
<pre id="subs-10" hidden>[ti:Lanterns on the Lotus Pond]
[ar:Mr Hoelee]
[00:10.69]Patter goes the summer rain upon the lotus leaf
[00:15.29]Washing all the dusty world and bringing cool relief
[00:19.89]Stepping on the wet bluestone beside the willow bridge
[00:24.49]Dragonflies are resting on the painted wooden ridge
[00:28.58]Fold a little paper boat and light a candlewick
[00:33.16]Make a wish before the current carries it so quick
[00:40.46]Floating down the lotus pond, a hundred lanterns glow
[00:46.38]Mirrored in the ripples where the silver fishes go
[00:49.62]Listen to the bamboo flute across the misty stream
[00:54.22]In the courtyard of the moon, we share a summer dream
[01:03.96]Silk fan in my little hand to chase the fireflies
[01:08.72]Red string braided in my hair beneath the lantern skies
[01:13.36]Grandma tells a fairy tale of rabbits in the moon
[01:18.22]While the sweet osmanthus flowers blossom in the June
[01:25.54]Floating down the lotus pond, a hundred lanterns glow
[01:30.02]Mirrored in the ripples where the silver fishes go
[01:34.62]Listen to the bamboo flute across the misty stream
[01:39.36]In the courtyard of the moon, we share a summer dream
[02:06.76]Red lanterns drifting far away...</pre>
</figure>
<figure class="subs-track">
<figcaption>Wings of the Kunpeng <span class="subs-meta">· Guofeng fusion · 19 lines · 214 s</span><a class="subs-dl" href="/subs/wings-of-the-kunpeng.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-11" src="https://content.hoelee.com/file/hoelee/music/Wings-of-the-Kunpeng-Mr-Hoelee.mp3"></audio>
<pre id="subs-11" hidden>[ti:Wings of the Kunpeng]
[ar:Mr Hoelee]
[00:25.18]Deep beneath the silent waves where no one ever sees
[00:31.60]Sleeps a tiny silver fish dreaming of the breeze
[00:38.16]Counting every falling tear that drops into the tide
[00:44.50]Waiting for the heavy gates of heaven to divide
[00:51.16]Do not fear the rising storm or shadows in the deep
[00:57.24]There is still a ancient promise that the ocean keeps
[01:06.34]Spread your wings and rise above the sea of clouds and rain
[01:13.18]Never let the mortal world bind you with a chain
[01:19.74]Fly across the mountain peaks where immortal rivers flow
[01:25.96]I will watch you turn to wind and let your spirit go
[01:49.10]Cycles of a thousand years are written in the stars
[01:54.96]Time will heal the broken shells and wash away the scars
[02:01.32]When the red camellia blooms upon the snowy shore
[02:07.58]We will meet beyond the sky and part ways nevermore
[02:16.86]Spread your wings and rise above the sea of clouds and rain
[02:23.52]Never let the mortal world bind you with a chain
[02:30.18]Fly across the mountain peaks where immortal rivers flow
[02:36.26]I will watch you turn to wind and let your spirit go
[02:48.84]Ah-ah-ah, fly into the wind...</pre>
</figure>
<figure class="subs-track">
<figcaption>The Puppeteer's Thread <span class="subs-meta">· Guofeng fusion · 19 lines · 222 s</span><a class="subs-dl" href="/subs/the-puppeteer-s-thread.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-12" src="https://content.hoelee.com/file/hoelee/music/The-Puppeteers-Thread-Mr-Hoelee.mp3"></audio>
<pre id="subs-12" hidden>[ti:The Puppeteer's Thread]
[ar:Mr Hoelee]
[00:24.12]Carved from a willow branch, painted with a smile
[00:34.16]Dressed in tiny embroidered silk, traveling mile by mile
[00:46.00]Ten thin threads of crimson silk tied upon my hands
[00:55.50]Dancing in the market square across the distant lands
[01:07.80]Crowds will gather when the gong begins to softly ring
[01:13.12]Laughing at the little doll that cannot speak or sing
[01:21.66]Dance in the lantern light, spin around the stage
[01:26.70]Telling all the legends of a long-forgotten age
[01:32.42]Though my heart is made of wood and cannot feel the rain
[01:37.66]Every pull upon the thread remembers joy and pain
[02:10.68]Autumn leaves are falling down upon the empty street
[02:15.82]Only echoes remain of the applause so sweet
[02:21.36]Keep me in the wooden box beside your warm fireplace
[02:26.98]Even when the paint fades off my little smiling face
[02:36.74]Dance in the lantern light, spin around the stage
[02:42.86]Telling all the legends of a long-forgotten age
[02:48.56]Though my heart is made of wood and cannot feel the rain
[02:54.02]Every pull upon the thread remembers joy and pain
[03:05.04]Ten thin threads of crimson silk...</pre>
</figure>
<figure class="subs-track">
<figcaption>Paper Airplane in September <span class="subs-meta">· Acoustic folk · 18 lines · 129 s</span><a class="subs-dl" href="/subs/paper-airplane-in-september.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-13" src="https://content.hoelee.com/file/hoelee/music/Paper-Airplane-in-September-Mr-Hoelee.mp3"></audio>
<pre id="subs-13" hidden>[ti:Paper Airplane in September]
[ar:Mr Hoelee]
[00:10.42]Sunlight on the wooden desk is moving inch by inch
[00:15.10]Sparrows on the telegraph wire never seem to flinch
[00:20.88]I fold a page of notebook paper creases nice and neat
[00:25.60]And throw it out the window to the quiet autumn street
[00:30.88]Fly away, paper plane, into the golden air
[00:36.36]Carry all the little words I didn't dare to share
[00:41.64]Goodbye to the summer clouds, hello to the breeze
[00:48.72]Floating past the bicycles and underneath the trees
[01:03.30]Chalk dust on the blackboard fades as afternoon goes by
[01:08.38]Clouds like cotton candy drift across the September sky
[01:13.76]Every simple little thing we took for granted then
[01:18.90]Stays inside a photograph we'll look at once again
[01:24.30]Fly away, paper plane, into the golden air
[01:29.66]Carry all the little words I didn't dare to share
[01:34.90]Goodbye to the summer clouds, hello to the breeze
[01:41.68]Floating past the bicycles and underneath the trees
[01:57.78]Underneath the autumn trees...
[02:02.18]Goodbye, summer days.</pre>
</figure>
<figure class="subs-track">
<figcaption>Porridge and Evening Smoke <span class="subs-meta">· Acoustic folk · 17 lines · 144 s</span><a class="subs-dl" href="/subs/porridge-and-evening-smoke.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-14" src="https://content.hoelee.com/file/hoelee/music/Porridge-and-Evening-Smoke-Mr-Hoelee.mp3"></audio>
<pre id="subs-14" hidden>[ti:Porridge and Evening Smoke]
[ar:Mr Hoelee]
[00:11.54]Smoke is rising from the roof into the purple sky
[00:17.04]While the evening swallows call and hurry on up high
[00:22.84]Steam upon the kitchen glass is blurring out the view
[00:28.48]Sitting on a wooden stool, I wait for dinner too
[00:34.02]One bowl of warm white rice, a dish of tender greens
[00:39.52]The simplest kind of happiness is what the evening means
[00:45.42]No matter how the outside world is noisy, cold, and wide
[00:50.98]The lamp upon the dining table keeps us warm inside
[01:09.84]Wrinkles on a gentle hand that smooths my messy hair
[01:14.88]Telling me to eat it all and sit up in my chair
[01:20.48]Years will pass like river water flowing to the sea
[01:26.26]But this quiet kitchen light will always stay with me
[01:33.04]One bowl of warm white rice, a dish of tender greens
[01:38.76]The simplest kind of happiness is what the evening means
[01:44.60]No matter how the outside world is noisy, cold, and wide
[01:50.14]The lamp upon the dining table keeps us warm inside
[01:57.40]The lamp is always on for you...</pre>
</figure>
<figure class="subs-track">
<figcaption>Green Train to the Sea <span class="subs-meta">· Acoustic folk · 17 lines · 109 s</span><a class="subs-dl" href="/subs/green-train-to-the-sea.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-15" src="https://content.hoelee.com/file/hoelee/music/Green-Train-to-the-Sea-Mr-Hoelee.mp3"></audio>
<pre id="subs-15" hidden>[ti:Green Train to the Sea]
[ar:Mr Hoelee]
[00:28.22]Clickety-clack upon the track, the green train starts to roll
[00:29.42]Leaving all the city gray behind the tunnel hole
[00:30.62]Forehead pressed against the glass, I watch the fields go by
[00:31.82]Golden wheat and windmills waving underneath the sky
[00:33.02]Take me where the spring wind blows across the open blue
[00:34.22]Ten miles of wildflowers blooming just for me and you
[00:38.36]Every station has a name I've never heard before
[00:42.68]Soon the scent of salty air will meet us at the shore
[00:57.62]Strangers sharing oranges and stories in the seat
[01:01.92]Sunlight dancing in the aisle around my dangling feet
[01:06.68]Postcards in my backpack waiting for a stamp and pen
[01:11.50]To tell the people back at home I'm coming back again
[01:16.24]Take me where the spring wind blows across the open blue
[01:21.14]Ten miles of wildflowers blooming just for me and you
[01:26.34]Every station has a name I've never heard before
[01:30.66]Soon the scent of salty air will meet us at the shore
[01:46.82]Look, there is the sea...</pre>
</figure>
<figure class="subs-track">
<figcaption>Sanctuary of the Dawn <span class="subs-meta">· Choral · 19 lines · 183 s</span><a class="subs-dl" href="/subs/sanctuary-of-the-dawn.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-16" src="https://content.hoelee.com/file/hoelee/music/Sanctuary-of-the-Dawn-Mr-Hoelee.mp3"></audio>
<pre id="subs-16" hidden>[ti:Sanctuary of the Dawn]
[ar:Mr Hoelee]
[00:22.82]Ahh-ahh, sanctus, ahh...
[00:25.64]Shadows fade before the light that rises in the east
[00:31.74]Every troubled storm is stilled and every sorrow ceased
[00:37.76]Through the tall stained-glass windows morning beams descend
[00:44.12]Shining on a quiet road where broken hearts can mend
[00:50.56]Peace be with you, weary soul, lay your burden down
[00:58.74]Where the silver rivers flow beyond the sleeping town
[01:05.08]Lift your eyes unto the hills where golden angels sing
[01:11.46]Rest beneath the gentle shelter of a shining wing
[01:21.16]Like a bell across the valley ringing clear and true
[01:27.18]Every dawn is bringing back a promise made anew
[01:34.18]Walk into the quiet light and leave the dark behind
[01:40.06]There is grace in every breath for all of humankind
[01:48.40]Peace be with you, weary soul, lay your burden down
[01:54.64]Where the silver rivers flow beyond the sleeping town
[02:01.02]Lift your eyes unto the hills where golden angels sing
[02:07.48]Rest beneath the gentle shelter of a shining wing
[02:15.30]Peace be with you... forevermore.
[02:26.48]Amen, ahh...</pre>
</figure>
<figure class="subs-track">
<figcaption>Look Upon Your Path <span class="subs-meta">· Choral · 17 lines · 122 s</span><a class="subs-dl" href="/subs/look-upon-your-path.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-17" src="https://content.hoelee.com/file/hoelee/music/Look-Upon-Your-Path-Mr-Hoelee.mp3"></audio>
<pre id="subs-17" hidden>[ti:Look Upon Your Path]
[ar:Mr Hoelee]
[00:09.64]Look upon the winding path where fallen leaves are blown
[00:14.64]Children walking hand in hand so no one is alone
[00:19.64]Even when the winter wind is cold against your face
[00:25.04]Every step you take today is leading to a place
[00:31.52]Shine your light into the dark, let your voice be heard
[00:36.60]Rising like the morning lark, a brave and little bird
[00:41.60]Though the night is long and deep, the stars are watching still
[00:46.68]Spring will wake the seeds asleep upon the quiet hill
[00:57.00]Write a song upon the wind for everyone who strays
[01:02.16]Hope is like a tiny spark that sets the sky ablaze
[01:07.48]Hold the hand beside you tight and never look below
[01:11.88]There are gardens waiting where the wildest rivers flow
[01:21.30]Shine your light into the dark, let your voice be heard
[01:26.36]Rising like the morning lark, a brave and little bird
[01:31.34]Though the night is long and deep, the stars are watching still
[01:36.44]Spring will wake the seeds asleep upon the quiet hill
[01:45.98]Look upon your path... the dawn is near.</pre>
</figure>
<figure class="subs-track">
<figcaption>Bells of the Winter Star <span class="subs-meta">· Choral · 18 lines · 178 s</span><a class="subs-dl" href="/subs/bells-of-the-winter-star.srt" download>.srt</a></figcaption>
<audio controls preload="metadata" oncontextmenu="return false;" controlslist="nodownload" data-lrc="subs-18" src="https://content.hoelee.com/file/hoelee/music/Bells-of-the-Winter-Star-Mr-Hoelee.mp3"></audio>
<pre id="subs-18" hidden>[ti:Bells of the Winter Star]
[ar:Mr Hoelee]
[00:08.50]Ding-dong, ding-dong, ring out the bells...
[00:18.20]Snowflakes falling from the sky in silence pure and white
[00:25.44]Dressing every cedar bough in robes of silver light
[00:34.56]Listen to the steeple bells across the frozen square
[00:43.42]Sending out a melody upon the midnight air
[00:52.92]Ring, silver bells, across the winter snow
[01:01.30]Tell all the world the star has begun to glow
[01:11.76]Gloria, gloria, hear the angels sing
[01:19.28]Peace on the earth this holy night will bring
[01:32.12]Candles in the frosted glass are shining warm and clear
[01:40.42]Guiding every traveler home at the end of year
[01:49.68]Every chime is like a prayer ascending to the sky
[01:58.26]Watched by all the quiet stars that never pass us by
[02:09.62]Ring, silver bells, across the winter snow
[02:18.22]Tell all the world the star has begun to glow
[02:28.00]Gloria, gloria, hear the angels sing
[02:37.14]Peace on the earth this holy night will bring
[02:49.30]Gloria... peace on the earth.</pre>
</figure>
<script>
// subs-track: scroll LRC in step with <audio>; current line stays centred
document.querySelectorAll('audio[data-lrc]').forEach((audio) => {
const raw = document.getElementById(audio.dataset.lrc).textContent;
const lines = raw.split('\n').map((l) => {
const m = l.match(/\[(\d+):(\d+)(?:\.(\d+))?\](.*)/);
return m ? { t: +m[1] * 60 + +m[2] + (+(m[3] || '0')) / 100, txt: m[4] } : null;
}).filter(Boolean);
const box = document.createElement('div');
box.className = 'subs-box';
lines.forEach((l) => { const p = document.createElement('p'); p.textContent = l.txt; box.appendChild(p); });
audio.parentNode.insertBefore(box, audio.nextSibling);
let cur = -1;
audio.addEventListener('timeupdate', () => {
const now = audio.currentTime;
// last line whose timestamp has passed; -1 before the first line starts
let i = -1;
for (let k = 0; k < lines.length; k++) { if (lines[k].t <= now) i = k; else break; }
if (i !== cur) {
if (cur >= 0) box.children[cur].classList.remove('on');
cur = i;
if (cur >= 0) {
const p = box.children[cur];
p.classList.add('on');
const br = box.getBoundingClientRect(), pr = p.getBoundingClientRect();
box.scrollTop += (pr.top - br.top) - (box.clientHeight - pr.height) / 2;
} else {
box.scrollTop = 0;
}
}
});
});
</script>