@wenathlan/debonair 2.0.94 → 2.0.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/docs/.gitkeep +0 -0
- package/docs/competitor-dissection.md +572 -0
- package/docs/enginemap.md +94 -0
- package/docs/planning.ladder.md +1107 -0
- package/docs/planning.v2.28-completo.md +69 -0
- package/docs/planning.versions.2.0.97-3.0.md +48 -0
- package/package.json +25 -1
- package/tests/.gitkeep +0 -0
- package/tests/analyze.test.ts +54 -0
- package/tests/arrangement.test.ts +109 -0
- package/tests/arranger.test.ts +116 -0
- package/tests/beatgrid.test.ts +0 -0
- package/tests/dawview.test.ts +104 -0
- package/tests/ducking.test.ts +0 -0
- package/tests/family.test.ts +80 -0
- package/tests/familyurl.test.ts +32 -0
- package/tests/fingerprint.test.ts +61 -0
- package/tests/genrematrix.test.ts +116 -0
- package/tests/harmonyengine.test.ts +204 -0
- package/tests/katexis.test.ts +97 -0
- package/tests/loudness.test.ts +0 -0
- package/tests/midiwriter.test.ts +183 -0
- package/tests/mixergraph.test.ts +0 -0
- package/tests/motionpref.test.ts +82 -0
- package/tests/musictheory.test.ts +231 -0
- package/tests/onboardingstate.test.ts +68 -0
- package/tests/pianoroll.test.ts +336 -0
- package/tests/remixplan.test.ts +0 -0
- package/tests/rhythmgrammar.test.ts +205 -0
- package/tests/solcss.test.ts +148 -0
- package/tests/spectrum.test.ts +59 -0
- package/tests/speechalign.test.ts +0 -0
- package/tests/stems.test.ts +127 -0
- package/tests/takeevents.test.ts +129 -0
- package/tests/takestore.test.ts +93 -0
- package/tests/timelinemodel.test.ts +0 -0
- package/tests/tuning.test.ts +27 -0
- package/tests/vocalsynth.test.ts +91 -0
- package/tests/wavwriter.test.ts +137 -0
package/README.md
CHANGED
|
@@ -8,9 +8,21 @@ Audio and DAW. Isolated marketing app for the operating system. Houses the katex
|
|
|
8
8
|
|
|
9
9
|
# Debonair Sol
|
|
10
10
|
|
|
11
|
-
Debonair is the audio workstation (DAW) of the DevThink family, running on the katexis engine. This Sol theme is the workstation's web surface — a Vite + React SPA whose library, generate, studio and settings routes drive
|
|
11
|
+
Debonair is the audio workstation (DAW) of the DevThink family, running on the katexis engine. This Sol theme is the workstation's web surface — a Vite + React SPA whose library, generate, studio and settings routes drive real engine plans (no mock anywhere: the studio plays the WebAudio transport of `Sol/studio/audioengine.ts` over the plans `arranger.ts` composes).
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
pnpm install
|
|
15
15
|
pnpm dev
|
|
16
16
|
```
|
|
17
|
+
|
|
18
|
+
## The contract (campaign 5-b)
|
|
19
|
+
|
|
20
|
+
- **test** — `pnpm test` runs `vitest run` over `tests/` (223+ cases across 20 files, node environment). `bun test` answers green on the same suite (bun aliases the vitest API).
|
|
21
|
+
- **typecheck** — `pnpm typecheck` (`tsc --noEmit`) must exit 0.
|
|
22
|
+
- **lint** — `npx biome check .` must answer 0 errors and 0 warnings.
|
|
23
|
+
- **restore:entry** — the vite build emits hashed bundles beside the sources and rewrites `index.html` to the hashed face. `pnpm restore:entry` restores the source face from HEAD, with two guards: it REFUSES (exit 1, nothing touched) while HEAD itself is not the source face (`script … App.tsx`), and it REFUSES while the HEAD face still carries the Google Fonts CDN link (the type triad self-hosts via `@fontsource`, imported by `App.tsx` — the face must never ride a font CDN again).
|
|
24
|
+
- **build hygiene** — `.gitignore` bars every hashed emit (`/index-*.js|css`, `/favicon-*.svg|png|ico`, `/manifest-*.webmanifest`, `/icon-*.png`, `/apple-touch-icon*.png`, `/registerSW-*.js`, `/sw.js`, `/*.woff2`); the pages workflow rebuilds per deploy, so only the canonical unhashed faces stay tracked. After a local build, run `pnpm restore:entry` to put `index.html` back on the source face. NEVER build twice without the source face back on disk: the build entry is the root `index.html`, so a second build over the hashed face compiles the previous emit (the double-hash signature — `favicon-XXXX-XXXX.svg` — the legacy tree carried).
|
|
25
|
+
|
|
26
|
+
## The family contract
|
|
27
|
+
|
|
28
|
+
The chrome links the sibling deploy units through `familyurl.ts` (the verbatim family body) over the one accent table of `family.ts` (spec §12) — the rail foot, the landing footer and `tests/family.test.ts` read the same table, so the row cannot drift.
|
package/docs/.gitkeep
CHANGED
|
File without changes
|
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
# Competitor Dissection — inputs for the kathesis engine
|
|
2
|
+
|
|
3
|
+
> Task K1. Read-only study of five competitor clones already downloaded to
|
|
4
|
+
> `allan/temp/`. Goal: extract concrete, importable logic (algorithms, data
|
|
5
|
+
> structures, render/export strategies, DAW-UI patterns) for the kathesis
|
|
6
|
+
> engines at the debonair root. Every claim carries a `file:line` reference
|
|
7
|
+
> against the clone as of this dissection. Nothing here was copied verbatim
|
|
8
|
+
> into the codebase — this document is the queue, not the implementation.
|
|
9
|
+
|
|
10
|
+
Sources dissected (with license, which gates what may be reused):
|
|
11
|
+
|
|
12
|
+
| Repo | What it is | License |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| `libsonare` | C++17 audio engine (analysis → mastering → mixing → MIDI → DAW runtime) shipped as WASM/Python/Node/C++ | Apache-2.0 |
|
|
15
|
+
| `pulsegridstudio` | Dependency-free browser DAW: one JS DSP module shared by AudioWorklet, export Worker and Node tests | MIT |
|
|
16
|
+
| `magenta-js` | TensorFlow.js music library (NoteSequence, quantization, melody/chord encodings, RNN/VAE models) | Apache-2.0 |
|
|
17
|
+
| `acestep.cpp` | GGML port of ACE-Step 1.5: prompt+lyrics → 48 kHz stereo music (LM + DiT + VAE) | MIT |
|
|
18
|
+
| `heartlib` | HeartMuLa family: 12.5 Hz music LM conditioned on tags+lyrics, HeartCodec tokenizer | Apache-2.0 |
|
|
19
|
+
|
|
20
|
+
kathesis baseline for comparison: pure-TS engines at the debonair root
|
|
21
|
+
(`musictheory`, `harmonyengine`, `rhythmgrammar`, `genrematrix`, `arranger`,
|
|
22
|
+
`takeevents`, `loudness` EBU R128, `ducking`, `mixergraph`, `speechalign`,
|
|
23
|
+
`beatgrid`, `remixplan`, `timelinemodel`, `playerbus`, `spectrum`
|
|
24
|
+
fft/hann/chroma, `fingerprint` landmarks, `analyze`, `vocalsynth` formants)
|
|
25
|
+
driven by the pipeline prompt+seed → planTake → scheduleTake → TakeEngine
|
|
26
|
+
(WebAudio 48 kHz).
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 1. libsonare — the analysis/mastering/mixing library
|
|
31
|
+
|
|
32
|
+
### What it is
|
|
33
|
+
|
|
34
|
+
A C++17 engine ("turns audio into data and data back into audio") with a C
|
|
35
|
+
API, WASM build for the browser, Python and Node bindings, plus a CLI
|
|
36
|
+
(`README.md:5-11`). ~95 named mastering processors, mixing scenes with buses
|
|
37
|
+
and sends, offline bounce of compiled timelines, realtime allocation-free
|
|
38
|
+
playback, analysis (BPM/key/chords/sections matching librosa defaults).
|
|
39
|
+
Zero GPL code, no model weights (`README.md:9-11`). The submodules that
|
|
40
|
+
matter to kathesis: `src/analysis/*`, `src/mastering/*`, `src/engine/*`,
|
|
41
|
+
`src/c_api/project_bounce.cpp`, `src/graph/*`.
|
|
42
|
+
|
|
43
|
+
### Pipeline
|
|
44
|
+
|
|
45
|
+
Analysis is a constellation of focused analyzers over one shared frontend:
|
|
46
|
+
`bpm_analyzer` (onset envelope → autocorrelation + Fourier tempogram),
|
|
47
|
+
`key_analyzer` (chroma × rotated key profiles), `chord_analyzer` (chroma
|
|
48
|
+
templates → **HMM Viterbi** decode), `section_analyzer` (section descriptors
|
|
49
|
+
→ self-similarity → repeats), plus meter/downbeat/timbre/melody analyzers
|
|
50
|
+
(`src/analysis/`, 24 files, ~9.5k lines). The master side is a named-processor
|
|
51
|
+
registry (`src/mastering/api/named_processor_registry.cpp`,
|
|
52
|
+
`insert_factory.cpp` 2.6k lines) whose parameters self-describe, surfaced
|
|
53
|
+
through a generated capability catalog (`tools/capability-catalog.json`,
|
|
54
|
+
top-level keys: `abi`, `chain`, `masteringPresets`, `presets`,
|
|
55
|
+
`processors`, `version`). The DAW side compiles a project into an
|
|
56
|
+
`arr::CompiledTimeline` and bounces it offline with instruments + mixer
|
|
57
|
+
(`src/c_api/project_bounce.cpp`).
|
|
58
|
+
|
|
59
|
+
### Concrete logics to import
|
|
60
|
+
|
|
61
|
+
1. **Cadence-graded chord HMM (Viterbi with beam).** Chord decoding as a
|
|
62
|
+
HMM where transition log-probabilities are graded by cadence strength —
|
|
63
|
+
`None/Weak/Full/Dominant` (V7→I with the tritone present outranks
|
|
64
|
+
plain V→I, which outranks weak-quality cadences, which are floored so a
|
|
65
|
+
weak cadence never scores below a related transition) — then a 2-row
|
|
66
|
+
Viterbi over beam-limited candidates with backpointers
|
|
67
|
+
(`src/analysis/chord_hmm.cpp:34-118`, floor at `:154-161`, Viterbi at
|
|
68
|
+
`:181-263`). This is the missing piece in `harmonyengine`'s chord
|
|
69
|
+
selection: kathesis currently picks chords by template/genre tables; the
|
|
70
|
+
cadence grading turns any such table into a progression-aware decoder.
|
|
71
|
+
2. **Swappable key profiles behind one rotation function.** Key detection
|
|
72
|
+
parameterized over Krumhansl-Schmuckler / Temperley / Shaath /
|
|
73
|
+
Bellman-Budge / Faraldo EDM profiles with a single
|
|
74
|
+
`rotate_profile(profile, semitones)` primitive
|
|
75
|
+
(`src/analysis/key_profiles.cpp:9-56`). `analyze.ts` currently hardcodes
|
|
76
|
+
one profile; making it a parameter costs one array-of-arrays and lets the
|
|
77
|
+
report state agreement across profiles as confidence.
|
|
78
|
+
3. **BPM: autocorrelation + parabolic peak refinement + Fourier tempogram
|
|
79
|
+
fallback.** FFT-based autocorrelation of the onset envelope, parabolic
|
|
80
|
+
interpolation of lag peaks, a librosa-compatible Fourier tempogram, and a
|
|
81
|
+
merge when either fails (`src/analysis/bpm_analyzer.cpp:244-283`,
|
|
82
|
+
`:319-353`, `:447-457`). Complements kathesis `beatgrid` onset-flux with
|
|
83
|
+
the tempogram path for fractional-BPM material.
|
|
84
|
+
4. **Section self-similarity with a confidence floor.** Build 12-chroma +
|
|
85
|
+
energy + vocal-likelihood descriptors per detected section, cosine
|
|
86
|
+
self-similarity matrix, count repeats per section, and *refuse to assert
|
|
87
|
+
a semantic label below a confidence floor* — emit the segment without the
|
|
88
|
+
label instead (`src/analysis/section_analyzer.cpp:513-529`,
|
|
89
|
+
floor at `:640-660`). Direct upgrade for `analyze.ts` structure and
|
|
90
|
+
`remixplan` arrangement proposals.
|
|
91
|
+
5. **Streaming loudness preview per platform.** For each platform table
|
|
92
|
+
entry (Spotify −14 LUFS/−1 dBTP, Apple Music −16/−1, YouTube −14/−1),
|
|
93
|
+
compute the normalization gain and a boolean ceiling-risk flag; the header
|
|
94
|
+
documents the BS.1770 channel-sum pitfall (a 0.5·(L+R) downmix reads ~6 dB
|
|
95
|
+
low on decorrelated stereo)
|
|
96
|
+
(`src/mastering/maximizer/streaming_preview.h:13-51`,
|
|
97
|
+
computation at `streaming_preview.cpp:14-29`). Trivially portable to
|
|
98
|
+
`loudness.ts` as a pure function — a natural "mastering targets" panel
|
|
99
|
+
for the debonair studio.
|
|
100
|
+
6. **Auto-derived bounce length + instrument tail probe.** Bounce end = max
|
|
101
|
+
over clips of `start+length` and last event frame; when the caller omits
|
|
102
|
+
the length, replay scheduled events through the instrument in render order
|
|
103
|
+
and ask it for its release tail (`materialize_tail_probe`), so MIDI-only
|
|
104
|
+
arrangements still include tails
|
|
105
|
+
(`src/c_api/project_bounce.cpp:46-68`, `:74-110`, contract note at
|
|
106
|
+
`:146-155`). Mirrors the kathesis need to compute take length + tail at
|
|
107
|
+
`scheduleTake`/export time instead of hardcoding a bar count.
|
|
108
|
+
7. **Coherent multichannel phase-vocoder stretch.** Bake time-stretch per
|
|
109
|
+
segment where all channels share a reference polarity aligned per bin by
|
|
110
|
+
correlation with channel 0 (anti-phase channels reinforce instead of
|
|
111
|
+
cancelling, `src/engine/tempo_sync.cpp:132-145`) and apply the reference
|
|
112
|
+
rotation `synthesis_phase − analysis_phase` to each channel's own analysis
|
|
113
|
+
phase, preserving inter-channel phase exactly
|
|
114
|
+
(`:174-186`); segment joins are smoothed by a crossfade anchored on the
|
|
115
|
+
first sample after the boundary (`:215-232`). This is the correct recipe
|
|
116
|
+
when `remixplan`/`beatgrid` need to warp imported audio to a tempo map.
|
|
117
|
+
8. **Self-describing parameter descriptors → generated UI.** Every processor
|
|
118
|
+
and synth engine declares its own parameters (range, default, unit,
|
|
119
|
+
display scale, cross-parameter bounds) and the host builds controls from
|
|
120
|
+
`capabilityCatalog()` instead of a hand-written table
|
|
121
|
+
(`README.md:39-41`; schema in `tools/capability-catalog.json`; enum shape
|
|
122
|
+
in `include/sonare/sonare_c_types_functions.h:190-333`). Pattern for
|
|
123
|
+
kathesis: one `paramDescriptors()` per engine feeding both the studio UI
|
|
124
|
+
and validation.
|
|
125
|
+
9. **Scene schema with role-resolved master.** Buses carry a `role` string
|
|
126
|
+
("master" wins over id "master" when resolving the output bus; scene
|
|
127
|
+
default role is "aux")
|
|
128
|
+
(`src/mixing/api/scene.h:132-141`, resolution in
|
|
129
|
+
`project_bounce.cpp:115-132`). A cleaner extension point than a hardcoded
|
|
130
|
+
master id in `mixergraph`.
|
|
131
|
+
10. **Serialization guardrails.** Bounce results are cleared before any
|
|
132
|
+
rejected call so a later query can never report diagnostics from a
|
|
133
|
+
bounce that never happened (`project_bounce.cpp:134-167`), and every
|
|
134
|
+
allocation is bounded by `checked_size_product` before it happens
|
|
135
|
+
(`tempo_sync.cpp:58-78`). Worth adopting as conventions in the
|
|
136
|
+
take/render path.
|
|
137
|
+
|
|
138
|
+
### What not to copy
|
|
139
|
+
|
|
140
|
+
- **`tools/gs/` (Roland GS tables, classic overlays, address censuses).**
|
|
141
|
+
The GS insertion-effect tables are reverse-engineered from Roland's
|
|
142
|
+
SC-88 material; GS is a Roland trademark. Study the *architecture* (SysEx
|
|
143
|
+
reception, two realisations of an insert), never ship the derived tables.
|
|
144
|
+
- **Brand and product chrome:** "sonare studio", libsonare docs/demos site,
|
|
145
|
+
audition harness, voice-match corpora (Bach excerpts).
|
|
146
|
+
- **Internal QA machinery** (`tools/parity/`, `tools/conformance/`,
|
|
147
|
+
`benchmarks/`, ABI tooling ~100 files): process scaffolding, not engine
|
|
148
|
+
logic; kathesis has its own gates.
|
|
149
|
+
- **Code as code:** Apache-2.0 permits use, but kathesis doctrine wants
|
|
150
|
+
pure-TS re-implementations; take the algorithms, write the TS, keep the
|
|
151
|
+
attribution note in the doc.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 2. pulsegridstudio — the dependency-free DAW
|
|
156
|
+
|
|
157
|
+
### What it is
|
|
158
|
+
|
|
159
|
+
A single-page DAW in plain JS (725 lines total): polyphonic synth, bass,
|
|
160
|
+
pluck, procedural drums, PCM sampler, TPT filter, saturation, tempo-synced
|
|
161
|
+
stereo delay, lookahead compressor, session/arrangement clips, piano roll,
|
|
162
|
+
volume automation, Web MIDI/keyboard overdub, IndexedDB autosave, and WAV
|
|
163
|
+
export — all sharing **one** DSP implementation used unchanged by the
|
|
164
|
+
AudioWorklet, the export Worker and Node tests (`README.md:5-9`,
|
|
165
|
+
`engine/dsp.js:1-4`). The layout is Ableton-inspired, explicitly declared as
|
|
166
|
+
independent (`README.md:11-12`).
|
|
167
|
+
|
|
168
|
+
### Pipeline
|
|
169
|
+
|
|
170
|
+
`AudioWorkletProcessor` owns a `PulseEngine` (worklet thread); the main
|
|
171
|
+
thread talks to it through a command port (`project`, `param`, `note`,
|
|
172
|
+
`launch`, `capture-*`) and receives one packed telemetry object at ~24 Hz
|
|
173
|
+
(`engine/worklet.js:37`). Export does **not** use `OfflineAudioContext`:
|
|
174
|
+
`renderProject` instantiates the same engine on a Worker and renders in
|
|
175
|
+
128-sample blocks, inserting a pause exactly at the musical endpoint so
|
|
176
|
+
releases/delay tails continue through the requested tail
|
|
177
|
+
(`engine/offline.js:14-21`), then `encodeWav` writes RIFF PCM 16/24-bit
|
|
178
|
+
(`engine/wav.js`).
|
|
179
|
+
|
|
180
|
+
### Concrete logics to import
|
|
181
|
+
|
|
182
|
+
1. **Offline render without OfflineAudioContext, with latency-prefix
|
|
183
|
+
discard.** Fixed 128-sample blocks; render total = musical frames +
|
|
184
|
+
tail + known internal latency; write each block at `dest = at +
|
|
185
|
+
i − maxLatency` so only the *known* latency prefix is discarded, never
|
|
186
|
+
musical signal; `engine.pause()` exactly at the musical endpoint to
|
|
187
|
+
carry release tails into the tail region
|
|
188
|
+
(`engine/offline.js:14-21`). This is the pattern for a kathesis
|
|
189
|
+
deterministic WAV export (Node/CI-safe, bit-comparable across block
|
|
190
|
+
sizes — they test exactly that).
|
|
191
|
+
2. **TakeEngine-grade scheduler details:**
|
|
192
|
+
- Clip launch quantization: a pending launch stores
|
|
193
|
+
`pendingBeat = ceil((beat + step/2) / quantum) * quantum` and flips at
|
|
194
|
+
a half-sample-resolution guard (`engine/dsp.js:57`, flip at `:62`).
|
|
195
|
+
- **Note chase on seek**: when a cursor jumps into the middle of a clip,
|
|
196
|
+
retrigger only notes still sounding at the seek position, with exact
|
|
197
|
+
remaining duration, restarting oscillator phase rather than faking
|
|
198
|
+
past DSP state (`engine/dsp.js:73-79`).
|
|
199
|
+
- Sorted-note cursor + half-step windows for event scheduling
|
|
200
|
+
(`engine/dsp.js:86`), loop detection by `cycle` + position regression
|
|
201
|
+
(`:70-73`).
|
|
202
|
+
These map 1:1 onto `takeevents.ts` schedule/seek fixes.
|
|
203
|
+
3. **Cross-track latency alignment.** Compressor look-aheads create
|
|
204
|
+
per-track latency; the engine computes `maxLatency` over all tracks and
|
|
205
|
+
gives every track `compensate = maxLatency − lookahead`, aligning all
|
|
206
|
+
tracks to the slowest (`engine/dsp.js:44`, delay lines at `:129-131`).
|
|
207
|
+
kathesis `playerbus` should apply the same rule when any node introduces
|
|
208
|
+
latency.
|
|
209
|
+
4. **Voice pool + steal-by-lowest-envelope.** Fixed 24 voices, steal the
|
|
210
|
+
quietest (`env` minimum) when full — no allocation in the render loop
|
|
211
|
+
(`engine/dsp.js:31`, `newVoice` at `:9`). Plus the **signature-diff
|
|
212
|
+
pattern**: musical data (clips/arrangement) is only re-sorted and
|
|
213
|
+
re-indexed when a JSON signature changes, while compact parameter
|
|
214
|
+
messages mutate coefficients in place (`:14-21`, `:45-52`).
|
|
215
|
+
5. **polyBLEP antialiasing in three lines.** `blep(t,dt)` correction applied
|
|
216
|
+
to square/saw only (`engine/dsp.js:7-8`) — good enough for a lightweight
|
|
217
|
+
oscillator upgrade in `vocalsynth`/`takeevents` synth voices.
|
|
218
|
+
6. **TPT SVF coefficients from a single `tan` call.** Topology-preserving
|
|
219
|
+
state-variable filter with `g = tan(π·fc/sr)`, `k = 1/Q`, stable at
|
|
220
|
+
audio rate, four state vars per channel (`engine/dsp.js:23-26`, tick at
|
|
221
|
+
`:125-126`) — a pure-TS filter kathesis can adopt for per-track cutoff.
|
|
222
|
+
7. **Master safety as bounded soft clip, plus smoothed faders + peak/RMS
|
|
223
|
+
telemetry.** `|x|>0.9 → sign·(0.9+0.1·tanh((|x|−0.9)·10))` — explicitly
|
|
224
|
+
"not a brickwall" (`engine/dsp.js:139-141`); per-sample 0.002-lerp toward
|
|
225
|
+
target volume/pan avoids zipper noise (`:132`); decaying peak/RMS meters
|
|
226
|
+
(`:135`) feed the UI. TakeEngine polish items.
|
|
227
|
+
8. **Live event ring buffer with drop accounting.** 512-slot pre-allocated
|
|
228
|
+
event ring; writer drops (and counts) when full; notes carry a
|
|
229
|
+
`contextFrame` translated into worklet time `engine.frame +
|
|
230
|
+
(contextFrame − currentFrame)` for latency-corrected live input
|
|
231
|
+
(`engine/dsp.js:42,59-60`, translation in `engine/worklet.js:27`).
|
|
232
|
+
9. **Capture block pool with transferable recycle.** 8 pre-allocated 8192-
|
|
233
|
+
frame stereo blocks; the worklet posts them zero-copy and the main thread
|
|
234
|
+
copies then returns the buffers via transfer list (`capture-return`)
|
|
235
|
+
(`engine/audio.js:21-23`, pool in `engine/worklet.js:5-7,39`).
|
|
236
|
+
Memory-stable recording without GC churn.
|
|
237
|
+
10. **Project validate-and-clamp loader + labeled undo history.**
|
|
238
|
+
`validateProject` throws on structural violations (version, ids unique,
|
|
239
|
+
counts, ranges) and *clamps* every numeric to an explicit ranges table
|
|
240
|
+
(`engine/model.js`, ranges at the `ranges={...}` literal), returning a
|
|
241
|
+
normalized object; `History` keeps ≤80 labeled whole-state snapshots for
|
|
242
|
+
undo/redo (`engine/model.js` `class History`). The `.pulse` container
|
|
243
|
+
serializes PCM as base64 with a 256 MB budget and per-sample finiteness
|
|
244
|
+
checks (`engine/storage.js` `serialize`/`deserialize`).
|
|
245
|
+
|
|
246
|
+
### What not to copy
|
|
247
|
+
|
|
248
|
+
- **Any Ableton Live reference in copy/UI claims** (`README.md:11-12` shows
|
|
249
|
+
their own disclaimer — kathesis ships its own FL-informed design and must
|
|
250
|
+
phrase inspiration the same way).
|
|
251
|
+
- **The demo song content** ("After Hours", clip names, note patterns in
|
|
252
|
+
`engine/model.js` `demoProject`) — someone's authored musical data.
|
|
253
|
+
- **WebGPU visual pipeline** (`engine/visual.js`) — outside kathesis scope
|
|
254
|
+
and duplicate of the Sol design system.
|
|
255
|
+
- **Brand bits**: the "Pulsegrid" name, `COLORS` palette, `.pulse` extension
|
|
256
|
+
(take the *validate-then-clamp* idea, not the format identity).
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 3. magenta-js — the interchange & encoding library
|
|
261
|
+
|
|
262
|
+
### What it is
|
|
263
|
+
|
|
264
|
+
Google's TensorFlow.js music library (`music/src`): the `NoteSequence`
|
|
265
|
+
proto as the central interchange schema, quantization utilities, melody and
|
|
266
|
+
chord encoders, conditioning controls, MIDI I/O, player/visualizer, and
|
|
267
|
+
model wrappers (MusicRNN, MusicVAE, CoConet, GANSynth, DDSP, Onsets &
|
|
268
|
+
Frames, Piano Genie, SPICE). License Apache-2.0. The parts relevant to
|
|
269
|
+
kathesis are the **pure data-structure** modules (`core/sequences.ts`,
|
|
270
|
+
`core/melodies.ts`, `core/chords.ts`, `core/constants.ts`,
|
|
271
|
+
`core/aux_inputs.ts`) — not the tfjs model stack.
|
|
272
|
+
|
|
273
|
+
### Pipeline
|
|
274
|
+
|
|
275
|
+
MIDI/audio in → `NoteSequence` (`music/src/protobuf`) →
|
|
276
|
+
`quantizeNoteSequence` (snap seconds→steps, validate single tempo /
|
|
277
|
+
power-of-2 time signature) → model-specific encodings (melody grid, chord
|
|
278
|
+
one-hots, drum pitch classes) → model → decode → player/visualizer. The
|
|
279
|
+
encoding layer is the reusable part: every model just consumes tensors
|
|
280
|
+
produced from the same quantized sequence.
|
|
281
|
+
|
|
282
|
+
### Concrete logics to import
|
|
283
|
+
|
|
284
|
+
1. **Quantize-to-step with an adjustable cutoff.**
|
|
285
|
+
`quantizeToStep(s, sps, cutoff=0.5) = floor(s·sps + (1−cutoff))` — the
|
|
286
|
+
cutoff is a *fraction of a step* that decides whether early notes round
|
|
287
|
+
up or down (`music/src/core/sequences.ts:27-36,101-106`). A quantize
|
|
288
|
+
knob for the debonair piano roll ("tight ↔ humanized") for free.
|
|
289
|
+
2. **Minimum-1-step note repair + negative-time rejection.** Quantized end
|
|
290
|
+
== quantized start → end+=1; negative times throw
|
|
291
|
+
(`sequences.ts:130-146`). Prevents zero-length note degeneracies kathesis
|
|
292
|
+
currently tolerates.
|
|
293
|
+
3. **Melody event-grid encoding.** `Int32Array` per step: `NO_EVENT(−1)`,
|
|
294
|
+
`NOTE_OFF(−2)`, else `pitch − minPitch + FIRST_PITCH`; built from a
|
|
295
|
+
sequence sorted by start then **pitch descending** so polyphony collapses
|
|
296
|
+
to the top voice when `ignorePolyphony`
|
|
297
|
+
(`music/src/core/melodies.ts:69-104`; constants `:1-55`). The canonical
|
|
298
|
+
compact form for `rhythmgrammar`/`arranger` leads.
|
|
299
|
+
4. **Conditioning controls: onset rhythm + Parsons contour.** `MelodyRhythm`
|
|
300
|
+
emits a depth-1 onset indicator; `MelodyShape` emits a depth-3
|
|
301
|
+
up/same/down one-hot Parsons contour that propagates the *first* direction
|
|
302
|
+
backwards through rests and continues the last direction to the end
|
|
303
|
+
(`melodies.ts:156-254`). Exactly the shape of control signal kathesis
|
|
304
|
+
needs to steer `arranger`/`rhythmgrammar` from a reference motif.
|
|
305
|
+
5. **Chord encoders with a NO_CHORD slot.** `MajorMinor` (1+2·12 one-hot),
|
|
306
|
+
`Triad` (1+4·12), `PitchChord` (root one-hot ⊕ pitch-class bitmap ⊕ bass
|
|
307
|
+
one-hot), all indexed by `quality·12 + root` with `N.C.` at 0
|
|
308
|
+
(`music/src/core/chords.ts:167-258`, quality from interval sets at
|
|
309
|
+
`:28-34`). Drop-in conditioning vocabulary for `harmonyengine` ↔
|
|
310
|
+
`genrematrix` handoffs.
|
|
311
|
+
6. **GM drum taxonomy as 9 pitch-class buckets.**
|
|
312
|
+
`DEFAULT_DRUM_PITCH_CLASSES` groups all GM drum notes into bass/snare/
|
|
313
|
+
closed-hat/open-hat/toms×3/crash/ride (`music/src/core/constants.ts:28-52`).
|
|
314
|
+
`rhythmgrammar` currently models kick/snare/hat only; this bucket table
|
|
315
|
+
covers arbitrary GM drums and maps neatly onto pulsegrid's procedural
|
|
316
|
+
drum ranges.
|
|
317
|
+
7. **Sustain-pedal CC64 → note extension, and consecutive-note merging.**
|
|
318
|
+
`applySustainControlChanges` folds pedal events into note lengths;
|
|
319
|
+
`mergeConsecutiveNotes` joins same-pitch neighbors
|
|
320
|
+
(`sequences.ts:578,504`). Both are needed before any quantized editing in
|
|
321
|
+
kathesis is honest about MIDI input.
|
|
322
|
+
8. **Sequence algebra: concatenate / trim / split-chunks.** Chunk a long
|
|
323
|
+
sequence into model-sized windows and reassemble, with relative-time
|
|
324
|
+
rewrites (`sequences.ts:743,788,873`). The pattern for chunked
|
|
325
|
+
generation of long takes.
|
|
326
|
+
9. **BinaryCounter auxiliary input.** A step counter encoded as −1/1 bits,
|
|
327
|
+
LSB first, as an auxiliary model input (`core/aux_inputs.ts:53-71`) — a
|
|
328
|
+
cheap positional feature for any step-conditioned generator in kathesis.
|
|
329
|
+
10. **Exception taxonomy per contract.** Dedicated error classes
|
|
330
|
+
(`MultipleTempoException`, `BadTimeSignatureException`,
|
|
331
|
+
`NegativeTimeException`, `QuantizationStatusException` —
|
|
332
|
+
`sequences.ts:38-74`) make failure modes part of the API surface;
|
|
333
|
+
mirrors how kathesis engines should throw typed errors.
|
|
334
|
+
|
|
335
|
+
### What not to copy
|
|
336
|
+
|
|
337
|
+
- **The TensorFlow.js dependency and all model wrappers**
|
|
338
|
+
(`music/src/music_vae`, `music_rnn`, `gansynth`, `ddsp`, `coconet`,
|
|
339
|
+
`transcription`, `piano_genie`, `spice`) + checkpoints: conflicts with
|
|
340
|
+
kathesis pure-TS doctrine, bundle budget, and the "no ML runtime" line
|
|
341
|
+
drawn in the engine docs; revisit only behind a worker/ONNX seam.
|
|
342
|
+
- **The protobuf stack** (`music/src/protobuf/proto.js` generated code):
|
|
343
|
+
replace with plain TS interfaces + the existing `takeevents` model.
|
|
344
|
+
- **tonal.js as a dependency** (used in `chords.ts:26`): kathesis'
|
|
345
|
+
`musictheory` already owns this; port the *encodings* only.
|
|
346
|
+
- **Demos, visualizer styling, brand** ("Magenta" name, demo HTMLs).
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## 4. acestep.cpp — prompt+lyrics → 48 kHz via GGML
|
|
351
|
+
|
|
352
|
+
### What it is
|
|
353
|
+
|
|
354
|
+
Portable C++17 GGML implementation of ACE-Step 1.5: Qwen3 text encoder +
|
|
355
|
+
Qwen3 LM (0.6B/1.7B/4B) that plans metadata + FSQ audio codes at 5 Hz, a
|
|
356
|
+
DiT (2B/4B) with flow-matching denoising at 25 Hz latents, and an
|
|
357
|
+
AutoencoderOobleck VAE decoding to stereo 48 kHz; HTTP server + browser UI
|
|
358
|
+
(`docs/ARCHITECTURE.md:1-9,38-58`). MIT licensed. Notable engineering: a
|
|
359
|
+
VRAM policy where exactly one GPU module is resident at a time
|
|
360
|
+
(`ARCHITECTURE.md:96-106`), GGUF bundling tokenizer+config (`:73-88`),
|
|
361
|
+
and cancel-aware generation.
|
|
362
|
+
|
|
363
|
+
### Pipeline
|
|
364
|
+
|
|
365
|
+
`AceRequest{caption, lyrics, bpm, duration, keyscale, timesignature,
|
|
366
|
+
vocal_language, seed, lm_*, inference_steps, guidance_scale, shift,
|
|
367
|
+
audio_cover_strength…}` (`src/request.h:11-64`) → prompt building + CoT
|
|
368
|
+
parsing (`src/prompt.h:14-55`) → **constrained decoding** of metadata
|
|
369
|
+
(PrefixTree + MetadataFSM) → LM emits audio codes (V=65536 compacted
|
|
370
|
+
sampling: temperature → top-k via `nth_element` → top-p nucleus →
|
|
371
|
+
multinomial; `src/sampling.h:14-60`) → FSQ codes → DiT context; DiT
|
|
372
|
+
denoises 25 Hz latents with APG guidance; VAE decodes tiled to 48 kHz
|
|
373
|
+
(`src/vae.h:456,561`).
|
|
374
|
+
|
|
375
|
+
### Concrete logics to import
|
|
376
|
+
|
|
377
|
+
1. **APG guidance for any cond/uncond generator.** Momentum-smoothed
|
|
378
|
+
difference `cond − uncond` (running average with momentum −0.75),
|
|
379
|
+
per-channel L2 norm clip to 2.5, decomposition into the component
|
|
380
|
+
parallel/orthogonal to the conditional prediction, and
|
|
381
|
+
`result = pred_cond + (scale−1)·orthogonal`
|
|
382
|
+
(`src/dit-sampler.h:21-123`; projection `:45-65`, forward `:74-123`).
|
|
383
|
+
This is a *portable* guidance improvement over plain CFG for the future
|
|
384
|
+
kathesis generation backend (only meaningful when a neural generator
|
|
385
|
+
lands, but the math is 80 lines).
|
|
386
|
+
2. **Batched CFG in one forward.** cond+uncond denoise in a single batched
|
|
387
|
+
forward pass, halving model compute per step; when memory-bound, two
|
|
388
|
+
forwards instead (`src/dit-sampler.h:170-171`). Same trick heartlib uses.
|
|
389
|
+
3. **Cover mode = timed context switching.** Generation can start from a
|
|
390
|
+
source context and switch to silence/text2music context after
|
|
391
|
+
`cover_steps`, with `audio_cover_strength` as the fraction of DiT steps
|
|
392
|
+
that keep source context (`src/dit-sampler.h:145-146,422-424`;
|
|
393
|
+
`src/request.h:64`). The conceptual skeleton for kathesis "remix/cover
|
|
394
|
+
from reference" (`remixplan`), even in a non-neural form: run N steps of
|
|
395
|
+
source-faithful planning then fade the planner to the target brief.
|
|
396
|
+
4. **Constrained decoding of structured metadata (PrefixTree FSM).** A
|
|
397
|
+
prefix tree of valid token sequences plus a state machine over
|
|
398
|
+
`bpm/duration/key:scale/time-signature/language` fields so an LM *cannot*
|
|
399
|
+
emit invalid YAML metadata (`src/metadata-fsm.h:10-58`). kathesis
|
|
400
|
+
`katexis.planTake` should validate/repair prompt→plan fields with the
|
|
401
|
+
same FSM mindset (enumerate legal field values, reject or repair).
|
|
402
|
+
5. **Compacted-logit sampling.** For code tokens, compact the vocab to the
|
|
403
|
+
legal subset (EOS + audio codes ≈65k) before top-k/top-p;
|
|
404
|
+
`nth_element` O(V) for top-k; sort only survivors for top-p
|
|
405
|
+
(`src/sampling.h:14-60`). Generalizes to "sample only from genre-legal
|
|
406
|
+
chords/scales" in any kathesis sampler.
|
|
407
|
+
6. **Pluggable solver registry with NFE accounting.** Solver interface with
|
|
408
|
+
`VelocityRecord` state, registry of euler/dpm/sde/stork with
|
|
409
|
+
`nfe`/order metadata and graceful fallback to euler on unknown names
|
|
410
|
+
(`src/solvers/solver-*.h`, dispatch+warning at
|
|
411
|
+
`src/dit-sampler.h:396-411`). The naming/structure to copy for any
|
|
412
|
+
step-wise kathesis generator ("solver" as strategy object, steps =
|
|
413
|
+
NFE).
|
|
414
|
+
7. **Philox seeded noise per sample.** Deterministic Philox counter-based
|
|
415
|
+
RNG for initial noise, seeds stored as int64 but consumed as low-32-bits
|
|
416
|
+
to match the reference (`src/philox.h`, `src/request.h:26-29`). Matches
|
|
417
|
+
kathesis mulberry32 determinism doctrine — Philox is the upgrade path if
|
|
418
|
+
array-level parallel noise is needed.
|
|
419
|
+
8. **Cancel callback threaded through generation.** `bool (*cancel)(void*)`
|
|
420
|
+
checked every step, with logged "Cancelled at step k/N"
|
|
421
|
+
(`src/dit-sampler.h:147-148,415-418`). kathesis take generation (which
|
|
422
|
+
can be slow) deserves the same first-class cancellation seam.
|
|
423
|
+
9. **Auto inference config per model tier.** `inference_steps 0 → auto
|
|
424
|
+
(turbo: 8, sft/base: 50)`, `guidance_scale 0 → auto`, `shift 0 → auto`
|
|
425
|
+
(`src/request.h:48-50`) — defaults resolved by model capability, so the
|
|
426
|
+
API surface stays minimal. Same idea for kathesis genre→quality
|
|
427
|
+
presets.
|
|
428
|
+
10. **Beat-frame hygiene at the request schema level.** `AceRequest` keeps
|
|
429
|
+
`duration`/`bpm` as *unset-able* (0/"" = unset) and lets the pipeline
|
|
430
|
+
derive them — the same unset-vs-explicit discipline kathesis plans
|
|
431
|
+
should adopt (`src/request.h:13-21`).
|
|
432
|
+
|
|
433
|
+
### What not to copy
|
|
434
|
+
|
|
435
|
+
- **Model weights/GGUFs** (HuggingFace `Serveurperso/ACE-Step-1.5-GGUF`),
|
|
436
|
+
the ACE-Step brand, and the browser UI chrome (screenshots in README).
|
|
437
|
+
- **The GGML/vendored tree** (`ggml/`, `vendor/`) — kathesis never ships a C
|
|
438
|
+
runtime.
|
|
439
|
+
- **Server plumbing** (`server.sh/cmd`, `model-store`, HTTP layer): the
|
|
440
|
+
debonair pipeline is in-app, not a local server product.
|
|
441
|
+
- License permits MIT reuse, but again: re-implement in TS where it lands.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## 5. heartlib — tags+lyrics music LM (HeartMuLa)
|
|
446
|
+
|
|
447
|
+
### What it is
|
|
448
|
+
|
|
449
|
+
Python/PyTorch package for the HeartMuLa family (Apache-2.0): HeartMuLa
|
|
450
|
+
music LM (llama3.2-torchtune backbones 300M→7B) over HeartCodec (12.5 Hz
|
|
451
|
+
causal codec, 48 kHz), conditioned on multilingual tags and lyrics; plus
|
|
452
|
+
HeartTranscriptor (whisper-tuned lyric transcription) and HeartCLAP
|
|
453
|
+
alignment (`README.md:13-21`). Their internal 7B is claimed Suno-adjacent
|
|
454
|
+
(`README.md:29-30`) — the direct architectural reference for what the
|
|
455
|
+
debonair "Suno-like" pipeline is really like under the hood.
|
|
456
|
+
|
|
457
|
+
### Pipeline
|
|
458
|
+
|
|
459
|
+
`HeartMuLaGenPipeline` (`src/heartlib/pipelines/music_generation.py`):
|
|
460
|
+
preprocess wraps tags in literal `<tag>…</tag>` tokens and adds BOS/EOS
|
|
461
|
+
(`:222-233`), builds a `[prompt_len, 8+1]` token matrix — one channel per
|
|
462
|
+
RVQ codebook plus a text channel — with the tags in the last channel and
|
|
463
|
+
the MUQ reference-embedding slot between tags and lyrics
|
|
464
|
+
(`:258-263`); CFG duplicates the batch with an unconditional mask
|
|
465
|
+
(`:268-282`). Forward: `generate_frame` per 80 ms frame with a KV-cached
|
|
466
|
+
backbone, top-k sampling, and per-frame EOS check against
|
|
467
|
+
`audio_eos_id` (`:297-353`); `max_audio_frames = ms // 80` caps length.
|
|
468
|
+
Postprocess: codec detokenize → save 48 kHz (`:355-359`). Lazy
|
|
469
|
+
load/unload purges CUDA cache between stages (`:171-198`).
|
|
470
|
+
|
|
471
|
+
The model core (`src/heartlib/heartmula/modeling_heartmula.py`): backbone
|
|
472
|
+
predicts codebook-0 token from the merged embedding sum; a small
|
|
473
|
+
**decoder LM** then predicts codebooks 1..8 conditioned on the backbone's
|
|
474
|
+
last hidden + c0 embedding (`generate_frame`, `:181-270`) — the MusicGen
|
|
475
|
+
two-stage RVQ pattern; CFG applies `uncond + (cond−uncond)·scale` on both
|
|
476
|
+
stages (`:226-231,255-262`). HeartCodec itself: SQ (single-quantizer,
|
|
477
|
+
causal) codec with Snake activations, downsample factors
|
|
478
|
+
`[3,4,4,4,5]` → 12.5 Hz, 8 codebooks @ 8192, plus a DiT/flow-matching
|
|
479
|
+
latent estimator in the same config
|
|
480
|
+
(`src/heartlib/heartcodec/configuration_heartcodec.py:6-55`,
|
|
481
|
+
`models/sq_codec.py`, `models/flow_matching.py:16-60`).
|
|
482
|
+
|
|
483
|
+
### Concrete logics to import
|
|
484
|
+
|
|
485
|
+
1. **The tags/lyrics prompt contract.** `<tag>…</tag>` + BOS/EOS framing
|
|
486
|
+
with a reserved embedding slot between tags and lyrics for a reference
|
|
487
|
+
audio embedding (`music_generation.py:222-263`) — this is, concretely,
|
|
488
|
+
the prompt grammar a Suno-like competitor uses; kathesis `planTake`
|
|
489
|
+
prompt schema should reserve the same three regions (style tags |
|
|
490
|
+
reference | lyrics) even before any neural consumer exists.
|
|
491
|
+
2. **80 ms frame quantum end-to-end.** 12.5 Hz codec ⇒ 80 ms per token
|
|
492
|
+
frame; generation length is `ms // 80` and every loop iterates a frame
|
|
493
|
+
(`music_generation.py:331-350`). kathesis `timelinemodel` benefits from
|
|
494
|
+
choosing one irreducible audio quantum for plans/schedules instead of
|
|
495
|
+
mixing seconds/frames/steps.
|
|
496
|
+
3. **Frame-level EOS stop check.** Stop the whole track when any codebook
|
|
497
|
+
emits `≥ audio_eos_id` (`:348-349`) — the stopping rule kathesis
|
|
498
|
+
generators lack today (takes run to a bar count instead of a musical
|
|
499
|
+
stop signal).
|
|
500
|
+
4. **Two-stage RVQ decoding split.** Big LM predicts coarse codebook 0;
|
|
501
|
+
small decoder fills remaining codebooks from the coarse hidden
|
|
502
|
+
(`modeling_heartmula.py:232-262`). As a *pure-TS analogy*: plan coarse
|
|
503
|
+
structure with the full engine, fill detail voices with a cheap
|
|
504
|
+
secondary pass reading only the coarse state — the layering kathesis
|
|
505
|
+
`arranger` → per-track voices should formalize.
|
|
506
|
+
5. **CFG via duplicated batch + learned unconditional embedding.** Where no
|
|
507
|
+
uncond text exists, a learned `unconditional_text_embedding` replaces
|
|
508
|
+
the condition under a boolean mask (`:196-229`) — portable to any
|
|
509
|
+
conditional kathesis generator (condition = plan; uncond = learned
|
|
510
|
+
null-plan vector).
|
|
511
|
+
6. **Preprocess/forward/postprocess pipeline shape with parameter
|
|
512
|
+
sanitization.** `_sanitize_parameters` splits kwargs into
|
|
513
|
+
preprocess/forward/postprocess groups with explicit defaults (cfg 1.5,
|
|
514
|
+
120 s cap, top-k 50) (`:200-211`) — the same three-phase contract the
|
|
515
|
+
kathesis take pipeline already wants; adopt the *defaults table*.
|
|
516
|
+
7. **Lazy load + stage-scoped unload.** Models load on first use and are
|
|
517
|
+
dropped (with cache purge) after their stage (`:114-198`) — the
|
|
518
|
+
memory-discipline analog for kathesis workers: load analysis or
|
|
519
|
+
synthesis resources per stage, never hold all engines live at once.
|
|
520
|
+
8. **Codec config as one file of numbers.** `HeartCodecConfig` enumerates
|
|
521
|
+
every rate that matters (48 kHz, 12.5 Hz latent, codebook size, down/
|
|
522
|
+
upsample factors) in one typed config (`configuration_heartcodec.py:6-55`)
|
|
523
|
+
— keep kathesis audio constants in one engine-level config object.
|
|
524
|
+
|
|
525
|
+
### What not to copy
|
|
526
|
+
|
|
527
|
+
- **Weights and HF checkpoints** (HeartMuLa-oss-3B, HeartCodec encoder) —
|
|
528
|
+
both out of bundle budget and license-adjacent concerns are nil (Apache)
|
|
529
|
+
but kathesis ships no model binaries.
|
|
530
|
+
- **`models/feature_extractors.py` frontend**: adapted from MusicFM
|
|
531
|
+
(ByteDance MIT notice at `:1-21`) and depends on Whisper/WavLM/torch
|
|
532
|
+
transformers — study, don't embed; keep attribution if ideas cross over.
|
|
533
|
+
- **Brand assets** (logo, Discord, demo page, "Suno-adjacent" marketing),
|
|
534
|
+
`assets/*.mp3`, MuLaCover weights.
|
|
535
|
+
- PyTorch/torchaudio dependency style: kathesis stays pure TS; the pipeline
|
|
536
|
+
*contract* is what gets imported.
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
## kathesis import queue (prioritized top 10)
|
|
541
|
+
|
|
542
|
+
Each item names the kathesis engine file at the debonair root that would
|
|
543
|
+
receive it. Order = value/effort for the current P1-P7 lineage (pure-TS,
|
|
544
|
+
48 kHz, deterministic).
|
|
545
|
+
|
|
546
|
+
| # | Logic (source) | Lands in |
|
|
547
|
+
| --- | --- | --- |
|
|
548
|
+
| 1 | Note chase on seek + launch quantization `pendingBeat = ceil((beat+step/2)/quantum)·quantum` (pulsegrid `dsp.js:57,62,73-86`) | `takeevents.ts` |
|
|
549
|
+
| 2 | Offline render block-loop without OfflineAudioContext: pause-at-musical-end, tail through releases, discard only known latency prefix; RIFF WAV 16/24-bit encoder (pulsegrid `offline.js:14-21`, `wav.js`) | `playerbus.ts` (+ export path in `takeevents.ts`) |
|
|
550
|
+
| 3 | Cadence-graded chord HMM (Viterbi + beam, Weak-floor rule) (libsonare `chord_hmm.cpp:34-118,143-166,181-263`) | `harmonyengine.ts` |
|
|
551
|
+
| 4 | Streaming loudness preview: platform table {Spotify −14/−1, Apple −16/−1, YouTube −14/−1} → gain + ceiling-risk flag (libsonare `streaming_preview.h:13-51`, `streaming_preview.cpp:14-29`) | `loudness.ts` |
|
|
552
|
+
| 5 | Quantize-to-step with cutoff + min-1-step repair + sustain-CC64 fold + consecutive-note merge (magenta `sequences.ts:27-36,101-157,504,578`) | `timelinemodel.ts` (quantize) + `takeevents.ts` |
|
|
553
|
+
| 6 | Melody event-grid (NO_EVENT/NOTE_OFF) + Parsons contour & onset-rhythm conditioning controls + GM drum pitch-class buckets (magenta `melodies.ts:69-104,156-254`, `constants.ts:28-52`) | `rhythmgrammar.ts` + `arranger.ts` |
|
|
554
|
+
| 7 | Section self-similarity labeling with confidence floor (libsonare `section_analyzer.cpp:513-529,640-660`) | `analyze.ts` |
|
|
555
|
+
| 8 | Cross-track latency alignment `compensate = maxLatency − lookahead` + fixed voice pool steal-by-lowest-env + signature-diff table rebuild (pulsegrid `dsp.js:14-21,31,44,45-52`) | `playerbus.ts` + `takeevents.ts` |
|
|
556
|
+
| 9 | Constrained metadata FSM / prefix tree for plan fields (unset-vs-explicit request schema) (acestep.cpp `metadata-fsm.h:10-58`, `request.h:13-64`) | `katexis.ts` (planTake) |
|
|
557
|
+
| 10 | TPT SVF coefficients from `tan` + polyBLEP oscillators + smoothed faders/pan + bounded tanh master guard (pulsegrid `dsp.js:7-8,23-26,125-141`) | `takeevents.ts` (TakeEngine voices) |
|
|
558
|
+
|
|
559
|
+
Runners-up (kept visible, not queued now): multichannel coherent phase
|
|
560
|
+
vococoder stretch + segment-join fades (libsonare `tempo_sync.cpp:132-232`)
|
|
561
|
+
→ future `spectrum.ts` stretch util for `remixplan`; APG guidance +
|
|
562
|
+
batched CFG (acestep.cpp `dit-sampler.h:21-123,170-171`) → future neural
|
|
563
|
+
generation seam; key-profile menu (libsonare `key_profiles.cpp:9-56`) →
|
|
564
|
+
`analyze.ts`; frame-level EOS stop + tags|reference|lyrics prompt grammar
|
|
565
|
+
(heartlib `music_generation.py:222-263,348-349`) → `katexis.ts`/future
|
|
566
|
+
generation; self-describing parameter descriptors (libsonare
|
|
567
|
+
`capability-catalog.json`) → all engines' UI seam.
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
*End of dissection. Written by the K1 agent; read-only study, no app code
|
|
572
|
+
touched.*
|