119 KiB
Scratch
Current slice:
-
User identified the three-pass corpus run's audible failure correctly: mode collapse into a short opening phrase followed by low-motion texture/noise.
song-scorenow owns song continuity metrics:candidate_active_coverage,candidate_motion_coverage,candidate_first_second_energy_share,candidate_tail_energy_share, andmode_collapse_risk. The old top pass-3 candidateagent_02__retrievedmesh__target_04_a05now scores asweak-mode-collapsewith first-second energy share0.883627and collapse risk1, proving the evaluator sees the cheap trick. Distillation ranking demotes collapse risk, candidate knowledge records carry the failure mode, and the swarm prompt now requires later-section motifs/events instead of hiding behind noise or pads. -
Follow-up trawl found real generalizable sound-production knowledge but weak composition: stable role owners for syrinx/acoustic leads, subtractive drums, additive/PAD beds, shaped texture/air/codec, and strong negative pressure against mode collapse. The redirect is composition-first: next passes must publish a Composition Map with meter/time signature, progression or tonal center, note-degree sampling, instrument-lane gates, section events, composition-scale automation, and mix movement. Parser sugar now includes
meter,sequence,chords, andmix, lowering to ordinaryparamandcurveowners alongside existingpatternandscale. -
Completed a three-pass corpus song curriculum run under
artifacts/parity/song-snippet-swarms/20260531T171802519: each pass prepared 25 ten-second targets fromD:\Music\Reinierfor five agents with five assignments each, then ran official scoring, playlist generation, semantic search, trial distillation, andmusic-distillpromotion. Pass 1 promoted 34 music-production knowledge records, pass 2 promoted 56, and pass 3 promoted 58. Final pass artifacts includepass-003/top-scoring-candidates.m3u,pass-003/distillation-report.md,pass-003/music-production-knowledge.cc, andpass-003/music-production-quality-standard.md. The run exposed two harness quality faults: spawned agents neededE:\Projects\CultLibas an added Codex directory to run private scorers, and render-failed attempts must be handled as negative evidence because candidate analysis files are absent. The pass-3 outer swarm failed after agent jobs 2/3/4/5 exited nonzero, so the run was finished by promoting existing attempt-05 patches from those agents into the official patch tree and running official scoring/promotion manually. -
Built the first pruned music-production CultCache from the full-song iterative swarm artifacts instead of copying the old hot trial store.
music-distillscans official pass summaries and abstraction ledgers, excludes iteration, smoke, and rerun scratch, then writes a fresh pagedMusicProductionKnowledgeDocumentstore with compact quality-standard, scene-role, failure-mode, candidate-pattern, and abstraction-ledger records. The current store isartifacts/parity/music-knowledge/20260531T121228337/music-production-knowledge.ccwith 37 records from 28 official scored rows: 1 master standard, 4 role doctrine records, 1 failure-pressure record, 16 rendered candidate-pattern records, and 15 syntax-sugar pressure ledgers. Explorer commandsmusic-searchandmusic-showread the store directly; smoke reports live beside it assearch-syrinx.md,search-drums.md, andshow-quality-standard.md. -
Song-snippet challenge harness is now a real local parity lane, not a hand-waved prompt.
tools/IpaTrialWorkerhassong-prepareandsong-score:song-preparedecodes a local audio file through NAudio, freezes a seeded ten-second mono 44.1 kHzreference.wav, writeschallenge.jsonandchallenge.md, and reports scene features including spectral centroid, rolloff, active duty, spectral flux, onset-autocorrelation tempo (tempo_bpm,beat_seconds,tempo_confidence), dominant pitch/register (dominant_hz,register_low_hz,register_high_hz,root_note), and deterministic scale hints (suggested_scale,scale_frequencies_hz).song-scorerenders agent-authored.aquacandidates against that frozen reference, writes candidate WAV/DSP/timeline/comparison artifacts, and stores typedIpaTrialResultrecords in a song.ccstore. -
tools/run-song-snippet-trial-swarm.ps1prepares the random clip fromD:\Music\Reinier\Heyoka\Gate Code\Heyoka - Alien Gibberish.mp3, then can dispatch passes of parallel external Codex agents. Agents are prompted to use scene voices, FM/AM/noise/envelopes, rhythmic controls from autocorrelation-derived tempo, and register-bounded explicit scale-frequency curves. Until native Strudel-likescale/notesugar exists, the live syntax isparampluscurve ... interp=hold loop=truebound into voice fields. Smoke prep with seed123produced a clip starting at305.2523swithtempo_bpm=92.30769,beat_seconds=0.65,dominant_hz=175,root_note=F3, andminor-pentatonic-plus-tritonescale frequencies from about174.614to698.457Hz. Focused worker build and-Passes 0swarm prep pass. A one-candidate score smoke atartifacts/parity/song-snippet-score-smoke/smoke-001now proves ordinary non-vocal scene patches can score; the first attempt failed becausesong-scoreassumed every candidate had aVocalNetworknamedvoice, so primitive timelines are now optional witnesses for song scenes instead of a required anatomy gate. -
Ran a three-phase, three-agent song-snippet experiment across different seeded segments under
artifacts/parity/song-snippet-swarms/20260531T014033022. Segment starts were143.0295s,169.7126s, and196.3956s; tempo hints varied (200,63.82979,150BPM) while register stayed B4-ish withdominant_hz=2004.545and scale frequencies493.883..987.767. Best log-mel cosine climbed from0.308233in pass 1 to0.356515in pass 2 and0.380805in pass 3. Still not close; the winning evidence is that agents converged on a reusable scene model: bright FM/formantalien-lead, clocked high-banddust-hat, continuouscodec-bed, andair-wash-hiss. Syrinx narrative lost to boring formant/noise machinery. Report:artifacts/parity/song-snippet-swarms/20260531T014033022/experiment-report.md. -
User correctly called out that the loose agents learned nothing. The actual failure was not just weak metrics; the candidate assignment was incoherent. Families were rotated across targets instead of aligned to phonetic owners: stop-release candidates landed on vowel/approximant lanes, while
pgot an oral-pressure tweak despite the evidence naming stop-release ownership as the weak seam.tools/run-ipa-trial-loop.ps1now passes the previous evaluation path into the hypothesizer, requiresPrevious Round Learning, requires aTarget-Class Lane Plan, forbids round-robin family assignment, and instructs the evaluator to fail class alignment when family/target assignments do not match phonetic owner classes or explicit transfer-test mutations. -
Loose one-round IPA source-golf run completed under
artifacts/parity/ipa-trial-loops/20260531T001831690with 25 candidates, source edits enabled, and focused pre-score build passing. The external agent did not edit tracked source and choseSource Edit Decision: none, which is acceptable evidence: the round found value-sweep pressure, not a repeated DSL/Faust owner failure. Metrics did not improve: seed logMean0.42306004vs loose logMean0.41700276, artMean stayed flat around0.181, rmsMean dropped from0.48316268to0.445383, releaseMean dropped from0.06991132to0.06348304, and radiationMean rose slightly from0.27946476to0.28285928. The useful lesson was harness coherence: the evaluator incorrectly judgedhypothesis-agent.mdinstead of the actual full reporthypotheses.md, and the scene-voice prompt allowed prose-only background modeling.tools/run-ipa-trial-loop.ps1now nameshypotheses.mdas the report of record and requires at least one scene/noise or recording-condition family to add actual auxiliary.aquavoicedeclarations while preserving the primary articulatory vocal network. -
Expanded the IPA trial-loop agent contract so future rounds can golf DSL syntax, lowering, and Faust machinery when the evidence says the owner is wrong.
tools/run-ipa-trial-loop.ps1now gives source-edit-enabled hypothesis agents authority to editsrc/,tests/,docs/, andtools/for named DSL/lowering/Faust/worker evidence hypotheses, requires asource-change-plan.mdwith owner map, invariant, expected movement, verification, and rollback trigger, and runs a focused test-project build before scoring if source edits were allowed. The prompt also requires aScene Voice Modelfor every family: primary articulatory voice, tract-noise voice, release/transient voice, background-room voice, and recording-condition voice, with ordinary AquaSynth voices/noise/FM/AM/ envelopes/filters/formants/additive/spectral primitives available for helper scene voices. Helper voices remain full-parity tools and cannot count as articulation unless primitive/gesture/clean-vocal witnesses move too. -
Added primitive timeline facts to IPA trial results as first-class CultCache evidence.
IpaTrialResultnow stores extractedPrimitiveTimelineFact[]values fromProbeTimelineReport: contact opening/closed blocks/reservoir peak/release peak/release block, source load pressure and flow peaks, branch admittance/exchanged flow, radiation boundary/output peaks, path area/delay, energy, and passivity ratios.IpaTrialWorker search/show/dumpindexes and reports those facts alongside metrics and artifact snippets, and trial summary CSVs now include release/radiation/passivity columns. Verified with a one-candidate smoke underartifacts/parity/ipa-timeline-fact-smoke/20260531T233217641: stored facts includecontact_closed_blocks=12,contact_release_peak=0.020328,contact_release_peak_block=11,radiation_output_peak=0.008015, andpath_passivity_max=1. Qdrant/Ollama search for stop release/radiation evidence returned through the vector organ withrelease-factsandpassivity-factstags. -
Upgraded the IPA trial retrieval organ from lexical metric search to a Qdrant/Ollama vector index modeled after VoidBot.
IpaTrialWorker searchnow builds evidence chunks from eachIpaTrialResult, includes metric text, hypotheses, evaluations, known lies, timing receipts, and local artifact snippets such as.aqua, timeline CSV, markdown, text, and DSP files, embeds them through local Ollamaqwen3-embedding:0.6b, stores them in Qdrant collectionaquasynth_ipa_trial_results, and returns vector-backed markdown search reports with vector scores, evidence tags, metric facts, contrast candidates, excerpts, andshowcommands. Qdrant is derived from the.ccstore, not a second truth. Verified against the live Docker Qdrant and local Ollama server onartifacts/parity/ipa-trial-worker-smoke/20260529T2204/ipa-trial-results.cc: explicit index wrote 25 chunks with 1024-dim vectors, and stop-closure search returned throughqdrant-ollama. The trial loop now runsindexbefore and after each round's scoring boundary, then passes--skip-index trueto agent searches so the agents query fresh vectors without re-embedding on every receipt. -
Retrieval tuning smokes found two gremlin-feeding flaws: generic weak-articulation language could pull off-class records into class-specific searches, and mixed target-set records could match every class because their target contains
a/m/s/p/u. The live ranker now adds class-affinity scoring, candidate-specific ownership for mixed lanes (mix-pis stop,mix-a/uare vowel,mix-mis nasal,mix-sis fricative), demotes mixed/generalization to a secondary transfer hint when a real class is present, and only labels dressing when the record text actually mentions dressing/FM/AM/envelope/helper evidence. Search reports now exposeclass_focusand per-hitclass_match. -
Ran five IPA prompt-optimization passes against the external trial-loop agent prompts. Pass 1 produced useful seam science but treated fallback file reads as evidence after
dotnet runfailed. Pass 2 proved live search/show receipts could work but showed retrieval wandering eats the turn. Pass 3 showed capped live retrieval was still too slow for prompt iteration through externalcodex exec. Pass 4 exposed an incoherent "do not run commands" boundary because the agent could neither read receipts nor write a report. Pass 5 succeeded with a fixed six-receipt packet and a reasoning-only boundary, producing sharper seam evidence: stop release ownership, voicing loudness leak, fricative place collapse, mixed-set contamination, and single-candidate optimizer ownership. Production prompts now require contrast pairs,showmetric values, primitive timeline excerpts or explicitmissing, class-consistent reference matrices,X owns Y so Z remains trueowner sentences, at least five micro-sweep perturbations before a seam is actionable, and a novelty gate that rejects loudness/dressing-only families as loss-landscape novelty. -
Added the external IPA trial loop as a real worker boundary instead of an in-chat report shuffle.
tools/IpaTrialWorkernow exposesseed,score,search,show, and audit-onlydumpcommands over a sharedipa-trial-results.ccCultCache store.searchis the semantic retrieval organ for agents: it expands speech/control vocabulary and ranks records with metric-aware evidence bias;showdrills into one trial.scorerenders agent-authored.aquacandidates throughIpaTrialOrchestrator.RunCandidateScriptsAsyncand upserts new typed trial results.tools/run-ipa-trial-loop.ps1now runs five external Codex rounds by default, each asking for a batch across five five-phoneme target sets rather than one-off patch golf; the script rejects a round before scoring unless it contains at least one candidate for every target lane. -
Active IPA exploration shape: vowels
a/i/u/e/o, nasals/approximantsm/n/ng/l/r, fricativess/z/f/v/th, stopsp/b/t/d/k, and mixed generalizationmix-a/mix-m/mix-s/mix-p/mix-u. Agent patch files must be named<targetId>__<family>__<hypothesis-name>.aquaso the scorer can bind them to target/reference lanes and the evaluator can group hypothesis families. Full-patch dressing remains allowed, but evaluator reports must say when it is compensating for failed primitive or gesture evidence. -
Verification so far:
dotnet build tools\IpaTrialWorker\IpaTrialWorker.csproj --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false -v minimalpasses;IpaTrialWorker searchreturns ranked evidence fromartifacts/parity/ipa-trial-worker-smoke/20260529T2204/ipa-trial-results.cc;tools\run-ipa-trial-loop.ps1 -Rounds 0 -SkipLocalTrialRuncreates a loop skeleton. Need final focused tests and optionally a one-round external Codex smoke if time/tooling allows. -
Prompt QA pass: ran three dry single-turn external Codex smoke probes for both hypothesizer and evaluator prompts under
artifacts/parity/ipa-prompt-smoke/pass-{1,2,3}. The refinements removed contradictory count/name instructions, hardened candidate naming to<targetId>__<family>__<hypothesis>.aqua, made family ids lowercase kebab-case, required exact 25-lane output, added pre-evidence digest and claim-audit sections, forced semantic-search/show receipts, added evidence quality ledgers/verdicts for specificity/comparability/falsifiability/reuse, and made the evaluator fail closed when receipts, target coverage, filename validation, or family extraction are incomplete. Final script syntax smoke passes withtools\run-ipa-trial-loop.ps1 -Rounds 0 -SkipLocalTrialRun. -
Implemented the first IPA trial render/scoring orchestration. Core now has typed
IpaTrialResultCultCache records plusIpaTrialResultCultCacheStore; Faust now hasIpaTrialOrchestrator.RunAsync, which generates candidate patches throughIpaGestureExperiment, renders them with Faust, compares spectrogram/articulation evidence against local PT fixture references, writes WAV/report artifacts, and stores the general trial-result.ccdatabase. The opt-in five-seed run wroteartifacts/parity/ipa-trials/20260529T214127955/five-seed-trials. -
First run showed the pipeline worked but vowels/nasals were effectively silent despite decent gesture scores. The refinement was architectural: primitive
SourcePortFaust lowering now emits an oscillatory voiced carrier tied to the network frequency, instead of feeding mostly DC pressure into a high-passed radiation load. Seed patch defaults now use stronger clean primitive source flow. Second run moved the intended layer: openalog-mel cosine0.5693,m0.5199,s0.5498with articulation0.4111; plosivepremains weak at-0.1024, pointing to closure/release ownership rather than source loudness. -
Verification: opt-in
IpaTrialOrchestratorWritesFiveSeedTrialsWhenEnabledpassed with Faust installed; focusedPatchScriptTests|IpaTrialResultsRoundTripThroughCultCachepass 94/94. -
Added the first scalable IPA gesture experiment harness.
IpaGestureExperiment.WriteRoundwrites a frozen round bundle withmanifest.yaml, candidate.aquascripts, primitive timeline CSVs fromProbeTimelineReport, gesture-layermetrics.csv, and per-candidateevidence.jsonl.IpaGestureExperiment.AnalyzeRoundwritesanalysis/metric-summary.csv,analysis/candidate-clusters.csv, andanalysis/science-brief.mdfor the science-worker handoff. The harness scores only descriptor/spline/primitive evidence (surface_coverage,motion_direction,contour_timing,primitive_timeline,gesture_score) and explicitly does not own clean vocal identity, full spectrogram parity, optimizer checkpoints, or worker orchestration. Verification:PatchScriptTestspass 93/93. -
Documented the IPA training scoring contract. Gesture score is measured at the descriptor/spline/primitive-timeline layer using coverage, direction, contour/timing, primitive consequences, and optional external articulation evidence. Training reports must keep
gesture_score,clean_vocal_score, andfull_parity_scoreseparate; full parity may use all AquaSynth synthesis tools and recording-condition helpers, but cannot count as articulation evidence unless the lower-layer scores also move. -
Added the first IPA/anatomy gesture DSL layer.
phoneme_gestureaccepts known IPA symbols or explicit descriptors likedescriptor=voiceless_labial-velar_fricative, maps place/manner/voicing to the primary anatomical surfaces, and emits ordinaryControlSplines. This is deterministic seed material for local dataset golf, not a claim that IPA labels contain exact numeric targets. Patches remain free to use normal FM/AM/modulators/envelopes/filters around the anatomical control stream. Verification:PatchScriptTestspass 92/92. -
Public gesture API pass implemented.
ControlSurfaceCatalog.FromPatch(patch)is the host-facing discovery surface for normalized controls; hosts can createControlSplineTimeline, edit future points, and callControlValuesAt(t)to stream ordinary surface controls into Faust without recompiling. Native Faust compiled patches now exposeAquaSynthCompiledPatch.ControlSurfacesand a safeControlValuesAt(timeline,t)helper that filters the semantic timeline to UI zones actually exported by the optimized DSP. Verification:PatchScriptTestspass 91/91 andNativeFaustRuntimeTestspass 5/5. -
Implemented the gesture/timeline owner cut for primitive vocals.
ControlSurfacenow exposes normalized runtime controls for primitive fields, andControlSplineowns linear/hold/Bezier motion over those surfaces. Primitive Faust lowering maps effective normalized surface values back into physical fields; explicit old@/parambindings remain base controls so PT fixture controls are not bypassed.ControlSplineTimelinesupports future point edits for realtime clients. -
tract_motionnow adapts velopharynx motion into a branch-openingControlSpline. A generated contact-opening spline was tested and deleted: PT timeline evidence showed the obstruction was already closed at block zero, so an invented open-then-close contact story was a compensator. Contact closure should come from articulator/area ownership, not local contact slew. -
Verification for this cut:
PatchScriptTestspass 90/90. Focused primitive timeline artifact test passes and writesartifacts/parity/primitive-vocal-timeline/20260529T185955965; summary: open-vowel 0.267624, front-vowel 0.246432, nasal-vowel 0.223792, bilabial-nasal-ma 0.226266, sibilant 0.177032, closure-release 0.155925. -
First primitive vocal teardown cut implemented.
AreaFunction,WaveguidePath,SourcePort,ConstrictionContact,BranchPort,RadiationLoad,ProbeTimeline, andVocalNetworkare model records with parser commands. PT-shapedtractauthoring now adapts into those primitive records instead of generatingvoices_0_area_*,voices_0_contact_*, orvoices_0_inj_*acoustic banks. The obsoleteEnsureTractAcousticNetworkgenerator was deleted. -
Faust lowering now prefers a compact primitive path for
Voice.VocalNetwork: one semantic path variable per tube usingde.fdelay*delay families, named primitive source/contact/branch/radiation locals, and debug probes under/debug/voice_0/path|source|contact|branch|radiation/.... ExplicitAcousticPortNetworkscripts still exist as a lower-level lab surface. -
ProbeTimelineReportwrites deterministic primitive samples asblock,primitive,signal,value; current fields include path area/delay, source load pressure/flow, contact opening/resistance/reservoir/released flow, branch admittance/exchanged flow, and radiation reflection, boundary_flow, flow, and output. Passivity/energy samples and PT/SndKit timeline comparison are next. -
Verification for this cut:
dotnet build tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false -v minimalpassed. Focused primitive/tract/fixture tests passed: 8 tests covering the new primitive DSL, PT tract adapter, primitive timeline, and fixture demotion away from generated graph banks. -
Second primitive evidence cut in progress: path telemetry now includes
incoming_wave,outgoing_wave,energy_in,energy_out, andpassivity_ratioin both Faust debug probes andProbeTimelineReport. Contact telemetry now includesresistance. AddedPrimitiveReferenceReport.ComparePinkTrombone, which compares static primitive geometry/delay/branch/contact/radiation fields against PT/SndKit fixture controls without requiring native reference binaries.PatchScripttests pass 86/86 after this cut. -
Third primitive evidence cut in progress:
PinkTromboneReferenceRenderernow hasRenderTimeline, exposing PT internal timeline samples from the renderer's own diameter/wave/reflection/transient arrays.PrimitiveReferenceReportcan role-normalize Aqua primitive timeline samples against PT timeline samples for oral/nasal path, velopharynx branch, obstruction contact, and lip radiation signals.PatchScripttests pass 88/88. -
Added
PinkTrombonePrimitiveTimelineComparisonWritesArtifacts; it writes per-fixtureaqua-primitive-timeline.csv,pt-internal-timeline.csv,comparison.csv, andsummary.txtunderartifacts/parity/primitive-vocal-timeline/<timestamp>. Focused artifact test passes. -
First comparison-driven law correction:
SourcePortnow ownsFlowScale(default.02) instead of primitive source flow silently emitting unit-scale waves; primitive radiation reflection now reports/uses declaredRadiationLoad.Reflectioninstead of aperture-modulating the coefficient;ProbeTimelineReportradiation flow now uses the path outgoing wave, matching the Faust law. New artifact20260529T155613895drops suite mean absolute timeline error from roughly1.2-1.3to0.15-0.27. Remaining obvious drift is branch/contact dynamics, which raises a real owner question: gesture slew inside ports or separate gesture/timeline primitive. -
Proprioception correction after user rejected baby-word golf as the rebuild owner. Diagnosis is now durable in
docs/acoustic-graph-proprioception.md: collapse generated graph-vocal lowering into a small set of instrumented physical primitives, compare primitive/sample-flow behavior against VTL, ArtiSynth, Story/TubeTalker, Smith/Faust, and PT/SndKit, then return to utterances as downstream witnesses. Next implementation pass should map current records/Faust locals ontoAreaFunction,WaveguidePath,ScatterJunction,SourcePort,ConstrictionContact,BranchPort,RadiationLoad, andProbeTimeline. -
Implemented the first graph-owned closure reservoir cut. Contact terminals no longer contribute through the generic node source sum. Ordinary two-port path scatter now emits per-contact closure, reservoir drive, reservoir, release, and out probes, and injects the release directionally into the same path scattering law (
0.80downstream,0.20upstream). This is the research supported move: closure pressure enters the traveling-wave path instead of acting as an output click or generic source gain. -
Latest opt-in thrombosis probe after the cut:
artifacts/parity/pink-trombone-graph-thrombosis-probes/20260529T021934812. Key peaks: lip contact closure0.936876, contact reservoir drive0.519667, contact reservoir6.024680, contact release0.485894, contact out0.548231, lip radiation flow0.581880, lip radiation admittance0.710362, modal source out1.233802, modal flow0.771656, sibilant/injection area 34 out0.099287. Previous contact out was about0.032413; the closure event now reaches the graph/radiation path. -
Latest utterance diagnostic:
artifacts/parity/pink-trombone-utterance-logmel/20260529T022214016. The speech verdict is still not accepted.thrombosisRMS improved from roughly0.0673to0.0761, but cosine stayed about0.331and silence mismatch worsened to0.7306. This means the closure cut is structurally correct but not sufficient. Do not claim speech parity. Next likely owner is either utterance/radiation output balance or more realistic contact filtering/active-frame duration; do not hide that under a global gain knob. -
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-build --disable-build-servers --filter "ParserSupportsPinkTromboneStyleTractVoice|TractVoiceCanLowerThroughAcousticGraph|FaustCompilerValidatesAcousticPathGraphWhenInstalled" -v normalpassed: 3 tests.AQUASYNTH_RUN_GRAPH_PROBES=1 dotnet test ... --filter "PinkTromboneThrombosisGraphDebugProbesWriteTimelineWhenNativeFaustIsInstalled"passed: 1 test in 2m09s.dotnet test ... --filter "PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstalled"passed: 1 test in 2m25s. Minimal verbosity sometimes exits silently on the long native render path; normal verbosity produced passing runs. -
Added graph-native debug probes for vocal source internals when
DebugProbeUiis enabled: tissue-valve pressure drive, modal tissue, aperture, flow, and output; turbulence-source reservoir/release/output; and contact reservoir/release/output. These are observation only, not audio-law changes. -
Added opt-in
PinkTromboneThrombosisGraphDebugProbesWriteTimelineWhenNativeFaustIsInstalled. It runs only whenAQUASYNTH_RUN_GRAPH_PROBES=1, compiles the generatedthrombosisgraph through native Faust debug UI, steps the streaming patch block by block, and writescandidate-debug.dsp,controls.csv,timeline.csv, andprobe-peaks.txt. -
Latest probe artifact:
artifacts/parity/pink-trombone-graph-thrombosis-probes/20260529T011547091. Key peaks: modal source out1.335230, modal flow0.791726, modal pressure drive0.741528, lip radiation flow0.337191, lip radiation admittance0.710362, sibilant/injection source at area 34 out0.099288, lip contact release out0.032413. The graph is not dead. The current failure is not a missing genericdriveknob or a silent source; it is weak articulation and output balance after graph/radiation scaling, with contact release still small and localized. -
No acoustic-law cut was made from this evidence. Next real change should use the probe timeline to decide whether to promote contact/closure into the scattering law or adjust the utterance harness/radiation output owner. Do not hide the finding behind a broad gain tweak.
-
Verification:
AQUASYNTH_RUN_GRAPH_PROBES=1 dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false --filter "PinkTromboneThrombosisGraphDebugProbesWriteTimelineWhenNativeFaustIsInstalled|FaustCompilerValidatesAcousticPathGraphWhenInstalled" -v minimalpassed: 2 tests in 2m01s. Default focused diagnostic without the env var also passed with the probe test returning immediately. -
PT utterance diagnostic crash recheck: the focused test is reproducible as slow but passing when stale child
dotnetprocesses are cleared and the test is run with enough wall-clock budget. Fresh verified artifact:artifacts/parity/pink-trombone-utterance-logmel/20260529T005420700. Per-utterance render timing now writesrender.txtbeside each candidate before/after the Faust render path:mama~31s,papa~45s,thrombosis~59s. The previous two-minute attached shell timeout was not a valid crash witness. -
Harness/process fix:
PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstallednow writescandidate-graph.dspandcontrols.csvbefore rendering, wraps each external Faust render in a three-minute per-utterance timeout, and writes stdout/stderr/timing torender.txt.FaustCompiler.RunAsyncnow kills the whole child process tree when cancellation fires, so timed-outfaustor nesteddotnet runwork cannot keep poisoning later runs. -
Current acoustic evidence after the source-law cleanup is weakness, not a loud low-frequency floor: latest utterance RMS ratios are
mama0.0876,papa0.1509,thrombosis0.0673.thrombosisstill fails the diagnostic cosine floor with cosine 0.3318. Next vocal work should inspect source-flow strength/articulation and radiation transfer with debug probes, not restore a genericdriveknob. -
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false --filter "PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstalled|FaustCompilerRendersTissueValveGraphWhenInstalled|FaustCompilerValidatesAcousticPathGraphWhenInstalled" -v minimalpassed: 3 tests in 2m17s. -
Research-guided machine cut: graph segment delay no longer clamps physical segment delay to a full sample.
WaveClockPolicynow owns the minimum legal delay: unit grid stays at 1 sample, half-sample grid and first-order Thiran bottom at 0.5, and Lagrange/crossfaded policies use their documented lower bound. Generatedtract propagation=graphnow usesHalfSampleGridto match PT's half-sample Kelly-Lochbaum regime instead of first-order Thiran. -
Rejected experiments in this pass:
- Flipping area-scatter reflection to the literal SndKit/PT sign made
thrombosisloud/unstable under Aqua's current port orientation, so the previous local sign convention remains. - Adding more high glottal harmonics worsened voiced-band behavior; the failure is not a missing sparkle source.
- Flipping area-scatter reflection to the literal SndKit/PT sign made
-
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false --filter "TractVoiceCanLowerThroughAcousticGraph|ParserSupportsTypedAcousticPathGraph|FaustCompilerValidatesAcousticPathGraphWhenInstalled|PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstalled|PinkTromboneFixturesReportLogMelParityWhenFaustIsInstalled" -v minimalpassed. Latest utterance artifact:artifacts/parity/pink-trombone-utterance-logmel/20260527T133539554;mamacosine/articulation0.5982/0.1952,papa0.8615/0.1979,thrombosis0.5217/0.2640. Latest static artifact:artifacts/parity/pink-trombone-logmel/20260527T133424894. -
User listening correctly rejected the log-mel witness:
thrombosiswas mostly silence plus breathy/squeaky bursts, andpapa/mamastill read as phone-vibration buzz.AudioComparisonnow includes articulation diagnostics instead of letting log-mel cosine own speech parity. -
New
AudioArticulationComparisonfields: envelope cosine, active-frame ratio, silence mismatch, envelope flux ratio, spectral flux ratio, motor-band ratio, speech-band ratio, and articulation score. Utterance reports now print a verdict. Latest artifact:artifacts/parity/pink-trombone-utterance-logmel/20260527T130026316; all three accepted utterance fixtures arenot-accepted-articulationwith articulation scoresmama0.1930,papa0.1829,thrombosis0.1848. This is correct: the harness now agrees with the ear instead of laundering filtered buzz through cosine. -
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false --filter "AudioAnalyzerComparesSimpleBuffers|PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstalled|PinkTromboneFixturesReportLogMelParityWhenFaustIsInstalled" -v minimalpassed. -
Latest graph radiation pass moved articulation authority into the acoustic boundary instead of the output tap.
AcousticRadiationPortaperture now blends boundary reflection between near-closed termination and declared open-end reflection. Radiation reads boundary flow (incoming - outgoing) and applies a stronger high-pass radiation slope, instead of reading raw incoming pressure and painting it after the fact. -
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false --filter "PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstalled" -v minimalpassed. Latest utterance artifact:artifacts/parity/pink-trombone-utterance-logmel/20260527T122757617;mamacosine0.5650RMS0.3297,papa0.8613/0.1282,thrombosis0.4347/0.2502. -
Static parity also passed:
artifacts/parity/pink-trombone-logmel/20260527T123141625; open/front/nasal/ma/sibilant/closure cosine0.6088/0.6826/0.6468/0.6153/0.4158/0.6198. -
The pass improved
mama/papaband shape and made aperture a real graph impedance control, butthrombosisstill loses voiced body and stops remain underpowered. Next pressure is graph-native pressure storage/release around severe constrictions and nasal/oral branch coupling, not more output color. -
Added a small higher-harmonic brightness term to the reusable glottal source. Utterance smoke passed under
artifacts/parity/pink-trombone-utterance-logmel/20260527T123628148. Post-flow radiation gain was then recalibrated from3.0to4.0;4.5was tested and rejected as too close to static soft-clip pressure. Latest utterance artifact:artifacts/parity/pink-trombone-utterance-logmel/20260527T124230804;mama0.5712,papa0.8659,thrombosis0.4379. Static smoke passed underartifacts/parity/pink-trombone-logmel/20260527T124311305. -
Added time-varying Pink Trombone utterance reference fixtures before any Aqua utterance metric golf.
PinkTromboneReferenceRenderer.RenderUtteranceinterpolates timestampedPinkTromboneControlPointcurves sample by sample, preserving the existing PT-style waveguide state. -
New fixture set:
mama,papa,lulek, andthrombosis. Each fixture owns explicit control points for PT frequency, intensity, tenseness, tongue index/diameter, constriction index/diameter, turbulence, velum, lip opening, reflections, gain, and burst. These are first-pass pronunciation sketches, not accepted references until user listening approves them. -
PinkTromboneUtteranceReferenceTests.PinkTromboneUtteranceFixturesWriteReferenceWavswrites PT reference WAVs,controls.csv, andsummary.txtunderartifacts/parity/pink-trombone-utterances/<timestamp>/<word>/. -
Latest artifact set:
artifacts/parity/pink-trombone-utterances/20260526T205230009. Reported PT reference peaks/RMS:mama0.7033/0.4213;papa0.7012/0.3618;lulek0.7200/0.4087;thrombosis0.7600/0.4658. Do not golf Aqua against these until the user has judged whether the PT reference words are recognizable enough to serve as targets. -
Golfed the actual graph tract path against the PT log-mel harness after the playground
Mapreset sounded like amplified buzzing. The failure was not a playground-only gain problem: generated graph topology reused velum as both branch valve and nostril aperture, while closed-nose leakage was carrying too much oral loudness. -
EnsureTractAcousticNetworknow treats velum as branch entrance area control by squaring the nasal branch terminal opening, while nostril radiation remains an independent aperture. Graph radiation was then cut from24.0to3.0because the previous value was a compensator for the leaky topology and drove the corrected graph into soft clipping. -
Added a
bilabial-nasal-maPT fixture using the playgroundMacontrols, and fixed PT fixture script generation so intensity/tenseness/glottal reflection actually reach bothglottisandtract. -
The playground renderer patch gain is now
0.48, keeping audition renders out of the clipped-buzz regime while still rendering the actual Aqua DSL/Faust graph. -
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --filter "PinkTromboneFixturesReportLogMelParityWhenFaustIsInstalled" --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false -v minimalpassed. Latest graph reports:open-vowelcosine0.6219RMS ratio0.9743;front-vowel0.6407/1.0024;nasal-vowel0.5375/1.1476;bilabial-nasal-ma0.4743/1.2206;sibilant0.3233/1.0008;closure-release0.0817/1.5534. Focused graph/parser tests andtools\TractGraphRendererbuild also passed. Live playground render check after this pass: Open peak/RMS about0.498/0.257; Ma about0.480/0.243. -
Replaced the vocal tract playground's browser-native source/filter witness with actual Aqua DSL graph rendering. The page now posts the visible controls to
/render;tools/TractGraphRendereremitstract propagation=graph, lowers throughFaustEmitter, renders throughFaustCompiler.RenderAsync, writes a WAV underartifacts/vocal-tract-playground, and the browser plays that returned audio. -
The fake JS
createTractSynthpath was deleted so the playground has one audio authority: Aqua DSL -> Faust graph lowering. The UI is render-on-demand, not realtime, because recompiling/rendering Faust per audition is the honest current machine. -
Verification:
dotnet build tools\TractGraphRenderer\TractGraphRenderer.csproj --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=falsepassed; direct renderer smoke wroteartifacts\vocal-tract-playground\smoke.wavwith peak0.15414488, RMS0.066947475, and no warnings; live serverPOST http://127.0.0.1:5126/renderreturned a WAV and/renders/...wavserved HTTP 200;node --checkpassed forapp.jsandserve.mjs. -
Added
tools/vocal-tract-playground, a static WebAudio playground for the current AquaSynthVocalTractControlTargetsurface. It exposes the 14 base voice-patch target controls plus six mel-envelope bands: these are the knobs the learned speech driver will predict from phonetic and utterance input. The page draws a tract-ish canvas and includes vowel/noise/nasal presets. -
This is intentionally a touchable control playground, not a claim of Pink Trombone-class tract physics. The canvas and audio are tied to the real AquaSynth control names so future renderer work has an inspectable handle.
-
Verification:
node --check tools\vocal-tract-playground\app.jsandnode --check tools\vocal-tract-playground\serve.mjs: passed. Local servernode tools\vocal-tract-playground\serve.mjsservedhttp://localhost:5125/; browser check rendered the UI, Play toggled audio, theEepreset moved sliders/visuals, and console errors were empty. -
Added
MelCepstralWarpEffectas a real AquaSynth offline/block audio effect: STFT -> log-mel -> DCT cepstra -> Simplex domain warp -> separable 5-tap Gaussian blur -> inverse cepstra/log-mel -> original-phase overlap-add resynthesis. This came from the Mimir bioacoustic decoder work, but the reusable audio-effect owner is AquaSynth. -
Added focused tests proving the effect preserves length/finite samples and that warp/blur parameters audibly change output.
-
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "MelCepstralWarpEffectTests" -v minimal: 2 passed. -
Tightened CultCache claim receipts into an explicit hazard-light witness shape.
CultCacheProofTruth.LatestListeningReceiptis no longer a loose string; it is nowCultCacheListeningReceiptwithSubject,TouchedSurface,RemainingContamination, andWitnessSentence. -
The default patch/speech claim catalog now carries those fields directly, so a card names what patch/reference was touched, what surface got exercised, what still contaminates the claim, and one human/domain witness sentence about whether the sound bites, blooms, or lies.
-
Regenerated
patches/aquasynth-patch-cultcache.ccfrom the typed catalog so the checked-in CultCache artifact matches the new receipt schema. -
Focused tests now assert receipt structure explicitly instead of only checking that some non-empty string exists.
-
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "CultCachePatchDocumentTests" -v minimal -
Added the first distributed speech-training contract:
SpeechRenderRequest,SpeechRenderResult, andSpeechTrainingCheckpointare typed CultCache documents insrc/AquaSynth.Core/SpeechDistributedTraining.cs. -
SpeechDistributedTrainingCoordinatornow creates render requests from the current pipeline, accepts worker-produced score gradients, and applies those gradients throughSpeechBackpropagationPipeline.TrainSingleFromSynthOutputGradient. The current worker proof scores control-vector MSE locally; the ownership shape is the same as remote compiled-Faust scoring. -
SpeechDistributedTrainingCultCacheStorereads and writes request, result, and checkpoint.ccstores through CultLib. No JSON queue, no bespoke serializer, no trainer pretending to own the renderer. -
New durable CultMesh training constraint: CultMesh should distribute compiled Faust render/scoring payloads and collect worker
SpeechRenderResultgradients, artifacts, timing receipts, and losses. Workers may witness and compute; they must not mutate model checkpoints. The authority trainer or one shard-primary trainer applies gradients throughSpeechBackpropagationPipelineand commitsSpeechTrainingCheckpointdocuments through normal CultCache/CultMesh shard authority. -
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "SpeechDistributedTrainingTests" -v minimal: 2 passed. -
Implemented the first CultMesh-distributed speech training step: Core now references
GameCult.Mesh, definesSpeechWorkerPayloadManifest,SpeechWorkerPayloadArtifact,SpeechWorkerAdmissionReceipt,SpeechCultMeshWorkerAssignment,SpeechCultMeshTrainingStepResult, andSpeechCultMeshRoles.RenderWorker, and persists payload/admission documents throughSpeechDistributedTrainingCultCacheStore. -
SpeechDistributedTrainingCoordinator.RunCultMeshTrainingStepnow creates requests, creates a worker payload manifest, admits only peers with valid CultMesh worker leases, records rejected peers, runs score-only worker assignments, collectsSpeechRenderResultgradients, and applies them centrally throughApplyResults. -
This is distributed training via CultMesh lease/admission and typed CultCache documents. It is not yet real remote process supervision or artifact chunk transfer; those remain CultMesh infrastructure surfaces. No worker API owns checkpoint mutation.
-
Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "SpeechDistributedTrainingTests" -v minimal: 3 passed.
Previous slice:
- Added a typed CultCache sound-claim document for CultMesh distribution:
patches/aquasynth-patch-cultcache.cc. - Cut the JSON artifact and the local hand-written MessagePack codec. AquaSynth
owns the typed
CultCachePatchDocumentcatalog; CultLib owns cache serialization throughGameCult.Caching.MessagePack. - Added
CultCachePatchDocumentrecord types in Core. The document bundles the fullpatches/library.yamlpatch database with patch claim cards and speech claim cards, andCultCachePatchDocumentStorereads/writes it through real CultCache APIs. - Patch claim cards now cover every
ReferenceRebuildCatalog.All()fixture patch: the three project-authored Zyn rebuilds and the three DX7 reference rebuilds. The PRC SYNTH1 calibrated patch also has a claim card because it is in the patch database as a hard public-domain DX7 pressure target. - Speech claim cards cover the eSpeak NG tiny workout and the compiled Faust speech loss surface. Both explicitly name utterance/phoneme source, target anatomy/profile, intent, tier, proof artifact, listening receipt surface, and known lies.
- Stock patch database entries are included as database entries, not promoted to serious claims without references. That preserves the law: sketches may exist, but parity/pressure/proof claims need named reference and receipt surfaces.
- Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "CultCachePatchDocumentTests" -v minimal: 4 passed.
Previous slice:
- Reworked the Faust-rendered speech-loss path toward the actual curriculum
machine:
CompiledFaustRenderedSpeechLossSurfacecompiles one native Faust patch with exportedspeech/output/Nhslider controls for every neural mapper output, then renders reference/candidate batches by setting controls on new DSP instances from the same compiled factory. AquaSynthCompiledPatchnow exposesControlPathsand supportsRender(IReadOnlyDictionary<string,float>).FaustNativeToolchainbuilds a C UI glue map from Faust control labels to native zones and writes parameter values beforecompute.- The compiled speech probe keeps every mapper output as an exported knob even when a current simple synth rung does not use the value strongly. The tiny keepalive term exists for that invariant: topology and control surface stay stable across curriculum rungs.
- Rendered proof found a real loss-surface hazard: dynamic low-pass cutoff can
exceed Nyquist at lower training sample rates and produce NaNs. The compiled
probe clamps cutoff to
ma.SR * 0.45. - Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "FaustRenderedSpeechLossSurfaceTests|NativeFaustRuntimeTests|SpeechBackpropagationPipelineTests" -v minimal: 6 passed. - Opt-in native batch proof:
AQUASYNTH_RUN_FAUST_SPEECH_LOSS=1 dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "CompiledFaustRenderedSpeechLossSurfaceReusesOnePatch" -v minimal: 1 passed.
Previous slice:
- Added the first Faust-rendered speech loss surface.
AquaSynth.Faustnow ownsFaustRenderedSpeechLossSurface, which turns aVocalTractControlTargetinto an inspectable AquaSynth script, renders it through Faust, compares rendered log-mel evidence, and estimatesd(loss)/d(controller output)with finite differences over selected output indices. - Added the missing Core backprop seam without making Core depend on Faust:
SpeechBackpropagationPipeline.TrainSingleFromSynthOutputGradientaccepts an external synth-output gradient, updates the synth driver, slices the returned semantic embedding gradient, and updates the utterance encoder. This is the handoff a Faust-rendered loss surface needs. - Added
VocalTractNeuralMapper.TrainSingleFromOutputGradientand allowedPackedNeuralNetwork.TrainSingleFromOutputGradientto preserve the external loss value in its result. - The normal focused tests verify external-gradient backprop without invoking
Faust. The heavier rendered proof is opt-in via
AQUASYNTH_RUN_FAUST_SPEECH_LOSS=1because the current renderer recompiles per finite-difference evaluation. - Verification:
dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "SpeechBackpropagationPipelineTests|FaustRenderedSpeechLossSurfaceTests" -v minimal: 3 passed. - Rendered proof verification:
AQUASYNTH_RUN_FAUST_SPEECH_LOSS=1 dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --filter "FaustRenderedSpeechLossSurfaceTests" -v minimal: 1 passed in about 1m22s. - Build verification:
dotnet build AquaSynth.sln -v minimal: succeeded. - Current honesty: this is a real Faust-rendered loss surface and a real backprop seam through both learned models. It is still black-box finite difference over controller outputs, not analytic differentiation through Faust DSP. The next coherent performance cut is render/compile caching or a differentiable proxy that is explicitly trained against Faust, not pretending recompiling Faust dozens of times is the final supercar.
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 AquaSynth work continues elsewhere.
Doctrine update:
- External synths are parity pressure for AquaSynth's DSL, not internals to clone. Only consume targets that can be backed by parity tests proving 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 AquaSynth organs. ZynAddSubFX
now lives under
external/zynaddsubfxas GPL development material pinned at3ab608c432996ba4d582176572c0b0f82328c825; it must not enter the NuGet package or runtime dependency graph.
Current slice:
-
Organ Choir exposed two separate Zyn PAD authorities that are now mapped: analog high-pass filters (
HP1/HP2, stages, and FILTER_ENVELOPE motion) and selected PAD table roots for OscilGen shift-base sources (base_function=7). The root policy is source-driven: normal PAD rebuilds keep the sample-0 oracle root, while shift-base OscilGen layers may use the selected note table root when the parity oracle provides it. -
Latest upstream PAD survey after this pass:
Organ Choir Pad2artifactartifacts/parity/zyn-upstream-pad-fixtures/0008-organ-choir-pad2-20260515T162034810, log-mel0.471483, envelope0.302978, RMS ratio0.878, centroid ratio1.011328, score0.541933. The violin-vs-wind issue was kit1 source-table shape: Aqua had ignored Zynbase_function_modulation=1andadaptive_harmonics=1, producing a smooth upper harmonic ramp. The importer now applies base-function phase modulation before DFT and adaptive harmonic remapping at the PAD table root. -
Direct kit1 table spectrum moved from violin-shaped to wind-shaped: 400-800 Hz energy is now
0.2713against Zyn0.2780; 8-16 kHz is0.1471against Zyn0.1355. -
The accepted fixtures stayed on the sample-0 root path: DoublePadBass log-mel
0.247674, score0.650319; Ghost Ensemble log-mel0.369402, score0.57229; Soft Pad log-mel0.317897, score0.608833. -
User listening now accepts the recent Zyn PAD fixture batch as reading the 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 AquaSynth.sln --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 shape as future regression context, not the active treadmill. Do not turn the base-function-7 selected-root rule into a global selected-table switch. That was tested and regressed accepted DoublePadBass.
-
Zyn PAD per-preset rebuilds now carry first-class Zyn PAD table semantics instead of only
spread=0plus harmonic magnitudes. -
SpectralBankownsPadSpectrumProfile, including Zyn PAD mode, bandwidth, bandwidth scale, harmonic profile, and harmonic-position warp.PadSynthWaveformuses the Zyn PAD profile/bandwidth formulas for those banks and keeps the old generic PADsynth path for ordinaryspectrum. -
ZynInstrumentReader.RebuildFirstPadAsAquaSynthScriptnow emits readable neutralpad_mode=,pad_bandwidth=,pad_bwscale=,pad_profile=..., andpad_position=...fields, and maps Zyn PAD volume with the source exponential gain curve instead of the old tiny linear/500guess. The parser still accepts olderzyn_*aliases for parity artifacts, but authored.aquashould 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 Soft Pad and Organ Choir Pad2 log-mel, while sin2x/DoublePadBass/Ghost regress. Treat it as live pressure on OscilGen coverage, not solved Zyn oscillator parity.
-
Latest focused verification:
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 Padlog-mel0.342738, score0.443083;Organ Choir Pad2log-mel0.573216, score0.434351;sin2x padlog-mel0.524421, score0.360653;DoublePadBasslog-mel0.689315, score0.226566;Ghost Ensemblelog-mel0.482155, score0.400393. -
Next coherent cut: either complete more OscilGen semantics (modulation/waveshaping/filter/adaptive harmonics) or gate the current approximation to the cases it truly owns. Do not present the mixed OscilGen subset as passing parity.
Current follow-up:
- Reworked Zyn PAD OscilGen partial extraction into a sampled stage-order pipeline for presets with live oscillator processing: base waveform, optional oscillator filter/waveshaper order, modulation, harmonic shift, then spectrum adjustment. The implementation covers a useful subset of oscillator filter types and waveshapers instead of pretending base-function convolution alone is the synth.
- Gated that pipeline so direct harmonic presets remain readable and capped at 32 partials. This cuts the earlier mistake where base-function-only presets grew huge partial lists without improving parity.
- Latest upstream PAD batch after this pass:
sin2x padlog-mel0.455193, score0.405637(better than the previous OscilGen subset's0.524421);Soft Padlog-mel0.342738, score0.443083;Ghost Ensemblelog-mel0.40922, score0.421156;Organ Choir Pad2log-mel0.664699, score0.369231;DoublePadBasslog-mel0.655288, score0.246664. - This is still not passing Zyn PAD parity. The likely next missing owners are full OscilGen filter/waveshape coverage, adaptive harmonics, and note/global filter/envelope behavior. Do not tune thresholds around these numbers.
Current user-ear correction:
- User clarified Soft Pad itself is fine; Ghost Ensemble was the one collapsing
into a Soft Pad-like identity. The bug was our direct-harmonic gate ignoring
Ghost's live
base_function=4power oscillator because no downstream oscillator stage was enabled. The gate now expands power-base multi-harmonic OscilGen sources, restoring Ghost to a 32-partial source. Latest Ghost: log-mel0.402789, score0.446977, and the.aquano longer looks like a two-partial Soft Pad knockoff. - DoublePadBass exposed a separate ownership bug: the preset is
kit_mode=1with 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 intoRebuildEnabledPadsAsAquaSynthScript; generated Aqua emitsdoublepadbass_0anddoublepadbass_1. - Latest DoublePadBass after multi-kit rebuild: log-mel
0.493451, score0.376854, RMS ratio0.826864. Raising the volume cap to3.0worsened it (log-mel0.521113, RMS ratio1.220809), so the cap was cut back to1.5. - User then identified the remaining DoublePadBass balance issue: Aqua
over-emphasized kit0's high buzz while Zyn's character comes from kit1's low
rumble. The cause was visible Zyn global filter data we were still ignoring:
kit0 has filter
category=0 type=2 freq=12, kit1 hasfreq=61. Static Zyn PAD low-pass now maps to layerlpf; the helper had to read nestedFILTERparams, not directFILTER_PARAMETERSchildren. - User still heard Aqua as all kazoo, while Zyn was deep bass with a tiny kazoo
overtone. The linear
freq/127LPF mapping was wrong: Zyn's old filter cutoff maps through2^((Pfreq / 64 - 1) * 5 + log2(1000)). Kit0freq=12is roughly 60 Hz, not 1.7 kHz; kit1freq=61is roughly 850 Hz, not 8.6 kHz. - Latest DoublePadBass after Zyn filter curve mapping: log-mel
0.334546, score0.351535, RMS ratio0.464596, with generated layersdoublepadbass_0 lpf=0.003325anddoublepadbass_1 lpf=0.047225. The character should now be deep-bass-first; remaining pressure is filter envelope/level recovery, not more static high-band brightness. - User still heard Aqua as kazoo-first. The next missing authority was not
brightness but pitch: DoublePadBass PAD frequency params set
coarse_detune=15360, and Zyn'sgetdetunewraps octave15to-1. Aqua had ignored PAD coarse/fine detune and played both spectral tables at261.6256 Hz; it now emitsfreq=130.8128for both enabled kit layers. - The same pass added explicit
lpf_orderso Zyn analogLP2filters lower to Faustfi.lowpass(2, ...)instead of pretending all low-passes are first order. Latest DoublePadBass: log-mel0.259298, score0.370218, centroid ratio1.027115; remaining pressure is loudness/envelope recovery. - 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. AquaSynth now has a general low-pass rate/level envelope
surface (
lpf_env=rl,lpf_start,lpf_rates,lpf_levels) and the Zyn importer mapsFILTER_ENVELOPEinto it. Latest DoublePadBass after this pass: log-mel0.241993, envelope distance0.554658, RMS ratio0.456173, score0.404382. - User then heard the hit level as right but the attack as less sharp, causing
a blare. The old Zyn envelope time conversion was also wrong: Aqua used
linear
dt/127, while Zyn's old envelope time is(2^(dt/127*12)-1)/100. DoublePadBass kit0 attack10is about0.00925s, not0.07874s. The importer now uses Zyn's logarithmic time curve and the PAD gain cap is relaxed only to3.0, not the full raw Zyn volume multiplier. Latest DoublePadBass: log-mel0.211646, envelope distance0.462822, RMS ratio0.511669, score0.450507. - User then heard the shape as right but Zyn still peaking quite a bit louder.
The remaining level delta was batch-wide output calibration, not another
DoublePadBass layer issue: latest pre-calibration PAD RMS ratios were
0.51..0.78. Generated Zyn PAD rebuilds now emitpatch gain=1.6. Latest DoublePadBass: WAV peak0.979against clipped Zyn reference peak1.0, log-mel0.211671, envelope distance0.226563, RMS ratio0.818669, score0.631168. - User accepted DoublePadBass and moved the ear target to Ghost Ensemble:
Aqua over-emphasized upper harmonics and sounded brighter/tinnier than Zyn.
The first missing general authority was Zyn PAD filter note tracking:
freq_track=97lowers Ghost's cutoff at C4 by the Zynlog2(note/440) * trackingrule. 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. AquaSynth now has explicit low-pass Q via
lpf_q/lpqon the filter model. Zyn PAD analog low-passqimports throughexp((q/127)^2 * ln(1000)) - 0.9; Ghost emitslpf_q=0.499021, which Faust lowers throughfi.resonlp(..., max(0.1, lpf_q), 1.0). - Latest Ghost after note tracking + Q:
artifact
artifacts/parity/zyn-upstream-pad-fixtures/0121-ghost-ensemble-20260515T131053271, log-mel0.375637, envelope distance0.363075, RMS ratio1.09995, centroid ratio1.010727, score0.561458. This improves from the post-tracking0.38424log-mel /1.155288RMS ratio, but a table-harmonic diagnostic still shows candidate h8/h10/higher partials hot against the Zyn table. Remaining Ghost pressure is OscilGen/PAD source-table shape, not static filter ownership. - Latest upstream PAD survey after Q kept the accepted batch intact:
DoublePadBass log-mel
0.247729, envelope0.208429, RMS ratio0.887621, score0.650069; Soft Pad log-mel0.316754, score0.6089. - User then heard Ghost as closer but still overly bright in the middle. A
Zyn oracle
harmonicsdiagnostic was added toZynPadReferenceso the exact normalized OscilGen harmonic vector can be dumped before PAD table generation. That proved Ghost's first 32 imported partial ratios already match Zyn's OscilGen output; the h8/h10 glare was not a first-page harmonic extraction bug. - Two tempting cuts were tested and rejected or narrowed: using Zyn's 1024-sample OscilGen base table helped Ghost but regressed the accepted DoublePadBass batch, so it was cut; raising generated OscilGen partial output from 32 to 64 worsened Ghost, so the readable 32-partial cap remains.
- The real Ghost middle-brightness fix was filter lowering ownership: explicit
lpf_qhad accidentally replaced a 4-pole Zyn-style low-pass with a single Faustresonlp, preserving Q but throwing away slope. Faust export now cascades resonant low-pass stages according tolpf_orderwhenlpf_qis present. Latest Ghost: artifactartifacts/parity/zyn-upstream-pad-fixtures/0121-ghost-ensemble-20260515T134050872, log-mel0.369402, envelope distance0.363685, RMS ratio1.054875, centroid ratio1.006808, score0.57229. DoublePadBass remains at log-mel0.247748, envelope0.208433, RMS ratio0.887555, score0.650029. - User accepted Ghost, DoublePadBass, and Soft Pad as nigh-indistinguishable
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 AquaSynth had translated them through a zero-based index and moved the type-13 spike filter from h2 to h3.ZynOscilFilterGainnow preserves Zyn's one-based index, and the upstream sin2x regression asserts h2 dominates h3 by more than 10x. - Latest sin2x after the oscillator-filter index fix:
artifact
artifacts/parity/zyn-upstream-pad-fixtures/0002-sin2x-pad-20260515T140540381, log-mel0.479782(from0.491437), envelope distance0.490113, RMS ratio1.28196, centroid ratio0.998145(from1.227953), score0.430193. The wrong overtone placement is fixed: remaining sin2x pressure is energy concentration/loudness/profile shape, not h3 accidentally wearing h2's jacket. - Zyn PAD harmonic profile lowering also now computes the profile amplitude
multiplier coordinate before width scaling, matching Zyn's
origxbehavior. It was effectively neutral for sin2x because that preset's width is near full, but the ownership is now faithful to the source formula.
Completed this slice:
- Added PAD spectral-cloud syntax attached to named layers:
spectrum layer=pad_low root=130.8128 spread=.012 partials=1:.07,1.5:.052. - The parser preserves each bank as
SpectralBankmodel data.PadSynthWaveformnow generates each bank as a PADsynth-style FFT table: frequency-domain harmonic spreading, deterministic random phase, one inverse FFT, and normalization. Faust export emits that staticwaveform/rdtablesource before applying the normal voice treatment path.root,spread, andpartialsare authoring-time table shape, not runtime controls. - Converted the Zyn PAD texture rebuild from individual PAD body voices to two
spectral banks under
pad_lowandpad_high; the air/noise layer remains a normal voice. - This is not full Zyn PAD engine parity across every harmonic profile, 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\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --filter "FullyQualifiedName~SpectralBank|FullyQualifiedName~ZynStyleReferenceRebuildsParseExportAndDeclarePressure|FullyQualifiedName~BuiltInReferenceScriptsParseAndExportFaust": 4 passed. - Wavetable replacement verification:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 94 passed. - FFT table generator focused verification:
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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 94 passed.
Previous slice:
- Promoted staged rate/level envelopes to normal voices and layer defaults.
Voice fields now accept
env=rl rates=... levels=... curves=... gate=...; the model storesVoice.RateLevelEnvelope, and Faust emission usesrl4_envfor those voices. - Converted Zyn PAD texture and vocal-layer rebuilds to use staged envelopes through named layers. This gives two non-additive targets asymmetric envelope contour authority without inventing a new parser.
- 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\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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 91 passed.
Previous slice:
- Added additive harmonic-bank syntax attached to named layers:
harmonics layer=body root=220 partials=1:.16,2:.075. - The parser preserves each bank as
HarmonicBank/HarmonicPartialmodel data, then lowers the partials into ordinary voices so Faust output remains inspectable. - Converted the Zyn additive lead rebuild from repeated partial voices to two
named banks under
bodyandshine. - 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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 90 passed.
Previous slice:
- Added Zyn-driven language golf through
layerdeclarations. A layer owns name, engine tag, optional MIDI key range metadata, default gain, and an effect-send label, then lowers to ordinary voices for now. - Converted the three Zyn-style rebuilds to use named layers:
additive
body/shine, PADpad_low/pad_high/air, and vocalair/body/breath. - This is an ownership scaffold, not hidden PAD/free-envelope/effect machinery. 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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 88 passed.
Previous slice:
- Hardened
ZynInstrumentReaderagainst the real upstream Zyn instrument bank: it now tolerates leading whitespace before XML declarations and counts only actualFORMANT_FILTER/FILTERblocks instead of all internal formant/vowel nodes. - Added
ZynInstrumentSurveyto rank.xizdirectories by feature pressure. The non-vendored upstream bank scan parsed1358/1358files atzynaddsubfx/instrumentscommite9f64a9. - Added
docs/zynaddsubfx-pressure-survey.md. Worst observed target:olivers-100/0032-Drum Kit.xizwith 16 enabled kit items, mixed ADD/SUB/PAD engines, 106 envelopes, 25 free envelopes, 73 LFOs, 37 filters, and 3 formant filters. - 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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 86 passed.
Previous slice:
- Added first Zyn-style AquaSynth rebuilds for the project-authored additive
lead, PAD texture, and vocal/formant layer fixtures. They live in
BuiltInScriptsandReferenceRebuildCatalog.ZynRebuilds. - The rebuild tests parse/export every Zyn script and compare matched feature claims against source fixture features where the same feature name exists.
- Current missing abstractions from this first Zyn pass: terse additive harmonic-bank syntax, a PAD/spectral source authority, free envelopes for 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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 83 passed.
Previous slice:
- Started the ZynAddSubFX phase and stopped treating DX7 as the active trench.
- Added
ZynInstrumentReaderfor.xiz-shaped XML. It reads plain XML and gzip-compressed XML, extracts instrument metadata and kit items, and emits neutralReferencePatchfeatures. - Added project-authored Zyn fixtures under
tests/AquaSynth.Dsl.Tests/Fixtures/ZynAddSubFX/ProjectAuthoredinstead 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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 81 passed.
Previous slice:
- Addressed the remaining
ANLGSYN 1beat as DX7 pitch-LFO pressure, not amplitude-LFO pressure. Rawanalog1.syxbytes showAMD=71but every operator hasAMS=0; the active path isPMD=32,PMS=1, sine LFO speed38, and delay33. - Added first-class operator-graph vibrato syntax:
opgraph ... vibrato=<depth> vibrato_hz=<hz> vibrato_delay=<seconds>. Faust lowering modulates the graph frequency with a faded LFO onset instead of a hard delay gate. - Lowered DX7 pitch LFO for the public-domain probe through that graph vibrato
surface. Latest
ANLGSYN 1metrics with the beat present: score.697885, log-mel.19496867, envelope.15124573, zero-crossing.9430519. - Tested and cut the earlier operator-tremolo direction for this target. It was
the wrong authority because ANLGSYN's operator
AMSvalues are all zero.
Previous slice:
- Reframed the latest ear report as envelope pressure, not harmonic pressure:
{ Mooger }needs a more aggressive attack contour;MELLOWSOLOneeded a smoother captured tail;RES SYNTH1still has a phase-like attack-modulation issue even though oscillator sync is enabled. - Extended only the
MELLOWSOLOpressure render from1.0sto1.25sso the existing0.6srelease after a0.65sgate is not chopped by the artifact boundary. Latest pressure metrics improve to score.5722256, log-mel.3472474, RMS.9883968. - Tested and cut a global traced-release-duration change. It shortened releases
too aggressively and broke PRC,
Piano Bass,RES SYNTH1, andANLGSYN 1; release duration remains part of the broader DX7 envelope model pressure. - Verified with bundled Python/dexed-py:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 76 passed.
Previous slice:
- Listening split the latest community set again:
Piano Bassis currently the anchor and should not be disturbed;ANLGSYN 1andRES SYNTH1were blowing out into drone at the modulator peak;{ Mooger }andMELLOWSOLOstill have overtone-emphasis issues. - Added scoped modulator peak headroom in the DX7 probe lowering:
algorithm-2 non-carrier applied envelopes cap only Level1 at
.92.Piano Bassremains unchanged;RES SYNTH1improves to score.8140223, log-mel.12369786, envelope.06489321;ANLGSYN 1keeps log-mel.19461302and sustained high-band evidence but aggregate score drops to.6980632, so its score gate is now.69. MELLOWSOLOnudges to log-mel.42906323, score.55206907, but remains a pressure artifact, not passing parity.- Tested and cut a wider summed-route headroom rule for
{ Mooger }(5.25/5.75for three-source sums). It worsened Mooger log-mel/envelope 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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore --filter "Dx7SysExTests|PublicDomainDx7MoogerAndPianoBassMeetRenderedParityWhenInstalled|PublicDomainDx7AnlgSyn1KeepsBuzzingModulationWhenInstalled|PublicDomainDx7MellowSoloWritesPressureWavsWhenInstalled|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled": 28 passed.
Previous slice:
- Listening report split the remaining DX7 mismatch:
RES SYNTH1mostly needed a harder attack,ANLGSYN 1still smells like missing LFO/operator attack behavior, andMELLOWSOLOis the clearest harmonic mismatch. - Fixed two note-dependent DX7 lowering gaps:
- operator key-scaling now uses the effective played MIDI note after voice transpose instead of hardcoded MIDI 60;
Dx7SysEx.OperatorRateScalingnow feedsApproximateAppliedRateLevelEnvelope/TraceInterpolatedEnvelope.
- Kept graph gain as loudness authority after the scaling change:
Piano Bassmoved from.90to.72. - Added
PublicDomainDx7MellowSoloWritesPressureWavsWhenInstalled; it writes listening artifacts but only gates as pressure (log-mel <= .45, score>= .5) because it is not passing parity by ear. - Cut a tempting output-level-dependent envelope trace experiment. It looked
more Dexed-shaped on paper, but worsened
MELLOWSOLOandANLGSYN 1, so it does not belong in the live machine yet. - Focused verification with bundled Python/dexed-py:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore --filter "Dx7SysExTests|PublicDomainDx7MoogerAndPianoBassMeetRenderedParityWhenInstalled|PublicDomainDx7AnlgSyn1KeepsBuzzingModulationWhenInstalled|PublicDomainDx7MellowSoloWritesPressureWavsWhenInstalled|PublicDomainDx7PrcSynth1WritesListeningWavsWhenInstalled": 28 passed.
Previous slice:
- Corrected DX7 ROM COM handling after user listening caught that the no-compensation probe had closer harmonics across the community patches and was mainly too quiet.
Dx7SysEx.OperatorOutputCompensationnow returns unity. Loudness recovery moved to graph gain instead of hidden carrier boosts.- Community parity gains with COM disabled:
{ Mooger }.75,Piano Bass.90,RES SYNTH1.75. RES SYNTH1is now in the passing community gate. Latest metrics: score.7277295, log-mel.1461968, envelope.10764466, RMS.941083, zero-crossing.1.1022931.DX1 LEAD BandMELLOWSOLOsound closer by ear with COM disabled and graph gain restored, but still fail numeric gates. Latest survey:DX1 LEAD Bscore.45156077, log-mel.43533683, RMS.8193191;MELLOWSOLOscore.5359293, log-mel.39420125, RMS.99559265.- Verified with bundled Python/dexed-py:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 74 passed.
Previous slice:
- Fixed the remaining
ANLGSYN 1drift that listening caught after the conditional output-clip pass. The old candidate still lost 2.5-5 kHz energy midway through the note. - Added
sustainFloortoDx7SysEx.ApproximateAppliedRateLevelEnvelopeand uses a.9floor for max-feedback source operators in the DX7 probe lowering. This keeps the self-feedback source driving the loop after the attack instead of sagging intodeeooh. - Added a sustained 2.5-5 kHz band-energy parity gate for
ANLGSYN 1; the old candidate was around.175at the sustained check, while the new lowering is above1.0. - Raised
Piano Bassgraph gain to.30; latest metrics: score.7552858, log-mel.16204594, envelope.06413663, RMS.9909909. - Fresh
ANLGSYN 1: score.7245976, log-mel.18460114, envelope.119950555, RMS.97143364, zero-crossing.97149533. - Verified with bundled Python/dexed-py:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 74 passed.
Earlier slice:
- Tightened
ANLGSYN 1after listening caught thedeeoohfailure: the max-feedback candidate had a better attack but lost sustained buzz midway. - Added conditional output nonlinearity in the DX7 probe lowering:
soft_clip=trueonly when a voice has DX7 feedback7and a self-feedback topology. PRC stayssoft_clip=false. - Fresh
ANLGSYN 1: score.70946133, log-mel.18456098, envelope.10628832, RMS.9816304, zero-crossing.8657629, centroid.95726264. - Fresh PRC after the conditional clip gate: score
.7546429, log-mel.13874851, envelope.067291394, RMS.99121606, zero-crossing.95325506.
Earlier slice:
- Retuned DX7 max-feedback lowering for
ANLGSYN 1. Route-index sweeps did not materially improve the missing high-band buzz; hotter feedback did. - Changed only feedback value
7from.66to2.2. Feedback value5remains.19, so the hard PRC target keeps its existing feedback amount. - Fresh
ANLGSYN 1withfeedback=2.2: log-mel.17553389, envelope.16478956, zero-crossing.90904, centroid.9519112, score.6448498. This improves spectral buzz while making envelope/RMS less tidy. - Band evidence versus the previous fixed-frequency candidate:
- 1.2-2.5 kHz candidate/reference energy:
.008 -> .656 - 2.5-5 kHz candidate/reference energy: near zero ->
.321
- 1.2-2.5 kHz candidate/reference energy:
- Verified with bundled Python/dexed-py:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 73 passed.
Earlier slice:
- Fixed DX7 fixed-frequency operator lowering after
ANLGSYN 1exposed the missing buzzing modulation. The old lowering treated fixed mode as a fake note ratio, so fixed carriers op1/op3 became0.5ratio against the graph frequency. Dexed treats fixed mode as absolute Hz. - Added
Dx7SysEx.FixedOperatorFrequencyHzusing Dexed's fixed-mode log-frequency formula and changedOperatorFrequencyRatioto returnfixedHz / graphFrequencyfor fixed operators. - Fresh
ANLGSYN 1candidate now lowers fixed op3 to ratio.009227and op1 to.007615againstfreq=130.8128, instead of flattening both to.5. - Added
PublicDomainDx7AnlgSyn1KeepsBuzzingModulationWhenInstalledwith focused gates. Latest metrics: log-mel.19427659, envelope.14924917, zero-crossing.94662774, centroid.9182808, score.659334. - Verified with bundled Python/dexed-py:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 73 passed.
Previous slice:
- Fixed the
Piano Bassoctave bug. The parsed voice hastranspose=12; the old generated AquaSynth script hardcodedfreq=261.6256, so it rendered an octave too high.Dx7SysEx.NoteFrequencyHz(midiNote, transpose)now treats transpose24as neutral and transpose12as one octave down. Dx7VoiceProbeScriptnow uses the voice transpose for graph frequency and for the detune note basis. FreshPiano Bassartifact emitsfreq=130.8128.- Narrowed the community parity gate to the two voices we can currently defend:
{ Mooger }and fixedPiano Bass.ANLGSYN 1,RES SYNTH1,DX1 LEAD B, andMELLOWSOLOremain pressure, not passing parity. - Fixed
Piano Bassmetrics: log-mel.16180529, envelope.13544041, zero-crossing.905511, score.64267576. - Verified with bundled Python/dexed-py:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 71 passed.
Previous slice:
- Added
PublicDomainDx7AnalogCommunityVoicesMeetBroadRenderedParityWhenInstalled, which renders actual public-domainanalog1.syxcommunity voices through Dexed and the current AquaSynth DX7 lowering. Kept four broad parity voices:ANLGSYN 1,{ Mooger },Piano Bass, andRES SYNTH1. - The test writes WAVs/reports under
artifacts/parity/dx7-community-analog1/<voice>/and gates log-mel<= .3, envelope distance<= .16, and score>= .5. - Latest kept-voice metrics:
ANLGSYN 1: log-mel.25955316, envelope.12271979, score.5709625{ Mooger }: log-mel.23776375, envelope.07168135, score.66662127Piano Bass: log-mel.19985504, envelope.14781862, score.5205584RES SYNTH1: log-mel.22371109, envelope.109231755, score.54040927
- First survey also tried
DX1 LEAD BandMELLOWSOLO; they were excluded 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:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 70 passed.
Previous slice:
- Added two split project-authored DX7 algorithm-8 rendered parity probes:
ProjectAuthoredDx7AlgorithmEightCascadeProbeMeetsParityWhenInstalledfor6 -> 5 -> 3, andProjectAuthoredDx7AlgorithmEightSummedPairProbeMeetsParityWhenInstalledfor4 + 5 -> 3. - Tightened the existing combined algorithm-8 stack gate now that real metrics
are known. The project-authored probes gate log-mel at
<= .06; latest real Dexed run:- combined stack: log-mel
0.04029555, score0.8664546 - summed pair: log-mel
0.042429477, score0.870778 - cascade: log-mel
0.03811625, score0.9157809
- combined stack: log-mel
- Project-authored DX7 parity tests now write listening WAVs and reports under
artifacts/parity/dx7-project-authored/<probe>/. These split probes are intentionally not part of the patch library: they are useful measuring tools, not pleasant or reusable stock. - Verified with bundled Python/dexed-py:
AQUASYNTH_DX7_PYTHON=<bundled python> dotnet test AquaSynth.sln --no-restore: 69 passed.
Previous slice:
- Added a structured
.aquapatch library underpatches/with:examples/,sfxr/,bfxr/,808/,fm-bell/,wobble-bass/,dx7/, andadvanced/. - Added
patches/library.yamlas the machine-readable index andpatches/README.mdas the folder contract. The library is development source material for stock, reference rebuilds, calibration probes, and patch inspiration, not a shipped package surface. - Exported the existing built-in/reference catalog into
.aquafiles and added the calibratedPRC SYNTH1hard DX7 candidate atpatches/dx7/public-domain/prc-synth1-calibrated.aqua. - Added a test contract: every
.aquaunderpatches/must parse throughPatchScript.Parseand export Faust, while package-boundary tests keeppatches/and.aquafiles out of the NuGet package. - Verified with
dotnet test AquaSynth.sln --no-restore: 67 passed.
Previous slice:
- Increased
Dx7SysEx.SummedOperatorModulationRouteIndexfrom1.6to6.0. 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.218and gates log-mel at<= .12with RMS normalization. - Latest hard
PRC SYNTH1after stronger stack scale and graph gain.25: log-mel0.13874426, envelope distance0.067291506, RMS ratio0.9912135, zero-crossing ratio0.95325506, centroid ratio1.1156512, score0.7546445. - Added
Dx7SysEx.ApproximateAppliedRateLevelEnvelope, which traces the 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 SYNTH1with the applied-envelope lowering. Latest focused run after fixing the peak picker: log-mel0.17186502(was0.24476814), envelope distance0.13057204(was0.43700194), RMS ratio1.0000212, zero-crossing ratio0.7815517, score0.6501268. - Listening note resolved: the prior applied-envelope lowering made op2 rise
late (
0.014 -> 0.613), causing the odd end lilt. The helper now finds the first near-peak before gate, so op2 hits early and decays (0.981 -> 0.843 -> 0.660) like the traced DX7 applied gain. - Extended staged operator envelopes with per-segment curves:
curves=lin,exp,exp,lin. Linear remains the default, and levels can now express deliberate transient overshoot above1instead of clipping away the DX7 evidence. - Added
Dx7SysEx.TraceEnvelope, a DX7 EG microscope that follows the internal rate/level state machine closely enough to expose gain and stage over time. - Added
Dx7SysEx.TraceInterpolatedEnvelope, which traces the gain actually applied by Dexed-style operator rendering: one EG sample per 64-sample block, linearly interpolated across the block. - Added an envelope comparison artifact test that writes
artifacts/parity/dx7-envelope-trace/egstep.csv. The first rows show both DX7 raw state and applied gain: raw jumps to2immediately, while applied gain ramps from.03125to2over the first 64-sample block and remains near1around 20 ms. AquaSynthenv=rlis 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=dx7runtime lowering, then cut it. The trace matched the Pythongraph.pyenvelope but not Dexed plugin audio, so the syntax was not allowed to survive. The durable result is the microscope and the applied-gain trace, not a half-proven model.
Previous slice:
- Added test-only project-authored Dexed patch rendering through
DexedPyRenderer.RenderPatchAsync. It builds adexed.Patchfrom explicit operator specs and renders it without adding any shipped fixture or package surface. - Added an independent project-authored algorithm-8 summed-stack parity test.
This backs the topology-aware route lowering outside the public-domain PRC
patch, so
SummedOperatorModulationRouteIndexis no longer only PRC-shaped evidence. - Cut the attempted DX7 EG exponential level curve again. On an isolated
envelope target, exponential EG levels plus a shorter timing scale improved
shape versus linear levels, but PRC still failed log-mel (
0.2857573at a tuned timing scale). The live lowering stays linear for EG levels until an isolated envelope target passes without harming the hard target.
Previous slice:
- Moved the remaining PRC cascaded-route scalar into a topology-aware DX7 route
helper.
Dx7SysEx.OperatorRouteIndex(topology, edge)now keeps the isolated two-op route scale (6.275) for standalone direct branches and uses the summed/cascaded scale (1.6) for sum edges and direct edges feeding a sum. - The PRC probe no longer owns any private route-index function. Latest focused
run still passes with log-mel
0.24476814, score0.5708394, RMS ratio1.0108943.
Previous slice:
- Added the ratio-detune and algorithm-output-compensation rungs to the DX7
lowering.
Dx7SysEx.OperatorFrequencyRationow applies ratio-mode detune from the Dexed/DX7 note formula, andDx7SysEx.OperatorOutputCompensationmaps ROMCOMvalues relative to the algorithm-32 six-output baseline. - The PRC probe no longer has a carrier-level scale table. It still has a
fenced cascaded-route constant (
1.6) for theop6/op5/op4 -> op3stack; that is now named as the next calibration target, not promoted into core lowering. - Latest PRC run with detune, COM compensation, graph gain
.39, and the fenced cascaded-route probe: log-mel0.24476814, score0.5708394, RMS ratio1.0108943, zero-crossing ratio0.7931764, centroid ratio1.1131053.
Previous slice:
- Completed the feedback calibration rung. Isolated Dexed feedback sweeps fit a
nonlinear AquaSynth feedback table:
0, .01, .02, .05, .10, .19, .38, .66for DX7 feedback values0..7. - Added
Dx7SysEx.OperatorFeedbackAmountand moved the PRC feedback lowering off the oldvoice.Feedback * 0.04constant. PRC barely changed because feedback value5maps to.19, close to the previous accidental.20. The win is ownership: feedback scaling is no longer folklore.
Previous slice:
- Completed the second calibration rung for isolated two-operator FM. A Dexed
sweep fits full-scale DX7 modulation at about
12.55radians. Given the current AquaSynth Faust formula, that maps to an AquaSynth route index of6.275for a full-level modulator. - Added
Dx7SysEx.OperatorModulationRouteIndexand a regression test for the calibrated phase-deviation scale. The hard PRC probe applies that scale only to the isolatedop2 -> op1branch; applying it blindly to the cascadedop6/op5/op4 -> op3stack made PRC worse, which confirms algorithm output compensation is a separate rung. - Latest PRC run with the carrier curve plus isolated-route calibration:
log-mel
0.2526254, score0.44758993, duration ratio0.9927914, RMS ratio0.8931149. The log-mel gate is back to<= 0.255.
Previous slice:
- Wrote
docs/dx7-calibration-plan.mdand referenced it from memory/spine. The ladder is now: single-carrier amplitude, two-op modulation index, feedback scaling, envelope level curve, algorithm output compensation, then hard PRC replay. - Completed the first calibration rung. A project-authored Dexed single-carrier
output-level sweep fits
2^((outputLevel - 99) / 8)for carrier amplitude.Dx7SysEx.OperatorOutputAmplitudenow owns that curve, andApproximateOperatorLeveluses it instead of the old internal-level proxy. - Added tests for the measured output-level curve. The hard PRC probe now gates
log-mel at
<= 0.26while the next rung calibrates modulation index; latest run after the carrier fix: log-mel0.2562075, score0.40430218. - Calibration lesson: the old operator level helper was not a harmless approximation. It made mid-level operators far too loud and let PRC-specific constants compensate for a broken foundation. Next pressure is route/index scaling for isolated two-operator FM.
Previous slice:
- Reoriented the
PRC SYNTH1hard probe around the perceptual metric that matched listening: log-mel distance. The probe now asserts log-mel<= 0.255plus 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, and656Hz. The prior AquaSynth candidate had too little80-160Hz body when based at392, while the corrected DX7 note basis restored the low body but exposed weak mid harmonic structure and high centroid/zero-crossing mismatch. - Current run with bundled Python and Faust: log-mel distance
0.25093183, score0.4135618, envelope distance0.3595946, duration ratio0.992578, RMS ratio1.0658501, zero-crossing ratio0.24567787, centroid ratio1.3291793. - Calibration lesson: the hard target is now a spectral calibration problem. DX7 output/index scaling still needs a real model; aggregate score can move in the wrong direction while log-mel and the ear move in the right direction.
Previous slice:
- Tightened the hard DX7
PRC SYNTH1probe from a "writes WAVs" smoke test to a modest passing parity target: threshold now requires score >=0.60. - The useful cuts were not new syntax. The candidate improved by removing
patch soft clipping, setting the graph base frequency to
392, and boosting theop3carrier branch to compensate the algorithm-8 output/body balance. Global detune and per-edge route damping both made the score worse and were cut. - Current best run with bundled Python and Faust writes timestamped artifacts
under
artifacts/parity/dx7-prc-synth1/<run>/: score0.6057491, log-mel distance0.27658066, envelope distance0.38489524, duration ratio0.98714787, RMS ratio0.9756519, zero-crossing ratio1.0458903, centroid ratio1.093785.
Previous slice:
- Added a hard DX7
PRC SYNTH1rendered parity probe that writes listening artifacts whendexed-pyand Faust are available:artifacts/parity/dx7-prc-synth1/reference-dexed.wav,candidate-aquasynth.wav,candidate.aqua, andreport.txt. - The probe rebuilds
analog1.syxvoice 17 with readable operator graph syntax and stagedenv=rloperator envelopes. It asserts a modest hard-target score floor instead of pretending exact DX7 parity is solved. - Current run with bundled Python and Faust: score
0.4581856, log-mel distance0.26397973, envelope distance0.4109424, duration ratio1.0173812, RMS ratio0.61393267, zero-crossing ratio1.1713804, centroid ratio1.0978767. - Calibration lesson: shortening the naive DX7 EG timing and lowering the graph
base frequency made the candidate much closer. The remaining mismatch is
still gain/timbre calibration, not missing
env=rlsyntax.
Previous slice:
- Added staged operator envelopes for operator graphs:
env=rl rates=.004,.12,.2,.4 levels=1,.7,.25,0. This gives the DSL a readable four-stage rate/level contour without infecting the general ADSR voice envelope model. - Added
RateLevelEnvelopeto the operator model, parser support for readable and compactenv=rlsyntax, Faustrl4_env(...)rendering, and a DX7 helper 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 AquaSynth.sln --no-restore: 53 passed. - Retried the hard
PRC SYNTH1probe 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 calibration remains the next pressure.
Previous slice:
- Added
Dx7OperatorLevelApproximation, which distills DX7 operator output level plus key/velocity scaling into a normal AquaSynthlevel=-style value. This remains DX7 reference-import knowledge, not a generic DSL feature. - Retried
PRC SYNTH1with 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 AquaSynth.sln --no-restore: 50 passed.
Previous slice:
- Tried the harder
analog1.syxvoice 17,PRC SYNTH1(algorithm 8). The 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 AquaSynth.sln --no-restore: 49 passed.
Previous slice:
- Added the first thresholded DX7 rendered-audio parity rebuild:
BuiltInScripts.Dx7StylePublicDomainMcMm53maps public-domainanalog1.syxvoice 13,MC-MM 5-3, to a terse AquaSynth sine patch. - Added
PublicDomainDx7McMm53MeetsFirstRenderedParityThresholdWhenInstalled, which renders the DX7 reference throughdexed-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. - This is behavioral parity for a simple sine-like rendered voice, not exact 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 AquaSynth.sln --no-restore: 48 passed.
Previous slice:
- Added a public-domain DX7 SysEx fixture from Musical Artifacts artifact 152:
tests/AquaSynth.Dsl.Tests/Fixtures/Dx7/PublicDomain/analog1.syx, with provenance and SHA-256 recorded beside it. - Added a test-only
dexed-pyreference renderer. It usesAQUASYNTH_DX7_PYTHONwhen set, otherwise probespy,python, andpython3; ifdexed-pyis absent, the render test returns without turning optional tooling into a hard dependency. - Added a
.nupkgboundary test that packsAquaSynth.Dsland 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 AquaSynth.sln --no-restore: 47 passed.
Previous slice:
- 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 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 AquaSynth.sln --no-restore: 44 passed.
Previous slice:
- Added
Dx7EnvelopeApproximation, which lowers a DX7 four-rate/four-level EG to a labeled AquaSynth ADSR approximation plus gate duration. - Reference rebuilds now record
operator_envelope_approximationas matched pressure andoperator_envelope_exactnessas still missing. - Doctrine now states that DX7 EG approximation is not exact DX7 envelope execution.
- Verified with
dotnet test AquaSynth.sln --no-restore: 43 passed.
Previous slice:
- Added field-site parameter binding for readable operator graph authoring:
graph gain/note fields, operator ratio/level/feedback/envelope fields, and
route index fields now accept
@/param. - Operator graph Faust emission now substitutes bound parameter expressions at
the exact
/opgraphs/...field paths. - Fixed AD operator envelope binding to use
/env/decayfor the second AD value, matching the ADSR model instead of calling it release by accident. - Verified with
dotnet test AquaSynth.sln --no-restore: 42 passed.
Previous slice:
- Added a patch-level
Playbackcontract forOneShot,Mono, andPolyplayback with Faust MIDI polyphony settings. instrument midi=true polyphony=8now lowers to Faust's standard[midi:on][nvoices:8]option andfreq,gain,gatecontrols.- Host/MIDI playback no longer emits per-voice
/voices/0/note/frequencyand/voices/0/note/gatecontrols; Faust architecture owns allocation. - Verified with
dotnet test AquaSynth.sln --no-restore: 41 passed.
Previous slice:
- Split note timing from envelope shape.
Notenow owns frequency, one-shot gate duration, and host/MIDI source;Envelopenow owns ADSR shape: attack, decay, sustain level, and release. - SFXR sustain duration now maps to
Note.GateSeconds; SFXR punch maps to a lower ADSR sustain level plus voice gain compensation during import/legacy parsing. - 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 ontosustain_level=. - Verified with
dotnet test AquaSynth.sln --no-restore: 40 passed.
Previous slice:
- Replaced the DX7 algorithm-8 authoring surface with readable operator graph
syntax:
operator,route, andcarrierdeclarations. - Added
env=ad:attack:decayandenv=adsr:attack:decay:sustain:releaseenvelope 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 AquaSynth.sln --no-restore: 36 passed.
Previous slice:
- Added a first-class
OperatorGraphmodel with operators, modulation edges, carriers, graph gain, and operator feedback. - Added
opgraphpatch-script syntax. Example:opgraph name=core freq=330 carriers=1,3 ops=6:4:.9,5:3:.8,4:2:.7:.18,3:2:.6,2:1:.75,1:1:.82 edges=6>5:1.1,5>3:.9,4>3:.75,2>1:.85 - Faust emission now mixes operator graphs alongside normal voices.
- 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 AquaSynth.sln --no-restore: 35 passed.
Earlier rebuild slice:
- Added
ReferenceRebuildandReferenceRebuildCatalogfor explicit reference-target rebuild attempts. - Added two DX7-style AquaSynth DSL rebuilds:
dx7/algo32-additive-organ: algorithm 32's six-carrier additive shape, 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 express6->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 AquaSynth.sln --no-restore: 34 passed.
Earlier topology slice:
- Added DX7 algorithm topology metadata for algorithms 1-32 using Ken Shirriff's reverse-engineered OPS algorithm ROM table.
Dx7SysEx.AlgorithmTopologynow exposes carrier operators, modulation edges, feedback-register writers, direct self-feedback operators, delayed-feedback targets, and raw ROM steps.Dx7Voice.Features()now emitscarrier_operators,modulation_edge_count,feedback_sources, andself_feedback_operators.- Representative tests cover algorithm 8, algorithm 16, and algorithm 32.
- Verified with
dotnet test AquaSynth.sln --no-restore: 31 passed.
Earlier slice:
- Added
Dx7SysExrecords and parsing for DX7 voice edit buffers, packed 128-byte voices, and packed 32-voice SysEx banks. - Extracted six operators, envelopes, algorithm, feedback, oscillator sync, pitch envelope, LFO, transpose, and voice name into neutral DX7 records.
- Added
Dx7Voice.ToReferencePatchand 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 AquaSynth.sln --no-restore: 28 passed.
Parameter slice:
- Added explicit
PatchParametercontracts: stable path, label, default, min, max, step, unit, automation-rate notes, and notes. - Added neutral
ReferencePatch,ReferenceSource, andReferenceFeaturecontracts with provenance/license/hash-ready fields. - Added
paramscript declarations and duplicate parameter path validation. - Updated Faust emission so declared parameters produce smoothed
hslidercontrols. - Implemented Option B parameter binding: numeric fields may reference declared
parameters with
@/path, for examplelpf=@/macro/brightness. The parser records an exact field binding such as/voices/0/filter/lpfand keeps the 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 AquaSynth.sln --no-restore: 23 passed.
Next likely slice:
- Refine operator graphs with parameter bindings inside graph fields and decide how host MIDI note age/retrigger semantics should be represented beyond the current frequency/gate controls.
- Keep tests focused on structure first, then add rendered audio comparison once the render path is explicit.
2026-05-31 song-scene evidence slice:
patternandscalepatch-script sugar are live. They create the backing parameter when needed and lower to hold-loop control curves, giving song workers Strudel-ish rhythmic/pitch controls without inventing parser magic.- Song snippet challenges now default to 30 seconds in the swarm harness, can assign random album sources per agent, and prepare a separate seeded challenge for each agent.
song-preparewrites target analysis artifacts:logmel-spectrogram.csv,logmel-band-stats.csv,rms-envelope.csv,rms-envelope-autocorr.csv, andanalysis.md.song-scoreupserts those artifacts into the.ccstore as typedSongChallengeEvidenceDocumentrecords and adds target metrics pluscultmesh://aquasynth/song-challenge-evidence/...artifact URIs to each result. Qdrant indexing now creates evidence chunks from those database records as well as trial summaries.- Smoke proof:
artifacts/parity/song-snippet-smoke/cultmesh-evidence/song-trial-results.cchas one scored candidate, five target evidence docs, six Qdrant chunks, and a search hit whose vector chunk is the song challenge analysis report. - Follow-up fix: full target evidence remains in
.cc, but Qdrant chunks now carry bounded excerpts with content hash/size metadata so the semantic organ does not try to embed multi-megabyte spectrogram CSVs as single documents. - Full album swarm proof:
artifacts/parity/song-snippet-swarms/20260531T031003707completed 3 passes x 5 agents x 30-second random album clips. Final store has 15 trials; final vector index has 90 chunks. Best cosine by pass: 0.434277, 0.590958, 0.502573. Best overall wasagent_04__shard_vowel_lead__bright_dust_grid_v2; strongest repeated pattern is bright formant/vowel lead plus clocked dust/noise grid. - Listening correction: those clocked dust/noise grids still sit on persistent
broad white hiss. Added
texture/noise_textureDSL sugar so air, dust, codec, room, and tape/vinyl noise are owned as gated, band-shaped scene roles. Future agents should not use full-duration rawwave=noisebeds for recording color. - Source corpus widened one folder up:
run-song-snippet-trial-swarm.ps1defaultsSourceFoldertoD:\Music\Reinier\Heyokaand recursively discovers supported audio files. Current local corpus is eight tracks acrossGate Code,Mandelbass, andMarklar.
2026-05-31 paired song-curriculum slice:
- Corrected the swarm contract: each agent receives two independent song challenges and must write one patch for each target. The point is not one blended answer; the point is to train the evidence substrate so a future zero-shot audio-production agent receives better context from CultCache and Qdrant.
- The dataset is now explicitly on trial. Patch files, hypotheses, challenge evidence, metrics, and evaluator/distiller output are curriculum material; individual patches are sample data and witnesses.
run-song-snippet-trial-swarm.ps1now accepts-SongsPerAgent, writesagent-XX/target-YY/challenge.json, expects patches underproposed-patches/agent-XX/target-YY, scores every target separately, and runs a distillation pass after each swarm pass.IpaTrialWorker distillwrites a pruned.ccstore plusSongTrialDistillationDocumentrecords summarizing reusable scene roles, transfer rules, failure patterns, kept trials, dropped noise, and aggregate metrics.- Semantic retrieval now indexes distillation documents as chunks linked to kept scored trial IDs, so the search merge can project distilled lessons into the next agent context instead of dropping them as orphan curriculum prose.
- One paired-curriculum pass completed at
artifacts/parity/song-snippet-swarms/20260531T074935298: five agents, two targets each, ten scored patches, ten challenge evidence bundles, sixty Qdrant chunks, and a distilled.ccstore. All ten verdicts werepressure; best log-mel cosine was0.502128, mean0.377955, worst0.27853, mean audio score0.339432. - Distillation kept all ten trials and summarized reusable roles as clocked dust/hat texture plus rubber/sub bass. That is useful but still not victory: the scene-noise lesson remains that background/recording color must be a shaped role owner, not static hiss.
2026-05-31 two-pass song playlist slice:
- Added per-pass playable playlist output to
run-song-snippet-trial-swarm.ps1. Each pass writestop-scoring-candidates.m3uandtop-scoring-candidates.md, ranked by log-mel cosine over candidates that actually rendered a WAV. - Scoring now keeps the swarm alive when an agent writes invalid Aqua syntax:
invalid parse/lowering/render preparation becomes a
render-failedtrial withcandidate_invalid/render_failedmetrics instead of aborting the curriculum pass. This was forced by an agent writing illegalwave=pulse. - Completed a two-pass run at
artifacts/parity/song-snippet-swarms/20260531T084455803. Pass 1 produced 10 trials, 8 playable candidates, best cosine0.386098, playable mean0.220027, and 2 render-failed syntax casualties. Pass 2 used distilled pass-1 evidence, produced 10 playable candidates, best cosine0.502435, mean cosine0.352907, and 8 pressure verdicts.
2026-05-31 song instrument-owner correction:
- User clarified the "8-bit distress signals" problem is the procedural song scoring/curriculum harness, not only the stock patch catalog. The harness is becoming the music generator's memory feeder through CultCache and Qdrant, so it must store instrument-role evidence, not just log-mel winners.
song-scorenow analyzes every candidate script and recordsinstrument_voice_syrinx,instrument_drum_subtractive,instrument_pad_additive,musical_instrument_score, andchip_distress_riskmetrics in the trial result. Verdict selection and distillation ranking now include this role evidence so simple oscillator blips cannot quietly train the future generator unless they are explicitly useful contrast.run-song-snippet-trial-swarm.ps1now tells agents the role ownership rule: voice-like leads should use syrinx/acoustic source ports with pressure/opening motion; drums/transients should use subtractive pitched bodies plus filtered noise skins; pads/beds should use additive/PADlayer,harmonics, andspectrumbanks. Ordinary voices remain helpers, not the main answer.- Added stock reference patches for
syrinx-voice,subtractive-drums, andadditive-pad, and changedPresets.AquaSynthVoice()to use the syrinx script instead of the old triangle/formant proxy. These are examples for the harness and agents, not a substitute for scoring ownership. - Smoke proof:
artifacts/parity/song-instrument-metric-smoke/smoke/summary.csvrecords a syrinx candidate withinstrument_voice_syrinx=1,musical_instrument_score=0.34, andchip_distress_risk=0.
2026-05-31 full-song iterative harness slice:
song-prepare --duration-seconds 0now means "freeze the full decoded source file from sample zero" instead of a random excerpt.run-song-snippet-trial-swarm.ps1has-FullSongs, keeps the source folder recursive, and widened local audio discovery to.mp3/.wav/.flac/.aiff/.aif/.ogg/.m4a/.mp4. Current Reinier parent corpus discovery sees 2421 supported audio files.- Song challenge analysis now includes
whitened-spectral-autocorr.csv, derived from autocorrelation of a band-whitened log-mel spectral-flux series. This is intended to expose repeating spectral/rhythmic structure after broad tone color is normalized away. song-scorewrites candidate-side render analysis artifacts from Faust output:candidate-analysis.md,candidate-logmel-spectrogram.csv,candidate-logmel-band-stats.csv,candidate-rms-envelope.csv,candidate-rms-envelope-autocorr.csv, andcandidate-whitened-spectral-autocorr.csv. Agents can now inspect their own render with the same feature vocabulary used for the target.- The swarm prompt now requires an in-agent studio loop: each worker must run
five local attempts per target, call
song-scoreon each attempt, read the candidate analysis/comparison artifacts, move timings/filters/gains/sources, and publish only one final.aquaper target to the official output folder. - Verification:
dotnet build tools/IpaTrialWorker/IpaTrialWorker.csprojpassed; zero-pass full-song swarm syntax smoke passed; candidate feature smoke wrote the new candidate autocorrelation and analysis artifacts underartifacts/parity/song-candidate-feature-smoke-2.
2026-05-31 CultCache paged trial-store slice:
- Full-song iterative swarm exposed the storage owner fault: the shared
song-trial-results.ccsingle-file MessagePack store grew to ~2.13 GB and failed at the end of pass 3 withSystem.OutOfMemoryExceptionwhile trying to allocate another whole-store buffer. The issue was not the song agents; it was the backing store treating cold old records as part of every hot write. - CultLib now has
DirectoryMessagePackBackingStore. In directory mode, the.ccpath is a small schema manifest and each record is an individual MessagePack page under<store>.records/.PushAllrewrites changed/deleted records and the manifest only; cold record files keep their timestamps and are not serialized into one giant byte array. CultCacheOpenOptions.UseDirectoryStoreselects the paged store, andCultCacheMessagePack.Create/OpenAsyncautomatically reopen a paged store when the.recordsdirectory exists. AquaSynth trial-result stores now always use directory mode throughIpaTrialResultCultCacheStore, so future song/IPA curriculum runs stop dragging the whole archive through RAM on each upsert.- Verification: CultLib
BackingStoreTestspass 14/14, including a cold-record timestamp test; AquaSynthdotnet build tools/IpaTrialWorker/IpaTrialWorker.csproj --no-restorepasses; AquaSynth--filter CultCachetests pass 7/7.
2026-05-31 producer-apprenticeship admission slice:
- User listening exposed a second owner fault after composition sugar: agents could still converge on the same voiced burst plus static/noisy weak percussion because syntax, activity, and broad role names were still enough to become ranked curriculum pressure.
song-scorenow analyzes a production profile beside the instrument and continuity profiles: required studio document coverage, producer musicianship score, composition section score, template loop risk, noise-percussion risk, and Aqua gap count.music-distillnow promotes candidate-pattern and role doctrine only from rendered rows that clear the producer/curriculum gate. Missing producer evidence, high template-loop risk, high noise-percussion risk, and weak-slop verdicts become failure-mode documents instead of reusable examples.run-song-snippet-trial-swarm.ps1is redirected from parity-worker posture to producer apprenticeship: each agent must writeproducer-brief.md,listening-journal.md,aqua-gap-ledger.md, andstudio-lesson.md, and use the self-iteration loop as a listening/revision record rather than a metric casino.
2026-06-01 Qdrant music retrieval and curator slice:
- The old music-production "semantic" injection was lexical keyword matching over short summaries. It is no longer the swarm path.
music-indexnow embeds fullMusicProductionKnowledgeDocumentpackets into Qdrant collectionaquasynth_music_production_knowledge;music-searchdefaults to Qdrant/Ollama retrieval and emits full owner, summary, transfer rules, AquaSynth patterns, failure modes, vector score, and retrieved chunk text. Lexical fallback is only an explicit debugging escape hatch.- After each musician phase,
run-song-snippet-trial-swarm.ps1starts a dedicatedknowledge-curatoragent. Its only output isknowledge-curation.md, with novel actionable entries, evidence paths, owner sentences, current AquaSynth lowering, and rejected-copy notes. music-distillingests those curator files ascurator-distillationdocuments, then the pass indexes the resulting.ccinto Qdrant before the next phase uses it.
2026-06-01 manual/textbook music curriculum slice:
- Added repo-native manuals under
docs/music-production-knowledge/:aqua-dsp-usage-manual.mdandopen-music-theory-production-distill.md. music-distillnow ingests those manuals asmanualknowledge documents in every fresh music.cc, so musician agents retrieve AquaSynth DSP usage, music theory, arrangement, groove, harmony, melody, production, and failure modes before prior-run candidate pressure.- Smoke proof:
artifacts/parity/manual-knowledge-smoke/20260601T001932produced a 16-document knowledge store with 2 manuals, indexed it into Qdrant, andmusic-searchretrieved the AquaSynth DSP manual withretrieval: qdrant-ollama.
2026-06-01 cumulative music knowledge store correction:
- User caught that
music-distillshould not reseed theory/manual documents after every pass. The swarm now creates one loop-levelmusic-production-knowledge.cc, seeds it once with manuals, indexes that base store, and keeps using that store for all pass retrieval. - After each pass,
music-distillruns with--input-storeequal to the loop-level store,--learned-only true, and--include-manuals false, so it appends/upserts worker/curator/candidate/failure evidence without rewriting the manual spine. - Added
music-intelligence-source-map.mdas a third manual: Every Noise is genre-vocabulary context, Echo Nest is dead, Spotify audio features are not a usable training substrate, AcousticBrainz is historical, and local Essentia-style extraction is the preferred signal path.