Skip to content

v0.3 — the radio stops repeating itself

Choose a tag to compare

@CharlesMod CharlesMod released this 18 Aug 20:10
· 12 commits to main since this release

Most of this release is one bug wearing different clothes: a range that exists
in your music, or in the model, had been replaced somewhere by a single value.

Every song had the same shape

Veins described their energy arc as the average of every track in them.
Averaging eighty tracks cancels out what makes them different and leaves only
the one thing they share — intros are quieter — so all four veins of a
443-track library came out "mid-peak", a label that distinguishes nothing and
then constrains everything. Measured: the library is 62% mid-peak, 25%
builds-to-end, 13% front-loaded, and generation was 100% mid-peak.

Veins now carry the distribution and each take rolls against it. Auto-built
cards also had "energy shape" listed under NEVER LOSE while appearing in
no mutation axis, so the dimension most responsible for one take feeling
unlike the last was the one explicitly forbidden to move.

Every song had the same section plan

The instrumental scaffold was deterministic: intro, instrumental,
instrumental, bridge, padding, outro — the bridge always fourth, five distinct
skeletons across every possible length. With sung takes capped at 25%, that
was one form for three quarters of the radio, and these tags are executable
structure. Now six forms (arch, through-composed, build/drop, rondo, ostinato,
suite) scaled to length: 24 distinct skeletons.

New installs generated with no key at all

Key parsing was gated on a parenthesis that only appears in hand-edited cards,
so every auto-generated card produced no key and the prompt fell back to "your
choice". Both dialects parse now, sharps survive (a trailing \b was turning
F# into F — silently transposing), and a group's mode carries forward over its
bare notes: "G/D/A minor, G major" is three minor keys and one major.

Nothing ever asked the music to do anything

Captions varied instrument, tempo, brightness and length — all surface — with
no vocabulary for motif development, modulation, call-and-response,
displacement or drop-out. 18 concrete techniques, one rolled per take.

The generator's own controls were frozen

top_k and the text encoder's cfg_scale are consumed by the autoregressive
sampler that chooses acoustic codes one at a time — the thing actually
choosing notes, which no caption wording can reach. Both were pinned for every
take ever generated, and one constant named CFG was feeding two unrelated
parameters (diffusion guidance and token-sampling guidance). They are separate
now and roll per take, as do the two seeds.

You can see the critic, and argue with it

Rejected takes are deleted, so the deck could never show that the radio was
working — it generates for minutes, bins the result, and leaves a log line
nobody reads. More than one person read that silence as a broken radio. There
is now a Critic panel with every verdict, its score against the bar, and the
accept rate; near misses are highlighted, because those are the ones a single
nudge would have banked. Stricter / looser buttons move the bar live.

Kept takes are a shelf, not a filename

Keeping worked; everything after it didn't. Keepers now list, replay, rename
and export as MP3, WAV or FLAC under their own name. Titles live in a sidecar
rather than renaming files, because the filename pattern doubles as the
path-traversal guard on the audio route.

Fixed

  • A silent LLM outage. llama-swap could not start its model because a
    configured projector file was missing; llama-server aborts before serving
    and the proxy reports only "upstream command exited prematurely". Every
    caption fell back to static card text, which also meant none of the
    technique, key or arc work above reached generation. The fallback is
    correct in the moment, but it was being banked — a full batch of them
    filled the queue and the radio spent forty takes on it. It now writes two.
  • Captures survive a full card. An allocation that does not fit retries
    after releasing cached memory, then describes a shorter excerpt rather than
    dropping the track. The listening pass sizes its clip from free VRAM at
    start — weights are a fixed ~7.7 GB but activations were ~5.2 GB and nobody
    was choosing them.
  • The three tenants hand the GPU over properly. The listening pass had no
    idea the lyricist existed, and the music server's boot could ask the pass
    for room but not the lyricist.
  • Steps are 30 always; the catch-up lever that dropped a starved spool to 20
    cheapened exactly the takes someone was waiting for.
  • analysis/capture.log is flushed per line — it exists for the moments a
    capture looks stuck, and was empty precisely then.

Known, and honest about it

Requested energy shapes arrive about 40% of the time, and builds-to-end
essentially never. The cause is upstream: takes end at a median 46% of the
length their caption plans for
, so the back half of a piece — where its
shape is decided — is never generated. Steering the caption is not the same as
steering the audio, and the code says so where it matters.