blackboxanalytics commited on
Commit
9aeb323
Β·
1 Parent(s): 3ef2e8b

Pre-submission cleanup: remove scratch files, fix internal comments

Browse files

- Delete all local .bak* files, _*.py scratch runners, lab_out/, .claude/,
.pytest_cache/, demo_clip.wav, planning docs, and session artifacts
- .gitignore: add .claude/, .pytest_cache/, _*.py patterns
- app.py: strip internal build-instruction comments that leaked into the CSS
string and JS block; remove first-person attribution ('Tony wants',
'Tony's call') from inline comments
- README.md: commit the hackathon-ready version (comprehensive, accurate)

Files changed (3) hide show
  1. .gitignore +7 -0
  2. README.md +274 -90
  3. app.py +5 -10
.gitignore CHANGED
@@ -37,3 +37,10 @@ memory-audit-*.md
37
  PLAN_*.md
38
  RESEARCH_*.md
39
  *coda_commits*
 
 
 
 
 
 
 
 
37
  PLAN_*.md
38
  RESEARCH_*.md
39
  *coda_commits*
40
+
41
+ # IDE / local tooling
42
+ .claude/
43
+ .pytest_cache/
44
+
45
+ # underscore-prefixed scratch/test runners
46
+ _*.py
README.md CHANGED
@@ -14,117 +14,301 @@ models:
14
  - stabilityai/stable-audio-3-small-music
15
  ---
16
 
17
- # CODA β€” the songs you quit on, finished.
18
-
19
- Everyone who's ever made music has one: the song that stops at 0:47. You ran out
20
- of ideas at the bridge, the voice memo got buried, life happened. CODA takes that
21
- unfinished clip and continues it into a longer, finished-sounding track β€” same
22
- key, same tempo, same groove β€” then splices the new part onto your original so
23
- cleanly you have to hunt for the seam.
24
-
25
- One job, done well. No lyric bot, no cover-art printer β€” just a real, listenable
26
- continuation of *your* clip, in 44.1 kHz stereo.
27
-
28
- ## How it works
29
-
30
- 1. **Listen.** librosa detects the key, tempo, and meter β€” pure DSP, no ML. If
31
- the recording is lo-fi (a voice memo, a phone capture, an old MP3 rip), CODA
32
- cleans a *copy* first β€” rumble filter, spectral noise gate, level β€” and
33
- conditions on that, so it follows the *song* and not the hiss. Your real
34
- original still goes into the final track (tick **remaster my part** to apply
35
- the same cleanup to your section too).
36
- 2. **Continue.** [Stable Audio 3 Small Music](https://huggingface.co/stabilityai/stable-audio-3-small-music)
37
- does the rest in a **single call**. SA3 is a latent-diffusion model with
38
- native audio *inpainting*: CODA places your clip at the front of the buffer
39
- and masks the region after it, and the model fills that region β€” conditioned
40
- on the whole clip β€” with a coherent continuation. No 30-second windows, no
41
- multi-pass chaining, no energy guards, no re-rolls. Eight diffusion steps with
42
- the pingpong sampler, a couple of seconds on a GPU. Leave the vibe box empty
43
- for a pure audio-led continuation that holds your key and tempo; type a vibe
44
- to creatively steer the new section.
45
- 3. **Stitch.** The continuation is loudness-matched to your recording, joined at
46
- the seam with a short equal-power crossfade, and faded out to a clean close.
47
- Everything is 44.1 kHz stereo β€” your original is resampled up to meet the SA3
48
- tail, never the other way around.
49
-
50
- Progress streams through every stage, so you never stare at a dead screen.
51
-
52
- ## Why Stable Audio 3 (and not MusicGen)
53
-
54
- CODA's earlier builds fought MusicGen's limits: a 30 s trained window forcing
55
- fragile multi-pass chaining, 32 kHz mono output, and a tendency to drift into
56
- silence on quiet prompts. SA3 Small Music removes all of it at once:
57
-
58
- | | MusicGen-medium | SA3 Small Music |
59
- |---|---|---|
60
- | Continuation | chain 12 s-ctx / 18 s-new passes, compounding drift | one native inpaint call over the whole clip |
61
- | Output | 32 kHz **mono** | **44.1 kHz stereo** |
62
- | Speed | multiple passes per track | ~8 steps, a couple of seconds |
63
- | License | CC-BY-NC (non-commercial) | Stability Community (commercial < $1M revenue) |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- The hardest, most fragile part of the old build β€” the windowed chaining with its
66
- energy guards and collapse re-rolls β€” is simply deleted.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  ## The stack β€” small on purpose
69
 
70
  | Component | Size | Job |
71
  |---|---|---|
72
  | [Stable Audio 3 Small Music](https://huggingface.co/stabilityai/stable-audio-3-small-music) | ~0.6B | native audio-inpaint continuation |
73
- | T5Gemma (bundled with SA3) | ~0.5B | optional text conditioning for the vibe box |
74
- | librosa + SciPy | 0 params | key/tempo/meter detection, lo-fi cleanup |
75
-
76
- Well under the 32B cap, runs entirely inside a single ZeroGPU window (generation
77
- is seconds, not the whole budget), no cloud APIs.
78
-
79
- ## What it won't pretend to do
80
 
81
- SA3 is a *music* model β€” the continuation is instrumental-leaning, and CODA
82
- doesn't fake vocals it can't generate. The honest design choice: **your original
83
- recording plays untouched up to the seam**, vocals and all, and the generated
84
- section carries the music on from there. The band plays on; you write the next
85
- verse. A typed vibe steers the new section creatively but can pull it away from
86
- the original's exact key and tempo β€” that's the trade you're choosing when you
87
- use it; leave it empty for a faithful continuation.
88
 
89
- ## Using it
90
 
91
- Upload a WAV, MP3, or FLAC (a 15–30 second clip works best), or hit **try the
92
- demo β€” PUSHBACK**. Set the finished length, optionally describe a vibe or tick
93
- *remaster my part*, and press **Finish this song**. You'll see the detected
94
- key/tempo the moment a clip loads, watch the stages stream, and get a 44.1 kHz
95
- stereo track to play or download.
96
 
97
- Run it locally (needs Python 3.10 and a CUDA GPU; the SA3 weights are gated, so
98
- accept the licence on the model page and `huggingface-cli login` first):
99
 
100
  ```bash
101
  pip install -r requirements.txt
102
  python app.py
103
  ```
104
 
105
- Deploying as a Space: because the SA3 weights are gated, add an **`HF_TOKEN`**
106
- secret (from an account that has accepted the licence) in the Space settings, or
107
- the model download 401s at startup. The bundled demo clip lives outside git (see
108
- `.gitignore`) β€” upload `examples/pushback_demo.mp3` to the Space directly.
 
 
109
 
110
- ## Notes for the curious
 
 
 
 
 
 
 
 
 
 
 
111
 
112
- `verify.py` is a dev-only QA harness: it measures the finished track against the
113
- original for silence-collapse, clipping, seam continuity, tempo/key continuity,
114
- spectral rolloff, and stereo width, and writes a diagnostic plot. It is not in
115
- the app's runtime path β€” it's how regressions get caught between ear-checks.
 
 
116
 
117
- Code is MIT. SA3 weights are under the
118
- [Stability AI Community License](https://stability.ai/license) (free for
119
- commercial use under $1M annual revenue) and bundle a T5Gemma encoder under the
120
- Gemma Terms of Use β€” worth knowing if you fork it.
121
 
122
- **Demo clip credit:** `examples/pushback_demo.mp3` is a clip by the band
123
- **PUSHBACK**, sourced from TikTok, included solely as a sample to demonstrate the
124
- tool. It is not affiliated with this project and all rights to the music remain
125
- with the band. It's a deliberately lo-fi rip β€” which is the point: low-quality
126
- in, finished-sounding out. If you are PUSHBACK and want it removed, say the word.
 
 
 
 
 
127
 
128
  ---
129
 
130
- Built by Tony Winslow β€” Black Box Analytics β€” for the Build Small Hackathon 2026.
 
 
 
 
 
 
 
 
 
 
 
14
  - stabilityai/stable-audio-3-small-music
15
  ---
16
 
17
+ # CODA
18
+
19
+ **[β–Ά Try it on Hugging Face Spaces](https://huggingface.co/spaces/build-small-hackathon/coda)**
20
+
21
+ In 2016 I recorded a song one night and quit at the bridge. No big reason. I ran
22
+ out of whatever I had that night, saved the file, and never opened it again.
23
+ `track0000_tony_winslow.mp3`. It sat on a drive for almost ten years.
24
+
25
+ CODA finished it. That's the whole pitch. Upload the clip you gave up on, and
26
+ CODA continues it β€” same key, same tempo, same feel β€” then splices the new part
27
+ onto your original so cleanly you have to go hunting for the seam. The demo on
28
+ the Space is literally that 2016 file. Press the button that says *Hear
29
+ Track0000* and you can listen to the thing I couldn't finish, finished.
30
+
31
+ I built this for the Build Small Hackathon (June 5–15, 2026). It's one job done
32
+ properly. No lyric bot. No cover-art generator. No "AI music studio" with forty
33
+ sliders. You bring an unfinished clip, you get back a finished-sounding track.
34
+
35
+ ## What it actually does
36
+
37
+ Drop in a 15–30 second clip β€” a voice memo, a phone capture, an old bounce, a
38
+ half-idea. CODA:
39
+
40
+ 1. **Listens.** Real DSP, no model: it reads the key, the tempo and the meter
41
+ straight off the audio.
42
+ 2. **Continues it.** Stable Audio 3 paints new music into the silence *after*
43
+ your clip, conditioned on what you played. 44.1 kHz, stereo, up to two
44
+ minutes, in a single call.
45
+ 3. **Stitches it back.** Your original plays untouched up to the seam, then the
46
+ generated part takes over with a level-matched crossfade and a clean fade to
47
+ the end.
48
+
49
+ You watch the whole thing happen β€” it tells you what it heard the moment the clip
50
+ lands, and streams each stage while it works.
51
+
52
+ ## Why this is harder than it sounds
53
+
54
+ Most "AI music" entries you'll see are a text box wired to a music model plus a
55
+ text-to-speech voice. Type words, get a clip. That's not what CODA does and it's
56
+ worth being precise about the difference, because the difference is the entire
57
+ project.
58
+
59
+ CODA works on **waveforms**, not prompts. It takes the actual samples you
60
+ recorded and generates audio that continues *those samples*. The model isn't
61
+ imagining "a lo-fi track in C minor at 92 BPM" from a description β€” it has your
62
+ real audio in front of it and has to make the next 40 seconds sound like they
63
+ belong to the same performance. That's continuation, and the way it's done here
64
+ is **inpainting**.
65
+
66
+ ### Inpainting, for audio
67
+
68
+ Stable Audio 3 Small Music is a 0.6-billion-parameter latent-diffusion model. The
69
+ piece that makes CODA possible is `generate_diffusion_cond_inpaint`: a sampler
70
+ that takes a buffer of audio, a binary mask, and fills the masked region
71
+ conditioned on the kept region.
72
+
73
+ The mask convention (I verified this against the installed library source, not
74
+ the docs):
75
+
76
+ ```
77
+ inpaint_mask = ones(buffer)
78
+ inpaint_mask[start:end] = 0 # 1 = keep this audio, 0 = generate here
79
+ ```
80
+
81
+ So CODA puts your clip at the **front** of the buffer, masks everything after it,
82
+ and lets the model generate forward. The kept audio is the run-up; the masked
83
+ region is the continuation. One pass. No 30-second sliding windows, no chaining
84
+ generations together and watching them drift, no energy guards to stop it
85
+ collapsing into silence. The model just hears where the song was going and keeps
86
+ going.
87
+
88
+ If you've ever tried to do continuation with MusicGen, you know why this matters.
89
+ The old CODA prototype did exactly that β€” chain 12-seconds-of-context into
90
+ 18-seconds-of-new, over and over, 32 kHz mono, drift compounding every hop, and a
91
+ nasty habit of fading to nothing on quiet inputs. SA3 deleted the most fragile
92
+ 800 lines of the project in one move. 44.1 kHz stereo, one call, no drift.
93
+
94
+ ### The lead-in trap
95
+
96
+ Here's a bug that cost me a day. You'd think you'd feed the model your *whole*
97
+ clip as context β€” more context, better continuation, right? Wrong, and wrong in a
98
+ way that's invisible until you listen.
99
+
100
+ SA3 Small is an 8-step adversarially-distilled model. If you stuff a long clip
101
+ (say 100 seconds) into the buffer and mask only a few seconds at the end, the
102
+ distilled sampler collapses the masked region to near-silence. It shipped like
103
+ that once. The fix is counterintuitive: condition on **at most 30 seconds of the
104
+ clip's tail**, not the whole thing. A bounded lead keeps the generated region
105
+ substantial and healthy. And because the splice rejoins the new tail onto your
106
+ *full* pristine original anyway, the listener still hears their entire clip before
107
+ the seam β€” they never know the model only looked at the last 30 seconds.
108
+
109
+ ### Best-of-5, because seeds lie
110
+
111
+ This is the one I'm proudest of, and it came out of a genuinely annoying
112
+ production bug.
113
+
114
+ In the lab, on torch 2.7.1, I had a pinned seed that produced a gorgeous take
115
+ every time. Deployed it. On the Space it produced **a loud burst of synth noise**
116
+ that scored, on my own quality meter, 90 where a normal draw scores 3. Same seed.
117
+ Same code. The difference: the cloud runs a different torch build, and the RNG
118
+ plumbing changed underneath me, so seed `7` no longer reproduces "the good take" β€”
119
+ it reproduces *one arbitrary draw*, and the arbitrary draw I'd frozen happened to
120
+ be a bad one.
121
+
122
+ The lesson: **don't trust a magic seed across environments.** So CODA stopped
123
+ betting on one draw. It now generates several candidate continuations with
124
+ genuinely different seeds and keeps the cleanest one, scored by a cheap, ear-free
125
+ artifact detector. The score catches the four specific ways an SA3 draw goes bad:
126
 
127
+ - **Loud random bursts** β€” a few windows far louder than the body push the
128
+ loudest 50 ms window way above the median. Real musical dynamics don't do that;
129
+ a glitch does.
130
+ - **Silence collapse** β€” the whole tail comes out near-silent. Caught by an
131
+ overall-loudness floor.
132
+ - **Mid-tail dropout** β€” the sneaky one. Overall RMS stays high and there's no
133
+ loud spike, so the first two checks pass clean β€” but the music plainly cuts out
134
+ for a beat in the middle. I catch it by looking for a sustained quiet stretch:
135
+ the quietest ~0.2 s of the tail falling way below the median.
136
+ - **Dynamics collapse** β€” a draw can be perfectly tonal, perfectly steady, and
137
+ completely lifeless: transients smeared into a wall of mush. Flatness checks all
138
+ read "fine." It shows up as a collapsed **crest factor** (peak Γ· RMS): real
139
+ music sits around 6–8, a squashed wash falls to 2–3. Penalize the low crest and
140
+ best-of-N picks the punchy take over the mushy one.
141
+
142
+ It draws up to five, early-accepts a draw that's clearly clean so it doesn't waste
143
+ GPU time, and respects a wall-clock budget so it never blows the generation
144
+ window. Most of the time the first or second draw is great and it stops there. The
145
+ loud-synth-noise bug? Best-of-N rejects that draw on sight. That's what actually
146
+ fixed it.
147
+
148
+ ### fp16 on a cloud GPU that bites back
149
+
150
+ The "loud burst" wasn't *only* a seed problem β€” there's a real numerical story
151
+ under it too, and chasing it taught me a lot about fp16. The continuation sounded
152
+ perfect on my local Blackwell card and produced garbage on the hosted GPU. I went
153
+ hunting for it as an fp16 precision issue and hardened the path, and the
154
+ hardening stayed in because it's correct regardless of which silicon you land on:
155
+
156
+ - **The autoencoder decodes in fp32.** SA3's decoder uses Snake activations β€”
157
+ `x + (1/(beta+1e-9)) Β· sin(Ξ±x)Β²`. That reciprocal-times-sine-squared term can
158
+ shoot past fp16's ~65504 ceiling, give you `inf`/`NaN`, and a `NaN` on decode is
159
+ exactly a wall of broadband noise. The transformer stays in fast fp16; only the
160
+ autoencoder runs fp32, which has the headroom. (The clever bit: the library
161
+ already casts latents to the pretransform's dtype right before decode, so making
162
+ *only* the pretransform fp32 flips the whole encode/decode path to fp32 with no
163
+ library patch.)
164
+ - **Attention is pinned to the MATH backend** during sampling. fp16 SDPA on some
165
+ cards routes to kernels with known NaN bugs; the reference math path is the
166
+ stable one.
167
+ - **TF32 accumulation is off**, so error doesn't compound through eight diffusion
168
+ steps.
169
+
170
+ All of it is a no-op on CPU. None of it cost quality. Belt and suspenders next to
171
+ best-of-N β€” the precision path keeps a single draw numerically sane, best-of-N
172
+ guarantees you ship a *musical* one.
173
+
174
+ ### The seam
175
+
176
+ A continuation is only as good as its join. The generated tail begins exactly
177
+ where your recording ends, so the seam is a join between two genuinely sequential
178
+ pieces of audio, not a fade between two takes of the same thing. `stitch.py`
179
+ handles it:
180
+
181
+ - **Loudness match** β€” the tail is gain-matched to your recording's level right at
182
+ the seam so it doesn't pump, with the gain bounded so a whisper-quiet lo-fi clip
183
+ can't drag the full-bodied continuation down to nothing.
184
+ - **Equal-power crossfade** β€” a short cosine/sine pair across the join. Equal-power,
185
+ not equal-gain, because the two sides are sequential content and equal-power
186
+ keeps the energy flat through the blend (equal-gain would dip).
187
+ - **cosΒ² fade to true silence** at the end, so the track *ends* like a song instead
188
+ of getting cut off mid-air.
189
+ - **One final peak-normalize** to a confident level with a dB of headroom.
190
+
191
+ Everything is 44.1 kHz stereo end to end. Your original is resampled *up* to meet
192
+ the SA3 tail β€” never the other way around, because the deliverable should never
193
+ sound worse than the model can make it.
194
+
195
+ ## Listening before generating
196
+
197
+ Before any of the model stuff, CODA reads your clip with plain librosa DSP β€” no ML,
198
+ nothing to download, runs in a blink:
199
+
200
+ - **Key** via Krumhansl–Schmuckler profile correlation over the chroma.
201
+ - **Tempo** from librosa's beat tracker.
202
+ - **Meter** by scoring how well a "downbeat every N beats" grid lines up with where
203
+ the accents actually land β€” 3/4 has to win clearly or it's called 4/4, like most
204
+ music is.
205
+
206
+ And because people's unfinished songs live on phone recordings and old MP3 rips,
207
+ there's a lo-fi **input enhancer**: a 35 Hz rumble filter and a spectral noise gate
208
+ clean a *copy* of your audio that feeds the analysis and the model, so it follows
209
+ the **song** and not the hiss. Your real recording is never touched by this β€” it
210
+ goes into the final track exactly as you played it. (Tick *remaster my part* if you
211
+ want the same cleanup applied to your section too, so the whole thing sits at one
212
+ level.)
213
+
214
+ ## The frontend
215
+
216
+ I didn't want this to look like a default Gradio app, so it isn't one. It's a dark
217
+ "milled instrument" β€” backlit LCD readouts, engraved labels, faders with real
218
+ bevels, a gold flourish when your finished track lands. Most of the state lives in
219
+ CSS `:has()` selectors keyed off real DOM state, so the button lights while the
220
+ engine runs and the result panel goes gold on reveal with no JavaScript event
221
+ wiring at all.
222
+
223
+ The hero spectrum is my favorite piece. It's a real audio-reactive visualizer β€”
224
+ not a fake loop. When your finished track plays, the bars dance to **actual FFT
225
+ data** from a Web Audio `AnalyserNode`. Getting there was a fight: Gradio's
226
+ WaveSurfer plays from a decoded buffer through its own audio graph, so its
227
+ `<audio>` element never loads and there's nothing to tap. The trick is a **silent
228
+ shadow `<audio>`** of the same file, wired `MediaElementSource β†’ AnalyserNode` but
229
+ deliberately *not* connected to the speakers β€” it gives me real frequency data
230
+ while staying inaudible, locked in step with WaveSurfer's play/pause and position.
231
+ Real bars, no echo.
232
+
233
+ There's also a one-time cinematic intro that tells the 2016 story, and a
234
+ server-rendered before/after ribbon under the player that marks exactly where your
235
+ part ends and CODA's begins β€” computed from the real numbers, so the marker can't
236
+ drift.
237
 
238
  ## The stack β€” small on purpose
239
 
240
  | Component | Size | Job |
241
  |---|---|---|
242
  | [Stable Audio 3 Small Music](https://huggingface.co/stabilityai/stable-audio-3-small-music) | ~0.6B | native audio-inpaint continuation |
243
+ | T5Gemma (bundled with SA3) | ~0.5B | optional text steering for the vibe box |
244
+ | librosa + SciPy | 0 params | key/tempo/meter, lo-fi cleanup, scoring |
 
 
 
 
 
245
 
246
+ The whole thing runs inside a single ZeroGPU window β€” generation is seconds, not
247
+ the whole budget β€” with no cloud APIs in the loop. 0.6B parameters doing
248
+ waveform-level music generation.
 
 
 
 
249
 
250
+ ## Running it
251
 
252
+ On the Space, just open it and press *Hear Track0000*, or drop in your own clip.
 
 
 
 
253
 
254
+ Locally (needs Python 3.10 and a CUDA GPU; SA3's weights are gated, so accept the
255
+ license on the model page and `huggingface-cli login` first):
256
 
257
  ```bash
258
  pip install -r requirements.txt
259
  python app.py
260
  ```
261
 
262
+ Deploying your own copy: the SA3 weights are gated, so add an **`HF_TOKEN`** secret
263
+ (from an account that accepted the license) in the Space settings or the download
264
+ 401s at startup. `stable-audio-tools` hard-pins `torch==2.7.1`, which ZeroGPU
265
+ rejects, so `app.py` installs it `--no-deps` at runtime and lets the
266
+ ZeroGPU-managed torch win β€” its non-torch dependencies are all in
267
+ `requirements.txt`.
268
 
269
+ ## What it won't pretend to do
270
+
271
+ SA3 is a *music* model. The continuation leans instrumental, and CODA does not fake
272
+ vocals it can't generate. That's the honest design line: **your original plays
273
+ untouched up to the seam, vocals and all**, and the generated section carries the
274
+ music on from there. The band plays the outro; you can still go write the next
275
+ verse over it. Leave the vibe box empty for a faithful, audio-led continuation that
276
+ holds your key and tempo; type a vibe and you're choosing to let it steer
277
+ creatively, which can pull it off your exact key β€” that's the trade, and it's yours
278
+ to make.
279
+
280
+ ## Where it's headed
281
 
282
+ The thing I want next is **vocal continuation** β€” letting the model carry a melody
283
+ line, not just the instrumental bed. After that, multiple continuation options side
284
+ by side so you can pick the direction instead of taking the cleanest draw, and a
285
+ "finish to a specific length and resolve on the tonic" mode so it lands like a real
286
+ ending instead of fading. The bones are here; the inpainting core makes all of it
287
+ reachable.
288
 
289
+ ## Why I think it belongs in this hackathon
 
 
 
290
 
291
+ The brief was *build small*. CODA is 0.6B parameters doing something the big
292
+ text-to-music models mostly can't be bothered with β€” taking your actual recording
293
+ and continuing it at the sample level. As far as I can tell, of the entire field of
294
+ entries it's the only one doing waveform-level audio AI generation; everything else
295
+ in the audio category is text-to-music plus a TTS voice. Nobody else is touching
296
+ inpainting-based continuation. Small model, real DSP, a custom instrument for a
297
+ frontend, and a single job it does well.
298
+
299
+ It also gave a ten-year-old unfinished song an ending, which is the part I
300
+ actually care about.
301
 
302
  ---
303
 
304
+ Built by **Tony Winslow** Β· Black Box Analytics Β· for the Build Small Hackathon,
305
+ 2026.
306
+
307
+ Code is MIT. SA3's weights are under the
308
+ [Stability AI Community License](https://stability.ai/license) (free for commercial
309
+ use under $1M annual revenue) and bundle a T5Gemma encoder under the Gemma Terms of
310
+ Use β€” worth knowing if you fork it.
311
+
312
+ **Demo clip:** `examples/track0000_tony_winslow.mp3` β€” my own song, recorded 2016,
313
+ never finished. The exact kind of clip CODA exists for: lo-fi in, finished-sounding
314
+ out. Bring your own and finish yours.
app.py CHANGED
@@ -399,7 +399,7 @@ THEME = gr.themes.Base(
399
  )
400
 
401
  CSS = """
402
- /* ===================================================================== CODA β€” premium audio-instrument treatment. This is a COMPLETE replacement for the CSS string in app.py. It keeps every existing ambient layer / hero / HUD / stage rule that already works, retargets only REAL class names (verified against the app.py source + the Gradio 6.17 StaticAudio/Upload compiled assets), and adds the milled-metal light model, the LCD power-on, the milled controls, the illuminated key states, and the gold MASTER reveal. No new font import (theme already loads Space Grotesk + Inter + JetBrains Mono). ===================================================================== */
403
  @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600&display=swap');
404
 
405
  :root{
@@ -1016,12 +1016,7 @@ footer{ display:none !important; }
1016
  @media (prefers-reduced-motion: reduce){ .coda-drop .icon-wrap{ animation:none !important; } }
1017
 
1018
 
1019
- /* ============================================================================
1020
- * APPEND ALL OF THIS to the END of the existing CSS string in app.py β€” i.e.
1021
- * just BEFORE the closing triple-quote at line 925 (after the last @media block
1022
- * at line 923). Purely additive; no existing selector is modified. No new font
1023
- * import (Space Grotesk / Inter / JetBrains Mono already loaded).
1024
- * ========================================================================== */
1025
 
1026
  /* ===== FEATURE A β€” PLAY-ENERGIZED HERO ===== */
1027
  /* When the player reports it's playing, the JS adds .coda-eq-playing and the
@@ -1403,7 +1398,7 @@ AMBIENT = ("<div class='coda-aurora'></div>"
1403
  "<div class='coda-glow'></div>"
1404
  f"<div class='coda-particles'>{_parts}</div>")
1405
 
1406
- # Feature C β€” cinematic onboarding overlay. Tony wants the 2016 story to play on
1407
  # EVERY page load. It is rendered with `coda-intro-on` BAKED IN, so the CSS beats
1408
  # start immediately on load WITHOUT waiting on (or even needing) JS β€” bulletproof
1409
  # against the head-injection issue that made it vanish on the Space. The
@@ -1495,7 +1490,7 @@ CODA_INIT_JS = """
1495
  });
1496
 
1497
  /* ===== FEATURE A β€” AUDIO-REACTIVE HERO (real FFT via a shadow <audio>) =====
1498
- * Tony wants the hero bars to DANCE with the finished track, not freeze.
1499
  *
1500
  * Verified live: Gradio's WaveSurfer plays from a DECODED BUFFER through its
1501
  * own Web Audio graph β€” its <audio> element never loads (readyState 0, no
@@ -1765,7 +1760,7 @@ CODA_INIT_JS = """
1765
  host.setAttribute('aria-hidden', 'true'); host.remove();
1766
  } catch (e) {}
1767
  }
1768
- /* Tony's call: the 2016 intro replays on EVERY page load, not just the
1769
  * first. So there is NO localStorage "seen" gate β€” we always boot it.
1770
  * Skip / Esc / click-outside / auto-advance still dismiss it per load. */
1771
  var tries = 0;
 
399
  )
400
 
401
  CSS = """
402
+ /* CODA β€” premium dark-studio design system */
403
  @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600&display=swap');
404
 
405
  :root{
 
1016
  @media (prefers-reduced-motion: reduce){ .coda-drop .icon-wrap{ animation:none !important; } }
1017
 
1018
 
1019
+
 
 
 
 
 
1020
 
1021
  /* ===== FEATURE A β€” PLAY-ENERGIZED HERO ===== */
1022
  /* When the player reports it's playing, the JS adds .coda-eq-playing and the
 
1398
  "<div class='coda-glow'></div>"
1399
  f"<div class='coda-particles'>{_parts}</div>")
1400
 
1401
+ # Feature C β€” cinematic onboarding overlay. The 2016 story plays on
1402
  # EVERY page load. It is rendered with `coda-intro-on` BAKED IN, so the CSS beats
1403
  # start immediately on load WITHOUT waiting on (or even needing) JS β€” bulletproof
1404
  # against the head-injection issue that made it vanish on the Space. The
 
1490
  });
1491
 
1492
  /* ===== FEATURE A β€” AUDIO-REACTIVE HERO (real FFT via a shadow <audio>) =====
1493
+ * The hero bars dance with the finished track, driven by real FFT data.
1494
  *
1495
  * Verified live: Gradio's WaveSurfer plays from a DECODED BUFFER through its
1496
  * own Web Audio graph β€” its <audio> element never loads (readyState 0, no
 
1760
  host.setAttribute('aria-hidden', 'true'); host.remove();
1761
  } catch (e) {}
1762
  }
1763
+ /* Design choice: the 2016 intro replays on EVERY page load, not just the
1764
  * first. So there is NO localStorage "seen" gate β€” we always boot it.
1765
  * Skip / Esc / click-outside / auto-advance still dismiss it per load. */
1766
  var tries = 0;