Calibrate DX7 stacked modulation brightness

This commit is contained in:
Meta Vens 2026-05-14 14:06:26 +01:00
commit abef14dbb6
9 changed files with 50 additions and 26 deletions

View file

@ -88,17 +88,20 @@ math is still fake in the places that matter perceptually.
- Replace hard `PRC SYNTH1` route probe logic with a topology-aware DX7
route rule: isolated direct branches keep the two-op scale, while
summed/cascaded branches use the summed-modulator scale.
- A project-authored algorithm-8 summed-stack parity test now backs the
topology-aware summed-modulator scale.
- The summed/cascaded scale is now `2.4`. A project-authored algorithm-8
summed-stack parity test backs the topology-aware scale outside PRC, and
the hard PRC replay improves to log-mel `0.16794802`, envelope distance
`0.09510617`, centroid ratio `1.1254044`, and score `0.68491656` after
graph gain normalization.
8. **Hard target replay**
- Re-run `PRC SYNTH1`.
- Keep the log-mel gate and listening artifacts.
- Raise thresholds only when the calibrated lowering improves for the right
reason.
- Current curved-envelope replay gates log-mel at `<= 0.18`, envelope
distance at `<= 0.14`, zero-crossing at `>= 0.75`, RMS ratio near unity,
and score at `>= 0.64`.
- Current curved-envelope plus stronger-stack replay gates log-mel at
`<= 0.18`, envelope distance at `<= 0.14`, zero-crossing at `>= 0.75`,
RMS ratio near unity, and score at `>= 0.64`.
## Rejected Path

View file

@ -81,9 +81,9 @@ First deliverable:
operator routing rather than a sine-like behavioral match. Staged operator
envelopes now exist as readable `env=rl rates=... levels=...` declarations
with per-segment curves. Direct DX7 rate/level lowering on `PRC SYNTH1`
forced EG timing/gain calibration; the current applied-envelope lowering
improves log-mel and envelope distance but exposes worse zero-crossing/phase
behavior. The hard PRC probe writes ignored listening artifacts under
forced EG timing/gain calibration; the current applied-envelope lowering and
stronger summed/cascaded route scale give PRC the same character with much
closer stacked-modulation brightness. The hard PRC probe writes ignored listening artifacts under
`artifacts/parity/dx7-prc-synth1` so metrics and ears can steer the next
calibration pass together. Listening showed aggregate score was a weak judge
for this target, so the hard PRC probe gates primarily on log-mel distance.

View file

@ -172,7 +172,7 @@ public static class Dx7SysEx
public const int PackedBankVoiceCount = 32;
public const int PackedBankDataLength = PackedVoiceLength * PackedBankVoiceCount;
public const float OperatorModulationRouteIndex = 6.275f;
public const float SummedOperatorModulationRouteIndex = 1.6f;
public const float SummedOperatorModulationRouteIndex = 2.4f;
public static Dx7Voice ParseVoice(ReadOnlySpan<byte> bytes)
{

View file

@ -41,3 +41,4 @@
{"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_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"}

View file

@ -25,6 +25,7 @@
"DX7 effective operator-level approximation",
"DX7 measured carrier output amplitude curve",
"DX7 isolated modulation-index route scale",
"DX7 summed/cascaded modulation route scale",
"DX7 calibrated feedback amount table",
"DX7 ratio detune lowering",
"DX7 ROM COM output compensation",
@ -72,9 +73,9 @@
"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, calibrated feedback amount table, ratio detune lowering, ROM COM output compensation, topology-aware route lowering, staged operator envelopes with per-segment curves, raw and block-interpolated DX7 envelope tracing, applied-envelope curved lowering, two Aquarium DSL rebuild attempts, first-class OperatorGraph support, 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.225, project-authored algorithm-8 summed-stack parity, 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, and feedback 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, while summed/cascaded algorithm-8 branches need a lower topology-aware route scale. Feedback now lowers through a fitted table instead of PRC-local constants. Ratio-mode detune belongs in operator frequency lowering. ROM COM values carry output-count compensation; because the amplitude curve was fitted against algorithm 32, DX7 carriers scale by 6/(COM+1). 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. 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. PRC log-mel is down to 0.17186502 with RMS at unity, but centroid/timbre mismatch remains.",
"next": "Use project-authored envelope and oscillator/phase sweeps to separate remaining centroid/timbre mismatch before broad DX7 import."
"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, ROM COM output compensation, topology-aware route lowering, staged operator envelopes with per-segment curves, raw and block-interpolated DX7 envelope tracing, applied-envelope curved lowering, two Aquarium DSL rebuild attempts, first-class OperatorGraph support, 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.18, project-authored algorithm-8 summed-stack parity, 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, and feedback 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 2.4 after PRC listening and a project-authored stack probe showed 1.6 was under-bright. Feedback lowers through a fitted table instead of PRC-local constants. Ratio-mode detune belongs in operator frequency lowering. ROM COM values carry output-count compensation; because the amplitude curve was fitted against algorithm 32, DX7 carriers scale by 6/(COM+1). 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. 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. PRC log-mel is down to 0.16794802 with RMS at unity; remaining mismatch is residual timbre/centroid, not broad envelope shape.",
"next": "Use broader project-authored DX7 sweeps to validate summed/cascaded route scale 2.4 and isolate remaining timbre/centroid mismatch before broad DX7 import."
},
"note_and_envelope_model": {
"rule": "Notes own frequency, gate duration, and host/MIDI source. Envelopes own ADSR level shape.",
@ -89,7 +90,7 @@
},
"last_verified": {
"command": "AQUARIUM_DX7_PYTHON=<bundled python> dotnet test AquariumSynthCSharp.slnx --no-restore",
"result": "66 passed; PRC log-mel 0.17186502, envelope distance 0.13057204, zero-crossing 0.7815517, score 0.6501268 after applied-envelope peak-picker fix",
"commit": "pending DX7 applied-envelope peak fix"
"result": "66 passed; PRC log-mel 0.16794802, envelope distance 0.09510617, centroid ratio 1.1254044, score 0.68491656 after summed route scale 2.4",
"commit": "pending DX7 summed route scale"
}
}

View file

@ -15,6 +15,15 @@ Doctrine update:
Completed this slice:
- Increased `Dx7SysEx.SummedOperatorModulationRouteIndex` from `1.6` to `2.4`.
This targets the missing harsh stacked-modulation brightness without adding a
generic drive/overdrive knob. The independent project-authored algorithm-8
summed-stack probe now uses graph gain `.218` and gates log-mel at `<= .12`
with RMS normalization.
- Latest hard `PRC SYNTH1` after stronger stack scale and graph gain `.309`:
log-mel `0.16794802`, envelope distance `0.09510617`, RMS ratio `1.00095`,
zero-crossing ratio `0.79647374`, centroid ratio `1.1254044`, score
`0.68491656`.
- Added `Dx7SysEx.ApproximateAppliedRateLevelEnvelope`, which traces the
Dexed-style block-interpolated applied EG gain and lowers it into Aquarium's
curved staged envelope surface, normalized so operator output level remains a

View file

@ -49,8 +49,8 @@ live_invariants:
- DX7 feedback lowers through `Dx7SysEx.OperatorFeedbackAmount`; 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 algorithm output compensation lowers through ROM `COM` values relative to the algorithm-32 six-output baseline; do not restore PRC-local carrier scale tables.
- DX7 route lowering is topology-aware: isolated direct branches use `OperatorModulationRouteIndex`; summed edges and direct edges feeding summed modulation use `SummedOperatorModulationRouteIndex`.
- `SummedOperatorModulationRouteIndex` is calibrated from the hard PRC target. It is no longer PRC-local, but project-authored algorithm-8 stack sweeps should tighten it before broad DX7 import.
- DX7 route lowering is topology-aware: isolated direct branches use `OperatorModulationRouteIndex` (`6.275`); summed edges and direct edges feeding summed modulation use `SummedOperatorModulationRouteIndex` (`2.4`).
- `SummedOperatorModulationRouteIndex` is backed by the hard PRC target and a project-authored algorithm-8 stack probe; do not restore the older under-bright `1.6` scale.
- DX7 calibration must proceed through isolated rungs in `docs/dx7-calibration-plan.md`; do not keep tuning hard PRC-specific constants as a substitute for a level/index model.
- Staged operator envelopes own multi-target operator level contours through `env=rl rates=... levels=...`; do not force DX7-style contours back into the general ADSR voice envelope model.
- Staged operator envelopes may use per-segment curves through `curves=lin,exp,...`; this belongs to the rate/level contour authority, not to the standard ADSR envelope.
@ -116,10 +116,10 @@ next_agent_start_here:
two-op modulation index, feedback, ratio detune, ROM COM output
compensation, and topology-aware route lowering are now fitted or mapped;
a project-authored algorithm-8 stack test now backs the summed route scale
outside PRC. Curved applied-envelope lowering now improves the hard PRC
log-mel and envelope metrics, but zero-crossing/phase behavior is worse.
Next pressure is oscillator/phase behavior or a project-authored envelope
sweep that can separate contour wins from remaining centroid/timbre damage.
outside PRC. Curved applied-envelope lowering plus stronger summed/cascaded
route scale now gives PRC the same character with closer harsh stacked
modulation. Next pressure is residual centroid/timbre mismatch and broader
project-authored DX7 sweeps before broad import.
must_read:
- AGENTS.md
- docs/audio-doctrine.md
@ -132,6 +132,15 @@ next_agent_start_here:
- "dotnet test AquariumSynthCSharp.slnx --no-restore"
completed_slices:
- date: 2026-05-14
summary: >
Increased `Dx7SysEx.SummedOperatorModulationRouteIndex` from 1.6 to 2.4
after listening identified missing harsh stacked-modulation brightness.
The stronger scale improves PRC log-mel to 0.16794802, envelope distance
to 0.09510617, centroid ratio to 1.1254044, and score to 0.68491656 with
RMS ratio 1.00095. 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"
- date: 2026-05-14
summary: >
Added `Dx7SysEx.ApproximateAppliedRateLevelEnvelope` and used it in the

View file

@ -101,7 +101,7 @@ public sealed class Dx7ReferenceParityTests
var script = Dx7VoiceProbeScript(
voice,
graphName: "dx7_prc_synth1_probe",
graphGain: 0.283f,
graphGain: 0.309f,
envelopeScale: 0.62f,
gateSeconds: null,
useAppliedEnvelope: true);
@ -165,7 +165,7 @@ public sealed class Dx7ReferenceParityTests
var script = Dx7VoiceProbeScript(
VoiceFromSpec(spec),
graphName: "dx7_algorithm8_summed_stack_probe",
graphGain: 0.39f,
graphGain: 0.218f,
envelopeScale: 0.62f,
gateSeconds: 0.45f);
var candidateSource = FaustEmitter.EmitScript(script);
@ -181,8 +181,9 @@ public sealed class Dx7ReferenceParityTests
var comparison = new AudioAnalyzer(new AudioAnalysisConfig(SampleRate: reference.SampleRate))
.Compare(reference.Samples, candidate.Samples);
Assert.True(comparison.LogMelDistance <= 0.31f, ParityReport(comparison));
Assert.True(comparison.Score >= 0.35f, ParityReport(comparison));
Assert.True(comparison.LogMelDistance <= 0.12f, ParityReport(comparison));
Assert.InRange(comparison.RmsRatio, 0.90f, 1.10f);
Assert.True(comparison.Score >= 0.45f, ParityReport(comparison));
}
[Fact]

View file

@ -246,8 +246,8 @@ public sealed class Dx7SysExTests
edge.TargetOperator == 5);
Assert.Equal(Dx7SysEx.OperatorModulationRouteIndex, Dx7SysEx.OperatorRouteIndex(topology, direct));
Assert.Equal(1.6f, Dx7SysEx.OperatorRouteIndex(topology, summed));
Assert.Equal(1.6f, Dx7SysEx.OperatorRouteIndex(topology, cascaded));
Assert.Equal(2.4f, Dx7SysEx.OperatorRouteIndex(topology, summed));
Assert.Equal(2.4f, Dx7SysEx.OperatorRouteIndex(topology, cascaded));
}
[Fact]