Add DX7 reference rebuild catalog
This commit is contained in:
parent
fec6c60096
commit
c746e913e0
7 changed files with 252 additions and 16 deletions
|
|
@ -602,6 +602,111 @@ public static class BuiltInScripts
|
|||
|
||||
public static readonly IReadOnlyList<string> AdvancedNames = ["aurora-pad", "machine-breath", "glass-creature", "ritual-sequence"];
|
||||
|
||||
public static readonly IReadOnlyList<string> Dx7StyleNames = ["algo32-additive-organ", "algo8-bright-pair"];
|
||||
|
||||
public const string Dx7StyleAlgorithm32AdditiveOrgan = """
|
||||
patch
|
||||
gain=0.58
|
||||
soft_clip=true
|
||||
|
||||
param
|
||||
name=drawbar
|
||||
path=/macro/drawbar
|
||||
default=0.78
|
||||
min=0
|
||||
max=1
|
||||
step=0.001
|
||||
unit=normalized
|
||||
|
||||
param
|
||||
name=shimmer
|
||||
path=/macro/shimmer
|
||||
default=0.08
|
||||
min=0
|
||||
max=0.3
|
||||
step=0.001
|
||||
unit=normalized
|
||||
|
||||
defaults
|
||||
wave=sine
|
||||
attack=0.002
|
||||
sustain=0.48
|
||||
decay=0.32
|
||||
lpf=0.96
|
||||
hpf=0.015
|
||||
drive=0.03
|
||||
|
||||
voice freq=196 gain=0.14
|
||||
voice freq=392 gain=@/macro/drawbar
|
||||
voice freq=588 gain=0.12
|
||||
voice freq=784 gain=0.08
|
||||
voice freq=980 gain=0.055
|
||||
voice
|
||||
freq=1176
|
||||
gain=0.035
|
||||
fold=@/macro/shimmer
|
||||
fm=1
|
||||
fm_index=0.18
|
||||
fm_decay=0.24
|
||||
""";
|
||||
|
||||
public const string Dx7StyleAlgorithm8BrightPair = """
|
||||
patch
|
||||
gain=0.52
|
||||
soft_clip=true
|
||||
|
||||
param
|
||||
name=brightness
|
||||
path=/macro/brightness
|
||||
default=2.6
|
||||
min=0
|
||||
max=5
|
||||
step=0.001
|
||||
unit=index
|
||||
|
||||
param
|
||||
name=strike
|
||||
path=/macro/strike
|
||||
default=0.18
|
||||
min=0.02
|
||||
max=0.6
|
||||
step=0.001
|
||||
unit=seconds
|
||||
|
||||
defaults
|
||||
wave=sine
|
||||
attack=0.001
|
||||
sustain=0.045
|
||||
decay=@/macro/strike
|
||||
hpf=0.02
|
||||
lpf=0.9
|
||||
|
||||
voice
|
||||
freq=330
|
||||
gain=0.16
|
||||
fm=2
|
||||
fm_index=@/macro/brightness
|
||||
fm_decay=0.22
|
||||
|
||||
voice
|
||||
freq=660
|
||||
gain=0.1
|
||||
fm=3
|
||||
fm_index=1.4
|
||||
fm_decay=0.16
|
||||
drive=0.08
|
||||
fold=0.05
|
||||
|
||||
voice
|
||||
freq=990
|
||||
gain=0.045
|
||||
sustain=0.025
|
||||
decay=0.34
|
||||
fm=1
|
||||
fm_index=0.55
|
||||
fm_decay=0.12
|
||||
""";
|
||||
|
||||
public static readonly IReadOnlyList<(string Name, string Script)> AdvancedReferenceScripts =
|
||||
[
|
||||
("aurora-pad", """
|
||||
|
|
@ -791,6 +896,7 @@ public static class BuiltInScripts
|
|||
foreach (var item in Classic808PrimitiveGolfScripts) yield return ("808", item.Name, item.Script);
|
||||
foreach (var item in FmBellPrimitiveGolfScripts) yield return ("fm-bell", item.Name, item.Script);
|
||||
foreach (var item in WobbleBassPrimitiveGolfScripts) yield return ("wobble-bass", item.Name, item.Script);
|
||||
foreach (var item in ReferenceRebuildCatalog.Dx7Rebuilds) yield return ("dx7", item.Name, item.Script);
|
||||
foreach (var item in AdvancedReferenceScripts) yield return ("advanced", item.Name, item.Script);
|
||||
}
|
||||
|
||||
|
|
|
|||
59
src/AquariumSynth.Dsl/ReferenceRebuilds.cs
Normal file
59
src/AquariumSynth.Dsl/ReferenceRebuilds.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
namespace AquariumSynth.Dsl;
|
||||
|
||||
public sealed record ReferenceRebuild(
|
||||
string Id,
|
||||
string Family,
|
||||
string Name,
|
||||
string ReferenceId,
|
||||
string Script,
|
||||
IReadOnlyList<ReferenceFeature> MatchedFeatures,
|
||||
IReadOnlyList<ReferenceFeature> MissingFeatures,
|
||||
string Notes);
|
||||
|
||||
public static class ReferenceRebuildCatalog
|
||||
{
|
||||
public static readonly IReadOnlyList<ReferenceRebuild> Dx7Rebuilds =
|
||||
[
|
||||
new(
|
||||
"dx7/algo32-additive-organ/aquarium",
|
||||
"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("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_envelopes", "per-operator four-stage DX7 EG", "Aquarium currently has attack/sustain/decay/punch, not DX7 rate/level envelopes."),
|
||||
new("output_compensation", "algorithm ROM COM", "Aquarium 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",
|
||||
"Algorithm 8 bright pair",
|
||||
"dx7/algo8-bright-pair",
|
||||
BuiltInScripts.Dx7StyleAlgorithm8BrightPair,
|
||||
[
|
||||
new("carrier_operators", "1,3", "Approximated as two audible Aquarium voices."),
|
||||
new("feedback_sources", "4", "Approximated with drive/fold and FM index decay on the brighter voice."),
|
||||
new("runtime_macros", "brightness,strike", "Field-site parameters expose useful sound controls without recompilation.")
|
||||
],
|
||||
[
|
||||
new("modulation_edges", "6->5,4+5->3,2->1", "The current voice DSL cannot express separate six-operator routing."),
|
||||
new("self_feedback_operators", "4", "There is no operator-local feedback edge; fold/drive is only a timbral approximation."),
|
||||
new("operator_envelopes", "independent DX7 rate/level envelopes", "Aquarium has simpler per-voice envelopes, not per-operator EGs.")
|
||||
],
|
||||
"This patch is deliberately a pressure test. It sounds in the family, but the missing edges are real and should become evidence for an operator graph layer if more DX7 targets need the same shape.")
|
||||
];
|
||||
|
||||
public static IEnumerable<ReferenceRebuild> All()
|
||||
{
|
||||
foreach (var rebuild in Dx7Rebuilds)
|
||||
{
|
||||
yield return rebuild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,3 +12,4 @@
|
|||
{"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":"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"}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"patch graph model",
|
||||
"patch parameter contracts",
|
||||
"reference patch contracts",
|
||||
"reference rebuild catalog",
|
||||
"DX7 SysEx structural parsing",
|
||||
"DX7 algorithm topology metadata",
|
||||
"patch script parser",
|
||||
|
|
@ -46,8 +47,9 @@
|
|||
"rule": "Add DSL abstractions only when reference rebuilds prove the missing invariant."
|
||||
},
|
||||
"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, and algorithm topology from the reverse-engineered OPS algorithm ROM table.",
|
||||
"next": "Rebuild tiny DX7-style references in Aquarium DSL and use topology mismatches to decide whether an operator graph layer is needed."
|
||||
"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, and two Aquarium DSL rebuild attempts.",
|
||||
"lesson": "Algorithm 32's additive six-carrier shape maps cleanly to six Aquarium voices. Algorithm 8 only approximates because Aquarium lacks explicit operator modulation edges, summed modulators, and operator-local self-feedback.",
|
||||
"next": "Decide whether the repeated DX7 topology mismatch justifies a first-class operator graph model; map ownership before implementing it."
|
||||
},
|
||||
"runtime_parameters": {
|
||||
"rule": "Patch parameters are runtime controls, not compile-time constants.",
|
||||
|
|
@ -57,7 +59,7 @@
|
|||
},
|
||||
"last_verified": {
|
||||
"command": "dotnet test AquariumSynthCSharp.slnx --no-restore",
|
||||
"result": "31 passed",
|
||||
"commit": "pending DX7 algorithm topology commit"
|
||||
"result": "34 passed",
|
||||
"commit": "pending DX7 rebuild catalog commit"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,20 @@ the synth library while Aquarium work continues elsewhere.
|
|||
|
||||
Completed this slice:
|
||||
|
||||
- Added `ReferenceRebuild` and `ReferenceRebuildCatalog` for explicit
|
||||
reference-target rebuild attempts.
|
||||
- Added two DX7-style Aquarium DSL rebuilds:
|
||||
- `dx7/algo32-additive-organ`: algorithm 32's six-carrier additive shape,
|
||||
which maps cleanly to six Aquarium 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.
|
||||
|
||||
Previous slice:
|
||||
|
||||
- Added DX7 algorithm topology metadata for algorithms 1-32 using Ken
|
||||
Shirriff's reverse-engineered OPS algorithm ROM table.
|
||||
- `Dx7SysEx.AlgorithmTopology` now exposes carrier operators, modulation
|
||||
|
|
@ -18,7 +32,7 @@ Completed this slice:
|
|||
- Representative tests cover algorithm 8, algorithm 16, and algorithm 32.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 31 passed.
|
||||
|
||||
Previous slice:
|
||||
Earlier slice:
|
||||
|
||||
- Added `Dx7SysEx` records and parsing for DX7 voice edit buffers, packed
|
||||
128-byte voices, and packed 32-voice SysEx banks.
|
||||
|
|
@ -29,7 +43,7 @@ Previous slice:
|
|||
- Checksum validation rejects bad wrapped SysEx payloads.
|
||||
- Verified with `dotnet test AquariumSynthCSharp.slnx --no-restore`: 28 passed.
|
||||
|
||||
Earlier slice:
|
||||
Parameter slice:
|
||||
|
||||
- Added explicit `PatchParameter` contracts: stable path, label, default, min,
|
||||
max, step, unit, automation-rate notes, and notes.
|
||||
|
|
@ -48,8 +62,7 @@ Earlier slice:
|
|||
|
||||
Next likely slice:
|
||||
|
||||
- Rebuild one or two small DX7-style sounds in Aquarium DSL.
|
||||
- Compare those rebuilds against DX7 topology features and document the missing
|
||||
graph concepts before adding any new DSL shape.
|
||||
- Decide whether the repeated DX7 algorithm-8 mismatch justifies a first-class
|
||||
operator graph model. Map ownership before implementing it.
|
||||
- Keep tests focused on structure first, then add rendered audio comparison once
|
||||
the render path is explicit.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
project: AquariumSynthCSharp
|
||||
spine_version: 1
|
||||
updated: 2026-05-13T00:49:07+01:00
|
||||
updated: 2026-05-13T00:54:02+01:00
|
||||
|
||||
prime_directive: >
|
||||
Build coherent synth machinery. References exist to reveal missing structure,
|
||||
|
|
@ -18,6 +18,7 @@ current_mechanism:
|
|||
analysis: src/AquariumSynth.Dsl/AudioAnalysis.cs
|
||||
built_ins: src/AquariumSynth.Dsl/BuiltInScripts.cs
|
||||
dx7_references: src/AquariumSynth.Dsl/Dx7SysEx.cs
|
||||
reference_rebuilds: src/AquariumSynth.Dsl/ReferenceRebuilds.cs
|
||||
tests: tests/AquariumSynth.Dsl.Tests/PatchScriptTests.cs
|
||||
doctrine: docs/audio-doctrine.md
|
||||
roadmap: docs/reference-synth-roadmap.md
|
||||
|
|
@ -41,10 +42,10 @@ reference_targets:
|
|||
priority: 1
|
||||
purpose: "Structured FM/operator graph pressure test."
|
||||
source: "https://github.com/asb2m10/dexed"
|
||||
status: "DX7 SysEx parser and algorithm topology extraction exist; tiny Aquarium DSL rebuilds are next."
|
||||
status: "DX7 SysEx parser, algorithm topology extraction, and two Aquarium DSL rebuild attempts exist; operator-graph decision is next."
|
||||
first_slice:
|
||||
- "Rebuild two small DX7-style references in Aquarium DSL."
|
||||
- "Compare rebuilds against DX7 topology features and document missing graph concepts."
|
||||
- "Decide whether DX7 algorithm-8-style mismatches justify a first-class operator graph model."
|
||||
- "If yes, map ownership before implementing it."
|
||||
zynaddsubfx:
|
||||
priority: 2
|
||||
purpose: "Additive, subtractive, PAD, formant, kit, and layered-instrument pressure test."
|
||||
|
|
@ -78,9 +79,9 @@ reference_targets:
|
|||
|
||||
next_agent_start_here:
|
||||
recommended_first_task: >
|
||||
Rebuild one or two tiny DX7-style references in Aquarium DSL, using the
|
||||
parsed DX7 topology features as pressure evidence. Do not import a giant
|
||||
bank.
|
||||
Decide whether the DX7 algorithm-8 rebuild mismatch justifies a first-class
|
||||
operator graph model. Map ownership first; do not smuggle it into Voice
|
||||
fields.
|
||||
must_read:
|
||||
- AGENTS.md
|
||||
- docs/audio-doctrine.md
|
||||
|
|
@ -92,6 +93,13 @@ next_agent_start_here:
|
|||
- "dotnet test AquariumSynthCSharp.slnx --no-restore"
|
||||
|
||||
completed_slices:
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added ReferenceRebuild catalog entries and two DX7-style Aquarium 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"
|
||||
- date: 2026-05-13
|
||||
summary: >
|
||||
Added DX7 algorithm topology metadata for algorithms 1-32 from the
|
||||
|
|
|
|||
|
|
@ -209,6 +209,53 @@ public sealed class PatchScriptTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dx7StyleReferenceRebuildsParseExportAndDeclarePressure()
|
||||
{
|
||||
foreach (var rebuild in ReferenceRebuildCatalog.Dx7Rebuilds)
|
||||
{
|
||||
var patch = PatchScript.Parse(rebuild.Script);
|
||||
var export = FaustEmitter.Emit(patch, new FaustExportOptions(rebuild.Id.Replace('/', '_').Replace('-', '_')));
|
||||
|
||||
Assert.Contains("process =", export.Source);
|
||||
Assert.NotEmpty(rebuild.MatchedFeatures);
|
||||
Assert.NotEmpty(rebuild.MissingFeatures);
|
||||
Assert.All(rebuild.MissingFeatures, feature => Assert.False(string.IsNullOrWhiteSpace(feature.Notes)));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dx7Algorithm32RebuildMatchesAdditiveCarrierShape()
|
||||
{
|
||||
var rebuild = ReferenceRebuildCatalog.Dx7Rebuilds.Single(item => item.ReferenceId == "dx7/algo32-additive-organ");
|
||||
var patch = PatchScript.Parse(rebuild.Script);
|
||||
var topology = Dx7SysEx.AlgorithmTopology(32);
|
||||
|
||||
Assert.Equal(topology.CarrierOperators.Count, patch.Voices.Count);
|
||||
Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "carrier_operators" && feature.Value == "1,2,3,4,5,6");
|
||||
Assert.Contains(rebuild.MatchedFeatures, feature => feature.Name == "modulation_edge_count" && feature.Value == "0");
|
||||
Assert.Equal(2, patch.Parameters.Count);
|
||||
Assert.Equal(2, patch.ParameterBindings.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dx7Algorithm8RebuildRecordsMissingOperatorGraph()
|
||||
{
|
||||
var rebuild = ReferenceRebuildCatalog.Dx7Rebuilds.Single(item => item.ReferenceId == "dx7/algo8-bright-pair");
|
||||
var patch = PatchScript.Parse(rebuild.Script);
|
||||
var topology = Dx7SysEx.AlgorithmTopology(8);
|
||||
|
||||
Assert.Equal(2, topology.CarrierOperators.Count);
|
||||
Assert.True(patch.Voices.Count > topology.CarrierOperators.Count, "Approximation adds a shimmer layer beyond the two DX7 carriers.");
|
||||
Assert.Contains(rebuild.MissingFeatures, feature => feature.Name == "modulation_edges");
|
||||
Assert.Contains(rebuild.MissingFeatures, feature => feature.Name == "self_feedback_operators");
|
||||
Assert.Equal(2, patch.Parameters.Count);
|
||||
Assert.Equal(3, patch.ParameterBindings.Count);
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/voices/0/fm/index");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/voices/0/env/decay");
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/voices/1/env/decay");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FaustEmitterProducesWobbleSource()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue