📌 Part of Blueprint: AI Agent & Local GPU Automation → L4: Automated AIGC & Media Pipelines

Why My AI Songs Kept Losing Their Endings: Running YuE2 on a 12 GB GPU

· 32 min read · AI yue2comfyuiai-musiclocal-aigpuvrammandarin

YuE2 is a 3B open-weights music model that sings Mandarin from a style prompt and a lyric sheet. I ran it locally on a 12 GB RTX 3060 through ComfyUI — twelve original songs in one serial queue — and the first batch came back with every single file exactly 240.000 seconds long. That number is not a coincidence, and it is not good news.

Every track was exactly 240.000 seconds

Twelve files, twelve identical durations to the millisecond:

01_A1_..._糖画小仙.mp3   duration=240.000000
02_A2_..._溪边捉云记.mp3  duration=240.000000
03_A3_..._寒露拾桂子.mp3  duration=240.000000
...

I had asked for max_duration=240 because the style guide I was working from said a 12-section structure would land around three and a half minutes. It landed on 240 seconds exactly — which means the model never decided to stop. It ran out of room.

A round number is a confession

YuE2 plans a song with an ABC planner: it reads the lyric sheet, decides how many bars each section gets, and emits a symbolic sketch. The music generator then sings that sketch and ends when the sketch ends. A finished song therefore comes out shorter than the cap you set — it stops on its own.

Here is the tell, and it costs one shell command:

d=$(ffprobe -v error -show_entries format=duration -of csv=p=0 take.mp3)
python -c "print(abs(float('$d') - 240.0) <= 0.005)"   # True = hard cut

If the duration equals max_duration to within a few milliseconds, the render was truncated. The lyric sheet wanted more time than the cap allowed, and the last thing being sung at the cutoff point got sliced off mid-phrase.

Confirming the outros were actually missing

Duration alone tells you that it was cut, not what was lost. So I pulled the tail of each take and transcribed it with a local speech model (SenseVoice, CPU — it stays running while the GPU renders):

ffmpeg -v error -y -i take.mp3 -ss 232 -t 20 -ar 16000 -ac 1 -c:a pcm_s16le t.wav
curl -s -X POST http://127.0.0.1:20129/v1/audio/transcriptions \
  -F "[email protected]" -F "language=zh"

(For tracks that had not even reached the final chorus, I widened the slice window back to the final 30 seconds with -ss 210 to locate the active section when truncation hit.) The results were unambiguous:

SongSung up toWhat was missing
糖画小仙final chorus, last linethe entire [Outro]
溪边捉云记[Bridge] at 215 ssolo + final chorus + outro
寒露拾桂子[Bridge] at 215 sfinal chorus + outro
纸鸢与旧木偶final chorus, line 5rest of chorus + outro

So: not a mixing artefact, not a fade-out. The songs were structurally incomplete.

Three fixes that did nothing, and one that half-worked

1. Raising the BPM — no effect

The obvious reasoning: faster tempo, more syllables per second, more lyrics fit in the same window. I tested this across the batch: the 117 BPM guofeng tracks and the 140 BPM DJ remixes had effectively identical throughput.

YuE2’s duration comes from the ABC planner’s bar count, not from the BPM token in your style prompt. The BPM tag shapes the feel; it does not buy you room. Stop tuning it for duration.

2. Re-running with the same seed — silently does nothing

ComfyUI was started with --cache-classic, so resubmitting a byte-identical prompt — same style, same lyrics, same seed — hits the node cache. The job “completes” in about ten seconds and hands you back the same truncated audio with a _00002 filename.

It looks like a fast, successful retry. It is a cache hit on a known-bad take.

3. Rolling new seeds — works about 3 times out of 4

The planner’s bar allocation depends on the seed, so a different seed really can produce a shorter, complete song from the same lyrics. This rescued three of my four clipped tracks:

SongOriginalNew seedResult
溪边捉云记clipped at 281 s20002279.7 s, complete
外婆的绿搪瓷碗clipped at 300 s20007251.9 s, complete
北溟有小鱼clipped at 300 s20005, 30005clipped again

The budget is characters per second — and it isn’t constant

I tried to turn this into arithmetic: count the Chinese characters, divide by a throughput figure, get the duration. The measurements refused to cooperate.

SongCharactersCapActualFits?
糖画小仙556272 s258.7 s✅
纸鸢与旧木偶572300 s279.9 s✅
溪边捉云记578281 s281.0 s❌ cut
小楼檐下听雨眠580300 s256.3 s✅
画卷小锦鲤634300 s285.9 s✅
三楼窗台的蒲公英693329 s247.4 s✅
弄堂口的竹蜻蜓692300 s250.0 s✅

Read the last two rows against the third. 693 characters finished in 247 seconds, while 578 characters overflowed 281 seconds. A lyrics-to-duration formula simply does not exist here — the observed throughput ranges from about 2.0 to 2.8 Chinese characters per second, depending on how the planner chops the sections.

So characters are useful for a budget warning, not for setting a timer.

The limit that actually binds: VRAM

Once you accept “give it enough room and let it close naturally”, the cap wants to be large. On a 12 GB card it cannot be.

Measured peak VRAM while rendering, sampled every five seconds with nvidia-smi during the run:

max_durationPeak VRAM
240 s10.3 GB
272 s11.65 GB
278 s11.07 GB
281 s12.06 GB
300 s12.03 GB

The card has 12,288 MiB (12 GB) of VRAM. 300 seconds is the practical ceiling — past that you are one desktop browser tab away from an out-of-memory abort in the middle of a six-minute render.

The fix

Three changes, all cheap:

  1. Set the cap to 300 s and let the planner close the song itself. Do not chase a target length; give it headroom and it ends where the music ends.
  2. Archive clipped takes instead of mixing them in. A take whose duration equals the cap goes to 未自然结尾\ (“did not end naturally”). The output folder then contains only complete songs, and re-renders never destroy a usable take.
  3. Cap the seed roulette at three attempts. Different seeds help, but a song whose lyrics genuinely need more than the VRAM ceiling allows will fail forever. Three strikes and you trim the lyric sheet — don’t burn an hour of GPU pretending the next seed will be the one.

The song that never fit

One of the twelve never made it. 北溟有小鱼 — 593 characters — failed five times:

AttemptParametersResult
1seed 10005, cap 287 shit 287 s
2seed 10005, cap 300 shit 300 s
3seed 20005, cap 300 shit 300 s
4seed 30005, cap 300 shit 300 s
5seed 40005, both instrumental sections removedhit 300 s

I even deleted the [Interlude] and [Instrumental Solo] markers — 12 sections down to 10, not one sung word changed — and it still overflowed. Its planner wants more time than a 12 GB card can give. The honest fix is to cut about 40 characters of lyric and re-render, and I would rather tell you that than ship a twelfth track with a bitten-off ending.

A trap I hit before any of this

Worth its own warning: YuE2 will sing the Chinese production notes in your lyric sheet.

If you paste lyrics that look like this — which is how most lyric sheets are written —

[Intro]
(重鼓点起,急促琵琶轮指,唢呐破空,合成器铺底)
嘿!哈!山海震!

…then that parenthetical line becomes a lyric. The model does not know it is a stage direction. Strip them before submitting:

clean = "\n".join(l for l in raw.split("\n")
                  if not re.match(r"^\s*[((].*[))]\s*$", l))

Arrangement and dynamics belong in the style prompt. The lyric box gets section tags and sung words, nothing else.

What I’d do differently

Eleven tracks

These are the ones that closed naturally, sung by a child voice, in Mandarin, on a 12 GB card that cost less than a year of cloud music credits. Each player below has synced lyrics — the timing was recovered by transcription and aligned against the written lyrics, since the model emits no timestamps.

1. 糖画小仙 — Sugar-Painting Fairy

Guofeng electronic · 556 characters · 259 s

2. 溪边捉云记 — Catching Clouds by the Stream

Guofeng electronic · 578 characters · 280 s

3. 寒露拾桂子 — Picking Osmanthus at Cold Dew

Guofeng electronic · 578 characters · 290 s

4. 纸鸢与旧木偶 — The Kite and the Old Puppet

Guofeng ballad · 572 characters · 280 s

5. 小楼檐下听雨眠 — Listening to Rain Under the Eaves

Guofeng ballad · 580 characters · 256 s

6. 外婆的绿搪瓷碗 — Grandma’s Green Enamel Bowl

Urban folk · 679 characters · 252 s

7. 弄堂口的竹蜻蜓 — The Bamboo Dragonfly at the Alley Mouth

Urban folk · 692 characters · 250 s

8. 三楼窗台的蒲公英 — Dandelion on the Third-Floor Windowsill

Urban folk · 693 characters · 247 s

9. 小哪吒借红绫 — Little Nezha Borrows the Red Sash

Guofeng DJ remix · 612 characters · 271 s

10. 画卷小锦鲤 — The Koi That Left the Painting

Guofeng DJ remix · 634 characters · 286 s

11. 山海小当家 — Little Boss of the Classic of Mountains and Seas

Guofeng DJ remix · 647 characters · 237 s

🚀 Automation & Custom AI Systems

Want a 24/7 bot or automation pipeline that never drops a lead?

Don't let customer inquiries slip away at midnight or on weekends. I build custom Telegram/WhatsApp AI assistants and deterministic workflows that connect directly to your catalogue, CRM, and order fulfillment.

Lee Teong Hoe

Lee Teong Hoe · Mr Hoelee

Full-stack developer & DevOps engineer based in Malaysia. I run my own production infrastructure and build web systems for small businesses — this blog is the living record.

Hiring? Profile & stack · Malaysian SME? Website design & development ↗ · All posts