Rename project to AquaSynth
This commit is contained in:
parent
5c972443bc
commit
64d0a6bf4f
47 changed files with 516 additions and 515 deletions
10
AGENTS.md
10
AGENTS.md
|
|
@ -1,14 +1,14 @@
|
|||
# AquariumSynthCSharp Instructions
|
||||
# AquaSynth Instructions
|
||||
|
||||
## Purpose
|
||||
|
||||
AquariumSynthCSharp is the C# authoring and compiler front-end for Aquarium
|
||||
AquaSynth is the C# authoring and compiler front-end for AquaSynth
|
||||
synth patches. It owns patch graph models, terse patch scripting, SFXR-derived
|
||||
patch mapping, analysis/scoring tools, preset catalogs, and Faust source/code
|
||||
generation for the Aquarium/Vortice engine path.
|
||||
generation for the AquaSynth/Vortice engine path.
|
||||
|
||||
The Rust crate may remain a reference lab and audio renderer. This repo should
|
||||
not depend on the Rust branch for reusable authoring, analysis, preset, or Faust
|
||||
The AquaSynth-rs branch may remain a reference lab and audio renderer. This repo should
|
||||
not depend on AquaSynth-rs for reusable authoring, analysis, preset, or Faust
|
||||
compiler behavior.
|
||||
|
||||
## Persistent State
|
||||
|
|
|
|||
8
AquaSynth.slnx
Normal file
8
AquaSynth.slnx
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<Solution>
|
||||
<Folder Name="/src/">
|
||||
<Project Path="src/AquaSynth.Dsl/AquaSynth.Dsl.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/tests/">
|
||||
<Project Path="tests/AquaSynth.Dsl.Tests/AquaSynth.Dsl.Tests.csproj" />
|
||||
</Folder>
|
||||
</Solution>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<Solution>
|
||||
<Folder Name="/src/">
|
||||
<Project Path="src/AquariumSynth.Dsl/AquariumSynth.Dsl.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/tests/">
|
||||
<Project Path="tests/AquariumSynth.Dsl.Tests/AquariumSynth.Dsl.Tests.csproj" />
|
||||
</Folder>
|
||||
</Solution>
|
||||
28
README.md
28
README.md
|
|
@ -1,12 +1,12 @@
|
|||
# Aquarium Synth CSharp
|
||||
# AquaSynth
|
||||
|
||||
C# front-end for Aquarium Synth patch scripts. It parses the Aquarium patch DSL
|
||||
C# front-end for AquaSynth patch scripts. It parses the AquaSynth patch DSL
|
||||
into a serializable patch graph, emits Faust `.dsp`, and can ask an installed
|
||||
Faust compiler to generate backend code such as C#, C++, C, or Rust.
|
||||
|
||||
This repo is the C# bridge for Aquarium/Vortice-land. Rust remains the reference
|
||||
This repo is the C# bridge for AquaSynth/Vortice-land. Rust remains the reference
|
||||
lab; this project is the tool that lets the engine script Faust without dragging
|
||||
the Rust crate into the room by the ankle.
|
||||
the AquaSynth-rs crate into the room by the ankle.
|
||||
|
||||
## Run
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ dotnet test
|
|||
```
|
||||
|
||||
DX7 reference-render tests use `dexed-py` when a Python with `dexed` and
|
||||
`numpy` is available. Set `AQUARIUM_DX7_PYTHON` to that interpreter to force a
|
||||
`numpy` is available. Set `AQUASYNTH_DX7_PYTHON` to that interpreter to force a
|
||||
specific runtime; otherwise the tests skip the render path and still parse the
|
||||
vendored public-domain fixture.
|
||||
|
||||
|
|
@ -26,23 +26,23 @@ ZynAddSubFX is pinned as a GPL test/development reference under
|
|||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
That source is a parity oracle only. Aquarium does not ship Zyn code, link it
|
||||
from `AquariumSynth.Dsl`, or treat it as runtime machinery.
|
||||
That source is a parity oracle only. AquaSynth does not ship Zyn code, link it
|
||||
from `AquaSynth.Dsl`, or treat it as runtime machinery.
|
||||
|
||||
## Package Boundary
|
||||
|
||||
Aquarium consumes this library as a pinned `AquariumSynth.Dsl` NuGet package,
|
||||
not as a live project reference. Breaking synth-library work should happen here
|
||||
freely, then Aquarium should intentionally update only after a new package
|
||||
version is packed and tested.
|
||||
Downstream consumers should pin this library as an `AquaSynth.Dsl` NuGet
|
||||
package, not use it as a live project reference. Breaking synth-library work
|
||||
should happen here freely, then consumers should intentionally update only after
|
||||
a new package version is packed and tested.
|
||||
|
||||
```powershell
|
||||
dotnet pack src\AquariumSynth.Dsl\AquariumSynth.Dsl.csproj -c Release
|
||||
dotnet pack src\AquaSynth.Dsl\AquaSynth.Dsl.csproj -c Release
|
||||
```
|
||||
|
||||
The test suite verifies that development fixtures, Python render helpers,
|
||||
external reference synth sources, and SysEx banks do not ship in
|
||||
`AquariumSynth.Dsl.nupkg`.
|
||||
`AquaSynth.Dsl.nupkg`.
|
||||
|
||||
## Shape
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ external reference synth sources, and SysEx banks do not ship in
|
|||
references for testing and for judging whether the DSL can express useful
|
||||
sound designs cleanly.
|
||||
- `SfxrParams`, `PatchScriptScoring`, `AudioAnalyzer`, and `Presets` carry the
|
||||
reusable Rust-side analysis, scoring, SFXR, and preset tools.
|
||||
reusable AquaSynth-rs-side analysis, scoring, SFXR, and preset tools.
|
||||
|
||||
Faust `2.85.5` supports `-lang csharp`, so the intended hot path is:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Aquarium Synth Audio Doctrine
|
||||
# AquaSynth Audio Doctrine
|
||||
|
||||
## Mission
|
||||
|
||||
AquariumSynthCSharp is the authoring and compiler surface for Aquarium synth
|
||||
AquaSynth is the authoring and compiler surface for AquaSynth
|
||||
patches. It should let us sketch sound quickly, compile to Faust, inspect the
|
||||
graph, compare results, and hand stable contracts to the C#/Vortice side.
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ That separation is the model for this repo:
|
|||
- 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
|
||||
DSP must be able to expose stable parameter paths so AquaSynth can vary a sound
|
||||
without recompiling the patch.
|
||||
- Host parameters should be smoothed where they cross into signal-rate behavior.
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ authorities.
|
|||
as a general envelope field.
|
||||
- Host/MIDI note mode should expose stable note frequency and note gate controls
|
||||
that the engine can wire to MIDI note-on/note-off behavior.
|
||||
- Faust-managed polyphony is the preferred MIDI path. Aquarium should describe a
|
||||
- Faust-managed polyphony is the preferred MIDI path. AquaSynth should describe a
|
||||
single voice graph and emit Faust's standard `freq`, `gain`, and `gate`
|
||||
controls with `[midi:on][nvoices:n]` options, leaving MIDI decoding and voice
|
||||
allocation to Faust architectures unless a concrete target proves that
|
||||
|
|
@ -122,7 +122,7 @@ authorities.
|
|||
## Metrics
|
||||
|
||||
Analysis exists to catch regressions and support search, not to crown winners.
|
||||
Aquarium Faust output can be rendered through Faust-generated C# in authoring
|
||||
AquaSynth Faust output can be rendered through Faust-generated C# in authoring
|
||||
tests, which gives us candidate audio buffers without depending on the old Rust
|
||||
renderer. That is only half of parity: reference targets still need a real
|
||||
external render or a captured, lawful fixture before the comparison means
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Objective
|
||||
|
||||
Make DX7 reference rebuilds prove Aquarium can emulate the machine, not merely
|
||||
Make DX7 reference rebuilds prove AquaSynth can emulate the machine, not merely
|
||||
draw a similar operator graph. The hard `PRC SYNTH1` target showed the current
|
||||
DSL surface is expressive enough to describe the topology, but the importer
|
||||
math is still fake in the places that matter perceptually.
|
||||
|
|
@ -10,7 +10,7 @@ math is still fake in the places that matter perceptually.
|
|||
## Current Mechanism
|
||||
|
||||
- `dexed-py` renders lawful public-domain or project-authored DX7 references.
|
||||
- Aquarium renders candidate patches through Faust-generated C#.
|
||||
- AquaSynth renders candidate patches through Faust-generated C#.
|
||||
- Tests compare rendered audio with log-mel, envelope, duration, RMS,
|
||||
zero-crossing, centroid, and listening WAV artifacts.
|
||||
- `OperatorGraph` owns topology: operators, routes, carriers, feedback, and
|
||||
|
|
@ -33,11 +33,11 @@ math is still fake in the places that matter perceptually.
|
|||
- Render project-authored DX7 algorithm-32 patches with one audible carrier.
|
||||
- Sweep operator output levels.
|
||||
- Fit output level to linear carrier amplitude.
|
||||
- Verify Aquarium single-carrier renders match relative RMS.
|
||||
- Verify AquaSynth single-carrier renders match relative RMS.
|
||||
|
||||
2. **Two-operator modulation index**
|
||||
- Render a carrier plus one modulator across modulator output levels.
|
||||
- Fit DX7 output level to Aquarium route/index scaling using log-mel and
|
||||
- Fit DX7 output level to AquaSynth route/index scaling using log-mel and
|
||||
harmonic energy, not RMS.
|
||||
- Keep carrier amplitude fixed while calibrating modulation index.
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ math is still fake in the places that matter perceptually.
|
|||
- Fit feedback amount separately from route/index scaling.
|
||||
|
||||
4. **Ratio detune**
|
||||
- Lower DX7 ratio-mode detune into Aquarium operator ratios.
|
||||
- Lower DX7 ratio-mode detune into AquaSynth operator ratios.
|
||||
- Keep detune as frequency behavior, not a modulation or chorus feature.
|
||||
|
||||
5. **Algorithm output compensation**
|
||||
|
|
@ -70,14 +70,14 @@ math is still fake in the places that matter perceptually.
|
|||
unlike the current linear `env=rl` approximation.
|
||||
- Dexed's rendered audio does not hear that raw state directly. The operator
|
||||
path samples EG once per 64-sample block and linearly interpolates the
|
||||
applied gain across the block, so a DX7-capable Aquarium envelope must
|
||||
applied gain across the block, so a DX7-capable AquaSynth envelope must
|
||||
model both the rate/level state machine and its block-interpolated output.
|
||||
- Aquarium staged operator envelopes now support per-segment curves, e.g.
|
||||
- AquaSynth staged operator envelopes now support per-segment curves, e.g.
|
||||
`env=rl rates=.00145,.0508,.5268,.35 levels=2,.297,.0156,0 curves=lin,exp,exp,exp`.
|
||||
This is a general staged-contour feature, not a DX7-specific syntax escape.
|
||||
- `Dx7SysEx.ApproximateAppliedRateLevelEnvelope` lowers a DX7 EG into a
|
||||
curved staged contour by tracing Dexed-style block-interpolated applied
|
||||
gain and normalizing it against Aquarium's separate operator-output level.
|
||||
gain and normalizing it against AquaSynth's separate operator-output level.
|
||||
On `PRC SYNTH1`, this improves log-mel from `0.24476814` to `0.17186502`,
|
||||
envelope distance from `0.43700194` to `0.13057204`, and zero-crossing
|
||||
ratio from `0.7931764` to `0.7815517` while keeping RMS at unity.
|
||||
|
|
@ -117,11 +117,11 @@ math is still fake in the places that matter perceptually.
|
|||
envelope distance at `<= 0.14`, zero-crossing ratio in `0.8..1.11`, and
|
||||
score at `>= 0.6`.
|
||||
- `Piano Bass` exposed a real pitch bug: the candidate ignored the DX7 voice
|
||||
transpose byte, so `transpose=12` rendered one octave too high. Aquarium
|
||||
transpose byte, so `transpose=12` rendered one octave too high. AquaSynth
|
||||
now uses `Dx7SysEx.NoteFrequencyHz(midiNote, transpose)`, where `24` is
|
||||
neutral.
|
||||
- `ANLGSYN 1` exposed a second real pitch/frequency bug: DX7 fixed-frequency
|
||||
operators were being lowered as fake note ratios. Aquarium now maps fixed
|
||||
operators were being lowered as fake note ratios. AquaSynth now maps fixed
|
||||
operators through the Dexed log-frequency formula and divides the absolute
|
||||
Hz by the graph base frequency. This restores the low fixed-frequency
|
||||
carrier/modulation buzz for op1/op3 instead of flattening the voice into
|
||||
|
|
@ -129,13 +129,13 @@ math is still fake in the places that matter perceptually.
|
|||
- Community listening then exposed two note-dependent lowering gaps:
|
||||
operator key-scaling was computed against hardcoded MIDI note 60, and DX7
|
||||
operator rate scaling was parsed but not applied to the block-interpolated
|
||||
envelope trace. Aquarium now lowers both against the effective played
|
||||
envelope trace. AquaSynth now lowers both against the effective played
|
||||
MIDI note after voice transpose. This makes `RES SYNTH1` attack much
|
||||
closer and improves `Piano Bass` log-mel, with graph gain rebalanced to
|
||||
`0.72` for `Piano Bass`.
|
||||
- `ANLGSYN 1` also exposed that the previous max-feedback value was too tame
|
||||
for audible community patches. DX7 feedback value `7` now lowers to
|
||||
Aquarium feedback `2.2`, while feedback value `5` remains at `0.19` for
|
||||
AquaSynth feedback `2.2`, while feedback value `5` remains at `0.19` for
|
||||
the hard PRC target. The hotter value restores much more of the 1.2-5 kHz
|
||||
buzzing-harmonic band, with envelope/RMS still imperfect.
|
||||
- Listening then caught that the max-feedback candidate still lost punch
|
||||
|
|
@ -145,7 +145,7 @@ math is still fake in the places that matter perceptually.
|
|||
gates `ANLGSYN 1` with a sustained 2.5-5 kHz band-energy check so the
|
||||
old drifting version cannot pass by global log-mel score alone.
|
||||
- Later listening caught `ANLGSYN 1` and `RES SYNTH1` blowing out into a
|
||||
drone at the modulator peak. Until Aquarium has a more exact DX7 EG/output
|
||||
drone at the modulator peak. Until AquaSynth has a more exact DX7 EG/output
|
||||
model, algorithm-2 non-carrier applied envelopes cap only the first staged
|
||||
peak at `0.92`. This leaves `Piano Bass` unchanged, improves `RES SYNTH1`,
|
||||
and keeps `ANLGSYN 1` judged primarily by log-mel plus sustained high-band
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Migration Checklist
|
||||
|
||||
This repo is now the authoring-side home for Aquarium Synth patch scripts and
|
||||
Faust generation. The Rust crate remains useful as a reference lab, but the
|
||||
This repo is now the authoring-side home for AquaSynth patch scripts and
|
||||
Faust generation. The AquaSynth-rs crate remains useful as a reference lab, but the
|
||||
current C# surface should not depend on somebody remembering what got built
|
||||
there.
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ there.
|
|||
classic 808, FM bell, wobble bass, and advanced layered patches.
|
||||
- Abstract SFXR reference script using defaults and templates.
|
||||
- SFXR parameter presets, mutation, shorthand atoms, and SFXR-to-patch mapping.
|
||||
- Aquarium preset patches: pluck, heartbeat, voice, and SFXR named bridge.
|
||||
- AquaSynth preset patches: pluck, heartbeat, voice, and SFXR named bridge.
|
||||
- Patch script scoring: terse, readability, and balanced metrics.
|
||||
- Audio analysis and comparison: envelope, log-mel spectrogram, spectral
|
||||
features, distance metrics, and score.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# Reference Synth Roadmap
|
||||
|
||||
AquariumSynthCSharp needs external synthesis references for the same reason the
|
||||
AquaSynth needs external synthesis references for the same reason the
|
||||
SFXR path was useful: a real target prevents the DSL from becoming a pile of
|
||||
locally plausible knobs. The goal is not to clone every synth's internals. The
|
||||
goal is to use known engines and patch formats as pressure tests, then rebuild
|
||||
selected sounds through Aquarium's own graph until the missing abstractions are
|
||||
selected sounds through AquaSynth's own graph until the missing abstractions are
|
||||
obvious.
|
||||
|
||||
## Objective
|
||||
|
|
@ -13,18 +13,18 @@ Build a reference-driven synth library workflow:
|
|||
|
||||
- Parse or describe external synth patches as structured reference models.
|
||||
- Render references when legally and technically practical.
|
||||
- Rebuild selected references in Aquarium patch DSL.
|
||||
- Rebuild selected references in AquaSynth patch DSL.
|
||||
- Compare audio with analysis metrics and listening notes.
|
||||
- Promote only the abstractions that make repeated reference rebuilds simpler.
|
||||
- Reject reference targets we cannot turn into parity tests. Parsing a format is
|
||||
inventory; proving Aquarium can reproduce the behavior is the point.
|
||||
inventory; proving AquaSynth can reproduce the behavior is the point.
|
||||
|
||||
The DSL should grow because a reference target demanded a missing invariant, not
|
||||
because a field name seemed maybe useful at 2 AM.
|
||||
|
||||
## Live Invariants
|
||||
|
||||
- Aquarium owns its patch graph. External synths are reference targets, not
|
||||
- AquaSynth 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
|
||||
|
|
@ -32,10 +32,10 @@ runtime dependencies.
|
|||
- Reference importers must preserve source provenance, license status, and the
|
||||
source format hash.
|
||||
- Tests must compare against rendered fixtures, extracted parameter topology, or
|
||||
known structural expectations that prove Aquarium can express the same behavior.
|
||||
known structural expectations that prove AquaSynth can express the same behavior.
|
||||
Weak "it parsed" tests do not prove expressivity, and references without a
|
||||
credible parity test path should not be consumed.
|
||||
- Aquarium Faust output can be rendered through Faust-generated C# for candidate
|
||||
- AquaSynth Faust output can be rendered through Faust-generated C# for candidate
|
||||
audio comparison. Reference audio still needs a real source fixture or renderer;
|
||||
do not compare a rebuild only against itself and call that parity.
|
||||
- DX7 reference audio uses `dexed-py` when available, with public-domain SysEx
|
||||
|
|
@ -43,7 +43,7 @@ credible parity test path should not be consumed.
|
|||
package content.
|
||||
- ZynAddSubFX source is pinned under `external/zynaddsubfx` as GPL
|
||||
test/development material. It may be compiled or wrapped only for parity
|
||||
tests; Aquarium must not ship, link, or runtime-depend on it.
|
||||
tests; AquaSynth must not ship, link, or runtime-depend on it.
|
||||
- Do not add a generic graph escape hatch until a specific family of references
|
||||
forces it.
|
||||
- When a reference target exceeds the current voice-centric DSL, document the
|
||||
|
|
@ -62,7 +62,7 @@ the Yamaha DX7 and accepts SysEx cartridge data. Its `msfa` synth engine remains
|
|||
Apache-2.0, which may matter if we use code as a reference rather than only
|
||||
format notes.
|
||||
|
||||
Pressure on Aquarium DSL:
|
||||
Pressure on AquaSynth DSL:
|
||||
|
||||
- Operator graph representation.
|
||||
- Multi-stage envelopes beyond ADSR.
|
||||
|
|
@ -76,9 +76,9 @@ First deliverable:
|
|||
- Add a `Dx7SysEx` parser for single voice and cartridge payloads.
|
||||
- Convert one or two public-domain or project-authored DX7-style voices into
|
||||
`ReferencePatch` records.
|
||||
- Build an Aquarium DSL approximation using explicit FM templates.
|
||||
- Build an AquaSynth DSL approximation using explicit FM templates.
|
||||
- Add mel/envelope/spectral comparison against rendered Dexed output from the
|
||||
public-domain fixture. Aquarium candidate rendering and `dexed-py` reference
|
||||
public-domain fixture. AquaSynth candidate rendering and `dexed-py` reference
|
||||
rendering exist, and `analog1.syx` voice 13 has the first thresholded parity
|
||||
rebuild. The next pressure is a harder voice that actually needs audible
|
||||
operator routing rather than a sine-like behavioral match. Staged operator
|
||||
|
|
@ -103,7 +103,7 @@ synthesis engines. It ships a large instrument library and exposes formant
|
|||
filters, state-variable filters, free envelope shapes, layered kits, modulation,
|
||||
and effects routing.
|
||||
|
||||
Pressure on Aquarium DSL:
|
||||
Pressure on AquaSynth DSL:
|
||||
|
||||
- Additive harmonic banks.
|
||||
- Non-ADSR envelope curves.
|
||||
|
|
@ -131,7 +131,7 @@ First deliverable:
|
|||
|
||||
The upstream ZynAddSubFX engine source is pinned as `external/zynaddsubfx`
|
||||
for parity tests, currently at `3ab608c432996ba4d582176572c0b0f82328c825`.
|
||||
That checkout is GPL reference machinery, not Aquarium implementation. Do not
|
||||
That checkout is GPL reference machinery, not AquaSynth implementation. Do not
|
||||
vendor the upstream Zyn instrument-bank submodule until its preset
|
||||
license/provenance is explicit enough for this repo. Use project-authored
|
||||
fixtures for parser shape and only promote external fixtures with clean source
|
||||
|
|
@ -144,7 +144,7 @@ PAD, additive banks, or formant motion.
|
|||
|
||||
The first language-golf response is `layer`: a named layer declaration owns
|
||||
engine tags, optional MIDI key range metadata, default gain, and an effect-send
|
||||
label while lowering to ordinary Aquarium voices. It is intentionally only an
|
||||
label while lowering to ordinary AquaSynth voices. It is intentionally only an
|
||||
ownership/routing scaffold for now; it does not add PAD synthesis, free
|
||||
envelopes, or effect buses by stealth.
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ PAD engine parity across all harmonic profiles, randomness controls, or
|
|||
multi-table pitch-zone behavior. `root`, `spread`, and `partials` are
|
||||
authoring-time table shape, not runtime controls.
|
||||
|
||||
The canonical Aquarium spelling for richer spectral-table shaping is neutral:
|
||||
The canonical AquaSynth spelling for richer spectral-table shaping is neutral:
|
||||
`pad_mode`, `pad_bandwidth`, `pad_bwscale`, `pad_profile`, and `pad_position`.
|
||||
The Zyn importer may populate those fields from Zyn's PAD controls, and the
|
||||
parser still accepts older `zyn_*` names in generated parity artifacts, but
|
||||
|
|
@ -204,7 +204,7 @@ repo contains categorized examples, and the standard libraries include
|
|||
oscillators, filters, delays, reverbs, physical models, DX7, virtual analog
|
||||
effects, wave-digital models, spatialization, and more.
|
||||
|
||||
Pressure on Aquarium DSL:
|
||||
Pressure on AquaSynth DSL:
|
||||
|
||||
- General signal graph expression.
|
||||
- Multichannel routing.
|
||||
|
|
@ -219,7 +219,7 @@ First deliverable:
|
|||
license/provenance, graph family, and expected compile behavior.
|
||||
- Select small fixtures from official examples first: comb string, additive
|
||||
drum, stereo reverb, physical model, WDF filter.
|
||||
- Use Faust references to decide whether Aquarium needs a lower-level graph DSL
|
||||
- Use Faust references to decide whether AquaSynth needs a lower-level graph DSL
|
||||
beneath the current instrument patch surface.
|
||||
|
||||
Sources:
|
||||
|
|
@ -235,7 +235,7 @@ Sources:
|
|||
Surge XT is a modern GPL-3.0 hybrid synth with a large real-world patch corpus.
|
||||
It is a strong long-term target, but it is too broad for the first import pass.
|
||||
|
||||
Pressure on Aquarium DSL:
|
||||
Pressure on AquaSynth DSL:
|
||||
|
||||
- Multi-scene patch structure.
|
||||
- Multiple oscillator algorithms.
|
||||
|
|
@ -256,10 +256,10 @@ Source: [Surge XT](https://github.com/surge-synthesizer/surge)
|
|||
### Tier 5: Cardinal/VCV-Style Modular Patches
|
||||
|
||||
Cardinal is a GPL-3.0 self-contained open-source modular synth based on VCV Rack
|
||||
code. It is the right target once Aquarium needs to prove arbitrary modular graph
|
||||
code. It is the right target once AquaSynth needs to prove arbitrary modular graph
|
||||
expression.
|
||||
|
||||
Pressure on Aquarium DSL:
|
||||
Pressure on AquaSynth DSL:
|
||||
|
||||
- Module graph representation.
|
||||
- Cables as first-class edges.
|
||||
|
|
@ -288,7 +288,7 @@ public sealed record ReferencePatch(
|
|||
ReferenceSource Source,
|
||||
IReadOnlyList<ReferenceFeature> Features,
|
||||
IReadOnlyList<PatchParameter> Parameters,
|
||||
string? AquariumScript);
|
||||
string? AquaSynthScript);
|
||||
|
||||
public sealed record ReferenceSource(
|
||||
string Kind,
|
||||
|
|
@ -310,8 +310,8 @@ public sealed record PatchParameter(
|
|||
```
|
||||
|
||||
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
|
||||
can be "known target, not yet translated" without pretending it is an AquaSynth
|
||||
patch, and an AquaSynth patch can say which values callers may vary without
|
||||
changing graph shape.
|
||||
|
||||
## Runtime Parameter Surface
|
||||
|
|
@ -319,10 +319,10 @@ changing graph shape.
|
|||
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
|
||||
AquaSynth should compile once for a graph shape and then push parameter values at
|
||||
runtime.
|
||||
|
||||
Aquarium DSL needs an explicit parameter declaration surface, likely separate
|
||||
AquaSynth DSL needs an explicit parameter declaration surface, likely separate
|
||||
from modulation buses:
|
||||
|
||||
```text
|
||||
|
|
@ -346,7 +346,7 @@ Lowering rules:
|
|||
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.
|
||||
4. Add two DX7-derived AquaSynth 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.
|
||||
|
|
@ -361,7 +361,7 @@ Lowering rules:
|
|||
of fields.
|
||||
- Do not compare only parse success. That proves the parser is lenient, not that
|
||||
the DSL can express the sound.
|
||||
- Do not use Faust as a hidden escape hatch for Aquarium patches. If a reference
|
||||
- Do not use Faust as a hidden escape hatch for AquaSynth patches. If a reference
|
||||
requires raw Faust, the DSL is missing an abstraction or the reference belongs
|
||||
in a lower-level graph layer.
|
||||
|
||||
|
|
@ -370,5 +370,5 @@ Lowering rules:
|
|||
- A new agent can pick one target family and know where to start.
|
||||
- Every reference fixture says what feature pressure it applies.
|
||||
- The DSL roadmap is driven by reference failures, not taste fumes.
|
||||
- Aquarium can keep using readable reference patches while the synth library
|
||||
- AquaSynth can keep using readable reference patches while the synth library
|
||||
grows toward serious DSP graph expression.
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
## Objective
|
||||
|
||||
Find the ZynAddSubFX instruments most likely to break Aquarium's current patch
|
||||
Find the ZynAddSubFX instruments most likely to break AquaSynth's current patch
|
||||
language before spending time on syntax polish.
|
||||
|
||||
This is a feature-pressure survey, not an audio parity claim. The upstream Zyn
|
||||
instrument bank is GPL reference feedstock through the pinned Zyn submodule
|
||||
tree. It is development/test material only: useful for reports, parity renders,
|
||||
and pressure selection, never package content or Aquarium patch-library stock.
|
||||
and pressure selection, never package content or AquaSynth patch-library stock.
|
||||
|
||||
## Source Checked
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ GPL PAD batch through the real Zyn oracle when the renderer is built:
|
|||
Each render lands in a per-synth timestamped folder under
|
||||
`artifacts/parity/zyn-upstream-pad-fixtures/`, with Zyn reference WAVs, source
|
||||
table WAVs, `report.txt`, and `candidate.aqua`. The candidate is now generated
|
||||
per preset by `ZynInstrumentReader.RebuildFirstPadAsAquariumScript`: first
|
||||
per preset by `ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript`: first
|
||||
enabled PAD kit item, OSCIL harmonic magnitudes, oracle-reported table
|
||||
basefreq, and basic volume/envelope scaffolding. The report names missing
|
||||
semantics such as Zyn harmonic profile shaping, bandwidth/profile behavior, and
|
||||
|
|
@ -62,7 +62,7 @@ library candidates.
|
|||
|
||||
## Pressure Conclusions
|
||||
|
||||
- **Named layers are real.** Anonymous Aquarium voices can sketch small Zyn
|
||||
- **Named layers are real.** Anonymous AquaSynth voices can sketch small Zyn
|
||||
layers, but drum kits and clonewheel-style instruments need stable layer names,
|
||||
key ranges, engine identity, and per-layer routing.
|
||||
- **Free envelopes are not optional forever.** Zyn's worst cases use dozens of
|
||||
|
|
@ -86,7 +86,7 @@ next abstractions risk becoming loose fields on anonymous voices.
|
|||
|
||||
## First Responses
|
||||
|
||||
Aquarium now has a minimal `layer` command:
|
||||
AquaSynth now has a minimal `layer` command:
|
||||
|
||||
```text
|
||||
layer name=pad_low engine=pad min_key=36 max_key=84 gain=.07
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# Aquarium Patch Library
|
||||
# AquaSynth Patch Library
|
||||
|
||||
This folder is the development patch library for Aquarium `.aqua` scripts. It is where reusable stock, reference rebuilds, calibration probes, and inspiration patches live as files instead of being trapped inside C# string constants or ignored render artifacts.
|
||||
This folder is the development patch library for AquaSynth `.aqua` scripts. It is where reusable stock, reference rebuilds, calibration probes, and inspiration patches live as files instead of being trapped inside C# string constants or ignored render artifacts.
|
||||
|
||||
The library is intentionally outside `src/` and is not part of the shipped `AquariumSynth.Dsl` NuGet package. Treat it as repo-owned source material for future synth consumers, examples, and parity work.
|
||||
The library is intentionally outside `src/` and is not part of the shipped `AquaSynth.Dsl` NuGet package. Treat it as repo-owned source material for future synth consumers, examples, and parity work.
|
||||
|
||||
## Layout
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
version: 1
|
||||
purpose: Development patch library for Aquarium DSL examples, parity rebuilds, and stock inspiration.
|
||||
package_boundary: Not included in AquariumSynth.Dsl.nupkg unless explicitly promoted later.
|
||||
version: 1
|
||||
purpose: Development patch library for AquaSynth DSL examples, parity rebuilds, and stock inspiration.
|
||||
package_boundary: Not included in AquaSynth.Dsl.nupkg unless explicitly promoted later.
|
||||
entries:
|
||||
- path: patches/808/clap.aqua
|
||||
family: 808
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageId>AquariumSynth.Dsl</PackageId>
|
||||
<Version>0.1.0-aquarium.1</Version>
|
||||
<PackageId>AquaSynth.Dsl</PackageId>
|
||||
<Version>0.1.0-aquasynth.1</Version>
|
||||
<Authors>GameCult</Authors>
|
||||
<Company>GameCult</Company>
|
||||
<Description>Aquarium synth patch DSL model, parser, analysis helpers, and Faust source emitter.</Description>
|
||||
<Description>AquaSynth patch DSL model, parser, analysis helpers, and Faust source emitter.</Description>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/GameCult/AquariumSynthCSharp</RepositoryUrl>
|
||||
<RepositoryUrl>https://github.com/GameCult/AquaSynth</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Numerics;
|
||||
|
||||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public sealed record AudioAnalysisConfig(
|
||||
float SampleRate = 44100,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public static class BuiltInScripts
|
||||
{
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Security.Cryptography;
|
||||
|
||||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public enum Dx7FrequencyMode
|
||||
{
|
||||
|
|
@ -316,7 +316,7 @@ public static class Dx7SysEx
|
|||
return new Dx7RateLevelEnvelopeApproximation(
|
||||
new RateLevelEnvelope(r1, l1, r2, l2, r3, l3, r4, l4),
|
||||
Math.Max(r1 + r2 + r3, 0.02f),
|
||||
"Approximation: DX7 EG uses four rate/level segments; Aquarium staged envelopes preserve the intermediate target levels.");
|
||||
"Approximation: DX7 EG uses four rate/level segments; AquaSynth staged envelopes preserve the intermediate target levels.");
|
||||
}
|
||||
|
||||
public static Dx7RateLevelEnvelopeApproximation ApproximateAppliedRateLevelEnvelope(
|
||||
|
|
@ -359,7 +359,7 @@ public static class Dx7SysEx
|
|||
RateLevelCurve.Exponential,
|
||||
RateLevelCurve.Exponential),
|
||||
gateSeconds,
|
||||
"Approximation: DX7 applied EG gain sampled per 64-sample block and normalized for Aquarium operator-level scaling.");
|
||||
"Approximation: DX7 applied EG gain sampled per 64-sample block and normalized for AquaSynth operator-level scaling.");
|
||||
}
|
||||
|
||||
public static IReadOnlyList<Dx7EnvelopeTracePoint> TraceEnvelope(
|
||||
|
|
@ -2,9 +2,9 @@ using System.Diagnostics;
|
|||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public sealed record FaustExportOptions(string Name = "aquarium_patch", bool Stereo = false);
|
||||
public sealed record FaustExportOptions(string Name = "aquasynth_patch", bool Stereo = false);
|
||||
|
||||
public sealed record FaustExport(string Source, IReadOnlyList<string> Warnings);
|
||||
|
||||
|
|
@ -655,7 +655,7 @@ public static class FaustCompiler
|
|||
faustPath ??= FindFaust();
|
||||
if (faustPath is null) return null;
|
||||
|
||||
var sourcePath = Path.Combine(Path.GetTempPath(), $"aquarium-synth-{Guid.NewGuid():N}.dsp");
|
||||
var sourcePath = Path.Combine(Path.GetTempPath(), $"aquasynth-{Guid.NewGuid():N}.dsp");
|
||||
await File.WriteAllTextAsync(sourcePath, source, cancellationToken);
|
||||
try
|
||||
{
|
||||
|
|
@ -691,7 +691,7 @@ public static class FaustCompiler
|
|||
if (faustPath is null) return null;
|
||||
|
||||
var frames = Math.Max(1, (int)MathF.Round(options.SampleRate * Math.Max(options.DurationSeconds, 1f / options.SampleRate)));
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), $"aquarium-synth-render-{Guid.NewGuid():N}");
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), $"aquasynth-render-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(tempDir);
|
||||
try
|
||||
{
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public enum Waveform
|
||||
{
|
||||
|
|
@ -309,7 +309,7 @@ public sealed record ReferencePatch(
|
|||
ReferenceSource Source,
|
||||
IReadOnlyList<ReferenceFeature> Features,
|
||||
IReadOnlyList<PatchParameter> Parameters,
|
||||
string? AquariumScript = null);
|
||||
string? AquaSynthScript = null);
|
||||
|
||||
public sealed record Repeat(float IntervalSeconds);
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Numerics;
|
||||
|
||||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
internal static class PadSynthWaveform
|
||||
{
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Globalization;
|
||||
|
||||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public sealed class PatchScriptException(int line, string message) : Exception($"line {line}: {message}")
|
||||
{
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
internal readonly record struct PatchScriptStatement(string Text, int Line);
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public static class Presets
|
||||
{
|
||||
public static SynthPatch AquariumPluck()
|
||||
public static SynthPatch AquaSynthPluck()
|
||||
{
|
||||
var envelope = new Envelope(0.002f, 0, 0.7246377f, 0.43f);
|
||||
return new SynthPatch
|
||||
|
|
@ -18,7 +18,7 @@ public static class Presets
|
|||
};
|
||||
}
|
||||
|
||||
public static SynthPatch AquariumHeartbeat()
|
||||
public static SynthPatch AquaSynthHeartbeat()
|
||||
{
|
||||
var envelope = new Envelope(0.004f, 0, 0.617284f, 0.2f);
|
||||
return new SynthPatch
|
||||
|
|
@ -33,7 +33,7 @@ public static class Presets
|
|||
};
|
||||
}
|
||||
|
||||
public static SynthPatch AquariumVoice()
|
||||
public static SynthPatch AquaSynthVoice()
|
||||
{
|
||||
var voice = Simple(new Oscillator(Waveform.Triangle, 220), new Envelope(0.018f, 0, 0.9259259f, 0.28f), 0.34f, 0.1944f) with
|
||||
{
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public sealed record ReferenceRebuild(
|
||||
string Id,
|
||||
|
|
@ -15,7 +15,7 @@ public static class ReferenceRebuildCatalog
|
|||
public static readonly IReadOnlyList<ReferenceRebuild> ZynRebuilds =
|
||||
[
|
||||
new(
|
||||
"zyn/project-additive-lead/aquarium",
|
||||
"zyn/project-additive-lead/aquasynth",
|
||||
"zynaddsubfx",
|
||||
"Project additive lead",
|
||||
"zyn/project/additive-lead",
|
||||
|
|
@ -24,17 +24,17 @@ public static class ReferenceRebuildCatalog
|
|||
new("engine_add", "1", "Represented as additive sine partials under named layer authority."),
|
||||
new("named_layers", "body,shine", "Layer declarations group partial voices under reusable ADD engine intent."),
|
||||
new("additive_harmonic_bank", "2 banks / 4 partials", "Harmonic-bank syntax records authored ADD partial sets before lowering to ordinary voices."),
|
||||
new("partial_voice_count", "4", "The additive shape lowers to four Aquarium partial voices."),
|
||||
new("partial_voice_count", "4", "The additive shape lowers to four AquaSynth partial voices."),
|
||||
new("envelope_count", "2", "Amplitude and pitch contour pressure maps to ADSR plus vibrato in the current patch surface."),
|
||||
new("lfo_count", "1", "The fixture's amplitude/frequency motion is represented as patch-level vibrato/macro motion.")
|
||||
],
|
||||
[
|
||||
new("zyn_addsynth_oscillator_detail", "Zyn ADDsynth harmonic phase/bandwidth details", "Aquarium records harmonic ratios and gains, but not Zyn's full ADDsynth oscillator table semantics."),
|
||||
new("zyn_free_envelope_exactness", "Zyn envelope parameter semantics", "The rebuild uses Aquarium ADSR/motion controls rather than Zyn's exact envelope timing model.")
|
||||
new("zyn_addsynth_oscillator_detail", "Zyn ADDsynth harmonic phase/bandwidth details", "AquaSynth records harmonic ratios and gains, but not Zyn's full ADDsynth oscillator table semantics."),
|
||||
new("zyn_free_envelope_exactness", "Zyn envelope parameter semantics", "The rebuild uses AquaSynth ADSR/motion controls rather than Zyn's exact envelope timing model.")
|
||||
],
|
||||
"This is the easy Zyn pressure case: Aquarium can now say the sound as named harmonic banks while keeping the emitted voice graph plain enough to inspect."),
|
||||
"This is the easy Zyn pressure case: AquaSynth can now say the sound as named harmonic banks while keeping the emitted voice graph plain enough to inspect."),
|
||||
new(
|
||||
"zyn/project-pad-texture/aquarium",
|
||||
"zyn/project-pad-texture/aquasynth",
|
||||
"zynaddsubfx",
|
||||
"Project PAD texture",
|
||||
"zyn/project/pad-texture",
|
||||
|
|
@ -49,12 +49,12 @@ public static class ReferenceRebuildCatalog
|
|||
new("slow_modulation", "patch_lfo", "The rebuild adds slow patch modulation because PAD texture wants motion even though the minimal fixture only marks PAD/filter/free-envelope pressure.")
|
||||
],
|
||||
[
|
||||
new("padsynth_wavetable_exactness", "Full Zyn PAD engine behavior", "Aquarium now uses frequency-domain spreading, deterministic random phase, and one inverse FFT, but does not cover every Zyn harmonic profile, randomness control, or pitch-zone table behavior."),
|
||||
new("free_envelope_shape", "arbitrary Zyn envelope points", "Aquarium has staged voice envelopes now, but not arbitrary point/free-mode Zyn envelope curves.")
|
||||
new("padsynth_wavetable_exactness", "Full Zyn PAD engine behavior", "AquaSynth now uses frequency-domain spreading, deterministic random phase, and one inverse FFT, but does not cover every Zyn harmonic profile, randomness control, or pitch-zone table behavior."),
|
||||
new("free_envelope_shape", "arbitrary Zyn envelope points", "AquaSynth has staged voice envelopes now, but not arbitrary point/free-mode Zyn envelope curves.")
|
||||
],
|
||||
"This is pressure, not a claim of full Zyn PAD parity. Aquarium can now state a layered FFT spectral cloud, while exact Zyn PAD profile coverage remains separate pressure."),
|
||||
"This is pressure, not a claim of full Zyn PAD parity. AquaSynth can now state a layered FFT spectral cloud, while exact Zyn PAD profile coverage remains separate pressure."),
|
||||
new(
|
||||
"zyn/project-vocal-layer/aquarium",
|
||||
"zyn/project-vocal-layer/aquasynth",
|
||||
"zynaddsubfx",
|
||||
"Project vocal layer",
|
||||
"zyn/project/vocal-layer",
|
||||
|
|
@ -62,15 +62,15 @@ public static class ReferenceRebuildCatalog
|
|||
[
|
||||
new("engine_add", "1", "The air/formant layer is represented as a formant-filtered oscillator voice."),
|
||||
new("engine_sub", "1", "The body layer is represented as a lower triangle voice."),
|
||||
new("layered_instrument", "yes", "Multiple Zyn kit items map to multiple Aquarium voices."),
|
||||
new("layered_instrument", "yes", "Multiple Zyn kit items map to multiple AquaSynth voices."),
|
||||
new("named_layers", "air,body,breath", "Layer declarations preserve source identity before voice expansion."),
|
||||
new("voice_rate_level_envelope", "3", "Each vocal layer uses a staged rate/level voice envelope for asymmetric onset and release shape."),
|
||||
new("formant_filter_count", "1", "Represented with Aquarium formant filters and a vowel macro."),
|
||||
new("formant_filter_count", "1", "Represented with AquaSynth formant filters and a vowel macro."),
|
||||
new("effect_count", "1", "Approximated with local drive/soft clipping rather than a Zyn effect slot.")
|
||||
],
|
||||
[
|
||||
new("kit_item_authority", "Zyn per-kit-item engine/effect routing", "Aquarium has layered voices but no named kit-item/layer contract with per-layer effect sends."),
|
||||
new("formant_motion", "Zyn formant/vowel morph details", "Aquarium can mix static formants, but richer vowel morphing remains pressure.")
|
||||
new("kit_item_authority", "Zyn per-kit-item engine/effect routing", "AquaSynth has layered voices but no named kit-item/layer contract with per-layer effect sends."),
|
||||
new("formant_motion", "Zyn formant/vowel morph details", "AquaSynth can mix static formants, but richer vowel morphing remains pressure.")
|
||||
],
|
||||
"This rebuild keeps the useful part: layered source plus formant intent. It also exposes that repeated Zyn-style kit targets will need explicit layer naming and routing rather than anonymous voice piles.")
|
||||
];
|
||||
|
|
@ -78,55 +78,55 @@ public static class ReferenceRebuildCatalog
|
|||
public static readonly IReadOnlyList<ReferenceRebuild> Dx7Rebuilds =
|
||||
[
|
||||
new(
|
||||
"dx7/algo32-additive-organ/aquarium",
|
||||
"dx7/algo32-additive-organ/aquasynth",
|
||||
"dx7",
|
||||
"Algorithm 32 additive organ",
|
||||
"dx7/algo32-additive-organ",
|
||||
BuiltInScripts.Dx7StyleAlgorithm32AdditiveOrgan,
|
||||
[
|
||||
new("carrier_operators", "1,2,3,4,5,6", "Six independent carriers map cleanly to six Aquarium voices."),
|
||||
new("carrier_operators", "1,2,3,4,5,6", "Six independent carriers map cleanly to six AquaSynth voices."),
|
||||
new("modulation_edge_count", "0", "No operator-to-operator modulation is needed for the additive shape."),
|
||||
new("self_feedback_operators", "6", "Approximated with fold/drive on the highest partial."),
|
||||
new("operator_envelope_approximation", "DX7 EG -> ADSR", "DX7 four-rate/four-level envelopes can now be lowered to labeled ADSR approximations.")
|
||||
],
|
||||
[
|
||||
new("operator_envelope_exactness", "per-operator four-stage DX7 EG", "Aquarium has an ADSR approximation helper, not exact DX7 rate/level envelope execution."),
|
||||
new("output_compensation", "algorithm ROM COM", "Aquarium voice gains are explicit and not derived from DX7 COM scaling.")
|
||||
new("operator_envelope_exactness", "per-operator four-stage DX7 EG", "AquaSynth has an ADSR approximation helper, not exact DX7 rate/level envelope execution."),
|
||||
new("output_compensation", "algorithm ROM COM", "AquaSynth voice gains are explicit and not derived from DX7 COM scaling.")
|
||||
],
|
||||
"This is the honest easy case: DX7 algorithm 32 is mostly additive synthesis, so the current voice DSL can represent the carrier layout without pretending to own a full operator graph."),
|
||||
new(
|
||||
"dx7/algo8-bright-pair/aquarium",
|
||||
"dx7/algo8-bright-pair/aquasynth",
|
||||
"dx7",
|
||||
"Algorithm 8 bright pair",
|
||||
"dx7/algo8-bright-pair",
|
||||
BuiltInScripts.Dx7StyleAlgorithm8BrightPair,
|
||||
[
|
||||
new("carrier_operators", "1,3", "Represented as carriers in a first-class Aquarium operator graph."),
|
||||
new("carrier_operators", "1,3", "Represented as carriers in a first-class AquaSynth operator graph."),
|
||||
new("modulation_edges", "6->5,4+5->3,2->1", "Represented as explicit operator edges in the graph."),
|
||||
new("feedback_sources", "4", "Represented as operator-local feedback approximation on operator 4."),
|
||||
new("runtime_macros", "brightness,strike", "Field-site parameters expose useful sound controls without recompilation."),
|
||||
new("operator_envelope_approximation", "DX7 EG -> ADSR", "DX7 four-rate/four-level envelopes can now be lowered to labeled ADSR approximations.")
|
||||
],
|
||||
[
|
||||
new("dx7_feedback_register", "DX7 feedback scaling/register details", "Aquarium operator feedback is now renderable as a one-sample delayed self-reference, but not calibrated to exact DX7 feedback scaling."),
|
||||
new("operator_envelope_exactness", "independent DX7 rate/level envelopes", "Aquarium has per-operator ADSR approximation, not exact DX7 EG execution.")
|
||||
new("dx7_feedback_register", "DX7 feedback scaling/register details", "AquaSynth operator feedback is now renderable as a one-sample delayed self-reference, but not calibrated to exact DX7 feedback scaling."),
|
||||
new("operator_envelope_exactness", "independent DX7 rate/level envelopes", "AquaSynth has per-operator ADSR approximation, not exact DX7 EG execution.")
|
||||
],
|
||||
"This patch is deliberately a pressure test. The new operator graph owns the topology; exact DX7 envelope and feedback-register behavior remain pressure for later refinement."),
|
||||
new(
|
||||
"dx7/public-domain-mc-mm-5-3/aquarium",
|
||||
"dx7/public-domain-mc-mm-5-3/aquasynth",
|
||||
"dx7",
|
||||
"Public-domain MC-MM 5-3",
|
||||
"dx7/public-domain/analog1/13",
|
||||
BuiltInScripts.Dx7StylePublicDomainMcMm53,
|
||||
[
|
||||
new("reference_fixture", "analog1.syx#13", "Public-domain DX7 SysEx fixture from Musical Artifacts artifact 152."),
|
||||
new("audio_parity", "score>=0.75 log_mel<0.12 envelope<0.10", "First rendered DX7 parity target using dexed-py reference audio and Faust-rendered Aquarium audio."),
|
||||
new("audio_parity", "score>=0.75 log_mel<0.12 envelope<0.10", "First rendered DX7 parity target using dexed-py reference audio and Faust-rendered AquaSynth audio."),
|
||||
new("dominant_pitch", "654.0639Hz", "The rendered reference behaves as a short C3-derived 5x-ratio sine-like tone."),
|
||||
new("operator_envelope_approximation", "DX7 EG -> ADSR", "ADSR timing is fitted to the rendered reference envelope.")
|
||||
],
|
||||
[
|
||||
new("operator_topology_exactness", "2->1 FM pair", "The first parity candidate matches the rendered behavior as a sine-like tone; it does not claim exact DX7 operator-level execution."),
|
||||
new("operator_envelope_exactness", "DX7 rate/level EG", "The candidate uses Aquarium ADSR timing matched to rendered audio.")
|
||||
new("operator_envelope_exactness", "DX7 rate/level EG", "The candidate uses AquaSynth ADSR timing matched to rendered audio.")
|
||||
],
|
||||
"This is the first thresholded audio parity rung. It proves the render/compare loop on a lawful fixture without pretending the DX7 internals are solved.")
|
||||
];
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public sealed record PatchScriptMetrics(
|
||||
int ByteCount,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public sealed record SfxrParams
|
||||
{
|
||||
|
|
@ -5,7 +5,7 @@ using System.Security.Cryptography;
|
|||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace AquariumSynth.Dsl;
|
||||
namespace AquaSynth.Dsl;
|
||||
|
||||
public sealed record ZynInstrument(
|
||||
string Name,
|
||||
|
|
@ -117,25 +117,25 @@ public static class ZynInstrumentReader
|
|||
public static ReferenceSource SourceForBytes(string uri, string license, ReadOnlySpan<byte> bytes, string notes = "") =>
|
||||
new("zyn-xiz", uri, license, Convert.ToHexString(SHA256.HashData(bytes)).ToLowerInvariant(), notes);
|
||||
|
||||
public static ZynPadRebuild RebuildFirstPadAsAquariumScript(
|
||||
public static ZynPadRebuild RebuildFirstPadAsAquaSynthScript(
|
||||
string path,
|
||||
float tableRootFrequencyHz,
|
||||
float playbackFrequencyHz = 261.6256f) =>
|
||||
RebuildFirstPadAsAquariumScript(File.ReadAllBytes(path), tableRootFrequencyHz, playbackFrequencyHz);
|
||||
RebuildFirstPadAsAquaSynthScript(File.ReadAllBytes(path), tableRootFrequencyHz, playbackFrequencyHz);
|
||||
|
||||
public static ZynPadRebuild RebuildEnabledPadsAsAquariumScript(
|
||||
public static ZynPadRebuild RebuildEnabledPadsAsAquaSynthScript(
|
||||
string path,
|
||||
IReadOnlyDictionary<int, float> tableRootFrequencyHzByKitItem,
|
||||
float playbackFrequencyHz = 261.6256f) =>
|
||||
RebuildEnabledPadsAsAquariumScript(File.ReadAllBytes(path), tableRootFrequencyHzByKitItem, playbackFrequencyHz);
|
||||
RebuildEnabledPadsAsAquaSynthScript(File.ReadAllBytes(path), tableRootFrequencyHzByKitItem, playbackFrequencyHz);
|
||||
|
||||
public static ZynPadRebuild RebuildEnabledPadsAsAquariumScript(
|
||||
public static ZynPadRebuild RebuildEnabledPadsAsAquaSynthScript(
|
||||
string path,
|
||||
IReadOnlyDictionary<int, ZynPadTableRoot> tableRootFrequencyHzByKitItem,
|
||||
float playbackFrequencyHz = 261.6256f) =>
|
||||
RebuildEnabledPadsAsAquariumScript(File.ReadAllBytes(path), tableRootFrequencyHzByKitItem, playbackFrequencyHz);
|
||||
RebuildEnabledPadsAsAquaSynthScript(File.ReadAllBytes(path), tableRootFrequencyHzByKitItem, playbackFrequencyHz);
|
||||
|
||||
public static ZynPadRebuild RebuildFirstPadAsAquariumScript(
|
||||
public static ZynPadRebuild RebuildFirstPadAsAquaSynthScript(
|
||||
ReadOnlySpan<byte> bytes,
|
||||
float tableRootFrequencyHz,
|
||||
float playbackFrequencyHz = 261.6256f)
|
||||
|
|
@ -150,19 +150,19 @@ public static class ZynInstrumentReader
|
|||
.Descendants("INSTRUMENT_KIT_ITEM")
|
||||
.FirstOrDefault(IsEnabledPadItem)
|
||||
?? throw new ArgumentException("Zyn instrument XML has no enabled PAD kit item");
|
||||
return RebuildPadItemsAsAquariumScript(
|
||||
return RebuildPadItemsAsAquaSynthScript(
|
||||
document,
|
||||
[item],
|
||||
new Dictionary<int, ZynPadTableRoot> { [IntAttribute(item, "id")] = new(tableRootFrequencyHz) },
|
||||
playbackFrequencyHz);
|
||||
}
|
||||
|
||||
public static ZynPadRebuild RebuildEnabledPadsAsAquariumScript(
|
||||
public static ZynPadRebuild RebuildEnabledPadsAsAquaSynthScript(
|
||||
ReadOnlySpan<byte> bytes,
|
||||
IReadOnlyDictionary<int, float> tableRootFrequencyHzByKitItem,
|
||||
float playbackFrequencyHz = 261.6256f)
|
||||
{
|
||||
return RebuildEnabledPadsAsAquariumScript(
|
||||
return RebuildEnabledPadsAsAquaSynthScript(
|
||||
bytes,
|
||||
tableRootFrequencyHzByKitItem.ToDictionary(
|
||||
pair => pair.Key,
|
||||
|
|
@ -170,7 +170,7 @@ public static class ZynInstrumentReader
|
|||
playbackFrequencyHz);
|
||||
}
|
||||
|
||||
public static ZynPadRebuild RebuildEnabledPadsAsAquariumScript(
|
||||
public static ZynPadRebuild RebuildEnabledPadsAsAquaSynthScript(
|
||||
ReadOnlySpan<byte> bytes,
|
||||
IReadOnlyDictionary<int, ZynPadTableRoot> tableRootFrequencyHzByKitItem,
|
||||
float playbackFrequencyHz = 261.6256f)
|
||||
|
|
@ -190,10 +190,10 @@ public static class ZynInstrumentReader
|
|||
throw new ArgumentException("Zyn instrument XML has no enabled PAD kit item");
|
||||
}
|
||||
|
||||
return RebuildPadItemsAsAquariumScript(document, items, tableRootFrequencyHzByKitItem, playbackFrequencyHz);
|
||||
return RebuildPadItemsAsAquaSynthScript(document, items, tableRootFrequencyHzByKitItem, playbackFrequencyHz);
|
||||
}
|
||||
|
||||
private static ZynPadRebuild RebuildPadItemsAsAquariumScript(
|
||||
private static ZynPadRebuild RebuildPadItemsAsAquaSynthScript(
|
||||
XDocument document,
|
||||
IReadOnlyList<XElement> items,
|
||||
IReadOnlyDictionary<int, ZynPadTableRoot> tableRootFrequencyHzByKitItem,
|
||||
|
|
@ -234,7 +234,7 @@ public static class ZynInstrumentReader
|
|||
throw new ArgumentException($"Missing PAD table root for kit item {kitId}.", nameof(tableRootFrequencyHzByKitItem));
|
||||
}
|
||||
|
||||
var tableRootFrequencyHz = ZynPadRootForAquarium(item, tableRoot);
|
||||
var tableRootFrequencyHz = ZynPadRootForAquaSynth(item, tableRoot);
|
||||
if (tableRootFrequencyHz <= 0)
|
||||
{
|
||||
throw new ArgumentException($"Invalid PAD table root for kit item {kitId}.", nameof(tableRootFrequencyHzByKitItem));
|
||||
|
|
@ -255,7 +255,7 @@ public static class ZynInstrumentReader
|
|||
return new ZynPadRebuild(name, items.Count == 1 ? IntAttribute(items[0], "id") : -1, script.ToString(), matched, missing);
|
||||
}
|
||||
|
||||
private static float ZynPadRootForAquarium(XElement item, ZynPadTableRoot tableRoot)
|
||||
private static float ZynPadRootForAquaSynth(XElement item, ZynPadTableRoot tableRoot)
|
||||
{
|
||||
var oscillator = item
|
||||
.Element("PAD_SYNTH_PARAMETERS")
|
||||
|
|
@ -319,7 +319,7 @@ public static class ZynInstrumentReader
|
|||
var partialText = string.Join(",", harmonics.Select(partial => $"{F(partial.Ratio)}:{F(partial.Gain)}"));
|
||||
|
||||
var featurePrefix = includeKitSuffix ? $"pad_kit_{kitId}_" : "pad_";
|
||||
matched.Add(new($"{featurePrefix}oscillator_harmonics", harmonics.Count.ToString(CultureInfo.InvariantCulture), "Mapped OSCIL/HARMONICS magnitudes into Aquarium spectrum partials."));
|
||||
matched.Add(new($"{featurePrefix}oscillator_harmonics", harmonics.Count.ToString(CultureInfo.InvariantCulture), "Mapped OSCIL/HARMONICS magnitudes into AquaSynth spectrum partials."));
|
||||
matched.Add(new($"{featurePrefix}oscillator_base_function", IntParam(oscillator, "base_function", 0).ToString(CultureInfo.InvariantCulture), "Expanded Zyn OscilGen base function into harmonic partials before PAD synthesis."));
|
||||
if (IntParam(oscillator, "base_function_modulation", 0) != 0)
|
||||
{
|
||||
|
|
@ -331,30 +331,30 @@ public static class ZynInstrumentReader
|
|||
}
|
||||
matched.Add(new($"{featurePrefix}oscillator_spectrum_adjust", $"{IntParam(oscillator, "spectrum_adjust_type", 0)}:{IntParam(oscillator, "spectrum_adjust_par", 64)}", "Applied Zyn OscilGen spectrum adjustment to generated harmonic partials."));
|
||||
matched.Add(new($"{featurePrefix}table_root", F(tableRootFrequencyHz), "Root frequency comes from the Zyn oracle generated sample basefreq."));
|
||||
matched.Add(new($"{featurePrefix}note_frequency", F(noteFrequencyHz), "Mapped Zyn PAD coarse/fine detune into Aquarium table playback frequency."));
|
||||
matched.Add(new($"{featurePrefix}volume", volume.ToString(CultureInfo.InvariantCulture), "Mapped PAD amplitude volume into Aquarium layer gain."));
|
||||
matched.Add(new($"{featurePrefix}bandwidth", bandwidth.ToString(CultureInfo.InvariantCulture), "Mapped Zyn PAD bandwidth into Aquarium spectral table generation."));
|
||||
matched.Add(new($"{featurePrefix}note_frequency", F(noteFrequencyHz), "Mapped Zyn PAD coarse/fine detune into AquaSynth table playback frequency."));
|
||||
matched.Add(new($"{featurePrefix}volume", volume.ToString(CultureInfo.InvariantCulture), "Mapped PAD amplitude volume into AquaSynth layer gain."));
|
||||
matched.Add(new($"{featurePrefix}bandwidth", bandwidth.ToString(CultureInfo.InvariantCulture), "Mapped Zyn PAD bandwidth into AquaSynth spectral table generation."));
|
||||
matched.Add(new($"{featurePrefix}bandwidth_scale", bandwidthScale.ToString(CultureInfo.InvariantCulture), "Mapped Zyn PAD bandwidth scaling exponent selection."));
|
||||
matched.Add(new($"{featurePrefix}harmonic_profile", profile, "Mapped Zyn PAD harmonic profile shape into Aquarium spectral table generation."));
|
||||
matched.Add(new($"{featurePrefix}harmonic_position", position, "Mapped Zyn PAD harmonic position warp into Aquarium spectral table generation."));
|
||||
matched.Add(new($"{featurePrefix}harmonic_profile", profile, "Mapped Zyn PAD harmonic profile shape into AquaSynth spectral table generation."));
|
||||
matched.Add(new($"{featurePrefix}harmonic_position", position, "Mapped Zyn PAD harmonic position warp into AquaSynth spectral table generation."));
|
||||
if (lowPass < 1)
|
||||
{
|
||||
matched.Add(new($"{featurePrefix}filter_lpf", F(lowPass), "Mapped static Zyn PAD global low-pass frequency into Aquarium layer filtering."));
|
||||
matched.Add(new($"{featurePrefix}filter_lpf_q", F(lowPassQ), "Mapped Zyn analog low-pass Q into Aquarium filter damping."));
|
||||
matched.Add(new($"{featurePrefix}filter_lpf_order", lowPassOrder.ToString(CultureInfo.InvariantCulture), "Mapped Zyn analog LP1/LP2 and stage count into Aquarium low-pass order."));
|
||||
matched.Add(new($"{featurePrefix}filter_lpf", F(lowPass), "Mapped static Zyn PAD global low-pass frequency into AquaSynth layer filtering."));
|
||||
matched.Add(new($"{featurePrefix}filter_lpf_q", F(lowPassQ), "Mapped Zyn analog low-pass Q into AquaSynth filter damping."));
|
||||
matched.Add(new($"{featurePrefix}filter_lpf_order", lowPassOrder.ToString(CultureInfo.InvariantCulture), "Mapped Zyn analog LP1/LP2 and stage count into AquaSynth low-pass order."));
|
||||
}
|
||||
if (highPass > 0)
|
||||
{
|
||||
matched.Add(new($"{featurePrefix}filter_hpf", F(highPass), "Mapped static Zyn PAD global high-pass frequency into Aquarium layer filtering."));
|
||||
matched.Add(new($"{featurePrefix}filter_hpf_order", highPassOrder.ToString(CultureInfo.InvariantCulture), "Mapped Zyn analog HP1/HP2 and stage count into Aquarium high-pass order."));
|
||||
matched.Add(new($"{featurePrefix}filter_hpf", F(highPass), "Mapped static Zyn PAD global high-pass frequency into AquaSynth layer filtering."));
|
||||
matched.Add(new($"{featurePrefix}filter_hpf_order", highPassOrder.ToString(CultureInfo.InvariantCulture), "Mapped Zyn analog HP1/HP2 and stage count into AquaSynth high-pass order."));
|
||||
}
|
||||
if (lowPassEnvelope is not null)
|
||||
{
|
||||
matched.Add(new($"{featurePrefix}filter_lpf_envelope", "ratelevel", "Mapped Zyn PAD filter envelope octave offsets into Aquarium low-pass cutoff motion."));
|
||||
matched.Add(new($"{featurePrefix}filter_lpf_envelope", "ratelevel", "Mapped Zyn PAD filter envelope octave offsets into AquaSynth low-pass cutoff motion."));
|
||||
}
|
||||
if (highPassEnvelope is not null)
|
||||
{
|
||||
matched.Add(new($"{featurePrefix}filter_hpf_envelope", "ratelevel", "Mapped Zyn PAD filter envelope octave offsets into Aquarium high-pass cutoff motion."));
|
||||
matched.Add(new($"{featurePrefix}filter_hpf_envelope", "ratelevel", "Mapped Zyn PAD filter envelope octave offsets into AquaSynth high-pass cutoff motion."));
|
||||
}
|
||||
if (filter?.Element("FILTER_LFO") is { } lfo && IntParam(lfo, "intensity", 0) != 0)
|
||||
{
|
||||
|
|
@ -1,92 +1,93 @@
|
|||
{"kind":"migration","lesson":"The C# repo must own reusable authoring, analysis, preset, scoring, and Faust-generation behavior; only the Rust renderer/runtime and experimental compiler branch are intentionally left behind.","source":"user direction and migration pass through commit 3246672"}
|
||||
{"kind":"realtime","lesson":"Runtime-facing audio code must avoid unbounded operations: allocation, locks, I/O, console output, OS calls, and context switches do not belong in audio callbacks.","source":"PortAudio callback documentation"}
|
||||
{"kind":"dsp_graph","lesson":"Treat patch scripts as deterministic dataflow graphs with explicit rate and block semantics; terse syntax is acceptable only when lowering remains inspectable.","source":"Pure Data block/subpatch model and Faust block-diagram model"}
|
||||
{"kind":"sfxr_parity","lesson":"SFXR normalized filter values are not linear cutoff frequencies. In Faust export, small SFXR high-pass values must remain very low; mapping hpf directly to thousands of Hz removes the body of pickup, jump, powerup, and blip presets while still leaving them audible enough for weak tests to pass.","source":"Aquarium engine native Faust parity test against C# SFXR reference renderer"}
|
||||
{"kind":"sfxr_parity","lesson":"SFXR normalized filter values are not linear cutoff frequencies. In Faust export, small SFXR high-pass values must remain very low; mapping hpf directly to thousands of Hz removes the body of pickup, jump, powerup, and blip presets while still leaving them audible enough for weak tests to pass.","source":"AquaSynth engine native Faust parity test against C# SFXR reference renderer"}
|
||||
{"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"}
|
||||
{"kind":"synth_test_ownership","lesson":"AquariumSynthCSharp owns reference-patch correctness. Aquarium should only smoke-test the engine synth host and bundled Faust boundary; SFXR/BFXR/reference parity belongs here so the engine can keep moving while the synth library is under active surgery.","source":"user questioned synth tests living in Aquarium"}
|
||||
{"kind":"package_boundary","lesson":"Aquarium consumes AquariumSynth.Dsl through a pinned package, not a live project reference. Breaking changes in AquariumSynthCSharp are allowed during synth construction as long as a new package version is packed and Aquarium is updated deliberately when the boundary should move.","source":"user wanted Aquarium builds insulated from synth-agent work"}
|
||||
{"kind":"runtime_patch_parameters","lesson":"Aquarium patch scripts now have first-class `param` declarations and patch/reference model contracts. Faust emission exposes declared parameters as smoothed hslider controls, but target binding is intentionally still absent and warned about; do not claim parameters shape sound until binding is designed.","source":"parameter contract implementation on 2026-05-13"}
|
||||
{"kind":"runtime_patch_parameters","lesson":"Aquarium parameter binding uses Option B: numeric field values may reference declared parameters with `@/path`, producing exact field bindings such as `/voices/0/filter/lpf`. The field owns the meaning; the parameter owns the runtime value. Avoid target-routing parameter semantics unless a new authority is deliberately mapped.","source":"user rejected target binding as a landmine; field-site binding implemented on 2026-05-13"}
|
||||
{"kind":"reference_synth_roadmap","lesson":"AquaSynth 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 AquaSynth DSL"}
|
||||
{"kind":"runtime_patch_parameters","lesson":"Synth patches must expose expressive runtime parameters. Faust supports this through UI controls and hosted parameter APIs, so AquaSynth 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"}
|
||||
{"kind":"synth_test_ownership","lesson":"AquaSynth owns reference-patch correctness. AquaSynth should only smoke-test the engine synth host and bundled Faust boundary; SFXR/BFXR/reference parity belongs here so the engine can keep moving while the synth library is under active surgery.","source":"user questioned synth tests living in AquaSynth"}
|
||||
{"kind":"package_boundary","lesson":"AquaSynth consumes AquaSynth.Dsl through a pinned package, not a live project reference. Breaking changes in AquaSynth are allowed during synth construction as long as a new package version is packed and AquaSynth is updated deliberately when the boundary should move.","source":"user wanted AquaSynth builds insulated from synth-agent work"}
|
||||
{"kind":"runtime_patch_parameters","lesson":"AquaSynth patch scripts now have first-class `param` declarations and patch/reference model contracts. Faust emission exposes declared parameters as smoothed hslider controls, but target binding is intentionally still absent and warned about; do not claim parameters shape sound until binding is designed.","source":"parameter contract implementation on 2026-05-13"}
|
||||
{"kind":"runtime_patch_parameters","lesson":"AquaSynth parameter binding uses Option B: numeric field values may reference declared parameters with `@/path`, producing exact field bindings such as `/voices/0/filter/lpf`. The field owns the meaning; the parameter owns the runtime value. Avoid target-routing parameter semantics unless a new authority is deliberately mapped.","source":"user rejected target binding as a landmine; field-site binding implemented on 2026-05-13"}
|
||||
{"kind":"dx7_reference_path","lesson":"DX7 reference elaboration starts with structural extraction, not translation. The repo now parses 155-byte voice edit buffers, 128-byte packed voices, and 4104-byte packed 32-voice SysEx banks into neutral DX7 records with checksum validation and ReferencePatch features. Next pressure point is explicit algorithm topology metadata for carriers, modulation edges, and feedback edge location.","source":"DX7 SysEx parser slice on 2026-05-13"}
|
||||
{"kind":"dx7_reference_path","lesson":"DX7 algorithm topology is now derived from the reverse-engineered OPS algorithm ROM table, not hand-drawn diagrams. Topology exposes carrier operators, modulation edges, feedback-register writers, self-feedback operators, delayed-feedback targets, and raw ROM steps. Use this as pressure evidence before adding an Aquarium operator graph layer.","source":"DX7 algorithm topology slice on 2026-05-13; Ken Shirriff OPS ROM table"}
|
||||
{"kind":"dx7_reference_rebuilds","lesson":"Two DX7-style Aquarium rebuilds now make the pressure explicit: algorithm 32 maps cleanly to layered additive voices, but algorithm 8 exposes missing graph structure (operator modulation edges, summed modulators, and operator-local self-feedback). Do not patch this with more Voice fields; decide whether an operator graph model owns this invariant.","source":"DX7 rebuild catalog slice on 2026-05-13"}
|
||||
{"kind":"dx7_reference_path","lesson":"DX7 algorithm topology is now derived from the reverse-engineered OPS algorithm ROM table, not hand-drawn diagrams. Topology exposes carrier operators, modulation edges, feedback-register writers, self-feedback operators, delayed-feedback targets, and raw ROM steps. Use this as pressure evidence before adding an AquaSynth operator graph layer.","source":"DX7 algorithm topology slice on 2026-05-13; Ken Shirriff OPS ROM table"}
|
||||
{"kind":"dx7_reference_rebuilds","lesson":"Two DX7-style AquaSynth rebuilds now make the pressure explicit: algorithm 32 maps cleanly to layered additive voices, but algorithm 8 exposes missing graph structure (operator modulation edges, summed modulators, and operator-local self-feedback). Do not patch this with more Voice fields; decide whether an operator graph model owns this invariant.","source":"DX7 rebuild catalog slice on 2026-05-13"}
|
||||
{"kind":"operator_graph_model","lesson":"DX7 algorithm-8 pressure justified a first-class OperatorGraph abstraction. OperatorGraph owns FM topology: operators, modulation edges, carriers, and feedback. Do not hide this authority inside Voice fields. Remaining DX7 pressure is exact feedback-register timing and rate/level envelopes.","source":"operator graph implementation slice on 2026-05-13"}
|
||||
{"kind":"operator_graph_authoring","lesson":"Operator graph authoring should use readable `operator`, `route`, and `carrier` declarations with `env=ad:...` or `env=adsr:...`. Compact `ops=`/`edges=` tuples are acceptable as importer/interchange scaffolding only, not the face of the DSL.","source":"user rejected number-soup operator syntax; readable operator graph syntax slice on 2026-05-13"}
|
||||
{"kind":"note_envelope_model","lesson":"Aquarium's general envelope model is ADSR: attack, decay, sustain level, release. Note timing belongs to `Note` records: frequency, gate duration, and host/MIDI source. SFXR sustain maps to note gate duration; SFXR punch maps to lower sustain level plus voice gain compensation so ADSR peak remains implicit 1 and the held level sits below the transient.","source":"user identified SFXR sustain as note duration and Punch as transient above sustain; punch mapping correction on 2026-05-13"}
|
||||
{"kind":"faust_polyphony","lesson":"Prefer Faust-managed MIDI polyphony over Aquarium graph inflation. Aquarium should emit a single voice graph with standard `freq`, `gain`, and `gate` controls plus `[midi:on][nvoices:n]`; Faust architectures own MIDI decoding and voice allocation unless a concrete target proves the boundary insufficient.","source":"Faust official MIDI/polyphony docs and user preference for Faust support on 2026-05-13"}
|
||||
{"kind":"note_envelope_model","lesson":"AquaSynth's general envelope model is ADSR: attack, decay, sustain level, release. Note timing belongs to `Note` records: frequency, gate duration, and host/MIDI source. SFXR sustain maps to note gate duration; SFXR punch maps to lower sustain level plus voice gain compensation so ADSR peak remains implicit 1 and the held level sits below the transient.","source":"user identified SFXR sustain as note duration and Punch as transient above sustain; punch mapping correction on 2026-05-13"}
|
||||
{"kind":"faust_polyphony","lesson":"Prefer Faust-managed MIDI polyphony over AquaSynth graph inflation. AquaSynth should emit a single voice graph with standard `freq`, `gain`, and `gate` controls plus `[midi:on][nvoices:n]`; Faust architectures own MIDI decoding and voice allocation unless a concrete target proves the boundary insufficient.","source":"Faust official MIDI/polyphony docs and user preference for Faust support on 2026-05-13"}
|
||||
{"kind":"operator_graph_parameters","lesson":"Readable operator graph fields bind runtime parameters at exact `/opgraphs/...` field paths: graph gain/note fields, operator ratio/level/feedback/envelope fields, and route index fields. Keep compact `ops=`/`edges=` as importer scaffolding and avoid graph-wide macro routing.","source":"operator graph field-site binding slice on 2026-05-13"}
|
||||
{"kind":"dx7_envelopes","lesson":"DX7 four-rate/four-level operator envelopes can be lowered to labeled Aquarium ADSR approximations plus gate duration, but this is not exact DX7 EG execution. Reference rebuilds should record approximation as matched pressure and exactness as still missing.","source":"DX7 envelope approximation slice on 2026-05-13; Yamaha DX7 manual describes EGs as four rates and four levels"}
|
||||
{"kind":"render_parity_harness","lesson":"Aquarium Faust output can now be compiled to Faust-generated C# and rendered into mono float samples for AudioAnalyzer comparisons. This proves the candidate side of parity; DX7 parity still requires a real Dexed/reference render or captured licensed fixture, not self-comparison.","source":"Faust render parity harness slice on 2026-05-13"}
|
||||
{"kind":"reference_parity_doctrine","lesson":"External synth references exist to exercise Aquarium DSL expressiveness, not to clone foreign internals. Consume only references that can be backed by parity tests proving Aquarium can reproduce the behavior in terse, readable syntax; parsing a format is inventory, not evidence.","source":"user clarified reference-synth purpose and parity-test requirement on 2026-05-13"}
|
||||
{"kind":"dx7_reference_rendering","lesson":"DX7 reference rendering now uses dexed-py as optional test tooling against a public-domain SysEx fixture. Keep fixtures and renderer helpers under the test project, preserve provenance and SHA-256 beside vendored banks, and keep AquariumSynth.Dsl.nupkg free of SysEx/Python/test assets.","source":"dexed-py public-domain fixture harness slice on 2026-05-13"}
|
||||
{"kind":"dx7_rendered_parity","lesson":"The first thresholded rendered DX7 parity target is analog1.syx voice 13, MC-MM 5-3. Aquarium matches the rendered behavior with a short sine-like patch and explicit score/log-mel/envelope/duration/RMS/zero-crossing/centroid thresholds. Treat this as proof of the parity loop, not proof of exact DX7 operator execution; next target should audibly require operator routing.","source":"first thresholded DX7 rendered parity slice on 2026-05-13"}
|
||||
{"kind":"dx7_envelopes","lesson":"DX7 four-rate/four-level operator envelopes can be lowered to labeled AquaSynth ADSR approximations plus gate duration, but this is not exact DX7 EG execution. Reference rebuilds should record approximation as matched pressure and exactness as still missing.","source":"DX7 envelope approximation slice on 2026-05-13; Yamaha DX7 manual describes EGs as four rates and four levels"}
|
||||
{"kind":"render_parity_harness","lesson":"AquaSynth Faust output can now be compiled to Faust-generated C# and rendered into mono float samples for AudioAnalyzer comparisons. This proves the candidate side of parity; DX7 parity still requires a real Dexed/reference render or captured licensed fixture, not self-comparison.","source":"Faust render parity harness slice on 2026-05-13"}
|
||||
{"kind":"reference_parity_doctrine","lesson":"External synth references exist to exercise AquaSynth DSL expressiveness, not to clone foreign internals. Consume only references that can be backed by parity tests proving AquaSynth can reproduce the behavior in terse, readable syntax; parsing a format is inventory, not evidence.","source":"user clarified reference-synth purpose and parity-test requirement on 2026-05-13"}
|
||||
{"kind":"dx7_reference_rendering","lesson":"DX7 reference rendering now uses dexed-py as optional test tooling against a public-domain SysEx fixture. Keep fixtures and renderer helpers under the test project, preserve provenance and SHA-256 beside vendored banks, and keep AquaSynth.Dsl.nupkg free of SysEx/Python/test assets.","source":"dexed-py public-domain fixture harness slice on 2026-05-13"}
|
||||
{"kind":"dx7_rendered_parity","lesson":"The first thresholded rendered DX7 parity target is analog1.syx voice 13, MC-MM 5-3. AquaSynth matches the rendered behavior with a short sine-like patch and explicit score/log-mel/envelope/duration/RMS/zero-crossing/centroid thresholds. Treat this as proof of the parity loop, not proof of exact DX7 operator execution; next target should audibly require operator routing.","source":"first thresholded DX7 rendered parity slice on 2026-05-13"}
|
||||
{"kind":"operator_feedback","lesson":"A harder DX7 algorithm-8 target exposed direct operator self-reference as non-renderable Faust. Operator feedback now emits as delayed Faust recursion, which keeps the render path alive and is closer to DX7 feedback pressure; exact DX7 feedback scaling remains unsolved.","source":"PRC SYNTH1 parity probe and delayed feedback render fix on 2026-05-13"}
|
||||
{"kind":"dx7_operator_levels","lesson":"DX7 operator output level is nonlinear and includes key/velocity offsets before envelope gain. Added a reference-import helper to approximate effective Aquarium operator levels, but PRC SYNTH1 still only improved to ~0.34 with static levels and ~0.42 with envelope tweaks; hard parity now points at DX7-style operator envelope/gain evolution rather than static level mapping alone.","source":"DX7 effective operator level probe on 2026-05-13"}
|
||||
{"kind":"dx7_operator_levels","lesson":"DX7 operator output level is nonlinear and includes key/velocity offsets before envelope gain. Added a reference-import helper to approximate effective AquaSynth operator levels, but PRC SYNTH1 still only improved to ~0.34 with static levels and ~0.42 with envelope tweaks; hard parity now points at DX7-style operator envelope/gain evolution rather than static level mapping alone.","source":"DX7 effective operator level probe on 2026-05-13"}
|
||||
{"kind":"staged_operator_envelopes","lesson":"Operator graphs now have a readable staged envelope surface, env=rl rates=... levels=..., backed by RateLevelEnvelope and Faust rl4_env rendering. This exercises the DSL with DX7-style multi-target contours without changing the general ADSR voice envelope. Direct DX7 rate/level lowering on PRC SYNTH1 peaked around ~0.316 in quick probes, so the next parity pressure is calibrated DX7 EG timing/gain rather than more syntax.","source":"staged operator envelope slice and PRC SYNTH1 probe on 2026-05-13"}
|
||||
{"kind":"dx7_prc_listening_artifacts","lesson":"The hard PRC SYNTH1 parity probe now writes ignored WAV artifacts for ear checks under artifacts/parity/dx7-prc-synth1. A calibrated readable operator-graph candidate with staged env=rl envelopes scores ~0.458: duration is close, while RMS and timbre remain off. Use listening plus metrics to choose the next calibration target instead of blindly adding DSL surface.","source":"PRC SYNTH1 listening WAV probe on 2026-05-13"}
|
||||
{"kind":"dx7_prc_calibration","lesson":"PRC SYNTH1 improved to a modest passing score of ~0.606 without new DSL surface. Removing soft clipping, using a 392 Hz graph base, and boosting the op3 carrier branch helped; global detune and per-edge route damping worsened metrics and were cut. Remaining pressure is DX7 output/index scaling or algorithm output compensation, not more envelope syntax.","source":"PRC SYNTH1 calibration pass on 2026-05-14"}
|
||||
{"kind":"dx7_prc_logmel","lesson":"Listening and log-mel agreed that the aggregate PRC SYNTH1 score was misleading. The Dexed reference has strong low/body partials around 131 Hz and 393 Hz; Aquarium's earlier candidate lacked the low body despite a better aggregate score. The probe now gates on log-mel <=0.255 with a loose aggregate floor, and remaining mismatch points at DX7 output/index scaling and algorithm compensation.","source":"PRC SYNTH1 perceptual/log-mel calibration on 2026-05-14"}
|
||||
{"kind":"dx7_prc_logmel","lesson":"Listening and log-mel agreed that the aggregate PRC SYNTH1 score was misleading. The Dexed reference has strong low/body partials around 131 Hz and 393 Hz; AquaSynth's earlier candidate lacked the low body despite a better aggregate score. The probe now gates on log-mel <=0.255 with a loose aggregate floor, and remaining mismatch points at DX7 output/index scaling and algorithm compensation.","source":"PRC SYNTH1 perceptual/log-mel calibration on 2026-05-14"}
|
||||
{"kind":"dx7_output_level_curve","lesson":"A project-authored Dexed single-carrier sweep shows DX7 carrier amplitude follows 2^((outputLevel - 99) / 8). The previous internal-level proxy made mid-level operators far too loud. `Dx7SysEx.OperatorOutputAmplitude` now owns the measured curve; next calibration rung is two-operator modulation index.","source":"DX7 single-carrier calibration rung on 2026-05-14"}
|
||||
{"kind":"dx7_modulation_index","lesson":"Isolated two-operator Dexed FM fits full-level modulation at about 12.55 radians. Under Aquarium's current Faust phase formula this maps to route index 6.275 for a full-level modulator. Apply this to isolated two-op branches, but do not blindly apply it to cascaded algorithm stacks before algorithm output compensation is modeled.","source":"DX7 two-operator modulation calibration rung on 2026-05-14"}
|
||||
{"kind":"dx7_feedback_scale","lesson":"Isolated Dexed feedback sweeps fit a nonlinear Aquarium feedback table: 0, .01, .02, .05, .10, .19, .38, .66 for DX7 feedback values 0-7. PRC feedback value 5 was already accidentally close via feedback*0.04; the table moves that knowledge into Dx7SysEx.OperatorFeedbackAmount.","source":"DX7 feedback calibration rung on 2026-05-14"}
|
||||
{"kind":"dx7_modulation_index","lesson":"Isolated two-operator Dexed FM fits full-level modulation at about 12.55 radians. Under AquaSynth's current Faust phase formula this maps to route index 6.275 for a full-level modulator. Apply this to isolated two-op branches, but do not blindly apply it to cascaded algorithm stacks before algorithm output compensation is modeled.","source":"DX7 two-operator modulation calibration rung on 2026-05-14"}
|
||||
{"kind":"dx7_feedback_scale","lesson":"Isolated Dexed feedback sweeps fit a nonlinear AquaSynth feedback table: 0, .01, .02, .05, .10, .19, .38, .66 for DX7 feedback values 0-7. PRC feedback value 5 was already accidentally close via feedback*0.04; the table moves that knowledge into Dx7SysEx.OperatorFeedbackAmount.","source":"DX7 feedback calibration rung on 2026-05-14"}
|
||||
{"kind":"dx7_detune_and_com","lesson":"PRC exposed two separate DX7 facts: ratio-mode detune must lower into operator frequency ratios, and ROM COM output compensation must be applied relative to the algorithm-32 six-output baseline used by the carrier-amplitude calibration. This cut the PRC carrier scale table; the remaining cascaded-route constant is still a fenced hard-target scar needing summed-modulator calibration.","source":"DX7 PRC parity rung on 2026-05-14"}
|
||||
{"kind":"dx7_topology_aware_route_index","lesson":"The PRC hard target proved DX7 route index cannot key only on ROM edge kind: a direct edge feeding a later summed branch behaves like part of the cascaded/summed stack, not like the isolated two-op branch. `Dx7SysEx.OperatorRouteIndex(topology, edge)` now owns this distinction; PRC no longer has a private route function.","source":"DX7 summed/cascaded route lowering on 2026-05-14"}
|
||||
{"kind":"dx7_project_authored_patch_rendering","lesson":"Project-authored Dexed patches can be generated directly inside tests from explicit operator specs. Use this for lawful calibration rungs instead of squeezing every DX7 fact out of public-domain hard patches.","source":"DX7 project-authored summed-stack parity on 2026-05-14"}
|
||||
{"kind":"dx7_envelope_curve_cut","lesson":"Reusing the operator output amplitude curve for DX7 EG levels is not ready: it can improve isolated envelope shape metrics with shorter timing, but it failed the hard PRC log-mel target. Keep EG levels linear until isolated envelope parity passes without regressing PRC.","source":"DX7 envelope level experiment on 2026-05-14"}
|
||||
{"kind":"dx7_envelope_trace","lesson":"Direct DX7 EG tracing shows the current `env=rl` abstraction is the wrong shape for some DX7 envelopes: the traced EG can spike above unit gain and drop below .02 within about 9 ms while `env=rl` is still near 1. A runtime `env=dx7` surface was attempted and cut because matching the local trace did not yet match Dexed plugin audio.","source":"DX7 envelope trace artifact on 2026-05-14"}
|
||||
{"kind":"dx7_envelope_applied_gain","lesson":"Dexed-style operator audio does not use the raw DX7 EG state directly. It samples the EG once per 64-sample block and linearly interpolates applied gain across the block. A DX7-capable Aquarium envelope must model that applied-gain timebase; matching raw EG trace alone can make a candidate far too quiet or otherwise wrong.","source":"DX7 interpolated envelope trace artifact on 2026-05-14"}
|
||||
{"kind":"curved_rate_level_envelope","lesson":"Aquarium staged operator envelopes now support per-segment curves and deliberate levels above unity. Keep this authority in `RateLevelEnvelope`: it protects the invariant that multi-target operator contours can model exponential synth envelopes without inventing one-off DX7 syntax.","source":"Curved rate/level envelope implementation on 2026-05-14"}
|
||||
{"kind":"dx7_applied_envelope_lowering","lesson":"`Dx7SysEx.ApproximateAppliedRateLevelEnvelope` improves the hard PRC target by tracing Dexed-style block-interpolated EG gain, normalizing it against Aquarium operator output level, and emitting curved `env=rl`. Latest PRC metrics: log-mel 0.21931955, envelope distance 0.10271241, RMS ratio 1.0003664, score 0.5026183. Zero-crossing worsened to 0.28642866, so contour parity exposed a remaining oscillator/phase mismatch rather than solving DX7 parity outright.","source":"DX7 applied-envelope PRC probe on 2026-05-14"}
|
||||
{"kind":"dx7_envelope_applied_gain","lesson":"Dexed-style operator audio does not use the raw DX7 EG state directly. It samples the EG once per 64-sample block and linearly interpolates applied gain across the block. A DX7-capable AquaSynth envelope must model that applied-gain timebase; matching raw EG trace alone can make a candidate far too quiet or otherwise wrong.","source":"DX7 interpolated envelope trace artifact on 2026-05-14"}
|
||||
{"kind":"curved_rate_level_envelope","lesson":"AquaSynth staged operator envelopes now support per-segment curves and deliberate levels above unity. Keep this authority in `RateLevelEnvelope`: it protects the invariant that multi-target operator contours can model exponential synth envelopes without inventing one-off DX7 syntax.","source":"Curved rate/level envelope implementation on 2026-05-14"}
|
||||
{"kind":"dx7_applied_envelope_lowering","lesson":"`Dx7SysEx.ApproximateAppliedRateLevelEnvelope` improves the hard PRC target by tracing Dexed-style block-interpolated EG gain, normalizing it against AquaSynth operator output level, and emitting curved `env=rl`. Latest PRC metrics: log-mel 0.21931955, envelope distance 0.10271241, RMS ratio 1.0003664, score 0.5026183. Zero-crossing worsened to 0.28642866, so contour parity exposed a remaining oscillator/phase mismatch rather than solving DX7 parity outright.","source":"DX7 applied-envelope PRC probe on 2026-05-14"}
|
||||
{"kind":"dx7_applied_envelope_peak_picker","lesson":"Listening caught a real lowering bug: the first applied-envelope approximation treated the first 64-sample block as the attack peak, which made slower rising op2 in PRC swell late (`0.014 -> 0.613`) instead of hitting early and decaying. Picking the first near-peak before gate gives op2 `0.981 -> 0.843 -> 0.660` and improves PRC to log-mel 0.17186502, RMS 1.0000212, zero-crossing 0.7815517, score 0.6501268.","source":"PRC SYNTH1 listening-guided envelope fix on 2026-05-14"}
|
||||
{"kind":"dx7_summed_route_scale","lesson":"Listening identified missing harsh stacked-modulation brightness. Raising `Dx7SysEx.SummedOperatorModulationRouteIndex` from 1.6 to 2.4 improves PRC to log-mel 0.16794802, envelope distance 0.09510617, centroid ratio 1.1254044, RMS ratio 1.00095, score 0.68491656, and also tightens the project-authored algorithm-8 summed-stack log-mel when graph gain is normalized. Keep isolated direct branches at 6.275; the stronger 2.4 scale belongs only to summed/cascaded DX7 branches.","source":"DX7 stacked modulation brightness calibration on 2026-05-14"}
|
||||
{"kind":"dx7_summed_route_scale_hotter","lesson":"Follow-up listening and band analysis showed the previous summed/cascaded scale still sounded underwater. Raising `Dx7SysEx.SummedOperatorModulationRouteIndex` to 6.0 and normalizing PRC graph gain to 0.25 improves PRC to log-mel 0.13874426, envelope distance 0.067291506, RMS ratio 0.9912135, zero-crossing ratio 0.95325506, centroid ratio 1.1156512, score 0.7546445. A hotter 7.0 scale did not buy enough log-mel improvement and worsened RMS/score, so 6.0 is the current coherent stop.","source":"DX7 stacked modulation brightness hot sweep on 2026-05-14"}
|
||||
{"kind":"patch_library","lesson":"Repo-owned Aquarium .aqua stock now lives under patches/ with library.yaml; every .aqua must parse/export in tests and the patch library must remain out of AquariumSynth.Dsl.nupkg unless intentionally promoted.","source":"Patch library folder slice on 2026-05-14"}
|
||||
{"kind":"patch_library","lesson":"Repo-owned AquaSynth .aqua stock now lives under patches/ with library.yaml; every .aqua must parse/export in tests and the patch library must remain out of AquaSynth.Dsl.nupkg unless intentionally promoted.","source":"Patch library folder slice on 2026-05-14"}
|
||||
{"kind":"dx7_algorithm8_split_route_parity","lesson":"The DX7 summed/cascaded route scale 6.0 is now backed by split project-authored algorithm-8 rendered probes, not only PRC or one combined stack. Latest real-Dexed run: combined stack log-mel 0.04029555 score 0.8664546, summed pair log-mel 0.042429477 score 0.870778, cascade log-mel 0.03811625 score 0.9157809. Keep isolated direct branches at 6.275 and summed/cascaded branches at 6.0 until broader evidence contradicts it.","source":"Split algorithm-8 parity probes on 2026-05-14"}
|
||||
{"kind":"patch_library_taste","lesson":"Not every parity probe belongs in the patch library. Harsh project-authored DX7 calibration probes should stay in tests and ignored listening artifacts unless they are musically useful stock; the navigable .aqua library is for reusable inspiration, not measurement torture signals.","source":"User listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_community_voice_parity","lesson":"Actual public-domain analog1.syx community voices are useful broader probes, but listening rejected the first loose gate. ANLGSYN 1, RES SYNTH1, DX1 LEAD B, and MELLOWSOLO should remain pressure until their timbre/zero-crossing mismatch is understood. Only Mooger and fixed Piano Bass are currently defensible rendered community parity targets.","source":"Community DX7 analog1.syx survey on 2026-05-14"}
|
||||
{"kind":"dx7_voice_transpose","lesson":"Piano Bass in analog1.syx proved imported DX7 voices must lower the voice transpose byte into graph frequency. Transpose 24 is neutral; transpose 12 lowers MIDI note 60 to 130.8128 Hz. Hardcoding 261.6256 made Piano Bass a full octave too high. After the fix, Piano Bass improves to log-mel 0.16180529, zero-crossing 0.905511, score 0.64267576. Do not call the broader analog1.syx survey passing; only Mooger and fixed Piano Bass are currently defensible.","source":"Piano Bass listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_fixed_frequency","lesson":"ANLGSYN 1 proved DX7 fixed-frequency operators must lower as absolute Hz divided by the graph base frequency, not as note ratios. Dexed fixed mode uses a log-frequency formula; op1 fixed 0/0 is about 1 Hz and op3 fixed 0/8 detune 14 is about 1.207 Hz, yielding ratios 0.007615 and 0.009227 against the transposed 130.8128 Hz graph base. This restores the low buzzing modulation and improves ANLGSYN 1 to log-mel 0.19427659, zero-crossing 0.94662774, score 0.659334.","source":"ANLGSYN 1 listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_max_feedback","lesson":"ANLGSYN 1 still sounded too 'woooh' after fixed-frequency lowering because high-band buzz was missing. Route-index sweeps did not help; increasing only DX7 feedback value 7 from 0.66 to 2.2 restored much more 1.2-5 kHz energy while leaving feedback value 5 at 0.19 for PRC. Latest ANLGSYN 1: log-mel 0.17553389, centroid 0.9519112, zero-crossing 0.90904, score 0.6448498. Envelope/RMS worsened, so this is a timbre correction, not final ANLGSYN parity.","source":"ANLGSYN 1 max-feedback listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_output_nonlinearity","lesson":"ANLGSYN 1 listening caught a remaining 'deeooh' failure: the max-feedback candidate had a close attack but lost sustained high-band punch halfway through. Enabling Aquarium's existing output soft clip only for max-feedback self-feedback DX7 voices improved ANLGSYN to score 0.70946133, log-mel 0.18456098, envelope 0.10628832, RMS 0.9816304 while PRC stayed passing with soft clip disabled at score 0.7546429 and log-mel 0.13874851. Do not apply the nonlinearity globally; PRC proves that would be a compensator.","source":"ANLGSYN 1 sustained-buzz parity correction on 2026-05-14"}
|
||||
{"kind":"dx7_output_nonlinearity","lesson":"ANLGSYN 1 listening caught a remaining 'deeooh' failure: the max-feedback candidate had a close attack but lost sustained high-band punch halfway through. Enabling AquaSynth's existing output soft clip only for max-feedback self-feedback DX7 voices improved ANLGSYN to score 0.70946133, log-mel 0.18456098, envelope 0.10628832, RMS 0.9816304 while PRC stayed passing with soft clip disabled at score 0.7546429 and log-mel 0.13874851. Do not apply the nonlinearity globally; PRC proves that would be a compensator.","source":"ANLGSYN 1 sustained-buzz parity correction on 2026-05-14"}
|
||||
{"kind":"dx7_max_feedback_envelope_floor","lesson":"Output soft clip alone did not fix ANLGSYN 1's mid-note drift. The self-feedback source operator was under-driven after the attack; preserving a 0.9 applied-envelope sustain floor for max-feedback source operators lifted the sustained 2.5-5 kHz band ratio from about 0.175 to above 1.0 and improved ANLGSYN 1 to score 0.7245976, log-mel 0.18460114, envelope 0.119950555, zero-crossing 0.97149533. Add sustained band gates when broad log-mel allows audible drift through.","source":"ANLGSYN 1 sustained high-band parity gate on 2026-05-14"}
|
||||
{"kind":"dx7_com_compensation_cut","lesson":"ROM COM carrier compensation was louder but harmonically wrong for the analog1 community pass. User listening preferred the no-COM renders across patches; the real issue was that they were too quiet. Cut hidden per-carrier COM boosts: `OperatorOutputCompensation` returns unity and graph gain owns loudness recovery. Passing community gains with no COM are Mooger 0.75, Piano Bass 0.90, RES SYNTH1 0.75. DX1 LEAD B and MELLOWSOLO sound closer by ear with no COM but remain numeric pressure targets.","source":"community DX7 listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_effective_note_scaling","lesson":"DX7 operator key-scaling and rate-scaling must lower against the effective played MIDI note after voice transpose, not hardcoded MIDI 60. `Dx7SysEx.OperatorRateScaling` now feeds the block-interpolated applied envelope trace, and imported operator levels use the effective note. This improves RES SYNTH1 attack/log-mel and Piano Bass harmonic metrics; Piano Bass graph gain rebalances from 0.90 to 0.72. MELLOWSOLO remains the clearest harmonic mismatch and now has a pressure artifact test rather than a fake parity pass. A trial output-level-dependent applied-envelope trace was cut because it worsened MELLOWSOLO and ANLGSYN 1.","source":"community DX7 listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_modulator_peak_headroom","lesson":"Listening found ANLGSYN 1 and RES SYNTH1 blowing out into a drone at the modulator-envelope peak while Piano Bass was spot on. The surviving DX7 probe change caps only algorithm-2 non-carrier applied-envelope Level1 at 0.92, preserving Piano Bass and improving RES SYNTH1 while keeping ANLGSYN judged by log-mel and sustained high-band evidence rather than aggregate score. A wider summed-route headroom experiment for Mooger fan-in was tested and cut because it worsened Mooger metrics and did not isolate the overtone-emphasis issue.","source":"community DX7 listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_mellowsolo_tail_window","lesson":"MELLOWSOLO pressure artifacts need a longer render window than 1.0s because the Aquarium candidate emits a 0.6s release from a 0.65s gate, so the old WAV cut the tail before it could finish. Extending only the MELLOWSOLO pressure render to 1.25s improves log-mel from about 0.429 to 0.347 and makes the tail audible without changing the synth lowering or passing parity targets. A global traced-release-duration experiment was tested and cut because it shortened releases too aggressively and broke PRC, Piano Bass, RES SYNTH1, and ANLGSYN 1. RES SYNTH1 has oscillator sync enabled, so its phase-like attack issue is more likely relative operator attack/peak shape than free-running oscillator phase.","source":"community DX7 listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_graph_pitch_lfo","lesson":"ANLGSYN 1's missing beat is DX7 pitch LFO, not amplitude LFO: raw analog1.syx has AMD=71 but all operator AMS values are 0, while PMD=32/PMS=1/sine speed 38/delay 33 are active. Aquarium operator graphs now own graph-level vibrato (`vibrato`, `vibrato_hz`, `vibrato_delay`) and the DX7 probe lowers that LFO to about depth 0.003694 at 5.993 Hz with a 0.233s fade-in. A hard delay gate was tested and cut because it pushed log-mel over the ANLGSYN gate; fade-in keeps ANLGSYN passing at log-mel about 0.19497 and score about 0.6979.","source":"ANLGSYN 1 pitch-LFO beat correction on 2026-05-14"}
|
||||
{"kind":"dx7_mellowsolo_tail_window","lesson":"MELLOWSOLO pressure artifacts need a longer render window than 1.0s because the AquaSynth candidate emits a 0.6s release from a 0.65s gate, so the old WAV cut the tail before it could finish. Extending only the MELLOWSOLO pressure render to 1.25s improves log-mel from about 0.429 to 0.347 and makes the tail audible without changing the synth lowering or passing parity targets. A global traced-release-duration experiment was tested and cut because it shortened releases too aggressively and broke PRC, Piano Bass, RES SYNTH1, and ANLGSYN 1. RES SYNTH1 has oscillator sync enabled, so its phase-like attack issue is more likely relative operator attack/peak shape than free-running oscillator phase.","source":"community DX7 listening correction on 2026-05-14"}
|
||||
{"kind":"dx7_graph_pitch_lfo","lesson":"ANLGSYN 1's missing beat is DX7 pitch LFO, not amplitude LFO: raw analog1.syx has AMD=71 but all operator AMS values are 0, while PMD=32/PMS=1/sine speed 38/delay 33 are active. AquaSynth operator graphs now own graph-level vibrato (`vibrato`, `vibrato_hz`, `vibrato_delay`) and the DX7 probe lowers that LFO to about depth 0.003694 at 5.993 Hz with a 0.233s fade-in. A hard delay gate was tested and cut because it pushed log-mel over the ANLGSYN gate; fade-in keeps ANLGSYN passing at log-mel about 0.19497 and score about 0.6979.","source":"ANLGSYN 1 pitch-LFO beat correction on 2026-05-14"}
|
||||
{"kind":"zyn_reference_start","lesson":"The ZynAddSubFX phase should start with structural feature extraction, not translation. Upstream Zyn instruments live in a separate bank submodule and the preset provenance is not clear enough to vendor casually, so the first parser slice uses project-authored .xiz fixtures. `ZynInstrumentReader` reads plain or gzip-compressed XML and classifies active ADD/SUB/PAD engines, kit layering, envelopes, free envelopes, LFOs, filters, formants, and effects into ReferencePatch features.","source":"ZynAddSubFX feature extraction kickoff on 2026-05-14"}
|
||||
{"kind":"zyn_reference_rebuilds","lesson":"The first Zyn-style Aquarium rebuilds can sketch additive lead, PAD texture, and vocal/formant layer fixtures with existing voices, macros, formants, filters, noise, and modulation, but the missing abstractions are now concrete: additive harmonic-bank syntax, PAD/spectral source generation, free envelopes for normal voices, named kit/layer routing with per-layer effect sends, and richer formant/vowel morphing. Keep these as named pressure before adding new DSL surface.","source":"ZynAddSubFX rebuild catalog slice on 2026-05-14"}
|
||||
{"kind":"zyn_reference_rebuilds","lesson":"The first Zyn-style AquaSynth rebuilds can sketch additive lead, PAD texture, and vocal/formant layer fixtures with existing voices, macros, formants, filters, noise, and modulation, but the missing abstractions are now concrete: additive harmonic-bank syntax, PAD/spectral source generation, free envelopes for normal voices, named kit/layer routing with per-layer effect sends, and richer formant/vowel morphing. Keep these as named pressure before adding new DSL surface.","source":"ZynAddSubFX rebuild catalog slice on 2026-05-14"}
|
||||
{"kind":"zyn_worst_case_survey","lesson":"Scanning the upstream ZynAddSubFX instrument bank at commit e9f64a9 found 1358 .xiz files and the hardened reader now parses all of them. The nastiest target is `olivers-100/0032-Drum Kit.xiz`: 16 enabled kit items, mixed ADD/SUB/PAD engines, 106 envelopes, 25 free envelopes, 73 LFOs, 37 filters, and 3 formant filters. The broader top list says named kit/layer routing should come before syntax golf for additive banks, PAD sources, or formant motion; otherwise new abstractions will have no coherent owner.","source":"ZynAddSubFX pressure survey on 2026-05-14"}
|
||||
{"kind":"layer_language_golf","lesson":"The first Zyn-driven language-golf abstraction is `layer`: named layer declarations own engine tags, optional MIDI key range metadata, default gain, and effect-send labels, while lowering to ordinary Aquarium voices for now. The abstraction generalizes across additive, PAD-texture, and vocal/formant rebuilds and gives future additive-bank, PAD-source, free-envelope, and formant-motion syntax a coherent owner. It deliberately does not implement those later features yet.","source":"Zyn named layer DSL slice on 2026-05-14"}
|
||||
{"kind":"harmonic_bank_language_golf","lesson":"Additive `harmonics` syntax now records authored ratio/gain partial banks under named layers and lowers them to ordinary Aquarium voices. This generalizes additive lead and future drawbar/partial-bank targets without hiding Zyn ADDsynth phase, bandwidth, oscillator shaping, or free-envelope semantics behind a fake parity claim.","source":"Zyn harmonic-bank DSL slice on 2026-05-14"}
|
||||
{"kind":"layer_language_golf","lesson":"The first Zyn-driven language-golf abstraction is `layer`: named layer declarations own engine tags, optional MIDI key range metadata, default gain, and effect-send labels, while lowering to ordinary AquaSynth voices for now. The abstraction generalizes across additive, PAD-texture, and vocal/formant rebuilds and gives future additive-bank, PAD-source, free-envelope, and formant-motion syntax a coherent owner. It deliberately does not implement those later features yet.","source":"Zyn named layer DSL slice on 2026-05-14"}
|
||||
{"kind":"harmonic_bank_language_golf","lesson":"Additive `harmonics` syntax now records authored ratio/gain partial banks under named layers and lowers them to ordinary AquaSynth voices. This generalizes additive lead and future drawbar/partial-bank targets without hiding Zyn ADDsynth phase, bandwidth, oscillator shaping, or free-envelope semantics behind a fake parity claim.","source":"Zyn harmonic-bank DSL slice on 2026-05-14"}
|
||||
{"kind":"voice_rate_level_envelopes","lesson":"The existing readable `env=rl rates=... levels=... curves=... gate=...` contour now applies to normal voices and therefore to named layer defaults, not only operator graphs. This gives PAD and vocal Zyn rebuilds staged non-ADSR onset/release shape while preserving the invariant that Note owns gate timing and envelope data owns level shape. Arbitrary Zyn free-envelope point curves remain missing pressure.","source":"Zyn staged voice envelope DSL slice on 2026-05-14"}
|
||||
{"kind":"pad_spectral_cloud","lesson":"PAD-style layers now have `spectrum layer=... root=... spread=... partials=ratio:gain,...`, recorded as `SpectralBank` and generated as PADsynth-style FFT tables: frequency-domain harmonic spreading, deterministic random phase, one inverse FFT, normalization, then Faust waveform/rdtable playback before ordinary voice treatment. This gives PAD texture rebuilds a real spectral source authority without inflating the voice graph; roots/spreads/partials are authoring-time table shape, not runtime controls. It still does not claim full Zyn PAD harmonic-profile/randomness/pitch-zone behavior.","source":"Zyn PAD spectral-cloud DSL slice on 2026-05-14"}
|
||||
{"kind":"zyn_reference_oracle","lesson":"ZynAddSubFX source is pinned as GPL test/development material under `external/zynaddsubfx` at 3ab608c432996ba4d582176572c0b0f82328c825. Treat it like dexed-py: a parity oracle for tests and artifacts, not Aquarium implementation, runtime dependency, or NuGet package content. Before further Zyn DSL golf, build a test-only PAD renderer/wrapper from this source and compare Aquarium rebuilds against actual Zyn behavior.","source":"Zyn source pinning for parity on 2026-05-14"}
|
||||
{"kind":"zyn_reference_oracle","lesson":"ZynAddSubFX source is pinned as GPL test/development material under `external/zynaddsubfx` at 3ab608c432996ba4d582176572c0b0f82328c825. Treat it like dexed-py: a parity oracle for tests and artifacts, not AquaSynth implementation, runtime dependency, or NuGet package content. Before further Zyn DSL golf, build a test-only PAD renderer/wrapper from this source and compare AquaSynth rebuilds against actual Zyn behavior.","source":"Zyn source pinning for parity on 2026-05-14"}
|
||||
{"date":"2026-05-14","area":"zyn-reference","lesson":"Pinned Zyn can build on Windows through MSYS2/MinGW when GUI/plugins are disabled, tests are enabled, Werror is off, and the stale non-async MiddleWare Part constructor call is patched. Apply Zyn compatibility patches to ignored artifact source copies, not the clean pinned submodule.","evidence":"tools/zyn-reference/build-zyn-reference.ps1 copies external/zynaddsubfx to artifacts/zyn-source-msys, applies tools/zyn-reference/patches/0001-msys-part-constructor.patch, builds PadNoteTest, and ctest -R PadNoteTest passes."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-parity","lesson":"The Zyn PAD oracle now emits real reference material through Zyn PADnoteParameters/PADnote, and the first project-authored PAD comparison is not close: log-mel 0.552296, envelope 0.774501, RMS ratio 0.234763, centroid ratio 1.025735, score 0.236117. Treat this as evidence to isolate source table generation, playback/gain, envelope, and fixture mapping before adding more Zyn DSL syntax.","evidence":"tools/zyn-reference/ZynPadReference.cpp plus tests/AquariumSynth.Dsl.Tests/ZynReferenceParityTests.cs write artifacts/parity/zyn-pad-reference/pad-texture-zyn.wav, pad-texture-aqua.wav, and report.txt when the Zyn artifact renderer is built."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-parity","lesson":"User listening correctly identified the first Aquarium PAD rebuild as too noisy. The fix was architectural cleanup before new syntax: cut unearned noise/drive/soft-clip from the rebuild, interpolate spectral table reads, and use Zyn-sized 131072-frame PAD tables. Score improved from 0.236117 to 0.487325, with RMS ratio 1.008516 and centroid ratio 1.083082. Remaining mismatch is source profile/table generation and envelope semantics, not decorative layers.","evidence":"artifacts/parity/zyn-pad-reference/report.txt after the de-bee pass; full dotnet test passed 96/96."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-parity","lesson":"The Zyn PAD oracle now emits real reference material through Zyn PADnoteParameters/PADnote, and the first project-authored PAD comparison is not close: log-mel 0.552296, envelope 0.774501, RMS ratio 0.234763, centroid ratio 1.025735, score 0.236117. Treat this as evidence to isolate source table generation, playback/gain, envelope, and fixture mapping before adding more Zyn DSL syntax.","evidence":"tools/zyn-reference/ZynPadReference.cpp plus tests/AquaSynth.Dsl.Tests/ZynReferenceParityTests.cs write artifacts/parity/zyn-pad-reference/pad-texture-zyn.wav, pad-texture-aqua.wav, and report.txt when the Zyn artifact renderer is built."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-parity","lesson":"User listening correctly identified the first AquaSynth PAD rebuild as too noisy. The fix was architectural cleanup before new syntax: cut unearned noise/drive/soft-clip from the rebuild, interpolate spectral table reads, and use Zyn-sized 131072-frame PAD tables. Score improved from 0.236117 to 0.487325, with RMS ratio 1.008516 and centroid ratio 1.083082. Remaining mismatch is source profile/table generation and envelope semantics, not decorative layers.","evidence":"artifacts/parity/zyn-pad-reference/report.txt after the de-bee pass; full dotnet test passed 96/96."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-parity","lesson":"The octave-low Zyn PAD mismatch came from conflating spectral table root with note playback frequency. `spectrum root` must own table/base frequency, while `freq` owns the played note. Using Zyn's sample basefreq 77.7813 with playback freq 261.6256, and removing gratuitous spread/vibrato, improved the PAD report to log-mel 0.353365, envelope 0.348752, RMS ratio 0.97283, centroid ratio 0.999243, score 0.612832.","evidence":"PatchScript now preserves spectrum freq as voice note frequency; PatchScriptTests.SpectralBankSeparatesTableRootFromPlaybackFrequency covers the invariant; artifacts/parity/zyn-pad-reference/report.txt records the improved score."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-parity","lesson":"Aqua's remaining detuned impression was caused by stacking same-note PAD spectral voices. Collapse body/high content into one coherent spectral table before adding layers for richness. A simple gain trim then brought loudness into line: RMS ratio 1.001704, centroid ratio 1.004072, score 0.6211.","evidence":"BuiltInScripts.ZynStylePadTexture now uses one active PAD spectrum with partials 1, 1.5, and 2 plus patch gain 1.1; artifacts/parity/zyn-pad-reference/report.txt records the focused render."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-fixtures","lesson":"More PAD fixtures immediately exposed which pressure is real: `pad-pure` and old `pad-texture` render identically through Zyn, so the filter/category XML in `pad-texture` was not live oracle behavior. `pad-harmonic` changes table and note output through explicit OSCIL harmonics and should be the next PAD parity rung.","evidence":"tests/AquariumSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored/pad-pure.xiz and pad-harmonic.xiz plus artifacts/parity/zyn-pad-fixtures/report.txt."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-fixtures","lesson":"More PAD fixtures immediately exposed which pressure is real: `pad-pure` and old `pad-texture` render identically through Zyn, so the filter/category XML in `pad-texture` was not live oracle behavior. `pad-harmonic` changes table and note output through explicit OSCIL harmonics and should be the next PAD parity rung.","evidence":"tests/AquaSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored/pad-pure.xiz and pad-harmonic.xiz plus artifacts/parity/zyn-pad-fixtures/report.txt."}
|
||||
{"date":"2026-05-15","area":"zyn-upstream-gpl-bank","lesson":"GPL Zyn presets are acceptable as test-only feedstock. The upstream instrument submodule at `external/zynaddsubfx/instruments` commit c5c912131b31df5fdf372d2f06a25aaf2375837f provides 1318 `.xiz` files; survey and PAD render tests write ignored reports/WAVs while the NuGet boundary still excludes `.xiz`, `external/`, and artifacts.","evidence":"ZynInstrumentTests.SurveysUpstreamGplInstrumentBankWhenAvailable and ZynReferenceParityTests.ZynPadReferenceRendererSurveysUpstreamGplPadFixturesWhenBuilt; focused Zyn tests passed 14/14."}
|
||||
{"date":"2026-05-15","area":"zyn-artifact-layout","lesson":"Zyn PAD listening artifacts now follow the DX7 parity shape: per-synth timestamped run folders with Zyn reference WAVs, source-table WAVs, `report.txt`, and `candidate.aqua`. Upstream GPL PAD runs write `candidate-aquarium.wav`; this was initially the current ZynStylePadTexture baseline and is now superseded by generated per-preset PAD rebuilds.","evidence":"ZynReferenceParityTests focused run passed 4/4 and wrote folders such as artifacts/parity/zyn-upstream-pad-fixtures/0121-ghost-ensemble-20260515T072330036."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-translation","lesson":"Zyn PAD artifacts now use per-preset generated `.aqua` instead of the generic baseline. `ZynInstrumentReader.RebuildFirstPadAsAquariumScript` translates the first enabled PAD kit item into one named PAD layer plus a `spectrum` bank using OSCIL harmonic magnitudes, Zyn oracle sample `basefreq` as table root, PAD volume as layer gain, and simple rate/level envelope scaffolding. Reports explicitly list missing Zyn semantics: bandwidth/profile spreading, harmonic profile shaping, and filter envelope/LFO lowering.","evidence":"ZynInstrumentTests.RebuildsProjectAuthoredPadAsAquariumSpectrumScript plus focused Zyn tests passed 13/13; latest upstream PAD reports include generated candidate scripts and log-mel scores from ~0.276 to ~0.637."}
|
||||
{"date":"2026-05-15","area":"zyn-artifact-layout","lesson":"Zyn PAD listening artifacts now follow the DX7 parity shape: per-synth timestamped run folders with Zyn reference WAVs, source-table WAVs, `report.txt`, and `candidate.aqua`. Upstream GPL PAD runs write `candidate-aquasynth.wav`; this was initially the current ZynStylePadTexture baseline and is now superseded by generated per-preset PAD rebuilds.","evidence":"ZynReferenceParityTests focused run passed 4/4 and wrote folders such as artifacts/parity/zyn-upstream-pad-fixtures/0121-ghost-ensemble-20260515T072330036."}
|
||||
{"date":"2026-05-15","area":"zyn-pad-translation","lesson":"Zyn PAD artifacts now use per-preset generated `.aqua` instead of the generic baseline. `ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript` translates the first enabled PAD kit item into one named PAD layer plus a `spectrum` bank using OSCIL harmonic magnitudes, Zyn oracle sample `basefreq` as table root, PAD volume as layer gain, and simple rate/level envelope scaffolding. Reports explicitly list missing Zyn semantics: bandwidth/profile spreading, harmonic profile shaping, and filter envelope/LFO lowering.","evidence":"ZynInstrumentTests.RebuildsProjectAuthoredPadAsAquaSynthSpectrumScript plus focused Zyn tests passed 13/13; latest upstream PAD reports include generated candidate scripts and log-mel scores from ~0.276 to ~0.637."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-profile-table-semantics","lesson":"Zyn PAD bandwidth/profile/position fields belong on SpectralBank as table-generation data, not in parity side channels. Mapping those fields and Zyn's exponential PAD volume curve improved gain/envelope evidence, but profile math alone did not solve log-mel parity.","evidence":"Focused Zyn tests passed 13/13 after adding PadSpectrumProfile and zyn_* script fields; upstream PAD batch still has log-mel roughly 0.34-0.69 depending on fixture."}
|
||||
{"date":"2026-05-15","topic":"zyn-oscilgen-approximation","lesson":"Expanding a subset of Zyn OscilGen base_function plus spectrum_adjust is conceptually the right owner for one-harmonic PAD presets, but the first approximation is mixed and must not be treated as solved parity.","evidence":"Soft Pad log-mel improved to 0.342738 and Organ Choir Pad2 to 0.573216, while sin2x pad regressed to 0.524421, DoublePadBass to 0.689315, and Ghost Ensemble to 0.482155. Next cut needs more OscilGen semantics or gating."}
|
||||
{"date":"2026-05-15","topic":"zyn-oscilgen-stage-order","lesson":"Zyn OscilGen partial extraction should only run the sampled waveform pipeline when oscillator processing stages are live; otherwise direct harmonics stay readable and capped. A broad base-function expansion made some presets worse without earning its complexity.","evidence":"After adding sampled filter/waveshape/modulation stage order and restoring a capped direct path, sin2x pad improved to log-mel 0.455193, while Soft Pad stayed 0.342738 and Ghost stayed 0.40922. DoublePadBass and Organ Choir remain poor, so this is an incremental rung, not parity."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-kit-layering","lesson":"Do not treat first enabled PAD kit item as a Zyn instrument when kit_mode is multi-kit. Multi-kit PAD presets need per-kit table roots and layered Aqua spectrum banks, or parity artifacts compare against an amputated preset.","evidence":"DoublePadBass has kit_mode=1 with enabled PAD kit items 0 and 1. Rebuilding/summing both moved log-mel from about 0.655 to 0.493 and generated doublepadbass_0 plus doublepadbass_1. Raising the volume cap to 3.0 worsened log-mel to 0.521 and was cut."}
|
||||
{"date":"2026-05-15","topic":"zyn-ghost-base-function","lesson":"A direct-harmonic readability gate must not erase source identity. Ghost Ensemble needed power-base OscilGen expansion even without downstream oscillator stages; otherwise it collapsed toward a generic two-partial pad.","evidence":"Ghost Ensemble has base_function=4 with two explicit harmonics. Expanding power-base multi-harmonic sources changed the candidate from two partials to 32 partials and improved score to 0.446977, with log-mel 0.402789."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-static-filter","lesson":"Zyn PAD static global filter frequency is audible layer-balance authority, not optional decoration. Read nested FILTER params under FILTER_PARAMETERS and lower old Zyn cutoff values through the exponential FilterParams curve, not a linear freq/127 guess.","evidence":"DoublePadBass kit0 filter freq=12 and kit1 freq=61. Linear mapping gave lpf=0.094488/0.480315 and still sounded like all kazoo. Zyn's curve maps them to lpf=0.003325/0.047225, improving log-mel to 0.334546 and making the generated patch deep-bass-first. Filter envelopes/LFOs and level recovery remain missing pressure."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-detune-and-filter-order","lesson":"Zyn PAD note frequency is not just the requested note plus table root; FREQUENCY_PARAMETERS coarse/fine detune are live playback authority, and analog LP2 needs a steeper low-pass than Aquarium's old one-pole default.","evidence":"DoublePadBass has coarse_detune=15360, which Zyn getdetune wraps from octave 15 to -1 octave. Emitting spectrum freq=130.8128 instead of 261.6256 and lpf_order=2 moved DoublePadBass log-mel from 0.334546 after static cutoff mapping to 0.259298; remaining gap is RMS/envelope."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-filter-envelope","lesson":"Zyn PAD FILTER_ENVELOPE is audible transient authority. Static cutoff parity can get the tone right while still missing the opening hit; Aquarium needs explicit low-pass cutoff envelopes with nonzero start levels.","evidence":"DoublePadBass sounded tonally right but softer at onset. Mapping Zyn ADSR-filter octave offsets into lpf_env=rl with lpf_start improved log-mel from 0.259298 to 0.241993, envelope distance from 0.631427 to 0.554658, RMS ratio from 0.390177 to 0.456173, and score from 0.370218 to 0.404382."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-detune-and-filter-order","lesson":"Zyn PAD note frequency is not just the requested note plus table root; FREQUENCY_PARAMETERS coarse/fine detune are live playback authority, and analog LP2 needs a steeper low-pass than AquaSynth's old one-pole default.","evidence":"DoublePadBass has coarse_detune=15360, which Zyn getdetune wraps from octave 15 to -1 octave. Emitting spectrum freq=130.8128 instead of 261.6256 and lpf_order=2 moved DoublePadBass log-mel from 0.334546 after static cutoff mapping to 0.259298; remaining gap is RMS/envelope."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-filter-envelope","lesson":"Zyn PAD FILTER_ENVELOPE is audible transient authority. Static cutoff parity can get the tone right while still missing the opening hit; AquaSynth needs explicit low-pass cutoff envelopes with nonzero start levels.","evidence":"DoublePadBass sounded tonally right but softer at onset. Mapping Zyn ADSR-filter octave offsets into lpf_env=rl with lpf_start improved log-mel from 0.259298 to 0.241993, envelope distance from 0.631427 to 0.554658, RMS ratio from 0.390177 to 0.456173, and score from 0.370218 to 0.404382."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-output-calibration","lesson":"After PAD table roots, detune, filter order, filter envelope, and logarithmic envelope times are mapped, remaining Zyn PAD loudness can be a generated-rebuild output calibration rather than another per-layer fixture tweak.","evidence":"Current PAD fixture RMS ratios before calibration were consistently low: DoublePadBass 0.511669, Soft Pad 0.619347, Organ Choir 0.588127, Ghost 0.730155, sin2x 0.775653. Emitting patch gain=1.6 moved DoublePadBass candidate WAV peak to 0.979 against clipped Zyn reference peak 1.0, envelope distance to 0.226563, RMS ratio to 0.818669, and score to 0.631168 while keeping batch RMS plausible."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-filter-q","lesson":"Zyn PAD analog filter Q is real filter damping authority and belongs as a general Aquarium filter surface (`lpf_q`), not as a fixture-specific cutoff/gain fudge.","evidence":"Ghost Ensemble has FILTER freq_track=97 and q=28. Adding note-tracked cutoff lowered Ghost lpf from 0.369706 to 0.282776 and adding explicit lpf_q=0.499021 moved log-mel from 0.38424 to 0.375637 and RMS ratio from 1.155288 to 1.09995. DoublePadBass remained acceptable and improved to log-mel 0.247729 / score 0.650069 after Q."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-filter-q","lesson":"Zyn PAD analog filter Q is real filter damping authority and belongs as a general AquaSynth filter surface (`lpf_q`), not as a fixture-specific cutoff/gain fudge.","evidence":"Ghost Ensemble has FILTER freq_track=97 and q=28. Adding note-tracked cutoff lowered Ghost lpf from 0.369706 to 0.282776 and adding explicit lpf_q=0.499021 moved log-mel from 0.38424 to 0.375637 and RMS ratio from 1.155288 to 1.09995. DoublePadBass remained acceptable and improved to log-mel 0.247729 / score 0.650069 after Q."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-q-order-cascade","lesson":"Explicit low-pass Q must not erase low-pass order. When a reference filter has both damping and slope, Faust lowering should cascade resonant stages according to `lpf_order` rather than replacing the filter with one generic resonant low-pass.","evidence":"Ghost Ensemble still sounded bright in the middle after lpf_q. Cascading resonlp stages for lpf_order=4 moved Ghost log-mel from 0.375637 to 0.369402 and RMS ratio from 1.09995 to 1.054875 while keeping DoublePadBass near its accepted score: log-mel 0.247748, score 0.650029. ZynPadReference harmonic dumps showed Ghost's first 32 imported OscilGen partial ratios already matched Zyn, so this was filter slope, not first-page harmonic extraction."}
|
||||
{"date":"2026-05-15","topic":"zyn-oscil-filter-index","lesson":"Zyn OscilGen oscillator filter functions use one-based harmonic indices. Do not translate them through a zero-based Aquarium index; that moves spectral features to the wrong partial and can make a preset sound like the wrong overtone is being emphasized.","evidence":"sin2x uses oscillator filter type 13. With zero-based indexing, Aquarium put the spike on h3 and had centroid ratio 1.227953. After preserving Zyn's one-based index, candidate partials are h2-dominant, centroid ratio improves to 0.998145, log-mel moves from 0.491437 to 0.479782, and UpstreamSin2xOscilFilterKeepsSpikeOnSecondHarmonicWhenAvailable asserts h2 > h3 * 10."}
|
||||
{"date":"2026-05-15","topic":"zyn-oscil-filter-index","lesson":"Zyn OscilGen oscillator filter functions use one-based harmonic indices. Do not translate them through a zero-based AquaSynth index; that moves spectral features to the wrong partial and can make a preset sound like the wrong overtone is being emphasized.","evidence":"sin2x uses oscillator filter type 13. With zero-based indexing, AquaSynth put the spike on h3 and had centroid ratio 1.227953. After preserving Zyn's one-based index, candidate partials are h2-dominant, centroid ratio improves to 0.998145, log-mel moves from 0.491437 to 0.479782, and UpstreamSin2xOscilFilterKeepsSpikeOnSecondHarmonicWhenAvailable asserts h2 > h3 * 10."}
|
||||
{"date":"2026-05-15","topic":"zyn-organ-highpass-selected-root","lesson":"Organ Choir's coherent octave blast needs real Zyn PAD high-pass ownership and selected table roots for OscilGen shift-base sources, but selected roots must not become the global default. The source rule is narrow: keep sample-0 roots unless the PAD OscilGen base function is the shift source (`base_function=7`) and the oracle provides the selected note table root.","evidence":"Organ Choir kit0 has analog HP2 with stages and FILTER_ENVELOPE, while kit1 uses base_function=7. Mapping hpf_order/hpf_env and using the selected 622.25 Hz table root only for kit1 moved the candidate's dominant peak to 522.67 Hz with 261 Hz at -1.29 dB, close to Zyn's 523.33 Hz lead and 261 Hz at -2.23 dB. Latest Organ log-mel is 0.499122 / score 0.51966, while accepted Soft Pad, Ghost, and DoublePadBass remain on sample-0 roots; global selected roots had regressed DoublePadBass."}
|
||||
{"date":"2026-05-15","topic":"zyn-organ-basefunc-mod-adaptive","lesson":"Organ Choir's violin-vs-wind mismatch was OscilGen source-table ownership, not pitch, envelope, or gain. Zyn `base_function_modulation` warps the phase before base-function sampling, and `adaptive_harmonics` remaps the prepared oscillator spectrum at the PAD table root; both must happen before PAD bandwidth/profile spreading.","evidence":"Before the fix, Aqua kit1 partials formed a smooth ramp (h3 -3.5 dB, h4 -5.1 dB, h8 -10.2 dB relative to h1) while Zyn's harmonic dump was sparse (h3 -27.1 dB, h4 -70.3 dB, h8 -50.2 dB). Applying base_function_modulation=1 and adaptive_harmonics=1 moved kit1 table energy to 400-800 Hz 0.2713 vs Zyn 0.2780 and 8-16 kHz 0.1471 vs Zyn 0.1355; Organ log-mel improved to 0.471483 and score to 0.541933 without changing accepted DoublePadBass, Ghost, or Soft Pad."}
|
||||
{"date":"2026-05-15","topic":"zyn-pad-ear-vs-logmel","lesson":"For sustained Zyn PAD fixtures, log-mel distance can remain pessimistic after the perceptual target has been reached. Keep it as a regression and triage signal, but do not keep grinding accepted fixtures solely to chase a DX7-like numeric threshold when listening and structural source-table evidence agree.","evidence":"After mapping selected roots, HP filter motion, Q/order cascades, one-based OscilGen filter indices, base-function phase modulation, and adaptive harmonics, the user accepted DoublePadBass, Ghost Ensemble, Soft Pad, Organ Choir, and the other recent community PAD fixtures by ear. Organ Choir still reports log-mel 0.471483 despite direct kit1 table energy matching the Zyn body/air balance and the listener judging all fixtures equivalent."}
|
||||
{"date":"2026-05-16","topic":"pad-syntax-generalization","lesson":"Reference-synth names must not become canonical Aquarium syntax or public patch-model vocabulary. Importers may translate Zyn controls, and parser aliases may keep old parity artifacts readable, but generated/authored `.aqua` should use Aquarium-native `pad_*` terms for general spectral-table intent.","evidence":"Zyn PAD parity had produced generated scripts with `zyn_mode`, `zyn_bandwidth`, `zyn_bwscale`, `zyn_profile`, and `zyn_position`, plus public model names like `ZynHarmonicProfile`. The generalization pass changed generated scripts to `pad_mode`, `pad_bandwidth`, `pad_bwscale`, `pad_profile`, and `pad_position`, renamed the public profile/position records and enums to PAD-native names, preserved legacy `zyn_*` parser aliases, and passed `dotnet test AquariumSynthCSharp.slnx --no-restore` with 108 tests."}
|
||||
{"date":"2026-05-16","topic":"pad-syntax-generalization","lesson":"Reference-synth names must not become canonical AquaSynth syntax or public patch-model vocabulary. Importers may translate Zyn controls, and parser aliases may keep old parity artifacts readable, but generated/authored `.aqua` should use AquaSynth-native `pad_*` terms for general spectral-table intent.","evidence":"Zyn PAD parity had produced generated scripts with `zyn_mode`, `zyn_bandwidth`, `zyn_bwscale`, `zyn_profile`, and `zyn_position`, plus public model names like `ZynHarmonicProfile`. The generalization pass changed generated scripts to `pad_mode`, `pad_bandwidth`, `pad_bwscale`, `pad_profile`, and `pad_position`, renamed the public profile/position records and enums to PAD-native names, preserved legacy `zyn_*` parser aliases, and passed `dotnet test AquaSynth.slnx --no-restore` with 108 tests."}
|
||||
{"date":"2026-05-16","topic":"project-rename-aquasynth","lesson":"The C# synth repo is now AquaSynth and the Rust reference branch is AquaSynth-rs. Keep repo wiring, package metadata, namespaces, solution/project names, env vars, docs, and state aligned to AquaSynth; do not reintroduce AquariumSynthCSharp/AquariumSynth.Dsl names.","evidence":"Renamed solution to AquaSynth.slnx, projects to src/AquaSynth.Dsl and tests/AquaSynth.Dsl.Tests, namespaces/package to AquaSynth.Dsl, package version suffix to 0.1.0-aquasynth.1, DX7 env var to AQUASYNTH_DX7_PYTHON, and origin to https://github.com/GameCult/AquaSynth.git. Verified `dotnet build AquaSynth.slnx --no-restore`, `dotnet test tests\\AquaSynth.Dsl.Tests\\AquaSynth.Dsl.Tests.csproj --no-build -v minimal` with 108 passed, and `dotnet pack src\\AquaSynth.Dsl\\AquaSynth.Dsl.csproj -c Release --no-restore` producing AquaSynth.Dsl.0.1.0-aquasynth.1.nupkg."}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
project: AquariumSynthCSharp
|
||||
project: AquaSynth
|
||||
mission: >
|
||||
C# authoring, analysis, and Faust generation layer for Aquarium synth patches,
|
||||
targeting the Aquarium/Vortice engine path without dragging the Rust renderer
|
||||
C# authoring, analysis, and Faust generation layer for AquaSynth patches,
|
||||
targeting the AquaSynth/Vortice engine path without dragging the Rust renderer
|
||||
into runtime dependencies.
|
||||
surfaces:
|
||||
instructions: AGENTS.md
|
||||
|
|
@ -10,32 +10,32 @@ surfaces:
|
|||
scratch: state/scratch.md
|
||||
evidence: state/evidence.jsonl
|
||||
spine: state/spine.yaml
|
||||
solution: AquariumSynthCSharp.slnx
|
||||
library: src/AquariumSynth.Dsl
|
||||
solution: AquaSynth.slnx
|
||||
library: src/AquaSynth.Dsl
|
||||
patch_library: patches
|
||||
tests: tests/AquariumSynth.Dsl.Tests
|
||||
tests: tests/AquaSynth.Dsl.Tests
|
||||
reference_roadmap: docs/reference-synth-roadmap.md
|
||||
dx7_public_domain_fixtures: tests/AquariumSynth.Dsl.Tests/Fixtures/Dx7/PublicDomain
|
||||
dx7_public_domain_fixtures: tests/AquaSynth.Dsl.Tests/Fixtures/Dx7/PublicDomain
|
||||
zyn_reference_source: external/zynaddsubfx
|
||||
zyn_upstream_instrument_bank: external/zynaddsubfx/instruments
|
||||
zyn_reference_build_script: tools/zyn-reference/build-zyn-reference.ps1
|
||||
zyn_pad_reference_renderer: tools/zyn-reference/ZynPadReference.cpp
|
||||
zyn_reference_build_patches: tools/zyn-reference/patches
|
||||
zyn_project_fixtures: tests/AquariumSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored
|
||||
package: AquariumSynth.Dsl 0.1.0-aquarium.1
|
||||
zyn_project_fixtures: tests/AquaSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored
|
||||
package: AquaSynth.Dsl 0.1.0-aquasynth.1
|
||||
modules:
|
||||
model: src/AquariumSynth.Dsl/Model.cs
|
||||
parser: src/AquariumSynth.Dsl/PatchScript.cs
|
||||
faust: src/AquariumSynth.Dsl/FaustExport.cs
|
||||
faust_rendering: src/AquariumSynth.Dsl/FaustExport.cs
|
||||
dx7_reference_render_tests: tests/AquariumSynth.Dsl.Tests/Dx7ReferenceParityTests.cs
|
||||
zyn_reference_reader: src/AquariumSynth.Dsl/ZynInstrument.cs
|
||||
package_boundary_tests: tests/AquariumSynth.Dsl.Tests/PackageBoundaryTests.cs
|
||||
sfxr: src/AquariumSynth.Dsl/SfxrParams.cs
|
||||
analysis: src/AquariumSynth.Dsl/AudioAnalysis.cs
|
||||
scoring: src/AquariumSynth.Dsl/ScriptMetrics.cs
|
||||
presets: src/AquariumSynth.Dsl/Presets.cs
|
||||
built_in_scripts: src/AquariumSynth.Dsl/BuiltInScripts.cs
|
||||
model: src/AquaSynth.Dsl/Model.cs
|
||||
parser: src/AquaSynth.Dsl/PatchScript.cs
|
||||
faust: src/AquaSynth.Dsl/FaustExport.cs
|
||||
faust_rendering: src/AquaSynth.Dsl/FaustExport.cs
|
||||
dx7_reference_render_tests: tests/AquaSynth.Dsl.Tests/Dx7ReferenceParityTests.cs
|
||||
zyn_reference_reader: src/AquaSynth.Dsl/ZynInstrument.cs
|
||||
package_boundary_tests: tests/AquaSynth.Dsl.Tests/PackageBoundaryTests.cs
|
||||
sfxr: src/AquaSynth.Dsl/SfxrParams.cs
|
||||
analysis: src/AquaSynth.Dsl/AudioAnalysis.cs
|
||||
scoring: src/AquaSynth.Dsl/ScriptMetrics.cs
|
||||
presets: src/AquaSynth.Dsl/Presets.cs
|
||||
built_in_scripts: src/AquaSynth.Dsl/BuiltInScripts.cs
|
||||
boundaries:
|
||||
leave_in_rust:
|
||||
- sample renderer
|
||||
|
|
@ -57,8 +57,8 @@ boundaries:
|
|||
- structured .aqua patch library
|
||||
checks:
|
||||
default: dotnet test
|
||||
package: dotnet pack src/AquariumSynth.Dsl/AquariumSynth.Dsl.csproj -c Release
|
||||
package: dotnet pack src/AquaSynth.Dsl/AquaSynth.Dsl.csproj -c Release
|
||||
faust_validation: automatic in tests when Faust is installed
|
||||
dexed_py_reference: optional in tests when AQUARIUM_DX7_PYTHON or a Python with dexed-py is available
|
||||
dexed_py_reference: optional in tests when AQUASYNTH_DX7_PYTHON or a Python with dexed-py is available
|
||||
zyn_reference_source: pinned submodule used only for parity tests; never package content
|
||||
zyn_upstream_instrument_bank: nested GPL submodule used only for test/development pressure surveys and oracle renders; never package content
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"project": "AquariumSynthCSharp",
|
||||
"mission": "Own Aquarium Synth patch authoring, analysis, preset mapping, and Faust generation in C# for the Aquarium/Vortice engine path.",
|
||||
"project": "AquaSynth",
|
||||
"mission": "Own AquaSynth patch authoring, analysis, preset mapping, and Faust generation in C# for the AquaSynth/Vortice engine path.",
|
||||
"current_boundary": {
|
||||
"leave_in_rust": [
|
||||
"Rust sample renderer",
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
"state/spine.yaml"
|
||||
],
|
||||
"reference_strategy": {
|
||||
"purpose": "Use external synths and DSP corpora as parity pressure for Aquarium's patch DSL and Faust emitter: the DSL must reproduce behavior in terse, readable Aquarium syntax, not clone foreign internals.",
|
||||
"purpose": "Use external synths and DSP corpora as parity pressure for AquaSynth's patch DSL and Faust emitter: the DSL must reproduce behavior in terse, readable AquaSynth syntax, not clone foreign internals.",
|
||||
"priority_order": [
|
||||
"DX7/Dexed SysEx for FM operator topology",
|
||||
"ZynAddSubFX instruments for additive, subtractive, PAD, formant, and layered patches",
|
||||
|
|
@ -80,13 +80,13 @@
|
|||
"rule": "Add DSL abstractions only when reference rebuilds prove the missing invariant. Do not consume references that cannot be backed by parity tests; parsing alone is inventory, not evidence of expressivity."
|
||||
},
|
||||
"dx7_reference_path": {
|
||||
"status": "DX7 SysEx parser extracts voice edit buffers, packed voices, packed 32-voice banks, six operators, envelopes, algorithm, feedback, oscillator sync, LFO, transpose, voice name, checksum validation, ReferencePatch features, algorithm topology from the reverse-engineered OPS algorithm ROM table, envelope-to-ADSR approximations, measured carrier output amplitude, isolated two-op modulation route scale, summed/cascaded route scale, calibrated feedback amount table, ratio detune lowering, voice transpose lowering, fixed-frequency operator lowering, ROM COM output compensation cut, operator key/rate scaling at the effective played note, topology-aware route lowering, staged operator envelopes with per-segment curves, raw and block-interpolated DX7 envelope tracing, applied-envelope curved lowering with optional sustain floor, two Aquarium DSL rebuild attempts, first-class OperatorGraph support with graph-level vibrato, public-domain SysEx fixture coverage, dexed-py reference rendering, project-authored Dexed patch rendering, Aquarium candidate rendering through Faust-generated C#, one thresholded rendered parity test for analog1.syx voice 13, a hard PRC SYNTH1 parity probe with listening WAV artifacts and log-mel <= 0.145, project-authored algorithm-8 summed-stack/cascade/summed-pair parity, rendered community parity for Mooger, Piano Bass, RES SYNTH1, and ANLGSYN 1 with a sustained high-band gate, a MELLOWSOLO pressure artifact test, and renderable delayed operator feedback.",
|
||||
"lesson": "Algorithm 32's additive six-carrier shape maps cleanly to six Aquarium voices. Algorithm 8 justified OperatorGraph: operators, modulation edges, carriers, feedback, and graph-level pitch motion belong to a graph authority, not Voice fields. The first rendered parity rung is behavioral and sine-like, not exact DX7 operator execution. A harder algorithm-8 target exposed that feedback must be delayed recursion in Faust, not a direct cyclic self-reference. Static DX7 output-level approximation helped import/rebuild math but was mathematically wrong for carrier amplitude. A single-carrier Dexed sweep shows carrier amplitude follows 2^((outputLevel - 99) / 8). Isolated two-op DX7 FM maps full-level modulation to Aquarium route index 6.275; summed/cascaded algorithm-8 branches now use 6.0 after PRC listening, a project-authored combined stack probe, and split cascade/summed-pair probes showed lower values were under-bright. Feedback lowers through a fitted table instead of PRC-local constants; ANLGSYN 1 showed max feedback value 7 needs a hotter Aquarium amount 2.2 to recover buzzy high bands, while value 5 remains 0.19 for PRC. ANLGSYN 1 then exposed a sustained-buzz gap: output soft clip helped but did not stop mid-note drift; max-feedback source operators need an applied-envelope sustain floor so the feedback loop stays driven after the attack. ANLGSYN 1's remaining beat is pitch LFO: AMD is nonzero but all operator AMS values are 0, while PMD/PMS lower cleanly to operator-graph vibrato with faded delay. Ratio-mode detune belongs in operator frequency lowering. DX7 voice transpose belongs in graph base frequency: transpose 24 is neutral, transpose 12 lowers MIDI note 60 to 130.8128 Hz. DX7 fixed-frequency operators are absolute Hz, not note ratios; ANLGSYN 1 proved fixed op1/op3 must lower to ratios around 0.007615/0.009227 against a 130.8128 Hz graph base to preserve low buzzing modulation. ROM COM carrier compensation was cut: user listening found no-COM renders harmonically closer and mainly too quiet, so `OperatorOutputCompensation` returns unity and graph gain owns loudness recovery. Operator key-scaling and rate-scaling must lower against the effective played MIDI note after transpose; hardcoded MIDI 60 made RES SYNTH1 too soft on attack and Piano Bass less harmonically accurate. Project-authored Dexed patch rendering now gives lawful calibration targets. Reusing the operator output curve for EG levels was tested and cut because it failed hard-target log-mel; later output-level-dependent and naive traced-release applied-envelope experiments were also cut because they worsened broader parity. Direct envelope tracing shows current linear `env=rl` cannot express DX7 EG spike/drop behavior. Dexed-style audio samples EG once per 64-sample block and interpolates applied gain, so raw EG parity alone is not audio parity. Staged operator envelopes now support linear/exponential segments and supranormal levels. `ApproximateAppliedRateLevelEnvelope` uses that surface and now picks the first near-peak before gate so slower rising modulators hit early instead of swelling late; it can also preserve a floor for max-feedback source sustain. Community gains with no COM and played-note scaling: Mooger 0.75, Piano Bass 0.72, RES SYNTH1 0.75. Algorithm-2 non-carrier applied envelopes currently cap the first peak at 0.92 to prevent ANLGSYN 1/RES SYNTH1 peak blowout while preserving Piano Bass. MELLOWSOLO is a pressure artifact test, not passing parity; its render window is 1.25s so the candidate release is audible instead of cut at the artifact boundary. Mooger needs a more aggressive attack contour, and RES SYNTH1's phase-like attack issue is likely relative operator attack/peak shape because oscillator sync is enabled. PRC remains passing on log-mel/envelope/RMS, with score floor lowered to 0.74 after rate scaling changed the aggregate score.",
|
||||
"status": "DX7 SysEx parser extracts voice edit buffers, packed voices, packed 32-voice banks, six operators, envelopes, algorithm, feedback, oscillator sync, LFO, transpose, voice name, checksum validation, ReferencePatch features, algorithm topology from the reverse-engineered OPS algorithm ROM table, envelope-to-ADSR approximations, measured carrier output amplitude, isolated two-op modulation route scale, summed/cascaded route scale, calibrated feedback amount table, ratio detune lowering, voice transpose lowering, fixed-frequency operator lowering, ROM COM output compensation cut, operator key/rate scaling at the effective played note, topology-aware route lowering, staged operator envelopes with per-segment curves, raw and block-interpolated DX7 envelope tracing, applied-envelope curved lowering with optional sustain floor, two AquaSynth DSL rebuild attempts, first-class OperatorGraph support with graph-level vibrato, public-domain SysEx fixture coverage, dexed-py reference rendering, project-authored Dexed patch rendering, AquaSynth candidate rendering through Faust-generated C#, one thresholded rendered parity test for analog1.syx voice 13, a hard PRC SYNTH1 parity probe with listening WAV artifacts and log-mel <= 0.145, project-authored algorithm-8 summed-stack/cascade/summed-pair parity, rendered community parity for Mooger, Piano Bass, RES SYNTH1, and ANLGSYN 1 with a sustained high-band gate, a MELLOWSOLO pressure artifact test, and renderable delayed operator feedback.",
|
||||
"lesson": "Algorithm 32's additive six-carrier shape maps cleanly to six AquaSynth voices. Algorithm 8 justified OperatorGraph: operators, modulation edges, carriers, feedback, and graph-level pitch motion belong to a graph authority, not Voice fields. The first rendered parity rung is behavioral and sine-like, not exact DX7 operator execution. A harder algorithm-8 target exposed that feedback must be delayed recursion in Faust, not a direct cyclic self-reference. Static DX7 output-level approximation helped import/rebuild math but was mathematically wrong for carrier amplitude. A single-carrier Dexed sweep shows carrier amplitude follows 2^((outputLevel - 99) / 8). Isolated two-op DX7 FM maps full-level modulation to AquaSynth route index 6.275; summed/cascaded algorithm-8 branches now use 6.0 after PRC listening, a project-authored combined stack probe, and split cascade/summed-pair probes showed lower values were under-bright. Feedback lowers through a fitted table instead of PRC-local constants; ANLGSYN 1 showed max feedback value 7 needs a hotter AquaSynth amount 2.2 to recover buzzy high bands, while value 5 remains 0.19 for PRC. ANLGSYN 1 then exposed a sustained-buzz gap: output soft clip helped but did not stop mid-note drift; max-feedback source operators need an applied-envelope sustain floor so the feedback loop stays driven after the attack. ANLGSYN 1's remaining beat is pitch LFO: AMD is nonzero but all operator AMS values are 0, while PMD/PMS lower cleanly to operator-graph vibrato with faded delay. Ratio-mode detune belongs in operator frequency lowering. DX7 voice transpose belongs in graph base frequency: transpose 24 is neutral, transpose 12 lowers MIDI note 60 to 130.8128 Hz. DX7 fixed-frequency operators are absolute Hz, not note ratios; ANLGSYN 1 proved fixed op1/op3 must lower to ratios around 0.007615/0.009227 against a 130.8128 Hz graph base to preserve low buzzing modulation. ROM COM carrier compensation was cut: user listening found no-COM renders harmonically closer and mainly too quiet, so `OperatorOutputCompensation` returns unity and graph gain owns loudness recovery. Operator key-scaling and rate-scaling must lower against the effective played MIDI note after transpose; hardcoded MIDI 60 made RES SYNTH1 too soft on attack and Piano Bass less harmonically accurate. Project-authored Dexed patch rendering now gives lawful calibration targets. Reusing the operator output curve for EG levels was tested and cut because it failed hard-target log-mel; later output-level-dependent and naive traced-release applied-envelope experiments were also cut because they worsened broader parity. Direct envelope tracing shows current linear `env=rl` cannot express DX7 EG spike/drop behavior. Dexed-style audio samples EG once per 64-sample block and interpolates applied gain, so raw EG parity alone is not audio parity. Staged operator envelopes now support linear/exponential segments and supranormal levels. `ApproximateAppliedRateLevelEnvelope` uses that surface and now picks the first near-peak before gate so slower rising modulators hit early instead of swelling late; it can also preserve a floor for max-feedback source sustain. Community gains with no COM and played-note scaling: Mooger 0.75, Piano Bass 0.72, RES SYNTH1 0.75. Algorithm-2 non-carrier applied envelopes currently cap the first peak at 0.92 to prevent ANLGSYN 1/RES SYNTH1 peak blowout while preserving Piano Bass. MELLOWSOLO is a pressure artifact test, not passing parity; its render window is 1.25s so the candidate release is audible instead of cut at the artifact boundary. Mooger needs a more aggressive attack contour, and RES SYNTH1's phase-like attack issue is likely relative operator attack/peak shape because oscillator sync is enabled. PRC remains passing on log-mel/envelope/RMS, with score floor lowered to 0.74 after rate scaling changed the aggregate score.",
|
||||
"next": "Use the now-validated algorithm-8 route scale, transpose lowering, and fixed-frequency lowering as fixed inputs while isolating remaining community-voice timbre mismatch, then expand to broader public-domain banks."
|
||||
},
|
||||
"zyn_reference_path": {
|
||||
"status": "Initial ZynInstrumentReader parses plain XML and gzip-compressed .xiz-shaped XML from project-authored fixtures into ZynInstrument records and ReferencePatch features. First Zyn-style Aquarium rebuilds exist for additive lead, PAD texture, and vocal/formant layer. `ZynInstrumentSurvey` can rank .xiz directories by feature pressure. Named `layer` declarations provide the first Zyn-driven DSL abstraction; additive `harmonics`, PAD `spectrum`, and staged `env=rl` voice envelopes now attach to those layers. Zyn PAD `spectrum` banks can now carry explicit `zyn_mode`, `zyn_bandwidth`, `zyn_bwscale`, `zyn_profile`, and `zyn_position` table-generation fields, and `PadSynthWaveform` lowers those through Zyn-style profile/bandwidth math. The pinned Zyn source now builds as a test-only MSYS2/MinGW oracle through `tools/zyn-reference/build-zyn-reference.ps1`, which patches an ignored artifact source copy, proves `PadNoteTest`, and builds `ZynPadReference`.",
|
||||
"lesson": "Start Zyn as structural classification, then move into explicit scoped rebuilds. Upstream Zyn presets live in a nested GPL instrument-bank submodule and may be used as test-only parity/pressure feedstock once provenance is recorded. The ZynAddSubFX engine source is pinned as GPL test/development material under `external/zynaddsubfx` at 3ab608c432996ba4d582176572c0b0f82328c825; use it as a parity oracle only, never as Aquarium runtime or NuGet package content. Zyn build fixes belong in `tools/zyn-reference/patches/` and apply to ignored artifact copies, not the clean pinned submodule. The PAD oracle now renders both generated PAD sample tables and note audio through Zyn `PADnoteParameters`/`PADnote`; optional parity artifacts live under `artifacts/parity/zyn-pad-reference` and `artifacts/parity/zyn-pad-fixtures`. The first project-authored PAD comparison proved the harness and showed Aquarium `spectrum` was not a close Zyn PAD emulation. User listening identified Zyn as pure wineglass and Aquarium as angry bees. Cutting unearned air/noise/drive/soft-clip from the rebuild, adding interpolated wavetable reads, and raising Aquarium spectral tables to Zyn's 131072-frame PAD size improved the report. A later pitch/drone pass split PAD table root from playback note frequency: `spectrum root=...` owns table/base frequency and `freq=...` owns the played note. Using Zyn's reported sample basefreq 77.7813 while playing 261.6256, removing gratuitous spread/vibrato, collapsing two same-note PAD voices into one coherent spectral table, and trimming gain improved the report to log-mel 0.35669, envelope 0.347572, RMS ratio 1.001704, centroid ratio 1.004072, score 0.6211. The first PAD fixture survey shows `pad-pure` and the old `pad-texture` render identically through Zyn, so the filter/category XML in `pad-texture` is not live pressure for this oracle path. `pad-harmonic` changes the source table and note output through explicit OSCIL harmonics, making it the next real PAD reference rung. The remaining gap is source-table/profile and envelope semantics, not more decorative patch layers. The report now also emits source-table WAVs for listening. The hardened reader parses the upstream GPL instrument bank at commit c5c912131b31df5fdf372d2f06a25aaf2375837f: 1318/1318 .xiz files; optional tests write a ranked report and render five upstream PAD listening fixtures under ignored artifacts. `RebuildFirstPadAsAquariumScript` now generates first-pass per-preset PAD `.aqua` candidates from the first enabled PAD kit item, OSCIL harmonic magnitudes, oracle-reported table base frequency, basic volume, and simple rate/level envelope scaffolding while reporting missing bandwidth/profile/filter semantics. The worst target is `olivers-100/0032-Drum Kit.xiz`, with 16 enabled kit items, mixed ADD/SUB/PAD engines, 106 envelopes, 25 free envelopes, 73 LFOs, 37 filters, and 3 formant filters. The first rebuilds show Aquarium can sketch small Zyn fixtures with existing voices/macros/formants/noise, and the upstream survey correctly pushed named kit/layer routing first. `layer` owns name, engine tag, optional key range metadata, default gain, and effect-send labels while lowering to ordinary voices. `harmonics` owns authored ratio/gain partial banks under those layers. `spectrum` owns PAD-style root/spread/partial clouds under named layers and generated table base frequency; playback `freq` remains note authority. Staged `env=rl` now applies to voices as well as operators, preserving Note as gate authority and envelope data as level-shape authority. Aquarium still does not claim Zyn ADDsynth phase/bandwidth details, full Zyn PAD harmonic-profile/randomness/pitch-zone behavior, arbitrary free-envelope point curves, or richer formant morphing.",
|
||||
"status": "Initial ZynInstrumentReader parses plain XML and gzip-compressed .xiz-shaped XML from project-authored fixtures into ZynInstrument records and ReferencePatch features. First Zyn-style AquaSynth rebuilds exist for additive lead, PAD texture, and vocal/formant layer. `ZynInstrumentSurvey` can rank .xiz directories by feature pressure. Named `layer` declarations provide the first Zyn-driven DSL abstraction; additive `harmonics`, PAD `spectrum`, and staged `env=rl` voice envelopes now attach to those layers. Zyn PAD `spectrum` banks can now carry explicit `zyn_mode`, `zyn_bandwidth`, `zyn_bwscale`, `zyn_profile`, and `zyn_position` table-generation fields, and `PadSynthWaveform` lowers those through Zyn-style profile/bandwidth math. The pinned Zyn source now builds as a test-only MSYS2/MinGW oracle through `tools/zyn-reference/build-zyn-reference.ps1`, which patches an ignored artifact source copy, proves `PadNoteTest`, and builds `ZynPadReference`.",
|
||||
"lesson": "Start Zyn as structural classification, then move into explicit scoped rebuilds. Upstream Zyn presets live in a nested GPL instrument-bank submodule and may be used as test-only parity/pressure feedstock once provenance is recorded. The ZynAddSubFX engine source is pinned as GPL test/development material under `external/zynaddsubfx` at 3ab608c432996ba4d582176572c0b0f82328c825; use it as a parity oracle only, never as AquaSynth runtime or NuGet package content. Zyn build fixes belong in `tools/zyn-reference/patches/` and apply to ignored artifact copies, not the clean pinned submodule. The PAD oracle now renders both generated PAD sample tables and note audio through Zyn `PADnoteParameters`/`PADnote`; optional parity artifacts live under `artifacts/parity/zyn-pad-reference` and `artifacts/parity/zyn-pad-fixtures`. The first project-authored PAD comparison proved the harness and showed AquaSynth `spectrum` was not a close Zyn PAD emulation. User listening identified Zyn as pure wineglass and AquaSynth as angry bees. Cutting unearned air/noise/drive/soft-clip from the rebuild, adding interpolated wavetable reads, and raising AquaSynth spectral tables to Zyn's 131072-frame PAD size improved the report. A later pitch/drone pass split PAD table root from playback note frequency: `spectrum root=...` owns table/base frequency and `freq=...` owns the played note. Using Zyn's reported sample basefreq 77.7813 while playing 261.6256, removing gratuitous spread/vibrato, collapsing two same-note PAD voices into one coherent spectral table, and trimming gain improved the report to log-mel 0.35669, envelope 0.347572, RMS ratio 1.001704, centroid ratio 1.004072, score 0.6211. The first PAD fixture survey shows `pad-pure` and the old `pad-texture` render identically through Zyn, so the filter/category XML in `pad-texture` is not live pressure for this oracle path. `pad-harmonic` changes the source table and note output through explicit OSCIL harmonics, making it the next real PAD reference rung. The remaining gap is source-table/profile and envelope semantics, not more decorative patch layers. The report now also emits source-table WAVs for listening. The hardened reader parses the upstream GPL instrument bank at commit c5c912131b31df5fdf372d2f06a25aaf2375837f: 1318/1318 .xiz files; optional tests write a ranked report and render five upstream PAD listening fixtures under ignored artifacts. `RebuildFirstPadAsAquaSynthScript` now generates first-pass per-preset PAD `.aqua` candidates from the first enabled PAD kit item, OSCIL harmonic magnitudes, oracle-reported table base frequency, basic volume, and simple rate/level envelope scaffolding while reporting missing bandwidth/profile/filter semantics. The worst target is `olivers-100/0032-Drum Kit.xiz`, with 16 enabled kit items, mixed ADD/SUB/PAD engines, 106 envelopes, 25 free envelopes, 73 LFOs, 37 filters, and 3 formant filters. The first rebuilds show AquaSynth can sketch small Zyn fixtures with existing voices/macros/formants/noise, and the upstream survey correctly pushed named kit/layer routing first. `layer` owns name, engine tag, optional key range metadata, default gain, and effect-send labels while lowering to ordinary voices. `harmonics` owns authored ratio/gain partial banks under those layers. `spectrum` owns PAD-style root/spread/partial clouds under named layers and generated table base frequency; playback `freq` remains note authority. Staged `env=rl` now applies to voices as well as operators, preserving Note as gate authority and envelope data as level-shape authority. AquaSynth still does not claim Zyn ADDsynth phase/bandwidth details, full Zyn PAD harmonic-profile/randomness/pitch-zone behavior, arbitrary free-envelope point curves, or richer formant morphing.",
|
||||
"next": "Continue Zyn PAD parity from the sampled OscilGen stage-order, multi-kit PAD, Zyn-curve static global-filter, low-pass/high-pass order, PAD frequency-detune, low-pass/high-pass filter-envelope, logarithmic Zyn envelope-time, generated Zyn PAD output-calibration, low-pass note tracking, explicit low-pass Q, Q+order cascade, one-based OscilGen oscillator-filter index, base-function-7 selected-table-root, base-function phase modulation, and adaptive-harmonics paths. Ghost Ensemble now expands its power-base multi-harmonic OscilGen source, applies Zyn filter note tracking from `freq_track`, emits `lpf_q` from the Zyn analog filter `q`, and preserves low-pass slope by cascading resonant Faust stages according to `lpf_order`; latest Ghost log-mel is 0.369402, envelope distance is 0.363685, RMS ratio is 1.054875, centroid ratio is 1.006808, and score is 0.57229. DoublePadBass is accepted by ear and latest survey reports log-mel 0.247674, envelope distance 0.208351, RMS ratio 0.888011, score 0.650319. Soft Pad is accepted by ear. Organ Choir now maps kit0 HP2/stage/filter-envelope motion and kit1's selected table root, `base_function_modulation=1`, and `adaptive_harmonics=1`; latest Organ log-mel is 0.471483, envelope distance 0.302978, RMS ratio 0.878, centroid ratio 1.011328, and score 0.541933. Its kit1 PAD table energy now matches the wind-body shape much more closely: 400-800 Hz 0.2713 vs Zyn 0.2780 and 8-16 kHz 0.1471 vs Zyn 0.1355. ZynPadReference has test-only `harmonics` and `selected` modes; selected roots are diagnostic/source-specific, not a global default, because global selected roots regressed accepted DoublePadBass. sin2x remains loud/concentrated after the one-based filter-index fix, so do not claim full Zyn PAD parity until broader OscilGen filtering/waveshaping/adaptive-harmonic behavior and note/global filter LFO ownership are mapped or deliberately excluded."
|
||||
},
|
||||
"note_and_envelope_model": {
|
||||
|
|
@ -97,12 +97,12 @@
|
|||
"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 declare stable exposed parameters with path/default/min/max/step metadata so callers can vary sound without recompiling.",
|
||||
"aquasynth_requirement": "AquaSynth DSL patches declare stable exposed parameters with path/default/min/max/step metadata so callers can vary sound without recompiling.",
|
||||
"binding_rule": "Parameter binding uses field-site references such as `lpf=@/macro/brightness` and `/opgraphs/0/operators/2/level`; the field owns meaning and the parameter owns the runtime value. Avoid target-routing semantics unless a new graph authority is deliberately mapped."
|
||||
},
|
||||
"last_verified": {
|
||||
"command": "dotnet test AquariumSynthCSharp.slnx --no-restore",
|
||||
"result": "Mapped Zyn base-function modulation and adaptive harmonics for Organ Choir; C# suite 107 passed",
|
||||
"commit": "pending Zyn Organ Choir OscilGen source-table mapping"
|
||||
"command": "dotnet build AquaSynth.slnx --no-restore; dotnet test tests\\AquaSynth.Dsl.Tests\\AquaSynth.Dsl.Tests.csproj --no-build -v minimal; dotnet pack src\\AquaSynth.Dsl\\AquaSynth.Dsl.csproj -c Release --no-restore",
|
||||
"result": "Renamed local repo, namespaces, package metadata, docs, state, and remote wiring to AquaSynth/AquaSynth-rs; test assembly passed 108 and pack produced AquaSynth.Dsl.0.1.0-aquasynth.1.nupkg",
|
||||
"commit": "pending AquaSynth rename wiring"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
148
state/scratch.md
148
state/scratch.md
|
|
@ -1,18 +1,18 @@
|
|||
# Scratch
|
||||
|
||||
Current standing order: grow AquariumSynthCSharp through external reference
|
||||
Current standing order: grow AquaSynth through external reference
|
||||
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 synth library while AquaSynth work continues elsewhere.
|
||||
|
||||
Doctrine update:
|
||||
|
||||
- External synths are parity pressure for Aquarium's DSL, not internals to
|
||||
- External synths are parity pressure for AquaSynth's DSL, not internals to
|
||||
clone. Only consume targets that can be backed by parity tests proving
|
||||
Aquarium can reproduce the behavior in terse, readable syntax.
|
||||
AquaSynth can reproduce the behavior in terse, readable syntax.
|
||||
- Parsing a synth format is inventory. Rebuilding and testing behavior is the
|
||||
proof.
|
||||
- Pinned reference synths are test-only oracles, not Aquarium organs. ZynAddSubFX
|
||||
- Pinned reference synths are test-only oracles, not AquaSynth organs. ZynAddSubFX
|
||||
now lives under `external/zynaddsubfx` as GPL development material pinned at
|
||||
`3ab608c432996ba4d582176572c0b0f82328c825`; it must not enter the NuGet
|
||||
package or runtime dependency graph.
|
||||
|
|
@ -44,7 +44,7 @@ Current slice:
|
|||
same as the references. Treat the remaining high log-mel values as regression
|
||||
pressure and diagnostic smoke, not as a mandate to keep sanding sounds that
|
||||
have already landed perceptually.
|
||||
- Verification: `dotnet test AquariumSynthCSharp.slnx --no-restore`: 107
|
||||
- Verification: `dotnet test AquaSynth.slnx --no-restore`: 107
|
||||
passed.
|
||||
- Next pressure can leave this Zyn PAD batch and move to the roadmap's next
|
||||
synth/abstraction rung; keep sin2x and broader OscilGen/PAD source-table
|
||||
|
|
@ -58,12 +58,12 @@ Current slice:
|
|||
bandwidth, bandwidth scale, harmonic profile, and harmonic-position warp.
|
||||
`PadSynthWaveform` uses the Zyn PAD profile/bandwidth formulas for those
|
||||
banks and keeps the old generic PADsynth path for ordinary `spectrum`.
|
||||
- `ZynInstrumentReader.RebuildFirstPadAsAquariumScript` now emits readable
|
||||
- `ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript` now emits readable
|
||||
neutral `pad_mode=`, `pad_bandwidth=`, `pad_bwscale=`, `pad_profile=...`,
|
||||
and `pad_position=...` fields, and maps Zyn PAD volume with the source
|
||||
exponential gain curve instead of the old tiny linear `/500` guess. The
|
||||
parser still accepts older `zyn_*` aliases for parity artifacts, but authored
|
||||
`.aqua` should use Aquarium-native PAD terms.
|
||||
`.aqua` should use AquaSynth-native PAD terms.
|
||||
- The translator now expands a useful subset of Zyn OscilGen base-function
|
||||
harmonic content plus spectrum adjustment before feeding PAD synthesis. This
|
||||
is a coherent source-table owner, but current parity is mixed: it improves
|
||||
|
|
@ -71,7 +71,7 @@ Current slice:
|
|||
regress. Treat it as live pressure on OscilGen coverage, not solved Zyn
|
||||
oscillator parity.
|
||||
- Latest focused verification:
|
||||
`dotnet test tests\AquariumSynth.Dsl.Tests\AquariumSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~ZynInstrumentTests|FullyQualifiedName~ZynReferenceParityTests"`:
|
||||
`dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~ZynInstrumentTests|FullyQualifiedName~ZynReferenceParityTests"`:
|
||||
13 passed.
|
||||
- Latest upstream PAD batch after OscilGen subset:
|
||||
`Soft Pad` log-mel `0.342738`, score `0.443083`;
|
||||
|
|
@ -119,7 +119,7 @@ Current user-ear correction:
|
|||
with two enabled PAD kit items across the full key range. The old parity path
|
||||
rendered and rebuilt only kit item 0. The upstream PAD test now sums enabled
|
||||
PAD kit notes and passes per-kit table roots into
|
||||
`RebuildEnabledPadsAsAquariumScript`; generated Aqua emits
|
||||
`RebuildEnabledPadsAsAquaSynthScript`; generated Aqua emits
|
||||
`doublepadbass_0` and `doublepadbass_1`.
|
||||
- Latest DoublePadBass after multi-kit rebuild: log-mel `0.493451`, score
|
||||
`0.376854`, RMS ratio `0.826864`. Raising the volume cap to `3.0` worsened it
|
||||
|
|
@ -152,7 +152,7 @@ Current user-ear correction:
|
|||
- User then heard the tone as right but the Zyn reference hitting harder at the
|
||||
beginning. The missing authority was Zyn's PAD filter envelope: Aqua had only
|
||||
the static cutoff, while Zyn adds ADSR-filter octave offsets before the
|
||||
global filter. Aquarium now has a general low-pass rate/level envelope
|
||||
global filter. AquaSynth now has a general low-pass rate/level envelope
|
||||
surface (`lpf_env=rl`, `lpf_start`, `lpf_rates`, `lpf_levels`) and the Zyn
|
||||
importer maps `FILTER_ENVELOPE` into it. Latest DoublePadBass after this
|
||||
pass: log-mel `0.241993`, envelope distance `0.554658`, RMS ratio `0.456173`,
|
||||
|
|
@ -179,7 +179,7 @@ Current user-ear correction:
|
|||
`log2(note/440) * tracking` rule. Aqua now applies that when importing PAD
|
||||
global filters.
|
||||
- Ghost still had too much upper tail, so the next cut was not a Ghost-only
|
||||
brightness knob. Aquarium now has explicit low-pass Q via `lpf_q`/`lpq` on
|
||||
brightness knob. AquaSynth now has explicit low-pass Q via `lpf_q`/`lpq` on
|
||||
the filter model. Zyn PAD analog low-pass `q` imports through
|
||||
`exp((q/127)^2 * ln(1000)) - 0.9`; Ghost emits `lpf_q=0.499021`, which Faust
|
||||
lowers through `fi.resonlp(..., max(0.1, lpf_q), 1.0)`.
|
||||
|
|
@ -219,7 +219,7 @@ Current user-ear correction:
|
|||
by ear, with Organ Choir still a bit tinny and sin2x still overdoing a high
|
||||
harmonic. The sin2x issue was a real OscilGen indexing bug, not a fixture
|
||||
brightness preference: Zyn oscillator filters receive one-based harmonic
|
||||
indices (`filter(1)` is the first harmonic), while Aquarium had translated
|
||||
indices (`filter(1)` is the first harmonic), while AquaSynth had translated
|
||||
them through a zero-based index and moved the type-13 spike filter from h2 to
|
||||
h3. `ZynOscilFilterGain` now preserves Zyn's one-based index, and the
|
||||
upstream sin2x regression asserts h2 dominates h3 by more than 10x.
|
||||
|
|
@ -252,16 +252,16 @@ Completed this slice:
|
|||
randomness control, or pitch-zone behavior. It is a source-level FFT
|
||||
partial-cloud authority for readable PAD rebuilds.
|
||||
- Focused verification before wavetable replacement passed:
|
||||
`dotnet test tests\AquariumSynth.Dsl.Tests\AquariumSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~SpectralBank|FullyQualifiedName~ZynStyleReferenceRebuildsParseExportAndDeclarePressure|FullyQualifiedName~BuiltInReferenceScriptsParseAndExportFaust"`:
|
||||
`dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~SpectralBank|FullyQualifiedName~ZynStyleReferenceRebuildsParseExportAndDeclarePressure|FullyQualifiedName~BuiltInReferenceScriptsParseAndExportFaust"`:
|
||||
4 passed.
|
||||
- Wavetable replacement verification:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
94 passed.
|
||||
- FFT table generator focused verification:
|
||||
`dotnet test tests\AquariumSynth.Dsl.Tests\AquariumSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~SpectralBank|FullyQualifiedName~FaustCompilerValidatesSpectralBank|FullyQualifiedName~ZynStyleReferenceRebuildsParseExportAndDeclarePressure"`:
|
||||
`dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~SpectralBank|FullyQualifiedName~FaustCompilerValidatesSpectralBank|FullyQualifiedName~ZynStyleReferenceRebuildsParseExportAndDeclarePressure"`:
|
||||
4 passed.
|
||||
- Full verification after FFT table generator:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
94 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -276,10 +276,10 @@ Previous slice:
|
|||
- Arbitrary Zyn free-envelope point curves remain missing pressure. This slice
|
||||
is the coherent staged-envelope rung, not a free-mode clone.
|
||||
- Focused verification passed:
|
||||
`dotnet test tests\AquariumSynth.Dsl.Tests\AquariumSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~LayeredVoiceRateLevelEnvelope|FullyQualifiedName~ZynStyleReferenceRebuildsParseExportAndDeclarePressure|FullyQualifiedName~BuiltInReferenceScriptsParseAndExportFaust"`:
|
||||
`dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~LayeredVoiceRateLevelEnvelope|FullyQualifiedName~ZynStyleReferenceRebuildsParseExportAndDeclarePressure|FullyQualifiedName~BuiltInReferenceScriptsParseAndExportFaust"`:
|
||||
3 passed.
|
||||
- Full verification with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
91 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -294,7 +294,7 @@ Previous slice:
|
|||
- This is not Zyn ADDsynth parity theater. Phase, bandwidth, oscillator
|
||||
shaping, and exact free-envelope behavior remain explicit pressure.
|
||||
- Verified with bundled Python/dexed-py still wired:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
90 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -309,7 +309,7 @@ Previous slice:
|
|||
Future additive-bank, PAD-source, free-envelope, and formant-motion syntax
|
||||
now has somewhere coherent to attach.
|
||||
- Verified with bundled Python/dexed-py still wired:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
88 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -328,12 +328,12 @@ Previous slice:
|
|||
- Survey conclusion: named kit/layer routing should probably precede syntax
|
||||
golf for additive banks, PAD sources, or formant motion.
|
||||
- Verified with bundled Python/dexed-py still wired:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
86 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Added first Zyn-style Aquarium rebuilds for the project-authored additive
|
||||
- Added first Zyn-style AquaSynth rebuilds for the project-authored additive
|
||||
lead, PAD texture, and vocal/formant layer fixtures. They live in
|
||||
`BuiltInScripts` and `ReferenceRebuildCatalog.ZynRebuilds`.
|
||||
- The rebuild tests parse/export every Zyn script and compare matched feature
|
||||
|
|
@ -343,7 +343,7 @@ Previous slice:
|
|||
normal voices, named kit/layer routing with per-layer effect sends, and richer
|
||||
formant/vowel morphing. No new runtime surface was added yet.
|
||||
- Verified with bundled Python/dexed-py still wired:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
83 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -353,13 +353,13 @@ Previous slice:
|
|||
gzip-compressed XML, extracts instrument metadata and kit items, and emits
|
||||
neutral `ReferencePatch` features.
|
||||
- Added project-authored Zyn fixtures under
|
||||
`tests/AquariumSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored` instead
|
||||
`tests/AquaSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored` instead
|
||||
of vendoring upstream preset-bank files with unclear root provenance.
|
||||
- Current Zyn classifier detects active ADD/SUB/PAD engines, enabled kit items,
|
||||
layering, envelopes, free envelopes, LFOs, filters, formant filters, and
|
||||
effects. This is inventory for choosing rebuild targets, not translation yet.
|
||||
- Verified with bundled Python/dexed-py still wired:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
81 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -392,7 +392,7 @@ Previous slice:
|
|||
too aggressively and broke PRC, `Piano Bass`, `RES SYNTH1`, and `ANLGSYN 1`;
|
||||
release duration remains part of the broader DX7 envelope model pressure.
|
||||
- Verified with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
76 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -414,7 +414,7 @@ Previous slice:
|
|||
and does not deserve to live. Mooger's "too hard" harmonics remain unresolved
|
||||
overtone-emphasis pressure, not a solved high-band-energy problem.
|
||||
- Focused verification with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter "Dx7SysExTests|PublicDomainDx7MoogerAndPianoBassMeetRenderedParityWhenInstalled|PublicDomainDx7AnlgSyn1KeepsBuzzingModulationWhenInstalled|PublicDomainDx7MellowSoloWritesPressureWavsWhenInstalled|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled"`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter "Dx7SysExTests|PublicDomainDx7MoogerAndPianoBassMeetRenderedParityWhenInstalled|PublicDomainDx7AnlgSyn1KeepsBuzzingModulationWhenInstalled|PublicDomainDx7MellowSoloWritesPressureWavsWhenInstalled|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled"`:
|
||||
28 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -436,7 +436,7 @@ Previous slice:
|
|||
more Dexed-shaped on paper, but worsened `MELLOWSOLO` and `ANLGSYN 1`, so it
|
||||
does not belong in the live machine yet.
|
||||
- Focused verification with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter "Dx7SysExTests|PublicDomainDx7MoogerAndPianoBassMeetRenderedParityWhenInstalled|PublicDomainDx7AnlgSyn1KeepsBuzzingModulationWhenInstalled|PublicDomainDx7MellowSoloWritesPressureWavsWhenInstalled|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled"`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter "Dx7SysExTests|PublicDomainDx7MoogerAndPianoBassMeetRenderedParityWhenInstalled|PublicDomainDx7AnlgSyn1KeepsBuzzingModulationWhenInstalled|PublicDomainDx7MellowSoloWritesPressureWavsWhenInstalled|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled"`:
|
||||
28 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -456,7 +456,7 @@ Previous slice:
|
|||
`DX1 LEAD B` score `.45156077`, log-mel `.43533683`, RMS `.8193191`;
|
||||
`MELLOWSOLO` score `.5359293`, log-mel `.39420125`, RMS `.99559265`.
|
||||
- Verified with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
74 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -476,7 +476,7 @@ Previous slice:
|
|||
- Fresh `ANLGSYN 1`: score `.7245976`, log-mel `.18460114`, envelope
|
||||
`.119950555`, RMS `.97143364`, zero-crossing `.97149533`.
|
||||
- Verified with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
74 passed.
|
||||
|
||||
Earlier slice:
|
||||
|
|
@ -505,7 +505,7 @@ Earlier slice:
|
|||
- 1.2-2.5 kHz candidate/reference energy: `.008 -> .656`
|
||||
- 2.5-5 kHz candidate/reference energy: near zero -> `.321`
|
||||
- Verified with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
73 passed.
|
||||
|
||||
Earlier slice:
|
||||
|
|
@ -523,13 +523,13 @@ Earlier slice:
|
|||
focused gates. Latest metrics: log-mel `.19427659`, envelope `.14924917`,
|
||||
zero-crossing `.94662774`, centroid `.9182808`, score `.659334`.
|
||||
- Verified with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
73 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Fixed the `Piano Bass` octave bug. The parsed voice has `transpose=12`; the
|
||||
old generated Aquarium script hardcoded `freq=261.6256`, so it rendered an
|
||||
old generated AquaSynth script hardcoded `freq=261.6256`, so it rendered an
|
||||
octave too high. `Dx7SysEx.NoteFrequencyHz(midiNote, transpose)` now treats
|
||||
transpose `24` as neutral and transpose `12` as one octave down.
|
||||
- `Dx7VoiceProbeScript` now uses the voice transpose for graph frequency and
|
||||
|
|
@ -540,14 +540,14 @@ Previous slice:
|
|||
- Fixed `Piano Bass` metrics: log-mel `.16180529`, envelope `.13544041`,
|
||||
zero-crossing `.905511`, score `.64267576`.
|
||||
- Verified with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
71 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Added `PublicDomainDx7AnalogCommunityVoicesMeetBroadRenderedParityWhenInstalled`,
|
||||
which renders actual public-domain `analog1.syx` community voices through
|
||||
Dexed and the current Aquarium DX7 lowering. Kept four broad parity voices:
|
||||
Dexed and the current AquaSynth DX7 lowering. Kept four broad parity voices:
|
||||
`ANLGSYN 1`, `{ Mooger }`, `Piano Bass`, and `RES SYNTH1`.
|
||||
- The test writes WAVs/reports under
|
||||
`artifacts/parity/dx7-community-analog1/<voice>/` and gates log-mel
|
||||
|
|
@ -561,7 +561,7 @@ Previous slice:
|
|||
from the passing gate because log-mel and zero-crossing mismatch were too
|
||||
large. That is pressure, not library stock.
|
||||
- Verified with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
70 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -582,7 +582,7 @@ Previous slice:
|
|||
intentionally not part of the patch library: they are useful measuring tools,
|
||||
not pleasant or reusable stock.
|
||||
- Verified with bundled Python/dexed-py:
|
||||
`AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore`:
|
||||
`AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore`:
|
||||
69 passed.
|
||||
|
||||
Previous slice:
|
||||
|
|
@ -600,7 +600,7 @@ Previous slice:
|
|||
- Added a test contract: every `.aqua` under `patches/` must parse through
|
||||
`PatchScript.Parse` and export Faust, while package-boundary tests keep
|
||||
`patches/` and `.aqua` files out of the NuGet package.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 67 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 67 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
|
|
@ -614,7 +614,7 @@ Previous slice:
|
|||
`0.9912135`, zero-crossing ratio `0.95325506`, centroid ratio `1.1156512`,
|
||||
score `0.7546445`.
|
||||
- Added `Dx7SysEx.ApproximateAppliedRateLevelEnvelope`, which traces the
|
||||
Dexed-style block-interpolated applied EG gain and lowers it into Aquarium's
|
||||
Dexed-style block-interpolated applied EG gain and lowers it into AquaSynth's
|
||||
curved staged envelope surface, normalized so operator output level remains a
|
||||
separate authority.
|
||||
- Retried hard `PRC SYNTH1` with the applied-envelope lowering. Latest focused
|
||||
|
|
@ -638,8 +638,8 @@ Previous slice:
|
|||
`artifacts/parity/dx7-envelope-trace/egstep.csv`. The first rows show both
|
||||
DX7 raw state and applied gain: raw jumps to `2` immediately, while applied
|
||||
gain ramps from `.03125` to `2` over the first 64-sample block and remains
|
||||
near `1` around 20 ms. Aquarium `env=rl` is a different contour entirely.
|
||||
The artifact now also includes a curved Aquarium staged-envelope candidate
|
||||
near `1` around 20 ms. AquaSynth `env=rl` is a different contour entirely.
|
||||
The artifact now also includes a curved AquaSynth staged-envelope candidate
|
||||
that tracks the applied-gain contour far more closely.
|
||||
- Tried adding a first `env=dx7` runtime lowering, then cut it. The trace
|
||||
matched the Python `graph.py` envelope but not Dexed plugin audio, so the
|
||||
|
|
@ -690,7 +690,7 @@ Previous slice:
|
|||
Previous slice:
|
||||
|
||||
- Completed the feedback calibration rung. Isolated Dexed feedback sweeps fit a
|
||||
nonlinear Aquarium feedback table: `0, .01, .02, .05, .10, .19, .38, .66`
|
||||
nonlinear AquaSynth feedback table: `0, .01, .02, .05, .10, .19, .38, .66`
|
||||
for DX7 feedback values `0..7`.
|
||||
- Added `Dx7SysEx.OperatorFeedbackAmount` and moved the PRC feedback lowering
|
||||
off the old `voice.Feedback * 0.04` constant. PRC barely changed because
|
||||
|
|
@ -701,7 +701,7 @@ Previous slice:
|
|||
|
||||
- Completed the second calibration rung for isolated two-operator FM. A Dexed
|
||||
sweep fits full-scale DX7 modulation at about `12.55` radians. Given the
|
||||
current Aquarium Faust formula, that maps to an Aquarium route index of
|
||||
current AquaSynth Faust formula, that maps to an AquaSynth route index of
|
||||
`6.275` for a full-level modulator.
|
||||
- Added `Dx7SysEx.OperatorModulationRouteIndex` and a regression test for the
|
||||
calibrated phase-deviation scale. The hard PRC probe applies that scale only
|
||||
|
|
@ -737,7 +737,7 @@ Previous slice:
|
|||
`<= 0.255` plus a loose aggregate score floor instead of treating aggregate
|
||||
score as the main judge.
|
||||
- Spectral diagnosis showed the Dexed reference has dominant peaks around
|
||||
`393`, `131`, `524`, and `656` Hz. The prior Aquarium candidate had too
|
||||
`393`, `131`, `524`, and `656` Hz. The prior AquaSynth candidate had too
|
||||
little `80-160` Hz body when based at `392`, while the corrected DX7 note
|
||||
basis restored the low body but exposed weak mid harmonic structure and high
|
||||
centroid/zero-crossing mismatch.
|
||||
|
|
@ -769,7 +769,7 @@ Previous slice:
|
|||
- Added a hard DX7 `PRC SYNTH1` rendered parity probe that writes listening
|
||||
artifacts when `dexed-py` and Faust are available:
|
||||
`artifacts/parity/dx7-prc-synth1/reference-dexed.wav`,
|
||||
`candidate-aquarium.wav`, `candidate.aqua`, and `report.txt`.
|
||||
`candidate-aquasynth.wav`, `candidate.aqua`, and `report.txt`.
|
||||
- The probe rebuilds `analog1.syx` voice 17 with readable operator graph syntax
|
||||
and staged `env=rl` operator envelopes. It asserts a modest hard-target score
|
||||
floor instead of pretending exact DX7 parity is solved.
|
||||
|
|
@ -792,7 +792,7 @@ Previous slice:
|
|||
that emits staged envelope script specs from four-rate/four-level operator EG
|
||||
data.
|
||||
- Verified the surface structurally and through the render path:
|
||||
`dotnet test AquariumSynthCSharp.slnx --no-restore`: 53 passed.
|
||||
`dotnet test AquaSynth.slnx --no-restore`: 53 passed.
|
||||
- Retried the hard `PRC SYNTH1` probe with direct DX7 rate/level lowering. The
|
||||
best quick score was only ~0.316, worse than the hand-tweaked ADSR candidate.
|
||||
The DSL can now express the missing contour shape, but DX7 EG timing/gain
|
||||
|
|
@ -801,33 +801,33 @@ Previous slice:
|
|||
Previous slice:
|
||||
|
||||
- Added `Dx7OperatorLevelApproximation`, which distills DX7 operator output
|
||||
level plus key/velocity scaling into a normal Aquarium `level=`-style value.
|
||||
level plus key/velocity scaling into a normal AquaSynth `level=`-style value.
|
||||
This remains DX7 reference-import knowledge, not a generic DSL feature.
|
||||
- Retried `PRC SYNTH1` with effective levels and envelope tweaks. Static level
|
||||
mapping alone did not rescue the hard target: quick probes moved from ~0.24
|
||||
to ~0.34, and envelope tweaks reached ~0.42. The next missing pressure is
|
||||
DX7-style operator envelope/gain evolution, not just static operator levels.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 50 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 50 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Tried the harder `analog1.syx` voice 17, `PRC SYNTH1` (algorithm 8). The
|
||||
initial routed Aquarium candidate scored badly (~0.23), which exposed a real
|
||||
initial routed AquaSynth candidate scored badly (~0.23), which exposed a real
|
||||
missing invariant rather than a threshold-tuning problem.
|
||||
- Reworked operator feedback emission from a cyclic smoothed self-reference to
|
||||
a renderable Faust feedback expression using delayed recursion. Added
|
||||
`FaustCompilerRendersOperatorFeedbackWhenInstalled`.
|
||||
- Exact DX7 feedback scaling and EG behavior are still not solved, but feedback
|
||||
no longer makes the Faust render path fall over.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 49 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 49 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Added the first thresholded DX7 rendered-audio parity rebuild:
|
||||
`BuiltInScripts.Dx7StylePublicDomainMcMm53` maps public-domain
|
||||
`analog1.syx` voice 13, `MC-MM 5-3`, to a terse Aquarium sine patch.
|
||||
`analog1.syx` voice 13, `MC-MM 5-3`, to a terse AquaSynth sine patch.
|
||||
- Added `PublicDomainDx7McMm53MeetsFirstRenderedParityThresholdWhenInstalled`,
|
||||
which renders the DX7 reference through `dexed-py`, renders the Aquarium
|
||||
which renders the DX7 reference through `dexed-py`, renders the AquaSynth
|
||||
candidate through Faust-generated C#, and asserts score, log-mel distance,
|
||||
envelope distance, duration/RMS ratios, zero-crossing ratio, and centroid
|
||||
ratio.
|
||||
|
|
@ -835,43 +835,43 @@ Previous slice:
|
|||
DX7 operator execution. The next DX7 pressure should be a harder voice that
|
||||
audibly needs the operator graph.
|
||||
- Verified with bundled Python plus `dexed-py`: parity test passed.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 48 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 48 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Added a public-domain DX7 SysEx fixture from Musical Artifacts artifact 152:
|
||||
`tests/AquariumSynth.Dsl.Tests/Fixtures/Dx7/PublicDomain/analog1.syx`, with
|
||||
`tests/AquaSynth.Dsl.Tests/Fixtures/Dx7/PublicDomain/analog1.syx`, with
|
||||
provenance and SHA-256 recorded beside it.
|
||||
- Added a test-only `dexed-py` reference renderer. It uses
|
||||
`AQUARIUM_DX7_PYTHON` when set, otherwise probes `py`, `python`, and
|
||||
`AQUASYNTH_DX7_PYTHON` when set, otherwise probes `py`, `python`, and
|
||||
`python3`; if `dexed-py` is absent, the render test returns without turning
|
||||
optional tooling into a hard dependency.
|
||||
- Added a `.nupkg` boundary test that packs `AquariumSynth.Dsl` and asserts
|
||||
- Added a `.nupkg` boundary test that packs `AquaSynth.Dsl` and asserts
|
||||
test fixtures, SysEx banks, and Python helpers are not shipped.
|
||||
- Verified with bundled Python plus `dexed-py`: the DX7 fixture renders through
|
||||
Dexed successfully.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 47 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 47 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Added `FaustCompiler.RenderAsync`, which compiles Aquarium Faust output to
|
||||
- Added `FaustCompiler.RenderAsync`, which compiles AquaSynth Faust output to
|
||||
Faust-generated C#, runs it in a temp .NET project, and returns a mono float
|
||||
sample buffer for analysis.
|
||||
- Added a render test that proves a generated Aquarium patch produces non-silent
|
||||
- Added a render test that proves a generated AquaSynth patch produces non-silent
|
||||
audio and can be compared through `AudioAnalyzer`.
|
||||
- DX7 audio parity is still not claimed: the candidate renderer exists, but the
|
||||
reference side needs Dexed output or a captured licensed fixture.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 44 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 44 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Added `Dx7EnvelopeApproximation`, which lowers a DX7 four-rate/four-level EG
|
||||
to a labeled Aquarium ADSR approximation plus gate duration.
|
||||
to a labeled AquaSynth ADSR approximation plus gate duration.
|
||||
- Reference rebuilds now record `operator_envelope_approximation` as matched
|
||||
pressure and `operator_envelope_exactness` as still missing.
|
||||
- Doctrine now states that DX7 EG approximation is not exact DX7 envelope
|
||||
execution.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 43 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 43 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
|
|
@ -882,7 +882,7 @@ Previous slice:
|
|||
the exact `/opgraphs/...` field paths.
|
||||
- Fixed AD operator envelope binding to use `/env/decay` for the second AD
|
||||
value, matching the ADSR model instead of calling it release by accident.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 42 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 42 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
|
|
@ -892,7 +892,7 @@ Previous slice:
|
|||
`[midi:on][nvoices:8]` option and `freq`, `gain`, `gate` controls.
|
||||
- Host/MIDI playback no longer emits per-voice `/voices/0/note/frequency` and
|
||||
`/voices/0/note/gate` controls; Faust architecture owns allocation.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 41 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 41 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
|
|
@ -905,7 +905,7 @@ Previous slice:
|
|||
- Added host note mode for MIDI-oriented patches through stable note frequency
|
||||
and note gate controls in generated Faust.
|
||||
- Moved built-in authoring examples off `punch=` and onto `sustain_level=`.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 40 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 40 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
|
|
@ -915,7 +915,7 @@ Previous slice:
|
|||
envelope forms for operator declarations.
|
||||
- Kept compact `ops=`/`edges=` syntax as parser/interchange scaffolding, but it
|
||||
is no longer the built-in authoring example.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 36 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 36 passed.
|
||||
|
||||
Previous slice:
|
||||
|
||||
|
|
@ -927,21 +927,21 @@ Previous slice:
|
|||
- Updated the DX7 algorithm-8 rebuild to use a real operator graph for the
|
||||
topology. The remaining missing feature is exact DX7 feedback-register timing
|
||||
and DX7 rate/level envelopes, not graph ownership.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 35 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 35 passed.
|
||||
|
||||
Earlier rebuild slice:
|
||||
|
||||
- Added `ReferenceRebuild` and `ReferenceRebuildCatalog` for explicit
|
||||
reference-target rebuild attempts.
|
||||
- Added two DX7-style Aquarium DSL rebuilds:
|
||||
- Added two DX7-style AquaSynth DSL rebuilds:
|
||||
- `dx7/algo32-additive-organ`: algorithm 32's six-carrier additive shape,
|
||||
which maps cleanly to six Aquarium voices.
|
||||
which maps cleanly to six AquaSynth voices.
|
||||
- `dx7/algo8-bright-pair`: algorithm 8's two-carrier FM shape, which is only
|
||||
an approximation because the current voice DSL cannot express
|
||||
`6->5`, `4+5->3`, `2->1`, or operator-local self-feedback.
|
||||
- Added matched/missing feature records so topology mismatch becomes evidence
|
||||
instead of being hidden inside prose.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 34 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 34 passed.
|
||||
|
||||
Earlier topology slice:
|
||||
|
||||
|
|
@ -954,7 +954,7 @@ Earlier topology slice:
|
|||
`modulation_edge_count`, `feedback_sources`, and
|
||||
`self_feedback_operators`.
|
||||
- Representative tests cover algorithm 8, algorithm 16, and algorithm 32.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 31 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 31 passed.
|
||||
|
||||
Earlier slice:
|
||||
|
||||
|
|
@ -965,7 +965,7 @@ Earlier slice:
|
|||
- Added `Dx7Voice.ToReferencePatch` and structural feature extraction so DX7
|
||||
voices can pressure the reference model before translation exists.
|
||||
- Checksum validation rejects bad wrapped SysEx payloads.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 28 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 28 passed.
|
||||
|
||||
Parameter slice:
|
||||
|
||||
|
|
@ -982,7 +982,7 @@ Parameter slice:
|
|||
parameter default as the graph value.
|
||||
- Faust emission substitutes the parameter expression only at the bound field
|
||||
site. Unbound parameters still emit a warning.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 23 passed.
|
||||
- Verified with `dotnet test AquaSynth.slnx --no-restore`: 23 passed.
|
||||
|
||||
Next likely slice:
|
||||
|
||||
|
|
|
|||
266
state/spine.yaml
266
state/spine.yaml
|
|
@ -1,4 +1,4 @@
|
|||
project: AquariumSynthCSharp
|
||||
project: AquaSynth
|
||||
spine_version: 1
|
||||
updated: 2026-05-15T14:15:00+01:00
|
||||
|
||||
|
|
@ -7,58 +7,58 @@ prime_directive: >
|
|||
not to justify piling parameters onto the current patch DSL.
|
||||
|
||||
current_objective: >
|
||||
Turn AquariumSynthCSharp into a reference-driven patch authoring and Faust
|
||||
Turn AquaSynth into a reference-driven patch authoring and Faust
|
||||
generation library. Use external synths and DSP corpora as pressure tests so
|
||||
Aquarium's DSL grows only when a real target proves the abstraction belongs.
|
||||
AquaSynth's DSL grows only when a real target proves the abstraction belongs.
|
||||
|
||||
current_mechanism:
|
||||
parser: src/AquariumSynth.Dsl/PatchScript.cs
|
||||
model: src/AquariumSynth.Dsl/Model.cs
|
||||
faust_emitter: src/AquariumSynth.Dsl/FaustExport.cs
|
||||
faust_renderer: src/AquariumSynth.Dsl/FaustExport.cs
|
||||
operator_graph_model: src/AquariumSynth.Dsl/Model.cs
|
||||
analysis: src/AquariumSynth.Dsl/AudioAnalysis.cs
|
||||
built_ins: src/AquariumSynth.Dsl/BuiltInScripts.cs
|
||||
parser: src/AquaSynth.Dsl/PatchScript.cs
|
||||
model: src/AquaSynth.Dsl/Model.cs
|
||||
faust_emitter: src/AquaSynth.Dsl/FaustExport.cs
|
||||
faust_renderer: src/AquaSynth.Dsl/FaustExport.cs
|
||||
operator_graph_model: src/AquaSynth.Dsl/Model.cs
|
||||
analysis: src/AquaSynth.Dsl/AudioAnalysis.cs
|
||||
built_ins: src/AquaSynth.Dsl/BuiltInScripts.cs
|
||||
patch_library: patches
|
||||
dx7_references: src/AquariumSynth.Dsl/Dx7SysEx.cs
|
||||
dx7_reference_fixtures: tests/AquariumSynth.Dsl.Tests/Fixtures/Dx7/PublicDomain
|
||||
dx7_reference_renderer_tests: tests/AquariumSynth.Dsl.Tests/Dx7ReferenceParityTests.cs
|
||||
dx7_references: src/AquaSynth.Dsl/Dx7SysEx.cs
|
||||
dx7_reference_fixtures: tests/AquaSynth.Dsl.Tests/Fixtures/Dx7/PublicDomain
|
||||
dx7_reference_renderer_tests: tests/AquaSynth.Dsl.Tests/Dx7ReferenceParityTests.cs
|
||||
zyn_reference_source: external/zynaddsubfx
|
||||
zyn_upstream_instrument_bank: external/zynaddsubfx/instruments
|
||||
zyn_reference_build_script: tools/zyn-reference/build-zyn-reference.ps1
|
||||
zyn_pad_reference_renderer: tools/zyn-reference/ZynPadReference.cpp
|
||||
zyn_reference_reader: src/AquariumSynth.Dsl/ZynInstrument.cs
|
||||
zyn_project_fixtures: tests/AquariumSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored
|
||||
reference_rebuilds: src/AquariumSynth.Dsl/ReferenceRebuilds.cs
|
||||
tests: tests/AquariumSynth.Dsl.Tests/PatchScriptTests.cs
|
||||
zyn_reference_reader: src/AquaSynth.Dsl/ZynInstrument.cs
|
||||
zyn_project_fixtures: tests/AquaSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored
|
||||
reference_rebuilds: src/AquaSynth.Dsl/ReferenceRebuilds.cs
|
||||
tests: tests/AquaSynth.Dsl.Tests/PatchScriptTests.cs
|
||||
doctrine: docs/audio-doctrine.md
|
||||
dx7_calibration_plan: docs/dx7-calibration-plan.md
|
||||
zyn_pressure_survey: docs/zynaddsubfx-pressure-survey.md
|
||||
roadmap: docs/reference-synth-roadmap.md
|
||||
parameter_contracts: src/AquariumSynth.Dsl/Model.cs
|
||||
parameter_contracts: src/AquaSynth.Dsl/Model.cs
|
||||
|
||||
live_invariants:
|
||||
- Aquarium owns its patch graph; external synths are references, not runtime dependencies.
|
||||
- AquaSynth owns its patch graph; external synths are references, not runtime dependencies.
|
||||
- Patch scripts lower into explicit graph records before Faust emission.
|
||||
- Operator graphs own FM topology: operators, modulation edges, carriers, and feedback. Do not hide this authority inside Voice fields.
|
||||
- Readable operator graph authoring uses `operator`, `route`, and `carrier` declarations; compact `ops=`/`edges=` is only scaffolding/interchange.
|
||||
- Notes own frequency, gate duration, and host/MIDI source; envelopes own ADSR level shape. Do not put note duration or SFXR punch back into the general envelope model.
|
||||
- Faust-managed MIDI polyphony is preferred: emit one voice graph with standard `freq`, `gain`, and `gate` controls plus `[midi:on][nvoices:n]` instead of inflating Aquarium graphs for local allocation.
|
||||
- Faust-managed MIDI polyphony is preferred: emit one voice graph with standard `freq`, `gain`, and `gate` controls plus `[midi:on][nvoices:n]` instead of inflating AquaSynth graphs for local allocation.
|
||||
- Generated Faust should remain inspectable and deterministic.
|
||||
- Aquarium Faust output may be rendered through Faust-generated C# for candidate audio comparison; reference parity still needs a real external render or captured licensed fixture.
|
||||
- Reference-patch correctness and synth parity tests live in AquariumSynthCSharp, not Aquarium.
|
||||
- AquaSynth Faust output may be rendered through Faust-generated C# for candidate audio comparison; reference parity still needs a real external render or captured licensed fixture.
|
||||
- Reference-patch correctness and synth parity tests live in AquaSynth, not AquaSynth.
|
||||
- Exposed patch parameters are runtime controls, not compile-time constants.
|
||||
- Parameter binding uses field-site references like `lpf=@/macro/brightness`; do not add target-routing semantics unless a later map proves a new authority is needed.
|
||||
- Operator graph parameter binding also uses exact field-site paths under `/opgraphs/...`; do not add graph-wide macro routing.
|
||||
- Operator feedback must render through Faust as delayed recursion, not as a direct cyclic self-reference.
|
||||
- DX7 operator output level approximation belongs in reference import/rebuild helpers, not the generic DSL model.
|
||||
- DX7 carrier output amplitude follows the measured `2^((outputLevel - 99) / 8)` curve; do not restore the old internal-level proxy.
|
||||
- DX7 isolated two-operator modulation uses Aquarium route index `6.275` for full-level modulators; do not apply that blindly to cascaded stacks.
|
||||
- DX7 isolated two-operator modulation uses AquaSynth route index `6.275` for full-level modulators; do not apply that blindly to cascaded stacks.
|
||||
- DX7 feedback lowers through `Dx7SysEx.OperatorFeedbackAmount`; feedback value 5 remains 0.19 for PRC, while feedback value 7 is much hotter at 2.2 to restore community-patch buzz. Do not restore PRC-local `feedback * constant` folklore.
|
||||
- DX7 ratio-mode detune lowers through `Dx7SysEx.OperatorFrequencyRatio`; do not silently drop detune from operator graph scripts.
|
||||
- DX7 voice transpose lowers through `Dx7SysEx.NoteFrequencyHz`; transpose 24 is neutral, 12 is one octave down. Do not hardcode `freq=261.6256` for imported voices.
|
||||
- DX7 fixed-frequency operators lower through `Dx7SysEx.FixedOperatorFrequencyHz` as absolute Hz divided by the graph base frequency; do not treat fixed mode as a note ratio.
|
||||
- DX7 ROM `COM` output compensation is not a carrier-balance authority in Aquarium lowering; `OperatorOutputCompensation` returns unity and graph gain owns loudness recovery.
|
||||
- DX7 ROM `COM` output compensation is not a carrier-balance authority in AquaSynth lowering; `OperatorOutputCompensation` returns unity and graph gain owns loudness recovery.
|
||||
- DX7 operator key-scaling and rate-scaling lower against the effective played MIDI note after voice transpose; do not hardcode MIDI 60 inside imported operator level or envelope timing.
|
||||
- DX7 route lowering is topology-aware: isolated direct branches use `OperatorModulationRouteIndex` (`6.275`); summed edges and direct edges feeding summed modulation use `SummedOperatorModulationRouteIndex` (`6.0`).
|
||||
- `SummedOperatorModulationRouteIndex` is backed by the hard PRC target, a project-authored algorithm-8 stack probe, and split cascade/summed-pair probes; do not restore the older under-bright `1.6` scale.
|
||||
|
|
@ -75,15 +75,15 @@ live_invariants:
|
|||
- Do not replace applied-envelope release with a naive traced threshold duration; it shortened releases too aggressively and broke broader DX7 parity.
|
||||
- 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.
|
||||
- Public-domain reference fixtures, GPL Zyn instrument-bank fixtures, dexed-py helpers, and pinned ZynAddSubFX source are test/development material only; the NuGet package must ship only AquariumSynth.Dsl.
|
||||
- ZynAddSubFX import starts as feature extraction and then explicit, scoped rebuilds. Upstream GPL `.xiz` instruments may be used as test-only pressure/parity feedstock with provenance reports, while project-authored `.xiz` fixtures remain the clean baseline. The Zyn engine source and instrument bank are pinned under `external/zynaddsubfx` for parity oracles only, not Aquarium runtime code.
|
||||
- Public-domain reference fixtures, GPL Zyn instrument-bank fixtures, dexed-py helpers, and pinned ZynAddSubFX source are test/development material only; the NuGet package must ship only AquaSynth.Dsl.
|
||||
- ZynAddSubFX import starts as feature extraction and then explicit, scoped rebuilds. Upstream GPL `.xiz` instruments may be used as test-only pressure/parity feedstock with provenance reports, while project-authored `.xiz` fixtures remain the clean baseline. The Zyn engine source and instrument bank are pinned under `external/zynaddsubfx` for parity oracles only, not AquaSynth runtime code.
|
||||
- Named `layer` declarations own Zyn-style kit/layer identity: engine tag, optional key range metadata, default gain, and effect-send labels. They lower to ordinary voices for now; do not smuggle PAD/free-envelope/effect behavior into them.
|
||||
- Additive `harmonics` declarations own authored ratio/gain partial banks under named layers. They lower to ordinary voices for now; do not pretend this covers Zyn ADDsynth phase, bandwidth, oscillator shaping, or free-envelope semantics.
|
||||
- Normal voices may use staged `env=rl` rate/level envelopes. Notes still own gate timing; envelopes own level shape. This is not arbitrary Zyn free-envelope point editing.
|
||||
- PAD `spectrum` declarations own authored partial clouds under named layers and split table root from playback pitch: `root` is source/base frequency, while `freq` is the note played by the spectral voice. They generate PADsynth-style FFT wavetables with frequency-domain spreading and deterministic random phase, then emit Faust table readers before ordinary voice treatment. Richer PAD table shaping uses neutral `pad_mode`, `pad_bandwidth`, `pad_bwscale`, `pad_profile`, and `pad_position` syntax. The parser may accept older `zyn_*` parity-artifact aliases, but generated/authored `.aqua` should not expose reference-synth names for general DSP intent. Do not pretend this covers every Zyn OscilGen modulation/waveshaping/filter/adaptive-harmonic path yet.
|
||||
- Zyn OscilGen oscillator filters use one-based harmonic indices: first harmonic is `1`, not `0`. Preserve that index when translating filter types or spectral peaks move to the wrong partial.
|
||||
- Zyn PAD analog high-pass filters are filter authority too: HP1/HP2 type, stages, and FILTER_ENVELOPE motion lower through `hpf_order` and `hpf_env=rl`, not ad hoc layer gain or brightness compensation.
|
||||
- Zyn PAD selected table roots are not a global default in Aquarium lowering. Keep sample-0 roots unless a source rule earns the selected root; currently OscilGen shift-base sources (`base_function=7`) may use the selected note table root because Organ Choir proved sample-0 roots leave the octave voice misaligned.
|
||||
- Zyn PAD selected table roots are not a global default in AquaSynth lowering. Keep sample-0 roots unless a source rule earns the selected root; currently OscilGen shift-base sources (`base_function=7`) may use the selected note table root because Organ Choir proved sample-0 roots leave the octave voice misaligned.
|
||||
- Zyn OscilGen base-function modulation is source-table authority: apply it as phase modulation before base-function sampling, not as later oscillator modulation or filter/EQ compensation.
|
||||
- Zyn adaptive harmonics remap the prepared oscillator spectrum at the PAD table root frequency before PAD bandwidth/profile spreading. Do not skip it for sources whose wind/body character depends on sparse remapped harmonics.
|
||||
- Filter damping is first-class: `lpf_q`/`lpq` owns explicit low-pass Q when a reference synth exposes analog filter damping. Low-pass order remains slope authority even when Q is present; Faust lowering cascades resonant low-pass stages instead of replacing order with one generic resonant filter. Do not fake Q by secretly moving cutoff, slope, or layer gain.
|
||||
|
|
@ -91,7 +91,7 @@ live_invariants:
|
|||
- Project-authored Dexed patches may be generated inside tests for calibration; do not ship them in the NuGet package or treat them as runtime dependencies.
|
||||
- Harsh calibration probes belong in tests and ignored artifacts, not in the patch library unless they are musically useful stock.
|
||||
- Listening WAV artifacts belong under ignored `artifacts/`; keep them out of NuGet and commits unless explicitly promoted as fixtures.
|
||||
- Do not consume external synth targets that cannot be backed by parity tests. Parsing is inventory; reproducing behavior through terse, readable Aquarium DSL is the proof.
|
||||
- Do not consume external synth targets that cannot be backed by parity tests. Parsing is inventory; reproducing behavior through terse, readable AquaSynth DSL is the proof.
|
||||
- Audio metrics are evidence, not final judgment.
|
||||
- Do not add a generic graph escape hatch until specific references force it.
|
||||
- Do not hide missing graph structure behind unrelated voice fields.
|
||||
|
|
@ -101,14 +101,14 @@ reference_targets:
|
|||
priority: 1
|
||||
purpose: "Structured FM/operator graph pressure test."
|
||||
source: "https://github.com/asb2m10/dexed"
|
||||
status: "DX7 SysEx parser, public-domain SysEx fixture, dexed-py reference rendering, project-authored Dexed patch rendering, first thresholded rendered parity test for analog1.syx voice 13, hard PRC SYNTH1 probe with listening WAV artifacts, project-authored algorithm-8 summed-stack parity, renderable delayed operator feedback, DX7 effective operator-level approximation, measured carrier output amplitude, isolated route index, feedback table, ratio detune lowering, voice transpose lowering, fixed-frequency lowering, ROM COM compensation cut, operator key/rate scaling at the effective played note, staged operator envelopes, DX7 envelope tracing, algorithm topology extraction, envelope-to-ADSR approximation, two Aquarium DSL rebuild attempts, first-class operator graph support, and Aquarium candidate rendering through Faust-generated C# exist."
|
||||
status: "DX7 SysEx parser, public-domain SysEx fixture, dexed-py reference rendering, project-authored Dexed patch rendering, first thresholded rendered parity test for analog1.syx voice 13, hard PRC SYNTH1 probe with listening WAV artifacts, project-authored algorithm-8 summed-stack parity, renderable delayed operator feedback, DX7 effective operator-level approximation, measured carrier output amplitude, isolated route index, feedback table, ratio detune lowering, voice transpose lowering, fixed-frequency lowering, ROM COM compensation cut, operator key/rate scaling at the effective played note, staged operator envelopes, DX7 envelope tracing, algorithm topology extraction, envelope-to-ADSR approximation, two AquaSynth DSL rebuild attempts, first-class operator graph support, and AquaSynth candidate rendering through Faust-generated C# exist."
|
||||
first_slice:
|
||||
- "Add a harder public-domain DX7 parity target that audibly needs operator routing."
|
||||
zynaddsubfx:
|
||||
priority: 2
|
||||
purpose: "Additive, subtractive, PAD, formant, kit, and layered-instrument pressure test."
|
||||
source: "https://github.com/zynaddsubfx/zynaddsubfx"
|
||||
status: "Initial ZynInstrumentReader reads plain or gzip-compressed .xiz XML from project-authored fixtures and classifies active ADD/SUB/PAD engines, enabled kit items, layering, envelopes, free envelopes, LFOs, filters, formants, and effects as ReferencePatch features. First Aquarium rebuilds exist for additive lead, PAD texture, and vocal/formant layer and now use named `layer` declarations. Additive rebuilds can use `harmonics` banks attached to layers, PAD rebuilds can use `spectrum` PADsynth-style FFT wavetable banks attached to layers, and PAD/vocal rebuilds use staged voice `env=rl` envelopes through layer defaults. `ZynInstrumentReader.RebuildFirstPadAsAquariumScript` now emits per-preset PAD `.aqua` rebuilds for enabled PAD kit items with OSCIL harmonic expansion, oracle-reported table base frequency, PAD detune, Zyn PAD profile/bandwidth/position semantics, static/filter-envelope low-pass mapping, low-pass note tracking, explicit low-pass Q, logarithmic Zyn envelope times, and calibrated PAD output gain. ZynAddSubFX source is pinned under `external/zynaddsubfx` at 3ab608c432996ba4d582176572c0b0f82328c825 for test-only parity work, and `tools/zyn-reference/build-zyn-reference.ps1` now builds an ignored patched source copy with MSYS2/MinGW, proves `PadNoteTest`, and builds `ZynPadReference`, including a test-only `harmonics` mode for dumping normalized OscilGen amplitudes before PAD generation. The optional PAD reports emit note and source-table WAV/listening artifacts. Latest accepted upstream PAD pressure has DoublePadBass close enough by ear with log-mel 0.247748 / score 0.650029 after Q/order cascade, while Ghost Ensemble improves to log-mel 0.369402 / score 0.57229. The remaining Ghost gap is no longer first-32 OscilGen harmonic extraction; oracle harmonic dumps match those ratios. The upstream GPL instrument bank is initialized at `external/zynaddsubfx/instruments` commit c5c912131b31df5fdf372d2f06a25aaf2375837f; survey tests parse 1318/1318 .xiz files, write a pressure report, and render a five-patch upstream PAD listening batch under ignored artifacts."
|
||||
status: "Initial ZynInstrumentReader reads plain or gzip-compressed .xiz XML from project-authored fixtures and classifies active ADD/SUB/PAD engines, enabled kit items, layering, envelopes, free envelopes, LFOs, filters, formants, and effects as ReferencePatch features. First AquaSynth rebuilds exist for additive lead, PAD texture, and vocal/formant layer and now use named `layer` declarations. Additive rebuilds can use `harmonics` banks attached to layers, PAD rebuilds can use `spectrum` PADsynth-style FFT wavetable banks attached to layers, and PAD/vocal rebuilds use staged voice `env=rl` envelopes through layer defaults. `ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript` now emits per-preset PAD `.aqua` rebuilds for enabled PAD kit items with OSCIL harmonic expansion, oracle-reported table base frequency, PAD detune, Zyn PAD profile/bandwidth/position semantics, static/filter-envelope low-pass mapping, low-pass note tracking, explicit low-pass Q, logarithmic Zyn envelope times, and calibrated PAD output gain. ZynAddSubFX source is pinned under `external/zynaddsubfx` at 3ab608c432996ba4d582176572c0b0f82328c825 for test-only parity work, and `tools/zyn-reference/build-zyn-reference.ps1` now builds an ignored patched source copy with MSYS2/MinGW, proves `PadNoteTest`, and builds `ZynPadReference`, including a test-only `harmonics` mode for dumping normalized OscilGen amplitudes before PAD generation. The optional PAD reports emit note and source-table WAV/listening artifacts. Latest accepted upstream PAD pressure has DoublePadBass close enough by ear with log-mel 0.247748 / score 0.650029 after Q/order cascade, while Ghost Ensemble improves to log-mel 0.369402 / score 0.57229. The remaining Ghost gap is no longer first-32 OscilGen harmonic extraction; oracle harmonic dumps match those ratios. The upstream GPL instrument bank is initialized at `external/zynaddsubfx/instruments` commit c5c912131b31df5fdf372d2f06a25aaf2375837f; survey tests parse 1318/1318 .xiz files, write a pressure report, and render a five-patch upstream PAD listening batch under ignored artifacts."
|
||||
first_slice:
|
||||
- "Use the Zyn PAD oracle report to isolate source-table, playback/gain, envelope, and fixture-mapping mismatch before further Zyn DSL golf."
|
||||
- "Use named layers as the owner before promoting richer formant morphing syntax."
|
||||
|
|
@ -123,7 +123,7 @@ reference_targets:
|
|||
first_slice:
|
||||
- "Add ExternalFaustReference catalog entries."
|
||||
- "Compile selected official examples as external references."
|
||||
- "Use failures to decide whether Aquarium needs a lower-level graph DSL."
|
||||
- "Use failures to decide whether AquaSynth needs a lower-level graph DSL."
|
||||
surge_xt:
|
||||
priority: 4
|
||||
purpose: "Modern hybrid synth and modulation matrix pressure test."
|
||||
|
|
@ -141,8 +141,8 @@ reference_targets:
|
|||
next_agent_start_here:
|
||||
recommended_first_task: >
|
||||
Continue the ZynAddSubFX phase. The first parser/classifier slice exists in
|
||||
`src/AquariumSynth.Dsl/ZynInstrument.cs` with project-authored fixtures
|
||||
under `tests/AquariumSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored`.
|
||||
`src/AquaSynth.Dsl/ZynInstrument.cs` with project-authored fixtures
|
||||
under `tests/AquaSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthored`.
|
||||
Named `layer` declarations own source identity, additive `harmonics` banks
|
||||
attach to those layers, PAD `spectrum` banks attach to those layers as
|
||||
PADsynth-style FFT wavetable sources, and staged `env=rl` envelopes now
|
||||
|
|
@ -151,7 +151,7 @@ next_agent_start_here:
|
|||
patched artifact copy and builds `ZynPadReference`, which emits PAD table
|
||||
samples or note audio from Zyn. The first optional project-authored PAD
|
||||
comparison writes WAV/report artifacts under `artifacts/parity/zyn-pad-reference`.
|
||||
User listening called the reference wineglass-pure and Aquarium angry bees.
|
||||
User listening called the reference wineglass-pure and AquaSynth angry bees.
|
||||
The current de-bee/pitch pass cuts unearned noise/drive/soft-clip,
|
||||
interpolates spectral wavetable reads, uses 131072-frame PAD tables, splits
|
||||
table `root` from playback `freq`, removes gratuitous spread/vibrato,
|
||||
|
|
@ -171,7 +171,7 @@ next_agent_start_here:
|
|||
- state/memory.json
|
||||
- state/evidence.jsonl
|
||||
verification:
|
||||
- "dotnet test AquariumSynthCSharp.slnx --no-restore"
|
||||
- "dotnet test AquaSynth.slnx --no-restore"
|
||||
|
||||
completed_slices:
|
||||
- date: 2026-05-15
|
||||
|
|
@ -186,7 +186,7 @@ completed_slices:
|
|||
(400-800 Hz 0.2713 vs 0.2780; 8-16 kHz 0.1471 vs 0.1355), and Organ
|
||||
improves to log-mel 0.471483 / score 0.541933 without changing accepted
|
||||
DoublePadBass, Ghost, or Soft Pad.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 107 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 107 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Mapped Organ Choir's remaining PAD voice-alignment issue to two real Zyn
|
||||
|
|
@ -199,20 +199,20 @@ completed_slices:
|
|||
Latest Organ candidate is led by the 523 Hz choir voice, with 261 Hz body
|
||||
at about -1.29 dB versus Zyn's -2.23 dB. Soft Pad, Ghost, and
|
||||
DoublePadBass remain on the accepted sample-0 root path.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 107 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 107 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Fixed Zyn OscilGen oscillator-filter harmonic indexing after user listening
|
||||
accepted Ghost, DoublePadBass, and Soft Pad but still heard sin2x
|
||||
over-emphasizing the wrong high harmonic. Zyn filter functions receive
|
||||
one-based harmonic numbers, so Aquarium's zero-based translation moved
|
||||
one-based harmonic numbers, so AquaSynth's zero-based translation moved
|
||||
sin2x's type-13 spike from h2 to h3. Preserving the Zyn index makes the
|
||||
generated sin2x table h2-dominant, improves centroid ratio from
|
||||
`1.227953` to `0.998145`, and moves log-mel from `0.491437` to
|
||||
`0.479782`. Organ Choir remains slightly tinny by ear and sin2x is still
|
||||
louder/concentrated, so the next pressure is output/profile shape rather
|
||||
than the wrong overtone index.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 106 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 106 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Added generated Zyn PAD output calibration after user listening found the
|
||||
|
|
@ -225,7 +225,7 @@ completed_slices:
|
|||
improves to `0.226563`, RMS ratio to `0.818669`, and score to `0.631168`.
|
||||
The rest of the current PAD batch stays in a plausible RMS range
|
||||
(`0.94..1.24` except DoublePadBass at `0.82`).
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 104 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 104 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Corrected Zyn PAD envelope timing after user listening reported that
|
||||
|
|
@ -237,7 +237,7 @@ completed_slices:
|
|||
multiplier remains cut because it overdrives the whole fixture batch.
|
||||
DoublePadBass improved to log-mel `0.211646`, envelope distance
|
||||
`0.462822`, RMS ratio `0.511669`, score `0.450507`.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 104 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 104 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Added a general low-pass rate/level envelope surface and mapped Zyn PAD
|
||||
|
|
@ -250,11 +250,11 @@ completed_slices:
|
|||
Zyn cutoff, preserving the immediate open-filter transient. DoublePadBass
|
||||
improved from log-mel `0.259298` / envelope distance `0.631427` to
|
||||
`0.241993` / `0.554658`; remaining pressure is mostly level/RMS.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 104 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 104 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Mapped two missing Zyn PAD authorities exposed by DoublePadBass listening:
|
||||
analog low-pass slope and PAD frequency detune. Aquarium now has a general
|
||||
analog low-pass slope and PAD frequency detune. AquaSynth now has a general
|
||||
`lpf_order` field which emits Faust `fi.lowpass(order, ...)`; Zyn analog
|
||||
`LP2` filters lower to `lpf_order=2` and include Zyn stage count. The Zyn
|
||||
PAD importer also applies Zyn `getdetune` semantics to
|
||||
|
|
@ -263,7 +263,7 @@ completed_slices:
|
|||
to `130.8128`. DoublePadBass log-mel moved from `0.334546` after static
|
||||
cutoff mapping to `0.259298`; the remaining gap is mostly envelope/RMS,
|
||||
not wrong pitch or high-band balance.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 103 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 103 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Mapped static Zyn PAD global low-pass filters into generated Aqua layers
|
||||
|
|
@ -275,7 +275,7 @@ completed_slices:
|
|||
`lpf=0.003325`, while kit1's `freq=61` lowers to `lpf=0.047225`. The
|
||||
louder gain-cap experiment stayed cut. Filter envelopes and LFOs remain
|
||||
explicit missing pressure.
|
||||
verification: "dotnet test tests\\AquariumSynth.Dsl.Tests\\AquariumSynth.Dsl.Tests.csproj --no-restore --filter FullyQualifiedName~ZynReferenceParityTests: 4 passed"
|
||||
verification: "dotnet test tests\\AquaSynth.Dsl.Tests\\AquaSynth.Dsl.Tests.csproj --no-restore --filter FullyQualifiedName~ZynReferenceParityTests: 4 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Addressed the two user-identified Zyn PAD offenders separately. Ghost
|
||||
|
|
@ -288,7 +288,7 @@ completed_slices:
|
|||
sums enabled PAD kit-note references, gathers per-kit table roots, and
|
||||
rebuilds enabled PAD kit layers into one Aqua script. A louder gain-cap
|
||||
experiment worsened DoublePadBass and was cut.
|
||||
verification: "dotnet test tests\\AquariumSynth.Dsl.Tests\\AquariumSynth.Dsl.Tests.csproj --no-restore --filter FullyQualifiedName~ZynReferenceParityTests: 4 passed"
|
||||
verification: "dotnet test tests\\AquaSynth.Dsl.Tests\\AquaSynth.Dsl.Tests.csproj --no-restore --filter FullyQualifiedName~ZynReferenceParityTests: 4 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Reworked the first Zyn OscilGen approximation into a sampled stage-order
|
||||
|
|
@ -300,10 +300,10 @@ completed_slices:
|
|||
improves the processed `sin2x pad` target versus the previous subset
|
||||
while keeping the pass honest: DoublePadBass and Organ Choir Pad2 still
|
||||
miss badly, so Zyn PAD parity remains open pressure.
|
||||
verification: "dotnet test tests\\AquariumSynth.Dsl.Tests\\AquariumSynth.Dsl.Tests.csproj --no-restore --filter FullyQualifiedName~ZynReferenceParityTests: 4 passed"
|
||||
verification: "dotnet test tests\\AquaSynth.Dsl.Tests\\AquaSynth.Dsl.Tests.csproj --no-restore --filter FullyQualifiedName~ZynReferenceParityTests: 4 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Promoted explicit Zyn PAD table semantics into the Aquarium model and
|
||||
Promoted explicit Zyn PAD table semantics into the AquaSynth model and
|
||||
parser. `SpectralBank` now carries `PadSpectrumProfile`; patch scripts can
|
||||
express Zyn PAD mode, bandwidth, bandwidth scale, harmonic profile, and
|
||||
harmonic-position warp through readable `zyn_*` fields, and
|
||||
|
|
@ -315,7 +315,7 @@ completed_slices:
|
|||
Organ Choir Pad2 improve, while sin2x, DoublePadBass, and Ghost Ensemble
|
||||
regress, so the next cut must either complete more OscilGen semantics or
|
||||
gate the approximation to the cases it owns.
|
||||
verification: "dotnet test tests\\AquariumSynth.Dsl.Tests\\AquariumSynth.Dsl.Tests.csproj --no-restore --filter \"FullyQualifiedName~ZynInstrumentTests|FullyQualifiedName~ZynReferenceParityTests\": 13 passed"
|
||||
verification: "dotnet test tests\\AquaSynth.Dsl.Tests\\AquaSynth.Dsl.Tests.csproj --no-restore --filter \"FullyQualifiedName~ZynInstrumentTests|FullyQualifiedName~ZynReferenceParityTests\": 13 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Initialized the upstream GPL ZynAddSubFX instrument bank submodule and
|
||||
|
|
@ -326,12 +326,12 @@ completed_slices:
|
|||
`artifacts/parity/zyn-upstream-pad-fixtures/`. Zyn PAD artifacts now use
|
||||
per-synth timestamped folders with reference WAVs, table WAVs,
|
||||
`candidate.aqua`, and `report.txt`; upstream GPL runs now render
|
||||
per-preset first-pass PAD rebuilds as `candidate-aquarium.wav`, with
|
||||
per-preset first-pass PAD rebuilds as `candidate-aquasynth.wav`, with
|
||||
reports naming which Zyn PAD semantics are still missing. The
|
||||
batch includes `Pads/0002-sin2x pad.xiz`, `Pads/0065-Soft Pad.xiz`,
|
||||
`Dual/0008-Organ Choir Pad2.xiz`, `Laba170bank/0098-DoublePadBass.xiz`,
|
||||
and `Companion/0121-Ghost Ensemble.xiz`.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore --filter FullyQualifiedName~ZynReferenceParityTests: 4 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore --filter FullyQualifiedName~ZynReferenceParityTests: 4 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Added more project-authored PAD fixtures and a Zyn-only PAD fixture
|
||||
|
|
@ -342,7 +342,7 @@ completed_slices:
|
|||
through the oracle, so the `pad-texture` filter/category XML was not live
|
||||
pressure; `pad-harmonic` changes both table and note output and is the
|
||||
next useful PAD rung.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 98 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 98 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Removed the detuned impression in the Zyn PAD rebuild by collapsing the
|
||||
|
|
@ -351,7 +351,7 @@ completed_slices:
|
|||
loud. Latest report: log-mel 0.35669, envelope 0.347572, RMS ratio
|
||||
1.001704, centroid ratio 1.004072, score 0.6211. This preserves the
|
||||
pitch/root split and avoids treating voice stacking as PAD richness.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 97 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 97 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Fixed the octave-low Zyn PAD rebuild by splitting spectral table root
|
||||
|
|
@ -362,11 +362,11 @@ completed_slices:
|
|||
Removing gratuitous spread/vibrato reduced the drone the user heard.
|
||||
Latest report: log-mel 0.353365, envelope 0.348752, RMS ratio 0.97283,
|
||||
centroid ratio 0.999243, score 0.612832.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 97 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 97 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
De-beed the project-authored Zyn PAD rebuild after listening identified
|
||||
Aquarium as a noisy swarm while Zyn sounded like a pure blown wineglass.
|
||||
AquaSynth as a noisy swarm while Zyn sounded like a pure blown wineglass.
|
||||
Cut the unearned `air` noise layer, drive, and soft clipping from the PAD
|
||||
rebuild; added interpolated Faust wavetable reads for spectral banks; and
|
||||
raised spectral PAD tables to Zyn's 131072-frame sample size. The optional
|
||||
|
|
@ -376,7 +376,7 @@ completed_slices:
|
|||
This is a real improvement from 0.236117 but not passing; remaining
|
||||
pressure is exact source profile/table generation and Zyn amplitude
|
||||
semantics.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 96 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 96 passed"
|
||||
- date: 2026-05-15
|
||||
summary: >
|
||||
Added `ZynPadReference`, a test-only executable copied into the ignored
|
||||
|
|
@ -385,12 +385,12 @@ completed_slices:
|
|||
`PADnoteParameters`/`PADnote` path, and writes either generated PAD table
|
||||
samples or rendered note audio as raw float32. Added an optional C# parity
|
||||
harness that runs the renderer when the artifact executable exists and
|
||||
writes Zyn/Aquarium WAVs plus a report under
|
||||
writes Zyn/AquaSynth WAVs plus a report under
|
||||
`artifacts/parity/zyn-pad-reference`. First report: log-mel 0.552296,
|
||||
envelope 0.774501, RMS ratio 0.234763, centroid ratio 1.025735, score
|
||||
0.236117, so the harness works and current Aquarium `spectrum` is not yet
|
||||
0.236117, so the harness works and current AquaSynth `spectrum` is not yet
|
||||
a close PAD emulation.
|
||||
verification: "powershell -NoProfile -ExecutionPolicy Bypass -File tools\\zyn-reference\\build-zyn-reference.ps1; dotnet test AquariumSynthCSharp.slnx --no-restore: 96 passed"
|
||||
verification: "powershell -NoProfile -ExecutionPolicy Bypass -File tools\\zyn-reference\\build-zyn-reference.ps1; dotnet test AquaSynth.slnx --no-restore: 96 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Built the pinned ZynAddSubFX source as a test-only MSYS2/MinGW parity
|
||||
|
|
@ -399,7 +399,7 @@ completed_slices:
|
|||
repo-owned compatibility patch for the stale `Part` constructor call,
|
||||
configures GUI/plugins off with tests on and `Werror=OFF`, builds
|
||||
`PadNoteTest`, and runs the CTest target. The next rung is a small
|
||||
reference renderer/wrapper that emits PAD audio or tables for Aquarium
|
||||
reference renderer/wrapper that emits PAD audio or tables for AquaSynth
|
||||
`spectrum` parity.
|
||||
verification: "powershell -NoProfile -ExecutionPolicy Bypass -File tools\\zyn-reference\\build-zyn-reference.ps1: PadNoteTest passed"
|
||||
- date: 2026-05-14
|
||||
|
|
@ -409,9 +409,9 @@ completed_slices:
|
|||
Added guard tests proving the source, license, PAD implementation files,
|
||||
and commit are present, and tightened the package-boundary test so
|
||||
`external/`, C++ sources, and headers do not ship in
|
||||
`AquariumSynth.Dsl.nupkg`. This establishes Zyn as a parity oracle, not
|
||||
Aquarium implementation.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 95 passed"
|
||||
`AquaSynth.Dsl.nupkg`. This establishes Zyn as a parity oracle, not
|
||||
AquaSynth implementation.
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 95 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added PAD spectral-cloud syntax for named layers. `spectrum
|
||||
|
|
@ -422,7 +422,7 @@ completed_slices:
|
|||
playback before ordinary voice treatment. The Zyn PAD texture rebuild now
|
||||
uses two spectral banks under `pad_low` and `pad_high`; full Zyn PAD
|
||||
profile/randomness/pitch-zone behavior remains missing pressure.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 94 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 94 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Promoted staged rate/level envelopes from operator graphs to normal
|
||||
|
|
@ -433,7 +433,7 @@ completed_slices:
|
|||
envelopes through named layers, proving the surface beyond a single
|
||||
fixture while leaving arbitrary Zyn free-envelope point curves as missing
|
||||
pressure.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 91 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 91 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added additive harmonic-bank syntax for named layers. `harmonics
|
||||
|
|
@ -443,17 +443,17 @@ completed_slices:
|
|||
banks under `body` and `shine`, while the catalog marks harmonic-bank
|
||||
support as matched and keeps Zyn ADDsynth phase/bandwidth/oscillator
|
||||
detail as missing pressure.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 90 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 90 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added the first Zyn-driven language-golf abstraction: `layer`.
|
||||
Layer declarations own name, engine tag, optional MIDI key range metadata,
|
||||
default gain, and effect-send labels while lowering to ordinary Aquarium
|
||||
default gain, and effect-send labels while lowering to ordinary AquaSynth
|
||||
voices. The three Zyn-style rebuilds now use named layers, proving the
|
||||
abstraction generalizes across additive, PAD-texture, and vocal/formant
|
||||
targets without adding fixture-specific shortcuts or hidden PAD/effect
|
||||
behavior.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 88 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 88 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Hardened the Zyn reader against the real upstream instrument bank and
|
||||
|
|
@ -466,10 +466,10 @@ completed_slices:
|
|||
envelopes, 73 LFOs, 37 filters, and 3 formant filters. The survey points
|
||||
to named kit/layer routing as the next owner abstraction before syntax
|
||||
golf.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 86 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 86 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added first Zyn-style Aquarium rebuilds for the project-authored additive
|
||||
Added first Zyn-style AquaSynth rebuilds for the project-authored additive
|
||||
lead, PAD texture, and vocal/formant layer fixtures. The rebuild catalog
|
||||
now records matched and missing features for each target, while tests
|
||||
parse/export the scripts and verify matched feature claims against source
|
||||
|
|
@ -477,7 +477,7 @@ completed_slices:
|
|||
additive harmonic-bank syntax, PAD/spectral source generation, free
|
||||
envelopes for normal voices, named kit/layer routing with per-layer effect
|
||||
sends, and richer formant/vowel morphing.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 83 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 83 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Started the ZynAddSubFX phase after closing the current DX7 community
|
||||
|
|
@ -488,7 +488,7 @@ completed_slices:
|
|||
kit items, layering, envelopes, free envelopes, LFOs, filters, formants,
|
||||
and effects. Upstream Zyn bank files were inspected but not vendored
|
||||
because preset provenance was not explicit enough for this first slice.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 81 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 81 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Reframed the latest community listening as envelope pressure rather than
|
||||
|
|
@ -499,7 +499,7 @@ completed_slices:
|
|||
to 1.25s, improving pressure log-mel to 0.3472474 and score to 0.5722256.
|
||||
Tested and cut a global traced-release-duration change because it broke
|
||||
PRC, `Piano Bass`, `RES SYNTH1`, and `ANLGSYN 1`.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 76 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 76 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added scoped modulator peak headroom after listening found `ANLGSYN 1`
|
||||
|
|
@ -513,7 +513,7 @@ completed_slices:
|
|||
0.42906323. Tested and cut a three-source summed-route headroom rule for
|
||||
`{ Mooger }`; it worsened Mooger metrics and did not isolate the overtone
|
||||
issue.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter Dx7... focused pass: 28 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter Dx7... focused pass: 28 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Lowered DX7 operator key-scaling and rate-scaling against the effective
|
||||
|
|
@ -526,7 +526,7 @@ completed_slices:
|
|||
and should not be promoted as passing stock. A trial that made envelope
|
||||
tracing depend on operator output level was cut because it worsened
|
||||
`MELLOWSOLO` and `ANLGSYN 1`.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter Dx7... focused pass: 28 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter Dx7... focused pass: 28 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Removed DX7 ROM COM carrier compensation after listening found the
|
||||
|
|
@ -538,7 +538,7 @@ completed_slices:
|
|||
0.10764466, RMS 0.941083. `DX1 LEAD B` and `MELLOWSOLO` sound closer by
|
||||
ear under no-COM/gain-restored lowering but still fail numeric gates, so
|
||||
they remain pressure targets.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 74 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 74 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Fixed the remaining `ANLGSYN 1` drift after listening found the
|
||||
|
|
@ -551,18 +551,18 @@ completed_slices:
|
|||
graph gain moved to 0.30, bringing its RMS ratio to 0.9909909. Latest
|
||||
`ANLGSYN 1`: score 0.7245976, log-mel 0.18460114, envelope 0.119950555,
|
||||
zero-crossing 0.97149533.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 74 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 74 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Tightened the `ANLGSYN 1` parity rung after listening caught the remaining
|
||||
`deeooh` failure: the hotter feedback attack was close, but sustained
|
||||
high-band buzz collapsed midway through the note. The DX7 probe lowering
|
||||
now enables Aquarium's existing output soft clip only for max-feedback
|
||||
now enables AquaSynth's existing output soft clip only for max-feedback
|
||||
voices with a self-feedback topology. PRC remains `soft_clip=false`.
|
||||
Latest `ANLGSYN 1`: score 0.70946133, log-mel 0.18456098, envelope
|
||||
0.10628832, RMS ratio 0.9816304, zero-crossing 0.8657629. Latest PRC:
|
||||
score 0.7546429, log-mel 0.13874851, envelope 0.067291394.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 73 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 73 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Retuned DX7 max-feedback lowering after listening found `ANLGSYN 1` still
|
||||
|
|
@ -575,7 +575,7 @@ completed_slices:
|
|||
rises from 0.8% to 65.6%, and 2.5-5 kHz from near zero to 32.1%.
|
||||
Envelope/RMS are still imperfect, so this is a timbre correction rather
|
||||
than the final word on ANLGSYN.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 73 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 73 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Fixed DX7 fixed-frequency operator lowering after listening caught
|
||||
|
|
@ -588,7 +588,7 @@ completed_slices:
|
|||
`ANLGSYN 1`; latest metrics improve to log-mel 0.19427659, envelope
|
||||
0.14924917, zero-crossing 0.94662774, centroid 0.9182808, score
|
||||
0.659334.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 73 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 73 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Fixed DX7 voice transpose lowering after listening caught `Piano Bass`
|
||||
|
|
@ -600,31 +600,31 @@ completed_slices:
|
|||
`RES SYNTH1`, `DX1 LEAD B`, and `MELLOWSOLO` remain pressure, not passing
|
||||
parity. Fixed `Piano Bass` improves to log-mel 0.16180529, envelope
|
||||
0.13544041, zero-crossing 0.905511, and score 0.64267576.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 71 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 71 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added a rendered public-domain community DX7 parity test against four
|
||||
actual `analog1.syx` voices from Musical Artifacts artifact 152:
|
||||
`ANLGSYN 1`, `{ Mooger }`, `Piano Bass`, and `RES SYNTH1`. The test
|
||||
renders Dexed references, lowers the same voices through the current
|
||||
Aquarium DX7 operator-graph path, writes listening WAV/report artifacts
|
||||
AquaSynth DX7 operator-graph path, writes listening WAV/report artifacts
|
||||
under `artifacts/parity/dx7-community-analog1/`, and gates broad parity
|
||||
at log-mel <= 0.3, envelope <= 0.16, score >= 0.5. First survey also
|
||||
tried `DX1 LEAD B` and `MELLOWSOLO`; they remain pressure because
|
||||
log-mel/zero-crossing mismatch is too large for the broad gate.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 70 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 70 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added split project-authored DX7 algorithm-8 parity probes for the
|
||||
cascaded `6 -> 5 -> 3` branch and summed `4 + 5 -> 3` branch. The tests
|
||||
render Dexed references, render Aquarium operator-graph candidates, write
|
||||
render Dexed references, render AquaSynth operator-graph candidates, write
|
||||
listening WAV/report artifacts under `artifacts/parity/dx7-project-authored/`,
|
||||
and gate log-mel at <= 0.06. Latest real-Dexed run: combined stack
|
||||
log-mel 0.04029555/score 0.8664546, summed pair 0.042429477/0.870778,
|
||||
cascade 0.03811625/0.9157809. The split probes remain test/artifact
|
||||
material rather than patch-library stock because they are calibration
|
||||
signals, not usable sounds.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore: 69 passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore: 69 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added a structured development patch library under `patches/` with a
|
||||
|
|
@ -632,8 +632,8 @@ completed_slices:
|
|||
existing stock/reference catalogs plus the calibrated PRC SYNTH1 parity
|
||||
candidate. Added tests so every library `.aqua` parses and exports Faust,
|
||||
while package-boundary tests assert `patches/` and `.aqua` files do not
|
||||
ship in the AquariumSynth.Dsl NuGet package.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 67 passed"
|
||||
ship in the AquaSynth.Dsl NuGet package.
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 67 passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Increased `Dx7SysEx.SummedOperatorModulationRouteIndex` from 1.6 to 6.0
|
||||
|
|
@ -642,27 +642,27 @@ completed_slices:
|
|||
to 0.067291506, centroid ratio to 1.1156512, and score to 0.7546445 with
|
||||
RMS ratio 0.9912135. The independent project-authored algorithm-8
|
||||
summed-stack test now uses graph gain 0.218 and tighter log-mel/RMS gates.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled|ProjectAuthoredDx7AlgorithmEightSummedStackMeetsParityWhenInstalled\": passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter \"PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled|ProjectAuthoredDx7AlgorithmEightSummedStackMeetsParityWhenInstalled\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added `Dx7SysEx.ApproximateAppliedRateLevelEnvelope` and used it in the
|
||||
hard PRC SYNTH1 probe. The helper traces Dexed-style block-interpolated
|
||||
applied EG gain, normalizes it against Aquarium operator-output scaling,
|
||||
applied EG gain, normalizes it against AquaSynth operator-output scaling,
|
||||
and emits curved `env=rl` syntax. PRC log-mel improved from 0.24476814 to
|
||||
0.21931955 and envelope distance from 0.43700194 to 0.10271241, with RMS
|
||||
ratio near unity. A follow-up fixed the peak picker for slower rising
|
||||
envelopes after listening exposed op2's false late swell; PRC now reaches
|
||||
log-mel 0.17186502, envelope distance 0.13057204, zero-crossing ratio
|
||||
0.7815517, and score 0.6501268.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled|ProjectAuthoredDx7AlgorithmEightSummedStackMeetsParityWhenInstalled|ApproximatesDx7AppliedEnvelopeAsCurvedRateLevelEnvelope\": passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter \"PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled|ProjectAuthoredDx7AlgorithmEightSummedStackMeetsParityWhenInstalled|ApproximatesDx7AppliedEnvelopeAsCurvedRateLevelEnvelope\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added per-segment curves to staged operator envelopes. `env=rl` remains
|
||||
the same rate/level contour surface, but can now express linear or
|
||||
exponential segments with deliberate levels above unity. The DX7 envelope
|
||||
trace artifact includes a curved Aquarium candidate that is much closer
|
||||
trace artifact includes a curved AquaSynth candidate that is much closer
|
||||
to Dexed's block-interpolated applied gain than the old linear contour.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"OperatorGraphSyntaxParsesReadableRateLevelEnvelope|OperatorGraphSyntaxParsesCurvedRateLevelEnvelope|ProjectAuthoredDx7EnvelopeTraceWritesComparisonArtifact\": passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore --filter \"OperatorGraphSyntaxParsesReadableRateLevelEnvelope|OperatorGraphSyntaxParsesCurvedRateLevelEnvelope|ProjectAuthoredDx7EnvelopeTraceWritesComparisonArtifact\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added `Dx7SysEx.TraceInterpolatedEnvelope` and extended the DX7 envelope
|
||||
|
|
@ -670,7 +670,7 @@ completed_slices:
|
|||
rendering samples the EG once per 64-sample block and interpolates the
|
||||
applied gain across the block, so matching the raw EG state alone is not
|
||||
enough for audio parity.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"TracesDx7EnvelopeAppliedBlockInterpolatedGain|TracesDx7EnvelopeInternalGainShape|ProjectAuthoredDx7EnvelopeTraceWritesComparisonArtifact\": passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore --filter \"TracesDx7EnvelopeAppliedBlockInterpolatedGain|TracesDx7EnvelopeInternalGainShape|ProjectAuthoredDx7EnvelopeTraceWritesComparisonArtifact\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added `Dx7SysEx.TraceEnvelope` and an envelope trace comparison artifact.
|
||||
|
|
@ -678,7 +678,7 @@ completed_slices:
|
|||
an initial gain spike above 1 followed by millisecond-scale collapse to a
|
||||
tiny sustain. A first `env=dx7` runtime lowering attempt was cut because
|
||||
matching the local trace did not match Dexed plugin audio.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"ProjectAuthoredDx7EnvelopeTraceWritesComparisonArtifact|TracesDx7EnvelopeInternalGainShape\": passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore --filter \"ProjectAuthoredDx7EnvelopeTraceWritesComparisonArtifact|TracesDx7EnvelopeInternalGainShape\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added test-only project-authored Dexed patch rendering and an independent
|
||||
|
|
@ -687,7 +687,7 @@ completed_slices:
|
|||
exponential DX7 EG level curve was tested and cut: it improved some
|
||||
envelope metrics but failed PRC log-mel, so EG levels remain linear until
|
||||
isolated envelope parity can pass without harming PRC.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"ProjectAuthoredDx7AlgorithmEightSummedStackMeetsParityWhenInstalled|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled|Dx7SysExTests\": passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter \"ProjectAuthoredDx7AlgorithmEightSummedStackMeetsParityWhenInstalled|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled|Dx7SysExTests\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Moved the remaining PRC cascaded-route scalar into
|
||||
|
|
@ -695,7 +695,7 @@ completed_slices:
|
|||
use the two-op route scale 6.275; summed edges and direct edges feeding a
|
||||
summed branch use the summed/cascaded route scale 1.6. The PRC probe no
|
||||
longer owns a private route-index function.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"Dx7SysExTests|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled\": passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter \"Dx7SysExTests|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added DX7 ratio-mode detune and algorithm output compensation to central
|
||||
|
|
@ -704,23 +704,23 @@ completed_slices:
|
|||
output counts relative to the algorithm-32 six-output amplitude baseline.
|
||||
The PRC probe no longer carries a manual carrier-level scale table; its
|
||||
remaining cascaded-route value is fenced as a hard-target probe scar.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"Dx7SysExTests|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled\": passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter \"Dx7SysExTests|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Completed the DX7 feedback calibration rung. Isolated feedback sweeps fit
|
||||
Aquarium feedback amounts `0, .01, .02, .05, .10, .19, .38, .66` for DX7
|
||||
AquaSynth feedback amounts `0, .01, .02, .05, .10, .19, .38, .66` for DX7
|
||||
feedback values 0-7. `Dx7SysEx.OperatorFeedbackAmount` now owns that
|
||||
table, and the PRC probe no longer uses a local `feedback * constant`.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"CalibratesDx7FeedbackToAquariumFeedbackAmount|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled\": passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter \"CalibratesDx7FeedbackToAquaSynthFeedbackAmount|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Completed the isolated two-operator modulation-index rung. Dexed sweeps
|
||||
fit full-level modulation at about 12.55 radians, which maps to Aquarium
|
||||
fit full-level modulation at about 12.55 radians, which maps to AquaSynth
|
||||
route index 6.275 under the current Faust phase formula. The PRC probe
|
||||
applies that calibrated route only to the isolated `op2 -> op1` branch;
|
||||
applying it to the cascaded stack made metrics worse, leaving algorithm
|
||||
output compensation as explicit pressure.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled: passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled: passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Added `docs/dx7-calibration-plan.md` and completed the first calibration
|
||||
|
|
@ -729,7 +729,7 @@ completed_slices:
|
|||
exposes `OperatorOutputAmplitude` and `ApproximateOperatorLevel` uses that
|
||||
measured curve instead of the old internal-level proxy. The PRC log-mel
|
||||
gate is temporarily 0.26 while the next rung calibrates modulation index.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter \"Dx7SysExTests|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled\": passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter \"Dx7SysExTests|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled\": passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Reoriented the hard DX7 `PRC SYNTH1` probe around log-mel distance after
|
||||
|
|
@ -738,25 +738,25 @@ completed_slices:
|
|||
dominant 393 Hz partial; the candidate now uses the DX7 note basis and
|
||||
scaled high modulators to reach log-mel 0.25093183, with remaining
|
||||
zero-crossing/centroid mismatch left as explicit pressure.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled: passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled: passed"
|
||||
- date: 2026-05-14
|
||||
summary: >
|
||||
Tightened the hard DX7 `PRC SYNTH1` probe to require score >= 0.60 and
|
||||
improved the candidate to 0.6057491. The useful calibration cuts were
|
||||
removing Aquarium soft clipping, setting the graph base frequency to 392,
|
||||
removing AquaSynth soft clipping, setting the graph base frequency to 392,
|
||||
and boosting the op3 carrier branch for algorithm-8 output/body balance.
|
||||
Global detune and per-edge route damping were tested and cut because they
|
||||
made the metrics worse.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled: passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled: passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added a hard DX7 `PRC SYNTH1` rendered parity probe that emits listening
|
||||
WAV artifacts under ignored `artifacts/parity/dx7-prc-synth1` when
|
||||
dexed-py and Faust are available. The Aquarium candidate uses readable
|
||||
dexed-py and Faust are available. The AquaSynth candidate uses readable
|
||||
operator graph syntax and staged `env=rl` envelopes, asserts a modest
|
||||
hard-target score floor, and currently scores 0.4581856 with duration
|
||||
close to the Dexed reference but remaining gain/timbre mismatch.
|
||||
verification: "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore --filter PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled: passed"
|
||||
verification: "AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.slnx --no-restore --filter PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled: passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added staged operator envelopes for operator graphs through
|
||||
|
|
@ -766,15 +766,15 @@ completed_slices:
|
|||
lowering on `PRC SYNTH1` only reached ~0.316 in quick probes, so the DSL
|
||||
surface exists but DX7 EG timing/gain calibration remains the next
|
||||
pressure.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 53 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 53 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added `Dx7OperatorLevelApproximation`, which maps DX7 operator output
|
||||
level plus key/velocity scaling into normal Aquarium operator levels for
|
||||
level plus key/velocity scaling into normal AquaSynth operator levels for
|
||||
reference rebuild work. Retried `PRC SYNTH1`; static level mapping alone
|
||||
did not produce parity, and envelope tweaks only reached ~0.42 score. The
|
||||
next pressure is DX7-style operator envelope/gain evolution.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 50 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 50 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Probed the harder `analog1.syx` voice 17 (`PRC SYNTH1`) and found the
|
||||
|
|
@ -782,53 +782,53 @@ completed_slices:
|
|||
cut was feedback: operator feedback now emits as Faust delayed recursion
|
||||
instead of a direct cyclic self-reference, and a render test covers it.
|
||||
Exact DX7 feedback scaling and EG behavior remain pressure.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 49 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 49 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added the first thresholded rendered DX7 parity rebuild for
|
||||
`analog1.syx` voice 13, `MC-MM 5-3`. The candidate is a terse Aquarium
|
||||
`analog1.syx` voice 13, `MC-MM 5-3`. The candidate is a terse AquaSynth
|
||||
sine-like behavioral match and the test compares dexed-py reference audio
|
||||
against Faust-rendered Aquarium audio using score, log-mel, envelope,
|
||||
against Faust-rendered AquaSynth audio using score, log-mel, envelope,
|
||||
duration, RMS, zero-crossing, and centroid thresholds. It does not claim
|
||||
exact DX7 operator execution.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 48 passed; focused dexed-py parity test passed with bundled Python"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 48 passed; focused dexed-py parity test passed with bundled Python"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added a public-domain DX7 SysEx fixture from Musical Artifacts artifact
|
||||
152, provenance metadata, and a test-only dexed-py renderer. The render
|
||||
test uses `AQUARIUM_DX7_PYTHON` when set and otherwise stays optional.
|
||||
Added a package-boundary test that packs `AquariumSynth.Dsl` and asserts
|
||||
test uses `AQUASYNTH_DX7_PYTHON` when set and otherwise stays optional.
|
||||
Added a package-boundary test that packs `AquaSynth.Dsl` and asserts
|
||||
fixtures, SysEx banks, and Python helpers do not ship in the NuGet package.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 47 passed; dexed-py render test passed with bundled Python"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 47 passed; dexed-py render test passed with bundled Python"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added `FaustCompiler.RenderAsync`, which compiles Aquarium Faust source to
|
||||
Added `FaustCompiler.RenderAsync`, which compiles AquaSynth Faust source to
|
||||
Faust-generated C#, runs it in a temp .NET project, and returns mono float
|
||||
samples. The first render test checks non-silent generated audio and feeds
|
||||
the buffer through `AudioAnalyzer`; DX7 audio parity remains blocked on a
|
||||
chosen reference renderer or captured fixture.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 44 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 44 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added `Dx7EnvelopeApproximation`, a labeled helper that lowers DX7
|
||||
four-rate/four-level envelopes to Aquarium ADSR plus gate duration.
|
||||
four-rate/four-level envelopes to AquaSynth ADSR plus gate duration.
|
||||
Reference rebuilds now distinguish approximated envelope lowering from
|
||||
still-missing exact DX7 EG execution.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 43 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 43 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added field-site parameter binding for readable operator graphs. Graph
|
||||
gain/note fields, operator ratio/level/feedback/envelope fields, and route
|
||||
index fields now bind through exact `/opgraphs/...` paths, and Faust
|
||||
emission substitutes those bound expressions in operator graph output.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 42 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 42 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added a patch-level Playback contract and `instrument` authoring surface
|
||||
for Faust-managed MIDI mono/polyphony. `instrument midi=true polyphony=8`
|
||||
emits `[midi:on][nvoices:8]` and standard `freq`, `gain`, and `gate`
|
||||
controls instead of Aquarium-owned voice allocation.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 41 passed"
|
||||
controls instead of AquaSynth-owned voice allocation.
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 41 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Standardized the live envelope model as ADSR and added explicit Note
|
||||
|
|
@ -837,14 +837,14 @@ completed_slices:
|
|||
ADSR sustain level plus voice gain compensation as compatibility import
|
||||
behavior. Generated Faust can emit one-shot ADSR envelopes or host
|
||||
gate/frequency controls.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 40 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 40 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added readable operator graph authoring syntax with `operator`, `route`,
|
||||
and `carrier` declarations, plus `env=ad:attack:decay` and
|
||||
`env=adsr:attack:decay:sustain:release` forms. Converted the DX7
|
||||
algorithm-8 rebuild away from compact number soup.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 36 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 36 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added first-class OperatorGraph support with operators, modulation edges,
|
||||
|
|
@ -852,14 +852,14 @@ completed_slices:
|
|||
normal voices. Updated the DX7 algorithm-8 rebuild to use the operator
|
||||
graph; remaining pressure is exact DX7 feedback-register timing and
|
||||
rate/level envelopes.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 35 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 35 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added ReferenceRebuild catalog entries and two DX7-style Aquarium DSL
|
||||
Added ReferenceRebuild catalog entries and two DX7-style AquaSynth DSL
|
||||
rebuilds. Algorithm 32 maps cleanly to six additive voices; algorithm 8
|
||||
exposes missing operator graph concepts including explicit modulation
|
||||
edges, summed modulators, and operator-local self-feedback.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 34 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 34 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added DX7 algorithm topology metadata for algorithms 1-32 from the
|
||||
|
|
@ -867,14 +867,14 @@ completed_slices:
|
|||
operators, modulation edges, feedback-register writers, self-feedback
|
||||
operators, delayed-feedback targets, raw ROM steps, and ReferencePatch
|
||||
feature pressure.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 31 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 31 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added DX7 SysEx records and parsing for 155-byte voice edit buffers,
|
||||
128-byte packed voices, and 4104-byte packed 32-voice banks. Extracted
|
||||
operators, envelopes, algorithm, feedback, oscillator sync, LFO,
|
||||
transpose, voice name, checksum validation, and ReferencePatch features.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 28 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 28 passed"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added PatchParameter and ReferencePatch contracts, `param` script parsing,
|
||||
|
|
@ -882,7 +882,7 @@ completed_slices:
|
|||
controls. Parameter binding uses field-site references such as
|
||||
`lpf=@/macro/brightness`; the emitter substitutes the parameter only at
|
||||
the exact bound field site and warns for unbound parameters.
|
||||
verification: "dotnet test AquariumSynthCSharp.slnx --no-restore: 23 passed"
|
||||
verification: "dotnet test AquaSynth.slnx --no-restore: 23 passed"
|
||||
|
||||
cut_line:
|
||||
- "Cut any importer that cannot state source provenance and license."
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\AquariumSynth.Dsl\AquariumSynth.Dsl.csproj" />
|
||||
<ProjectReference Include="..\..\src\AquaSynth.Dsl\AquaSynth.Dsl.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -2,7 +2,7 @@ using System.Diagnostics;
|
|||
using System.Text.Json;
|
||||
using System.Text;
|
||||
|
||||
namespace AquariumSynth.Dsl.Tests;
|
||||
namespace AquaSynth.Dsl.Tests;
|
||||
|
||||
public sealed class Dx7ReferenceParityTests
|
||||
{
|
||||
|
|
@ -319,8 +319,8 @@ public sealed class Dx7ReferenceParityTests
|
|||
var dx7 = Dx7SysEx.TraceEnvelope(envelope, gateSeconds: 0.75f, durationSeconds: 1.1f);
|
||||
var dx7Applied = Dx7SysEx.TraceInterpolatedEnvelope(envelope, gateSeconds: 0.75f, durationSeconds: 1.1f);
|
||||
var approximation = ScaledEnvelope(Dx7SysEx.ApproximateRateLevelEnvelope(envelope), 0.62f, 0.75f);
|
||||
var aquarium = TraceRateLevelEnvelope(approximation.Envelope, approximation.GateSeconds, durationSeconds: 1.1f);
|
||||
var aquariumCurved = TraceRateLevelEnvelope(
|
||||
var aquasynth = TraceRateLevelEnvelope(approximation.Envelope, approximation.GateSeconds, durationSeconds: 1.1f);
|
||||
var aquasynthCurved = TraceRateLevelEnvelope(
|
||||
new RateLevelEnvelope(
|
||||
64f / 44100,
|
||||
2f,
|
||||
|
|
@ -341,27 +341,27 @@ public sealed class Dx7ReferenceParityTests
|
|||
var path = Path.Combine(artifactDir, "egstep.csv");
|
||||
|
||||
using var writer = new StreamWriter(path);
|
||||
writer.WriteLine("time_seconds,dx7_raw_gain,dx7_applied_gain,aquarium_rl_gain,aquarium_curved_gain,dx7_stage");
|
||||
for (var i = 0; i < Math.Min(dx7.Count, aquarium.Length); i += 64)
|
||||
writer.WriteLine("time_seconds,dx7_raw_gain,dx7_applied_gain,aquasynth_rl_gain,aquasynth_curved_gain,dx7_stage");
|
||||
for (var i = 0; i < Math.Min(dx7.Count, aquasynth.Length); i += 64)
|
||||
{
|
||||
writer.WriteLine(string.Join(
|
||||
",",
|
||||
F(dx7[i].TimeSeconds),
|
||||
F(dx7[i].Gain),
|
||||
F(dx7Applied[i].Gain),
|
||||
F(aquarium[i]),
|
||||
F(aquariumCurved[i]),
|
||||
F(aquasynth[i]),
|
||||
F(aquasynthCurved[i]),
|
||||
dx7[i].Stage.ToString(System.Globalization.CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
var linearShape = NormalizedDistance(
|
||||
dx7Applied.Select(point => point.Gain).ToArray(),
|
||||
aquarium);
|
||||
aquasynth);
|
||||
var curvedShape = NormalizedDistance(
|
||||
dx7Applied.Select(point => point.Gain).ToArray(),
|
||||
aquariumCurved);
|
||||
Assert.True(linearShape > 0.55f, $"expected current Aquarium envelope to visibly differ; shape distance {linearShape}, artifact: {path}");
|
||||
Assert.True(curvedShape < linearShape * 0.6f, $"expected curved Aquarium envelope to improve shape; linear {linearShape}, curved {curvedShape}, artifact: {path}");
|
||||
aquasynthCurved);
|
||||
Assert.True(linearShape > 0.55f, $"expected current AquaSynth envelope to visibly differ; shape distance {linearShape}, artifact: {path}");
|
||||
Assert.True(curvedShape < linearShape * 0.6f, $"expected curved AquaSynth envelope to improve shape; linear {linearShape}, curved {curvedShape}, artifact: {path}");
|
||||
}
|
||||
|
||||
private static string FixturePath(params string[] parts) =>
|
||||
|
|
@ -370,7 +370,7 @@ public sealed class Dx7ReferenceParityTests
|
|||
private static string ArtifactPath(params string[] parts)
|
||||
{
|
||||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (current is not null && !File.Exists(Path.Combine(current.FullName, "AquariumSynthCSharp.slnx")))
|
||||
while (current is not null && !File.Exists(Path.Combine(current.FullName, "AquaSynth.slnx")))
|
||||
{
|
||||
current = current.Parent;
|
||||
}
|
||||
|
|
@ -771,7 +771,7 @@ public sealed class Dx7ReferenceParityTests
|
|||
var peak = Math.Max(Peak(reference), Peak(candidate));
|
||||
var scale = peak <= 0 ? 1 : 0.98f / peak;
|
||||
WriteWav(Path.Combine(directory, "reference-dexed.wav"), reference, sampleRate, scale);
|
||||
WriteWav(Path.Combine(directory, "candidate-aquarium.wav"), candidate, sampleRate, scale);
|
||||
WriteWav(Path.Combine(directory, "candidate-aquasynth.wav"), candidate, sampleRate, scale);
|
||||
File.WriteAllText(Path.Combine(directory, "candidate.aqua"), script);
|
||||
File.WriteAllText(
|
||||
Path.Combine(directory, "report.txt"),
|
||||
|
|
@ -780,7 +780,7 @@ public sealed class Dx7ReferenceParityTests
|
|||
ParityReport(comparison),
|
||||
$"wav normalization scale: {scale}",
|
||||
$"reference: {Path.Combine(directory, "reference-dexed.wav")}",
|
||||
$"candidate: {Path.Combine(directory, "candidate-aquarium.wav")}"));
|
||||
$"candidate: {Path.Combine(directory, "candidate-aquasynth.wav")}"));
|
||||
}
|
||||
|
||||
private static void WriteWav(string path, IReadOnlyList<float> samples, int sampleRate, float scale)
|
||||
|
|
@ -893,7 +893,7 @@ internal static class DexedPyRenderer
|
|||
var python = await FindPythonWithDexedAsync(cancellationToken);
|
||||
if (python is null) return null;
|
||||
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), $"aquarium-dx7-render-{Guid.NewGuid():N}");
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), $"aquasynth-dx7-render-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(tempDir);
|
||||
try
|
||||
{
|
||||
|
|
@ -945,7 +945,7 @@ internal static class DexedPyRenderer
|
|||
var python = await FindPythonWithDexedAsync(cancellationToken);
|
||||
if (python is null) return null;
|
||||
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), $"aquarium-dx7-patch-render-{Guid.NewGuid():N}");
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), $"aquasynth-dx7-patch-render-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(tempDir);
|
||||
try
|
||||
{
|
||||
|
|
@ -988,7 +988,7 @@ internal static class DexedPyRenderer
|
|||
|
||||
private static async Task<PythonCommand?> FindPythonWithDexedAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var configuredPython = Environment.GetEnvironmentVariable("AQUARIUM_DX7_PYTHON");
|
||||
var configuredPython = Environment.GetEnvironmentVariable("AQUASYNTH_DX7_PYTHON");
|
||||
var candidates = new List<PythonCommand>();
|
||||
if (!string.IsNullOrWhiteSpace(configuredPython))
|
||||
{
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using AquariumSynth.Dsl;
|
||||
using AquaSynth.Dsl;
|
||||
|
||||
namespace AquariumSynth.Dsl.Tests;
|
||||
namespace AquaSynth.Dsl.Tests;
|
||||
|
||||
public sealed class Dx7SysExTests
|
||||
{
|
||||
|
|
@ -221,7 +221,7 @@ public sealed class Dx7SysExTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void CalibratesDx7OutputLevelToAquariumRouteIndex()
|
||||
public void CalibratesDx7OutputLevelToAquaSynthRouteIndex()
|
||||
{
|
||||
var fullScalePhaseDeviationRadians = 2 * Dx7SysEx.OperatorOutputAmplitude(99) * Dx7SysEx.OperatorModulationRouteIndex;
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ public sealed class Dx7SysExTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void CalibratesDx7FeedbackToAquariumFeedbackAmount()
|
||||
public void CalibratesDx7FeedbackToAquaSynthFeedbackAmount()
|
||||
{
|
||||
Assert.Equal(0, Dx7SysEx.OperatorFeedbackAmount(0));
|
||||
Assert.Equal(0.19f, Dx7SysEx.OperatorFeedbackAmount(5));
|
||||
|
|
@ -10,4 +10,4 @@ Artifacts artifact 152, "DX7 patches 1".
|
|||
- SHA-256: `5AC120DF3A538DFB9A4B17A218F71B1D136269D2C30A33E676C1D6DDE2AC3AD2`
|
||||
|
||||
This fixture is test/development material only. It must not be packed into
|
||||
`AquariumSynth.Dsl.nupkg`.
|
||||
`AquaSynth.Dsl.nupkg`.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# Project-Authored ZynAddSubFX Fixtures
|
||||
|
||||
These `.xiz` files are tiny Aquarium-authored XML fixtures shaped like
|
||||
These `.xiz` files are tiny AquaSynth-authored XML fixtures shaped like
|
||||
ZynAddSubFX instrument files. They are not copied from an upstream Zyn bank.
|
||||
|
||||
Purpose:
|
||||
|
|
@ -19,4 +19,4 @@ Current fixtures:
|
|||
- `pad-harmonic.xiz`
|
||||
- `vocal-layer.xiz`
|
||||
|
||||
License: project-authored for AquariumSynthCSharp tests.
|
||||
License: project-authored for AquaSynth tests.
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<INSTRUMENT>
|
||||
<INFO>
|
||||
<string name="name">AQ Additive Lead</string>
|
||||
<string name="author">AquariumSynthCSharp tests</string>
|
||||
<string name="author">AquaSynth tests</string>
|
||||
<string name="comments">Project-authored additive fixture.</string>
|
||||
<par name="type" value="0"/>
|
||||
</INFO>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<INSTRUMENT>
|
||||
<INFO>
|
||||
<string name="name">AQ Pad Harmonic</string>
|
||||
<string name="author">AquariumSynthCSharp tests</string>
|
||||
<string name="author">AquaSynth tests</string>
|
||||
<string name="comments">Project-authored PAD fixture with explicit oscillator harmonics.</string>
|
||||
<par name="type" value="0"/>
|
||||
</INFO>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<INSTRUMENT>
|
||||
<INFO>
|
||||
<string name="name">AQ Pad Pure</string>
|
||||
<string name="author">AquariumSynthCSharp tests</string>
|
||||
<string name="author">AquaSynth tests</string>
|
||||
<string name="comments">Project-authored default PAD fixture for pure source-table parity.</string>
|
||||
<par name="type" value="0"/>
|
||||
</INFO>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<INSTRUMENT>
|
||||
<INFO>
|
||||
<string name="name">AQ Pad Texture</string>
|
||||
<string name="author">AquariumSynthCSharp tests</string>
|
||||
<string name="author">AquaSynth tests</string>
|
||||
<string name="comments">Project-authored PAD fixture.</string>
|
||||
<par name="type" value="0"/>
|
||||
</INFO>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<INSTRUMENT>
|
||||
<INFO>
|
||||
<string name="name">AQ Vocal Layer</string>
|
||||
<string name="author">AquariumSynthCSharp tests</string>
|
||||
<string name="author">AquaSynth tests</string>
|
||||
<string name="comments">Project-authored layered vocal/formant fixture.</string>
|
||||
<par name="type" value="0"/>
|
||||
</INFO>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace AquariumSynth.Dsl.Tests;
|
||||
namespace AquaSynth.Dsl.Tests;
|
||||
|
||||
public sealed class PackageBoundaryTests
|
||||
{
|
||||
|
|
@ -9,20 +9,20 @@ public sealed class PackageBoundaryTests
|
|||
public async Task NuGetPackageContainsOnlyPublishedSynthSurface()
|
||||
{
|
||||
var root = RepositoryRoot();
|
||||
var outputDir = Path.Combine(Path.GetTempPath(), $"aquarium-pack-{Guid.NewGuid():N}");
|
||||
var outputDir = Path.Combine(Path.GetTempPath(), $"aquasynth-pack-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(outputDir);
|
||||
try
|
||||
{
|
||||
var result = await RunAsync(
|
||||
"dotnet",
|
||||
["pack", Path.Combine(root, "src", "AquariumSynth.Dsl", "AquariumSynth.Dsl.csproj"), "-c", "Release", "--no-restore", "-o", outputDir]);
|
||||
["pack", Path.Combine(root, "src", "AquaSynth.Dsl", "AquaSynth.Dsl.csproj"), "-c", "Release", "--no-restore", "-o", outputDir]);
|
||||
Assert.Equal(0, result.ExitCode);
|
||||
|
||||
var package = Assert.Single(Directory.GetFiles(outputDir, "AquariumSynth.Dsl.*.nupkg"));
|
||||
var package = Assert.Single(Directory.GetFiles(outputDir, "AquaSynth.Dsl.*.nupkg"));
|
||||
using var archive = ZipFile.OpenRead(package);
|
||||
var entries = archive.Entries.Select(entry => entry.FullName).ToArray();
|
||||
|
||||
Assert.Contains(entries, entry => entry.StartsWith("lib/net10.0/AquariumSynth.Dsl.dll", StringComparison.Ordinal));
|
||||
Assert.Contains(entries, entry => entry.StartsWith("lib/net10.0/AquaSynth.Dsl.dll", StringComparison.Ordinal));
|
||||
Assert.Contains("README.md", entries);
|
||||
Assert.DoesNotContain(entries, entry => entry.StartsWith("tests/", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.DoesNotContain(entries, entry => entry.StartsWith("Fixtures/", StringComparison.OrdinalIgnoreCase));
|
||||
|
|
@ -44,7 +44,7 @@ public sealed class PackageBoundaryTests
|
|||
private static string RepositoryRoot()
|
||||
{
|
||||
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquariumSynthCSharp.slnx")))
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquaSynth.slnx")))
|
||||
{
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using AquariumSynth.Dsl;
|
||||
using AquaSynth.Dsl;
|
||||
|
||||
namespace AquariumSynth.Dsl.Tests;
|
||||
namespace AquaSynth.Dsl.Tests;
|
||||
|
||||
public sealed class PatchScriptTests
|
||||
{
|
||||
|
|
@ -161,9 +161,9 @@ public sealed class PatchScriptTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void AquariumPresetsExportFaust()
|
||||
public void AquaSynthPresetsExportFaust()
|
||||
{
|
||||
foreach (var patch in new[] { Presets.AquariumPluck(), Presets.AquariumHeartbeat(), Presets.AquariumVoice(), Presets.Sfxr("pickup") })
|
||||
foreach (var patch in new[] { Presets.AquaSynthPluck(), Presets.AquaSynthHeartbeat(), Presets.AquaSynthVoice(), Presets.Sfxr("pickup") })
|
||||
{
|
||||
var export = FaustEmitter.Emit(patch);
|
||||
Assert.Contains("process =", export.Source);
|
||||
|
|
@ -832,7 +832,7 @@ public sealed class PatchScriptTests
|
|||
public async Task FaustCompilerCanEmitCSharpWhenInstalled()
|
||||
{
|
||||
var export = FaustEmitter.EmitScript("v w=sin f=440 g=.2 s=.1 d=.2");
|
||||
var output = Path.Combine(Path.GetTempPath(), $"aquarium-synth-{Guid.NewGuid():N}.cs");
|
||||
var output = Path.Combine(Path.GetTempPath(), $"aquasynth-{Guid.NewGuid():N}.cs");
|
||||
try
|
||||
{
|
||||
var validation = await FaustCompiler.CompileAsync(
|
||||
|
|
@ -916,7 +916,7 @@ public sealed class PatchScriptTests
|
|||
private static string RepositoryRoot()
|
||||
{
|
||||
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquariumSynthCSharp.slnx")))
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquaSynth.slnx")))
|
||||
{
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using AquariumSynth.Dsl;
|
||||
using AquaSynth.Dsl;
|
||||
|
||||
namespace AquariumSynth.Dsl.Tests;
|
||||
namespace AquaSynth.Dsl.Tests;
|
||||
|
||||
public sealed class SfxrPatchReferenceTests
|
||||
{
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using AquariumSynth.Dsl;
|
||||
using AquaSynth.Dsl;
|
||||
|
||||
namespace AquariumSynth.Dsl.Tests;
|
||||
namespace AquaSynth.Dsl.Tests;
|
||||
|
||||
public sealed class ZynInstrumentTests
|
||||
{
|
||||
|
|
@ -18,7 +18,7 @@ public sealed class ZynInstrumentTests
|
|||
ZynInstrumentReader.SourceForBytes("fixture://zyn/project/additive-lead.xiz", "project-authored", bytes));
|
||||
|
||||
Assert.Equal("AQ Additive Lead", instrument.Name);
|
||||
Assert.Equal("AquariumSynthCSharp tests", instrument.Author);
|
||||
Assert.Equal("AquaSynth tests", instrument.Author);
|
||||
Assert.Contains(reference.Features, feature => feature.Name == "engine_add" && feature.Value == "1");
|
||||
Assert.Contains(reference.Features, feature => feature.Name == "engine_sub" && feature.Value == "0");
|
||||
Assert.Contains(reference.Features, feature => feature.Name == "engine_pad" && feature.Value == "0");
|
||||
|
|
@ -148,11 +148,11 @@ public sealed class ZynInstrumentTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void RebuildsProjectAuthoredPadAsAquariumSpectrumScript()
|
||||
public void RebuildsProjectAuthoredPadAsAquaSynthSpectrumScript()
|
||||
{
|
||||
var path = FixturePath("ZynAddSubFX", "ProjectAuthored", "pad-harmonic.xiz");
|
||||
|
||||
var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquariumScript(path, tableRootFrequencyHz: 77.7813f);
|
||||
var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(path, tableRootFrequencyHz: 77.7813f);
|
||||
var patch = PatchScript.Parse(rebuild.Script);
|
||||
|
||||
Assert.Equal("AQ Pad Harmonic", rebuild.InstrumentName);
|
||||
|
|
@ -181,7 +181,7 @@ public sealed class ZynInstrumentTests
|
|||
return;
|
||||
}
|
||||
|
||||
var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquariumScript(path, tableRootFrequencyHz: 109.999f);
|
||||
var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(path, tableRootFrequencyHz: 109.999f);
|
||||
var patch = PatchScript.Parse(rebuild.Script);
|
||||
|
||||
var bank = Assert.Single(patch.SpectralBanks);
|
||||
|
|
@ -200,7 +200,7 @@ public sealed class ZynInstrumentTests
|
|||
return;
|
||||
}
|
||||
|
||||
var rebuild = ZynInstrumentReader.RebuildEnabledPadsAsAquariumScript(
|
||||
var rebuild = ZynInstrumentReader.RebuildEnabledPadsAsAquaSynthScript(
|
||||
path,
|
||||
new Dictionary<int, ZynPadTableRoot>
|
||||
{
|
||||
|
|
@ -275,7 +275,7 @@ public sealed class ZynInstrumentTests
|
|||
private static string RepositoryRoot()
|
||||
{
|
||||
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquariumSynthCSharp.slnx")))
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquaSynth.slnx")))
|
||||
{
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace AquariumSynth.Dsl.Tests;
|
||||
namespace AquaSynth.Dsl.Tests;
|
||||
|
||||
public sealed class ZynReferenceParityTests
|
||||
{
|
||||
|
|
@ -12,8 +12,8 @@ public sealed class ZynReferenceParityTests
|
|||
|
||||
Assert.True(Directory.Exists(zynRoot), "ZynAddSubFX reference source submodule is missing. Run `git submodule update --init --recursive`.");
|
||||
Assert.True(File.Exists(Path.Combine(zynRoot, "COPYING")), "ZynAddSubFX reference source should keep its GPL license file.");
|
||||
Assert.True(File.Exists(Path.Combine(zynRoot, "src", "Params", "PADnoteParameters.cpp")), "PAD parameter implementation is the parity source, not Aquarium runtime code.");
|
||||
Assert.True(File.Exists(Path.Combine(zynRoot, "src", "Synth", "PADnote.cpp")), "PAD note implementation is the parity source, not Aquarium runtime code.");
|
||||
Assert.True(File.Exists(Path.Combine(zynRoot, "src", "Params", "PADnoteParameters.cpp")), "PAD parameter implementation is the parity source, not AquaSynth runtime code.");
|
||||
Assert.True(File.Exists(Path.Combine(zynRoot, "src", "Synth", "PADnote.cpp")), "PAD note implementation is the parity source, not AquaSynth runtime code.");
|
||||
Assert.Contains("GNU GENERAL PUBLIC LICENSE", await File.ReadAllTextAsync(Path.Combine(zynRoot, "COPYING")));
|
||||
|
||||
var revision = await RunAsync("git", ["-C", zynRoot, "rev-parse", "HEAD"]);
|
||||
|
|
@ -35,12 +35,12 @@ public sealed class ZynReferenceParityTests
|
|||
var artifactDir = Path.Combine(root, "artifacts", "parity", "zyn-pad-reference", RunFolderName("pad-texture"));
|
||||
Directory.CreateDirectory(artifactDir);
|
||||
|
||||
var input = Path.Combine(root, "tests", "AquariumSynth.Dsl.Tests", "Fixtures", "ZynAddSubFX", "ProjectAuthored", "pad-texture.xiz");
|
||||
var input = Path.Combine(root, "tests", "AquaSynth.Dsl.Tests", "Fixtures", "ZynAddSubFX", "ProjectAuthored", "pad-texture.xiz");
|
||||
var zynRaw = Path.Combine(artifactDir, "reference-zyn.f32");
|
||||
var zynWav = Path.Combine(artifactDir, "reference-zyn.wav");
|
||||
var zynTableRaw = Path.Combine(artifactDir, "reference-zyn-table0.f32");
|
||||
var zynTableWav = Path.Combine(artifactDir, "reference-zyn-table0.wav");
|
||||
var aquaWav = Path.Combine(artifactDir, "candidate-aquarium.wav");
|
||||
var aquaWav = Path.Combine(artifactDir, "candidate-aquasynth.wav");
|
||||
var reportPath = Path.Combine(artifactDir, "report.txt");
|
||||
|
||||
var command = string.Join(' ', [
|
||||
|
|
@ -93,7 +93,7 @@ public sealed class ZynReferenceParityTests
|
|||
$"zyn_table_rms: {Rms(zynTableSamples):0.######}"
|
||||
};
|
||||
|
||||
var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquariumScript(input, ParseBaseFrequency(tableReference.Stdout));
|
||||
var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(input, ParseBaseFrequency(tableReference.Stdout));
|
||||
report.AddRange(rebuild.MatchedFeatures.Select(feature => $"matched_{feature.Name}: {feature.Value}"));
|
||||
report.AddRange(rebuild.MissingFeatures.Select(feature => $"missing_{feature.Name}: {feature.Value} - {feature.Notes}"));
|
||||
var aquaExport = FaustEmitter.EmitScript(rebuild.Script, new FaustExportOptions("zyn_pad_texture"));
|
||||
|
|
@ -129,7 +129,7 @@ public sealed class ZynReferenceParityTests
|
|||
return;
|
||||
}
|
||||
|
||||
var fixtureDir = Path.Combine(root, "tests", "AquariumSynth.Dsl.Tests", "Fixtures", "ZynAddSubFX", "ProjectAuthored");
|
||||
var fixtureDir = Path.Combine(root, "tests", "AquaSynth.Dsl.Tests", "Fixtures", "ZynAddSubFX", "ProjectAuthored");
|
||||
var artifactDir = Path.Combine(root, "artifacts", "parity", "zyn-pad-fixtures");
|
||||
Directory.CreateDirectory(artifactDir);
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ public sealed class ZynReferenceParityTests
|
|||
Assert.Equal(0, note.ExitCode);
|
||||
var table = await RunAsync(bash, ["-lc", ZynPadCommand(root, input, tableRaw, 0, "0")]);
|
||||
Assert.Equal(0, table.ExitCode);
|
||||
var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquariumScript(input, ParseBaseFrequency(table.Stdout));
|
||||
var rebuild = ZynInstrumentReader.RebuildFirstPadAsAquaSynthScript(input, ParseBaseFrequency(table.Stdout));
|
||||
await File.WriteAllTextAsync(Path.Combine(runDir, "candidate.aqua"), rebuild.Script);
|
||||
|
||||
var noteSamples = await ReadFloat32Async(noteRaw);
|
||||
|
|
@ -254,7 +254,7 @@ public sealed class ZynReferenceParityTests
|
|||
var noteWav = Path.Combine(runDir, "reference-zyn.wav");
|
||||
var tableRaw = Path.Combine(runDir, "reference-zyn-table0.f32");
|
||||
var tableWav = Path.Combine(runDir, "reference-zyn-table0.wav");
|
||||
var aquaWav = Path.Combine(runDir, "candidate-aquarium.wav");
|
||||
var aquaWav = Path.Combine(runDir, "candidate-aquasynth.wav");
|
||||
|
||||
var noteStdouts = new List<string>();
|
||||
var noteLayers = new List<float[]>();
|
||||
|
|
@ -290,7 +290,7 @@ public sealed class ZynReferenceParityTests
|
|||
}
|
||||
|
||||
var noteSamples = SumSamples(noteLayers);
|
||||
var rebuild = ZynInstrumentReader.RebuildEnabledPadsAsAquariumScript(input, tableRoots);
|
||||
var rebuild = ZynInstrumentReader.RebuildEnabledPadsAsAquaSynthScript(input, tableRoots);
|
||||
await File.WriteAllTextAsync(Path.Combine(runDir, "candidate.aqua"), rebuild.Script);
|
||||
|
||||
Assert.True(noteSamples.Length > 0);
|
||||
|
|
@ -361,7 +361,7 @@ public sealed class ZynReferenceParityTests
|
|||
private static string RepositoryRoot()
|
||||
{
|
||||
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquariumSynthCSharp.slnx")))
|
||||
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AquaSynth.slnx")))
|
||||
{
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
Test-only AquariumSynthCSharp ZynAddSubFX PAD oracle.
|
||||
Test-only AquaSynth ZynAddSubFX PAD oracle.
|
||||
|
||||
This file links against the pinned ZynAddSubFX reference source in an ignored
|
||||
artifact build. It is development/parity tooling, not Aquarium runtime code.
|
||||
artifact build. It is development/parity tooling, not AquaSynth runtime code.
|
||||
*/
|
||||
|
||||
#include "../globals.h"
|
||||
|
|
|
|||
Loading…
Reference in a new issue