AI/ML

Local AI Music on an RTX 3090: ACE-Step 1.5 vs LeVo 2, Measured — and the Pitfalls Nobody Mentions

ACE-Step 1.5 (MIT) made a 36-second track in about 32 s on an RTX 3090; LeVo 2 took 414 s for four songs and is research-only. The agent couldn't hear, so every check was a number. Ten pitfalls, measured.

·26 min read
#ACE-Step#LeVo 2#SongGeneration#Stable Audio 3#AI music#RTX 3090#licensing#audio analysis#ffmpeg

TL;DR: I wanted background music for short videos and a small game, made locally and usable commercially. Over two days on one RTX 3090, an AI coding agent (Claude Code) installed and ran three open audio models:

  • ACE-Step 1.5 (MIT): an instrumental track of 36–46 s took 31–33 s at 50 steps and CFG 7, using 13.0–13.4 GB of VRAM. This is the one I can actually use.
  • LeVo 2 (Tencent SongGeneration v2-large): 414 s for four songs with the fastest setup that worked. I thought it sounded a bit better, but its license allows academic, research and education use only.
  • Stable Audio 3 Small-SFX (code MIT, model under Stability's community license): about 3 s per sound effect.

The agent can't listen to audio. So every quality check it ran was a measurement: loudness, a 0.1-second loudness curve, silence detection, left/right phase, spectrograms. Those checks caught real problems: ACE-Step padding the end of a track with silence and cutting the music off, and one track that lost 9.3 dB when played on a single speaker. They did not catch the main one. I listened to the first 21 tracks and all of them were meh. That verdict, not a number, is what changed the settings.

The three models, as measured on this machine

The setup

GPURTX 3090 24 GB (shared with other jobs on the same machine)
OSWindows 11; LeVo 2 ran inside WSL Ubuntu
MusicACE-Step 1.5: DiT acestep-v15-xl-sft (4B) and acestep-v15-turbo (2B), planner LM acestep-5Hz-lm-1.7B, CPU offload on
Songs with vocalsLeVo 2 (songgeneration_v2_large), via a community fork (details below)
Sound effectsStable Audio 3 Small-SFX
Checksffmpeg (ebur128, silencedetect, volumedetect, showspectrumpic), Python with numpy + soundfile

Who did what

My callsDone by the AI agent
"Can we make music too?" Then: local, good quality, personal test firstShortlisted models, installed ACE-Step, LeVo 2 and Stable Audio 3
Pick the next experiments: more genres, a LeVo 2 comparison, sound effectsRan every generation, timed it, recorded VRAM
"LeVo 2 seems a bit better." Then: try to speed it upInstalled flash-attention, found the real bottleneck, measured full-memory mode
The rule for anything I publish or sell: commercially usable models only. And the question that exposed a gap: "LeVo 2 can be used commercially, right?"Read the license files on disk after that question; corrected its own earlier "commercial-grade" wording about LeVo 2
Listening. Batches 1–2: "all meh: too bland, a bit cheap-sounding"Ran the "find a direction" and "prescription" batches designed from that verdict (by a planning agent, below); found the shift default and added the phase check
Picking what works (three tracks) and cutting one I'd picked at firstMeasured every track, built the phase check into generation

The work orders for the background-music batches, including the direction search, the eight directions, the banned words and the 80-to-30-second cut, were written by a planning agent in my setup, from my verdicts. Claude Code on the 3090 executed them. Every number in this post comes from those runs' logs and metadata files, or from re-running the scripts below on the same files.

Licensing, read from the files

My standing rule: if I can't use it commercially, it doesn't go into anything I publish. But I started this as a personal test and asked for whatever performed well, so the licences were read after the first generations, not before. LeVo 2 was installed, run and rated before anyone opened its license file; my question "LeVo 2 can be used commercially, right?" is what sent the agent to read it. When it did, it read the license files that came with each install, not the marketing pages. (The Stability revenue threshold below is from Stability's license page; no model license file was on disk.)

  • ACE-Step 1.5: the repo's LICENSE is MIT, and the checkpoint cards say license: mit. The card states the generated music can be used commercially.
  • LeVo 2 / SongGeneration: the bundled license grants use "only for academic, research and education purposes", and you must "refrain from using it for any commercial or production purposes under any circumstances". The v2-large model card says license: unknown.
  • Stable Audio 3 Small-SFX: the code repo's LICENSE is MIT. The README sends you to the Stability AI Community License for the model: free, including commercial use, for individuals and organisations with under US$1M in annual revenue; above that you need an enterprise license. The model itself is gated on Hugging Face, so you need an account and a token.
  • MusicGen (not installed, so no file to read): its weights are non-commercial according to its model card online, which ruled it out early.

One correction on the record: when the agent first shortlisted LeVo 2, it called it "commercial-grade". It meant quality, but that's not how it reads. After my question it read the license file and corrected this. That's why no LeVo 2 audio appears in this post. The comparison is in words and numbers only.

None of this is legal advice. Read the licenses yourself.

Speed and memory on the 3090

SettingAudio lengthTimePeak VRAM
ACE-Step XL-sft50 steps, shift 3, CFG 736 s31.3–33.4 s per track13.0–13.2 GB
ACE-Step XL-sft100 steps36 s41.1 s13.2 GB
ACE-Step XL-sft50 steps80 s35.4–36.4 s (one batch), 54.9–63.2 s (another)13.1–13.4 GB
ACE-Step XL-sft50 steps156 s98.2 s13.3 GB
ACE-Step turbo8 / 20 steps, shift 336 s24.8 / 23.6 s8.1 / 8.3 GB
ACE-Step, loadcached / first run incl. download22–38 s / 309 s
LeVo 2default (low-memory mode)4 songs, 41–81 s each433 snot measured
LeVo 2+ flash-attention 2.7.4same 4 songs414 snot measured
LeVo 2forced full-memory mode1 song / 4 songs195 s / 2,451 s24,303 of 24,576 MiB (99% of the card)
Stable Audio 3 SFX1–10 s clips2.9–4.3 s per clip; load 52 snot measured

ACE-Step VRAM is PyTorch's peak reserved memory for the process, with CPU offload on. The LeVo 2 figure is nvidia-smi for the whole card. LeVo 2 times include its model load, which I don't have separately. I can't explain the 36 s vs 56 s gap between the two 80-second batches. Settings were identical, and the slower one may have shared the GPU.

Per second of music is fairer than per song. LeVo 2's default run made 249.7 s of audio in 433 s, about 1.7 s of compute per second of music, including its model load. ACE-Step XL-sft at 50 steps made 36 s tracks in about 32 s, about 0.9 s per second of music, excluding load.

What I heard: LeVo 2 vs ACE-Step

Same four lyric sheets (three Korean, one English rock song) through both models. I said "LeVo 2 seems a bit better."

The agent pointed out two things that make that judgment shaky, and both are measurable:

Same lyricsLeVo 2 length / mean volume / peakACE-Step length / mean volume / peak
Children's song (Korean)47.6 s / −14.6 dB / 0.0 dBFS40.0 s / −15.5 dB / −1.4 dBFS
Ballad (Korean)80.9 s / −12.5 dB / 0.0 dBFS45.0 s / −19.9 dB / −2.0 dBFS
Dance pop (Korean)79.8 s / −13.6 dB / 0.0 dBFS40.0 s / −18.2 dB / −1.6 dBFS
Rock (English)41.4 s / −14.1 dB / 0.0 dBFS40.0 s / −16.4 dB / −1.3 dBFS

LeVo 2 was louder in all four pairs, by 0.9 to 7.4 dB, and it wrote longer arrangements with interludes and repeats. Louder usually sounds better. The agent offered a blind, loudness-matched A/B test. I skipped it and asked for the speed test instead, so my "a bit better" is an unblinded opinion on four songs. (The ACE-Step side of this test also ran at only 8 steps; see pitfall 2.) Korean isn't on LeVo 2's official language list (zh, en, es, ja, etc.). ACE-Step's docs list Korean among 50+ languages. I didn't rate pronunciation for either.

Since LeVo 2 is research-only, the comparison stopped there. Everything below is ACE-Step.

The pitfalls (each one measured)

1. ACE-Step pads the end with silence and cuts the music off

The first background-music batch asked for 42-second tracks with ACE-Step's built-in 3-second fade-out. The model stopped the music 3.9–8.3 s early and filled the rest with silence. In four of six tracks the music stopped dead, still at −18 to −28 dB, right before the silence. The built-in fade landed on the silent tail, where it did nothing. One track had only 33.7 s of actual music.

Loudness over time for one track, before and after the fix

Asking for a longer track doesn't fix it. At 46 s the silent tails were still 1.4–7.2 s, and three or four of six still ended abruptly (one is borderline).

Fix: generate 4–6 s longer than you need. Then find the last 0.1 s window louder than −45 dBFS, put a 3-second fade before that point, and keep 0.4 s of silence. The script is below.

2. The default step count is for the turbo model

GenerationParams defaults to inference_steps=8, which is the turbo setting. The very first test ran the 4B XL-sft model at those 8 steps by accident. My first report from that test said ACE-Step took "about 12 s per song" and was about 9× faster than LeVo 2; both figures were at 8 steps, so neither is in this post's tables. The code's own docstring gives 32–100 steps for the base model. All later batches used 50 steps.

3. shift 1.0 is the default; the docs' best-quality setting is 3.0

Batches 1–2 used the default shift=1.0. The inference guide's "For Best Quality" list says shift=3.0, along with at least 64 steps, use_adg=True and guidance 7.0–9.0. We changed only shift (steps stayed at 50, ADG stayed off), so this is not the guide's full best-quality setting. Batch 3 compared them on one prompt. The numbers differ (shift 1: −13.9 LUFS, loudness range 8.1 LU, the last 10 s sinking to −25 dB; shift 3: −11.8 LUFS, with a new high layer coming in at 23 s). But see the next pitfall: they aren't the same song. More steps weren't better either: 100 steps took 41 s instead of 33 s and came out flatter (loudness range 1.0 LU, the same texture start to finish).

4. The same seed doesn't give the same song

Five checkpoint-comparison tracks with seed 3303 came out in five different keys, as reported by the planner LM: G minor, F♯ major, C♯ minor, F minor and G♯ minor. A sixth run with exactly the settings of one of them came out in B♭ major. The seed fixes the diffusion part, but the planner LM's sampling (temperature 0.85) still varies. So any A/B of settings mixes "different setting" with "different song". Compare several seeds per setting, or fix the LM's audio codes, before you believe a setting comparison.

5. Some seeds come out strongly out of phase between left and right

One batch-3 track (a gentle cinematic piece, seed 3303) had a left/right correlation of −0.86. Summed to mono, which is what a single-speaker device, a mono Bluetooth speaker or a phone's mono accessibility mode does, it lost 9.3 dB. The same prompt with seed 4404 measured +0.17 and −2.3 dB.

L/R correlation over time for two seeds of the same prompt

It isn't rare. Re-measuring the 21 tracks from batches 1–2 found 5 of 21 losing more than 3 dB in mono. In batch 4 the check ran inside generation and re-rolled the seed on a fail: 4 of 8 first seeds failed (−5.6, −5.3, −3.2 and −3.1 dB). An extra take of B1 with the LM rewriting the caption needed two re-rolls. In batch 5, 0 of 9 failed.

Mono-sum loss for all 21 batch 1–2 tracks

Fix: measure the mono loss on every track (script below), and re-roll anything worse than −3 dB.

6. A fixed BPM overrides "slowing down"

A comic "deflating" cue asked for a slowing tempo, with BPM set to 90. The agent measured the beat interval from onsets: 0.66–0.67 s (90 BPM) from 0 to 21 s, with no slowdown. Without a BPM and with "ritardando, tempo gradually slows down" up front, one take's intervals went 0.33 → 0.64 → 1.30 s. Whether that is a real slowdown or just sparser rhythm can't be told from the numbers. If you set BPM, the model holds it.

7. "It gets louder" isn't the same as "it builds"

For a build-up cue, the first idea was to compare the first 5 s with the last 5 s. The take with the biggest jump (+30.1 LU) got loud once at 9 s and then stayed flat for 20 s. The check that picked a steady riser: 5-second RMS must never go down. Two of four seeds passed. The best rose 24 dB in RMS (+28.3 LU) all the way to the end.

8. Letting the LM rewrite the caption changes the instruments

ACE-Step can let its LM rewrite your caption (use_cot_caption). In batch 4, the LM rewrote a lo-fi caption with a muted trumpet into funk-jazz with an alto sax solo, and rewrote a folk caption without its cello, upright bass and brushed drums, adding shaker and hand drums. (These are the rewritten captions; I didn't verify each instrument by ear.) Leave it off if you need the instruments you asked for. (I ended up liking one rewritten track anyway; see below.)

9. Stable Audio 3 SFX: fractional lengths give a humming blob

Game stings requested at 2.5, 3.5 or 4.5 s came out as a droning noise instead of the sound. All 36 in that batch were thrown away. Whole seconds (2, 3, 4) worked.

10. LeVo 2 install: the official code doesn't run v2, and "full memory" is slower

  • The official GitHub repo was unreachable when I tried it. The LeVo code I found failed to load the v2 weights on a vocabulary size mismatch (151,652 vs 151,646). A community fork that supports v2 worked.
  • It needed setuptools<81 (for pkg_resources) and TORCH_FORCE_NO_WEIGHTS_ONLY_LOAD=1 with PyTorch 2.6. That variable turns off PyTorch's safe checkpoint loading, so use it only with checkpoints you trust.
  • One prompt file was a Git LFS pointer, not the data. The agent fetched the real file and checked its hash. Another file (new_auto_prompt.pt) couldn't be found anywhere, so the "auto style prompt" feature was disabled. This test didn't use it.
  • The script switches itself to a low-memory mode when the GPU has less than 32 GB. Flash-attention only took that from 433 s to 414 s (4%). Forcing full-memory mode made one song take 195 s including load, which looked promising. Four songs in a row took 2,451 s: VRAM hit 24.3 GB and spilled into system memory, about 6× slower. Low-memory mode + flash-attention is the best this card does.

Measuring music without ears

The agent can't hear, so it never claimed a track "sounds good". It checked for things that are wrong in a measurable way, and left taste to me. Every block below was re-run for this post, on copies of the real files. The output is pasted exactly.

Where does the music end, and does it stop abruptly? Same logic as the production script: last 0.1 s window above −45 dBFS. "Abrupt" means the final 0.5 s is less than 6 dB quieter than the second before it.

"""Where does the music really end, and does it stop abruptly?
usage: python music_end.py FILE.wav [...] [--fix OUTDIR]
"""
import sys
from pathlib import Path

import numpy as np
import soundfile as sf

GATE = -45.0           # a 0.1 s window quieter than this counts as silence (dBFS)
FADE, TAIL = 3.0, 0.4  # the fix: 3 s fade-out before the real end, keep 0.4 s of silence


def rms_db(mono, sr, step=0.1):
    w = int(sr * step)
    return np.array([20 * np.log10(np.sqrt(np.mean(mono[i:i + w] ** 2)) + 1e-9)
                     for i in range(0, len(mono) - w + 1, w)])


args = sys.argv[1:]
out = None
if "--fix" in args:
    i = args.index("--fix")
    out, args = Path(args[i + 1]), args[:i] + args[i + 2:]
for path in args:
    x, sr = sf.read(path, always_2d=True)
    r = rms_db(x.mean(axis=1), sr)
    k = np.flatnonzero(r > GATE)[-1]            # last window that still has music
    end = (k + 1) * 0.1
    before = r[max(0, k - 14):k - 4].mean()      # the 1 s before the final 0.5 s
    last = r[k - 4:k + 1].mean()                 # the final 0.5 s of music
    verdict = "ABRUPT" if last - before > -6 else "fades out"
    print(f"{Path(path).name}: file {len(x) / sr:.1f} s | music ends {end:.1f} s | "
          f"silent tail {len(x) / sr - end:.1f} s | last 0.5 s {last:.0f} dB vs {before:.0f} dB -> {verdict}")
    if out:
        y = x[:int(end * sr)].copy()
        n = int(sr * FADE)
        y[-n:] *= np.linspace(1.0, 0.0, n)[:, None] ** 2
        y = np.concatenate([y, np.zeros((int(sr * TAIL), x.shape[1]))])
        out.mkdir(parents=True, exist_ok=True)
        sf.write(str(out / Path(path).name), y, sr, subtype="PCM_16")

On the six round-1 tracks (requested length 42 s):

$ python music_end.py *.wav
calm-1.wav: file 42.0 s | music ends 36.9 s | silent tail 5.1 s | last 0.5 s -24 dB vs -20 dB -> ABRUPT
calm-2.wav: file 42.0 s | music ends 37.3 s | silent tail 4.7 s | last 0.5 s -42 dB vs -36 dB -> ABRUPT
tension-1.wav: file 42.0 s | music ends 36.4 s | silent tail 5.6 s | last 0.5 s -22 dB vs -23 dB -> ABRUPT
tension-2.wav: file 42.0 s | music ends 38.0 s | silent tail 4.0 s | last 0.5 s -18 dB vs -15 dB -> ABRUPT
twist-1.wav: file 42.0 s | music ends 38.1 s | silent tail 3.9 s | last 0.5 s -38 dB vs -25 dB -> fades out
twist-2.wav: file 42.0 s | music ends 33.7 s | silent tail 8.3 s | last 0.5 s -28 dB vs -22 dB -> ABRUPT

The rule is crude, and you can see it here. It flags five, but calm-2 had already faded to −36 dB on its own before ending at −42. The four that really stop dead are the ones still at −18 to −28 dB when the music ends. That's the "four of six" in pitfall 1. Applying the fix and measuring again:

$ python music_end.py tension-1.wav --fix fixed
tension-1.wav: file 42.0 s | music ends 36.4 s | silent tail 5.6 s | last 0.5 s -22 dB vs -23 dB -> ABRUPT
$ python music_end.py fixed/tension-1.wav
tension-1.wav: file 36.8 s | music ends 35.7 s | silent tail 1.1 s | last 0.5 s -41 dB vs -32 dB -> fades out

The re-measured tail is 1.1 s rather than the 0.4 s that was kept, because the last 0.7 s of the fade is already below the −45 dB gate.

Silence, double-checked with ffmpeg. No Python needed:

$ ffmpeg -hide_banner -nostats -i twist-2.wav -af silencedetect=noise=-50dB:d=0.5 -f null - 2>&1 | grep -o "silence_.*"
silence_start: 33.618083
silence_end: 42 | silence_duration: 8.381917

Run on finished tracks, this also catches gaps in the middle of a track. None of the delivered tracks had any.

Loudness. Integrated LUFS and loudness range (LRA). An LRA around 1 LU means the same density from start to finish, which matched "flat" more than once:

$ ffmpeg -hide_banner -nostats -i B1.wav -af ebur128 -f null - 2>&1 | grep -E "^ +(I|LRA):"
    I:          -9.4 LUFS
    LRA:         4.7 LU

Phase: will it survive one speaker?

"""Will this track survive a single phone speaker? L/R correlation and mono-sum loss.
usage: python phase.py FILE.wav [...]
"""
import sys
from pathlib import Path

import numpy as np
import soundfile as sf

for path in sys.argv[1:]:
    x, sr = sf.read(path, always_2d=True)
    l, r = x[:, 0], x[:, 1]
    corr = np.corrcoef(l, r)[0, 1]                          # +1 = mono, 0 = unrelated, -1 = inverted
    stereo = 10 * np.log10(np.mean((l ** 2 + r ** 2) / 2))  # average power of the two channels
    mono = 10 * np.log10(np.mean(((l + r) / 2) ** 2))       # power after summing to one speaker
    win = [np.corrcoef(l[i:i + sr], r[i:i + sr])[0, 1] for i in range(0, len(l) - sr, sr)]
    print(f"{Path(path).name}: corr {corr:+.2f} | mono loss {mono - stereo:+.1f} dB | "
          f"worst 1 s window {min(win):+.2f} at {int(np.argmin(win))} s")
$ python phase.py B4-s3303.wav B4-s4404.wav B4-s5505.wav
B4-s3303.wav: corr -0.86 | mono loss -9.3 dB | worst 1 s window -0.89 at 9 s
B4-s4404.wav: corr +0.17 | mono loss -2.3 dB | worst 1 s window -0.26 at 17 s
B4-s5505.wav: corr +0.71 | mono loss -0.7 dB | worst 1 s window +0.23 at 18 s

Spectrograms, as eyes. The agent read spectrograms to describe structure: when the bass comes in, where the drums drop out, whether there's a wavering, vibrato-like line that might be a stray vocal in an "instrumental" track.

$ ffmpeg -hide_banner -v error -y -i B1.wav -lavfi showspectrumpic=s=1024x384:stop=8000:legend=1 B1-spectrogram.png

Spectrogram of the batch-3 folk track: the bass enters at about 5 s

What these checks can't tell you: whether it's any good. Every delivered batch-1 and batch-2 track ended on a fade, had no silence in the middle and no clipping by sample peak (−1.0 to −1.4 dBFS; true peak not measured). Five of the 21 did fail the mono check above, including the steady riser from pitfall 7 (−4.8 dB). I still didn't want any of them.

How my ears steered it

Batches 1–2 (21 tracks): "all meh". The reason I gave was that they sounded too bland, and a bit cheap. These used 50 steps, shift 1.0, scene-style prompts ("calm lofi instrumental background music … relaxed and unobtrusive, smooth ending") and an [Instrumental] lyric tag.

Batch 3, "find a direction": no more tracks, eight directions instead, one take each.

  • Prompts became genre + 3–5 named instruments + mood + BPM + mix texture ("warm analog tape, wide stereo, crisp drums"). Words that make things bland ("background music", "unobtrusive", "minimal") were dropped.
  • shift went from 1.0 to 3.0, with steps kept at 50 (100 was flatter). A five-track checkpoint comparison sat alongside.
  • The lyric field got structure tags: [Intro] [Instrumental] [Outro].
  • Directions A1–A4 for my "tried it, didn't work" shorts: lo-fi hip hop, minimal glitch electronic, indie folk pop with ukulele, light chiptune. B1–B4 for a calm "morning info" series: acoustic folk with fingerpicked guitar, acoustic pop with marimba, neo-soul, cinematic piano and strings.
  • The phase check was added (pitfall 5). One direction was re-rolled because of it.

Batch 4, "prescription": the same eight directions with fixes aimed at "bland" and "cheap":

  • Generate 80 s and keep the liveliest 30 s, cut on bar lines. Full structure tags ([intro] [verse] [chorus] [bridge] [chorus] [outro]).
  • Movement words (call-and-response, countermelody, dynamic build, fills) and BPM raised 5–15 (B1: 96 → 106).
  • Real-instrument and recording words instead of preset-sounding ones ("8-bit", "plucked synth", "simple" and "loop" were banned by a script).
  • The phase check moved inside generation.

My picks after hearing batches 1–4: batch 4 B1, batch 4 B1 with the LM-rewritten caption, and batch 3 B1. All three are fingerpicked acoustic guitar with warm, real-sounding instruments. I'd also picked the batch 3 neo-soul track, then took it back. And none of the four "tried it, didn't work" directions made it, in either batch (eight tracks in all).

Batch 5 kept the core recipe (fingerpicked steel guitar, nylon guitar answering it, upright bass, brushed drums, the same settings), changed the mood, and added one lead instrument per track (tin whistle, muted trumpet, pizzicato strings, cello), at 92–116 BPM; plus three new seeds of batch 4 B1.

So did shift 3 fix it? I can't say that. Prompts, structure tags and settings all changed between batches, and the same seed doesn't even give the same song. What I can say: from batch 3 on, the checks kept measurable defects (abrupt ends, phase problems) out of the delivered tracks, and my ears picked the direction.

Samples

Five ACE-Step clips (MIT). Each is the first 25 s of the track (01–04 delivered tracks, 05 the raw rejected take), with a 0.3 s fade-in and a 2.5 s fade-out, loudness-matched to −16 LUFS so that no clip wins by being louder. 160 kbps MP3.

01 · batch 1 calm (one of the 21 'meh' tracks, shift 1.0) 02 · batch 3 B1 folk (a pick, shift 3.0) 03 · batch 4 B1 folk (a pick) 04 · batch 4 B1 folk, LM-rewritten caption (a pick) 05 · rejected anti-phase take (play in stereo, then on one phone speaker)

FileWhat it isPrompt (caption)ModelStepsShiftSeedBPMClip
01-batch1-calm-shift1.mp3Batch 1, one of the 21 "meh" trackscalm lofi instrumental background music, soft mellow piano chords, gentle laid-back beat, warm bass, slow tempo, relaxed and unobtrusive, smooth endingXL-sft + LM 1.7B501.011017525 s
02-batch3-B1-folk-shift3.mp3Batch 3 B1, one of my picksacoustic folk instrumental, warm steel-string acoustic guitar fingerpicking, gentle nylon guitar harmony, soft upright bass, light brushed percussion, sunrise morning mood, reassuring, honest and hopeful, intimate close-miked recording, warm analog tape, natural room ambienceXL-sft + LM 1.7B503.033039625 s
03-batch4-B1-folk.mp3Batch 4 B1, one of my picksacoustic folk instrumental, steel-string acoustic guitar fingerpicking, nylon guitar countermelody, upright bass, real brushed drums with gentle swing and fills, warm cello lines, flowing driving rhythm, call-and-response between guitars, dynamic build into a fuller chorus, sunrise morning mood, reassuring, honest and hopeful, rich layered harmonies, live-recorded instruments, studio-quality mix, professional mastering, warm analog, tape saturation, room ambienceXL-sft + LM 1.7B503.07717 (6606 failed the phase check)10625 s
04-batch4-B1-folk-lm-rewrite.mp3Batch 4 B1 with the LM rewriting the caption, one of my pickssame as 03; the LM turned it into "multiple layered acoustic guitars … shaker and what sounds like a cajon or hand drums"XL-sft + LM 1.7B503.09939 (7717, 8828 failed)10625 s
05-antiphase-B4-seed3303.mp3The rejected anti-phase take. Play it in stereo, then on one phone speakercinematic instrumental, soft felt piano melody, warm string ensemble swells, gentle cello, slow build, hopeful and reassuring, emotional but restrained, morning light, lush hall reverb, wide stereo, high fidelity orchestral recordingXL-sft + LM 1.7B503.033037625 s

All five: CFG 7, LM 1.7B with thinking on, instrumental. Lyric tags: [Instrumental] (01), [Intro] [Instrumental] [Outro] (02, 05), [intro] [verse] [chorus] [bridge] [chorus] [outro] (03, 04). The anti-phase clip still measures corr −0.86 and −9.3 dB after MP3 encoding.

Limits

  • The agent can't hear. Every "quality" statement in its reports is a measurement or a description of a spectrogram. Taste came only from me, one listener.
  • The LeVo 2 vs ACE-Step comparison is four songs, not blind, not loudness-matched, and ACE-Step ran at 8 steps in it.
  • Not measured: LeVo 2 VRAM in its default mode, LeVo 2 load time on its own, Stable Audio 3 VRAM, and Korean pronunciation quality for either song model.
  • Only the 4B XL-sft and 2B turbo ACE-Step checkpoints and the 1.7B planner LM were on this machine. The XL-turbo and the 4B planner LM weren't tried.
  • AI-generated music can resemble existing music by accident. None of my prompts named a person, song or work, but that doesn't rule it out.

What I'd do from the start next time

  1. Read the license file on disk before the first generation, and keep non-commercial models out of anything you might publish.
  2. For ACE-Step XL-sft, what I used: 50 steps, shift=3.0, CFG 7. The guide's best-quality list also says at least 64 steps and ADG on, which I didn't try. Generate longer than you need. Find the real end, fade, and trim.
  3. Run the mono-loss check on every take, and re-roll anything below −3 dB. (With this script, fully uncorrelated wide stereo gives about −3 dB, so the rule in practice rejects net-negative correlation.)
  4. Describe the genre, named real instruments, the movement and the recording. Leave out "background music" and "unobtrusive".
  5. Judge settings with several seeds each, because the same seed isn't the same song.
  6. Match loudness before anyone compares by ear, me included.
  7. Keep the human verdict in the loop early. My "all meh" after 21 tracks was the most useful input in the whole project, and no script would have produced it.

관련 글