From 4241dc1070ac10779cff6b6ea24d75a5b4a16a4f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 12 May 2026 22:57:56 +0100 Subject: [PATCH] Add runtime patch parameter doctrine --- docs/audio-doctrine.md | 12 ++++++ docs/reference-synth-roadmap.md | 65 ++++++++++++++++++++++++++++----- state/evidence.jsonl | 1 + state/memory.json | 5 +++ state/scratch.md | 6 ++- state/spine.yaml | 8 +++- 6 files changed, 84 insertions(+), 13 deletions(-) diff --git a/docs/audio-doctrine.md b/docs/audio-doctrine.md index 310dd99..46020a4 100644 --- a/docs/audio-doctrine.md +++ b/docs/audio-doctrine.md @@ -63,6 +63,9 @@ That separation is the model for this repo: - The DSL owns musical intent and graph construction. - The Faust emitter owns pure signal expression. - The engine owns scheduling, buffers, device I/O, threading, and presentation. +- Patch parameters are runtime controls, not compile-time constants. A compiled + DSP must be able to expose stable parameter paths so Aquarium can vary a sound + without recompiling the patch. - Host parameters should be smoothed where they cross into signal-rate behavior. Generated Faust should be stable, boring, and inspectable. Cleverness belongs in @@ -78,12 +81,17 @@ target in an ergonomic, visible way. Rules: - Every modulation target must have a stable semantic name. +- Every exposed parameter must declare a stable path, default, min, max, step, + unit or scale when meaningful, and whether it is safe to automate at control + rate. - Global controls and voice-local modulators should share target names. - Modulators need waveform, rate, depth, phase, and bias. - Buses are authoring conveniences; compiled patches should expose individual target lanes. - UI/control-rate movement should be smoothed before it becomes audible zipper noise. +- Recompilation is for graph shape changes. Parameter changes must flow through + the hosted DSP control API. ## Metrics @@ -114,6 +122,10 @@ but civilization has survived worse. - Faust architecture docs: a Faust program is pure DSP mapping inputs to outputs; architecture files connect that DSP to drivers and controllers. +- Faust UI controls: `hslider`, `vslider`, `nentry`, `button`, and `checkbox` + expose runtime controls; UI helper classes such as `MapUI` provide + `setParamValue`/`getParamValue` style access by path or short name. + - Faust signals library: buses, block termination, interpolation, repeat, and smoothing are first-class signal-composition tools; smooth control crossings instead of letting UI steps become audio artifacts. diff --git a/docs/reference-synth-roadmap.md b/docs/reference-synth-roadmap.md index 615d92c..f1e936b 100644 --- a/docs/reference-synth-roadmap.md +++ b/docs/reference-synth-roadmap.md @@ -23,6 +23,9 @@ because a field name seemed maybe useful at 2 AM. - Aquarium owns its patch graph. External synths are reference targets, not runtime dependencies. +- Expressive parameters are part of the patch contract. Callers must be able to + change exposed values at runtime through the hosted DSP parameter API instead + of recompiling the patch. - Reference importers must preserve source provenance, license status, and the source format hash. - Tests may compare against rendered fixtures, extracted parameter topology, or @@ -182,6 +185,7 @@ public sealed record ReferencePatch( string Name, ReferenceSource Source, IReadOnlyList Features, + IReadOnlyList Parameters, string? AquariumScript); public sealed record ReferenceSource( @@ -190,22 +194,63 @@ public sealed record ReferenceSource( string License, string Hash, string Notes); + +public sealed record PatchParameter( + string Path, + string Label, + float Default, + float Min, + float Max, + float Step, + string Unit, + string AutomationRate, + string Notes); ``` -This keeps source authority visible. A reference can be "known target, not yet -translated" without pretending it is an Aquarium patch. +This keeps source authority and runtime control authority visible. A reference +can be "known target, not yet translated" without pretending it is an Aquarium +patch, and an Aquarium patch can say which values callers may vary without +changing graph shape. + +## Runtime Parameter Surface + +Faust supports this directly through UI controls such as `hslider`, `vslider`, +`nentry`, `button`, and `checkbox`. Hosted DSP code can expose a parameter map +and update control zones with `setParamValue`/`getParamValue` style APIs, so +Aquarium should compile once for a graph shape and then push parameter values at +runtime. + +Aquarium DSL needs an explicit parameter declaration surface, likely separate +from modulation buses: + +```text +param name=brightness path=/macro/brightness default=0.45 min=0 max=1 step=0.001 +param name=strike path=/exciter/strike default=0.2 min=0 max=1 step=0.001 +``` + +Lowering rules: + +- Parameter paths must be stable across recompiles unless the script changes the + declared path. +- Parameters lower to Faust controls with the declared default, range, and step. +- Audio-sensitive parameters should be smoothed at the signal crossing. +- Modulators and exposed parameters may target the same semantic value, but the + combined authority must be explicit. +- Recompile only when the graph, routing, oscillator type, operator topology, or + other structural shape changes. ## Work Order -1. Create reference model contracts and tests. -2. Add DX7 SysEx parser and feature extraction. -3. Add two DX7-derived Aquarium DSL rebuilds. -4. Add audio fixture workflow for rendered references. -5. Add Zyn XML feature extraction. -6. Add Faust reference catalog entries and compile checks. -7. Reassess DSL shape: keep voice DSL, split lower-level graph DSL, or add +1. Create reference model contracts, parameter contracts, and tests. +2. Add explicit patch parameter declarations and Faust parameter emission. +3. Add DX7 SysEx parser and feature extraction. +4. Add two DX7-derived Aquarium DSL rebuilds with exposed macro controls. +5. Add audio fixture workflow for rendered references. +6. Add Zyn XML feature extraction. +7. Add Faust reference catalog entries and compile checks. +8. Reassess DSL shape: keep voice DSL, split lower-level graph DSL, or add explicit operator/routing sublanguage. -8. Only then touch Surge or Cardinal. +9. Only then touch Surge or Cardinal. ## Rejected Shortcuts diff --git a/state/evidence.jsonl b/state/evidence.jsonl index 741f752..23e3464 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -5,3 +5,4 @@ {"kind":"dsl_reference_corpus","lesson":"BFXR, SFXR, 808, FM, and wobble presets are reference patches for testing and DSL design, not terseness trophies. Built-ins should be readable enough to teach the patch language, and the parser should support multi-line commands instead of forcing all expressive patches into one-line golf.","source":"user clarified preset purpose for patch DSL iteration"} {"kind":"advanced_reference_patches","lesson":"The synth reference catalog needs complex examples that combine defaults, templates, multiple voices, modulation buses, FM, formants, noise layers, repeat, and soft clipping. These patches expose DSL readability and composition pressure better than short one-shot SFX presets.","source":"user asked for sophisticated patch references"} {"kind":"reference_synth_roadmap","lesson":"AquariumSynthCSharp should use external synth and DSP corpora as reference targets, not just internal demo patches. Start with DX7/Dexed SysEx for structured FM, then ZynAddSubFX, Faust examples/libraries, Surge XT, and Cardinal as progressively broader pressure tests. Keep provenance and license state explicit before vendoring fixtures.","source":"user clarified any synth can be broken down and rebuilt via Aquarium DSL"} +{"kind":"runtime_patch_parameters","lesson":"Synth patches must expose expressive runtime parameters. Faust supports this through UI controls and hosted parameter APIs, so Aquarium should compile a graph once and vary declared parameter values without recompilation. Recompile only for structural graph changes.","source":"user asked whether Faust can vary one number without recompiling"} diff --git a/state/memory.json b/state/memory.json index a5631e3..a9887aa 100644 --- a/state/memory.json +++ b/state/memory.json @@ -41,6 +41,11 @@ ], "rule": "Add DSL abstractions only when reference rebuilds prove the missing invariant." }, + "runtime_parameters": { + "rule": "Patch parameters are runtime controls, not compile-time constants.", + "faust_surface": "Faust UI controls expose parameter zones that hosts can update with setParamValue/getParamValue-style APIs.", + "aquarium_requirement": "Aquarium DSL patches must be able to declare stable exposed parameters with path/default/min/max/step metadata so callers can vary sound without recompiling." + }, "last_verified": { "command": "dotnet test", "result": "15 passed", diff --git a/state/scratch.md b/state/scratch.md index 4b2d617..9a0c538 100644 --- a/state/scratch.md +++ b/state/scratch.md @@ -5,8 +5,12 @@ targets, not through speculative field sprawl. `state/spine.yaml` and `docs/reference-synth-roadmap.md` are the handoff surfaces for agents working on the synth library while Aquarium work continues elsewhere. -The next likely slice is DX7/Dexed: +The next likely slice is parameter contracts, then DX7/Dexed: +- Add explicit patch parameter contracts: stable path, label, default, min, max, + step, unit/scale, and automation-rate notes. +- Update Faust emission so declared parameters become runtime controls instead + of baked constants. - Add neutral reference model contracts with provenance/license/hash fields. - Implement a DX7 SysEx parser skeleton for single voices and cartridge payloads. - Extract operator topology, envelopes, ratios, feedback, levels, LFO, and pitch diff --git a/state/spine.yaml b/state/spine.yaml index 4b4cc65..d9198b5 100644 --- a/state/spine.yaml +++ b/state/spine.yaml @@ -25,6 +25,8 @@ live_invariants: - Aquarium owns its patch graph; external synths are references, not runtime dependencies. - Patch scripts lower into explicit graph records before Faust emission. - Generated Faust should remain inspectable and deterministic. + - Exposed patch parameters are runtime controls, not compile-time constants. + - Recompile only for graph shape changes; vary declared parameters through the hosted DSP control API. - Reference fixtures must preserve provenance, license status, source hash, and feature pressure. - Audio metrics are evidence, not final judgment. - Do not add a generic graph escape hatch until specific references force it. @@ -72,8 +74,9 @@ reference_targets: next_agent_start_here: recommended_first_task: > - Implement reference model contracts and a DX7 SysEx parser skeleton with - feature extraction tests. Do not start by importing a giant bank. + Implement reference model and patch parameter contracts, then add a DX7 + SysEx parser skeleton with feature extraction tests. Do not start by + importing a giant bank. must_read: - AGENTS.md - docs/audio-doctrine.md @@ -88,4 +91,5 @@ cut_line: - "Cut any importer that cannot state source provenance and license." - "Cut weak tests that only prove parser leniency." - "Cut voice-field sprawl when a target needs topology." + - "Cut any design that requires recompiling a patch to move an exposed musical parameter." - "Split a lower-level graph DSL if Faust/Cardinal-style references make the voice DSL lie."