No description
  • HTML 62.5%
  • C# 24.2%
  • Faust 5%
  • JavaScript 3.7%
  • Python 2%
  • Other 2.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Aqua d77f1bc3cb Research note: /t/ closure leak and burst level
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 18:58:47 +00:00
docs Research note: /t/ closure leak and burst level 2026-11-12 18:58:47 +00:00
external Port Pink Trombone reference renderer 2026-05-26 22:20:42 +01:00
patches sfxr explosion + abstract golf: patch repeat no longer cuts the envelope; waivers removed (#36) 2026-11-11 07:30:59 +00:00
research Ground vocal source law research 2026-05-29 00:00:54 +01:00
scripts Share Dings MCP across agent sessions 2026-08-21 21:18:45 +02:00
spikes/faust-aot-thruster spike: README reports 74 of 400000 as a single run's figure 2026-11-07 05:33:49 +00:00
src Tongue-sealed stops close completely and burst at half the gain 2026-11-12 18:41:41 +00:00
state Centralize Dings playback and volume 2026-07-15 01:18:09 +01:00
tests/AquaSynth.Dsl.Tests Tongue-sealed stops close completely and burst at half the gain 2026-11-12 18:41:41 +00:00
tools Stop place: one place table owns the closure index; a non-labial plosive's burst enters the tract at its place 2026-11-12 17:50:15 +00:00
.gitignore Add aqua-feel: headless feel meter and gate; fix PRC SYNTH1 clipping and thruster low-rpm hiss 2026-11-05 15:31:35 +00:00
.gitmodules Port Pink Trombone reference renderer 2026-05-26 22:20:42 +01:00
AGENTS.md Rename project to AquaSynth 2026-05-16 05:49:44 +01:00
AquaSynth.sln Add curated AquaSynth dings MCP service 2026-07-14 01:06:12 +01:00
CLAUDE.md Wire AGENTS.md into Claude Code memory 2026-09-03 22:21:20 +02:00
Directory.Build.props Pin CultLib abd1a92e; [CultRole] audit; ElementId on every list element type (#35) 2026-11-11 08:31:22 +00:00
Directory.Build.targets Pin CultLib 2.0.0 for builds 2026-10-22 19:46:37 +02:00
icon-package.png Refresh AquaSynth icon artwork 2026-05-17 14:11:08 +01:00
icon.png Refresh AquaSynth icon artwork 2026-05-17 14:11:08 +01:00
README.md Lowering: patch repeat restarts pitch and arpeggio, not the envelope; README store-kind rollback note (#37) 2026-11-11 09:27:29 +00:00

AquaSynth

AquaSynth icon

C# patch authoring, analysis, and Faust toolchain for AquaSynth. It parses the .aqua DSL into a serializable patch graph, emits Faust .dsp, and owns the path from patch intent to generated DSP artifacts.

This repo is the C# bridge for AquaSynth/Vortice-land. Rust remains the reference lab; this project is the tool that lets the engine script Faust without dragging the AquaSynth-rs crate into the room by the ankle.

Run

dotnet test

DX7 reference-render tests use dexed-py when a Python with dexed and numpy is available. Set AQUASYNTH_DX7_PYTHON to that interpreter to force a specific runtime; otherwise the tests skip the render path and still parse the vendored public-domain fixture.

ZynAddSubFX is pinned as a GPL test/development reference under external/zynaddsubfx. Initialize it with:

git submodule update --init --recursive

That source is a parity oracle only. AquaSynth does not ship Zyn code, link it from published packages, or treat it as runtime machinery.

Package Boundary

Downstream consumers should pin the NuGet packages from this repo, not use live project references. Breaking synth-library work should happen here freely, then consumers should intentionally update only after new package versions are packed and tested.

dotnet pack src\AquaSynth.Core\AquaSynth.Core.csproj -c Release
dotnet pack src\AquaSynth.Faust\AquaSynth.Faust.csproj -c Release

AquaSynth.Core owns patch meaning: model records, the .aqua parser, authoring helpers, analysis/scoring tools, presets, and Faust source emission. AquaSynth.Faust depends on Core and owns toolchain/rendering work: Faust CLI validation, target-code generation, live patch compilation, native libfaust loading, compile manifests, DSP factory lifetime, and offline/sample rendering.

The test suite verifies that development fixtures, Python render helpers, external reference synth sources, and SysEx banks do not ship in published packages.

Shape

  • PatchScript.Parse(script) lowers terse script into SynthPatch.
  • FaustEmitter.Emit(patch) emits Faust source.
  • FaustCompiler.ValidateAsync(source) compile-checks with Faust when present from AquaSynth.Faust.
  • FaustCompiler.CompileAsync(source, options) writes generated backend code through an installed or resolved Faust compiler from AquaSynth.Faust.
  • FaustCompiler.CompileWebAssemblyScriptAsync(...) and CompileWebAssemblyAsync(...) emit browser-ready .dsp, .wasm, and Faust JSON UI metadata artifacts.
  • AquaSynthPatchCompiler from AquaSynth.Faust is the live host-facing boundary for compiling .aqua scripts into hosted DSP factories.
  • AquaSynthNativeCompiler remains the lower native libfaust compiler machinery behind that boundary.
  • BuiltInScripts.ReferenceScripts() carries readable SFXR, BFXR-flavored, 808, FM bell, wobble bass, syrinx-voice, subtractive-drum, additive/PAD, and advanced layered patches. They are stable references for testing and for judging whether the DSL can express useful sound designs cleanly.
  • SfxrParams, PatchScriptScoring, AudioAnalyzer, and Presets carry the reusable AquaSynth-rs-side analysis, scoring, SFXR, and preset tools.

The authoring/test lane can compile Faust-generated C# for easy .NET rendering and parity checks:

var patch = PatchScript.Parse("""
    voice
        wave=saw
        freq=55
        gain=0.2
        sustain=0.5
        decay=0.2
    """);
var export = FaustEmitter.Emit(patch, new FaustExportOptions("bass"));
await FaustCompiler.CompileAsync(
    export.Source,
    new FaustCompileOptions(FaustTargetLanguage.CSharp, "Generated/Bass.cs"));

The browser lane uses Faust's WebAssembly backend and keeps the same ownership: AquaSynth emits the .dsp, .wasm, and JSON UI description; the host supplies WebAudio scheduling and parameter binding.

await FaustCompiler.CompileWebAssemblyScriptAsync(
    "v w=sin f=880 g=.12 sustain=.04 decay=.2",
    new FaustWebAssemblyCompileOptions("Generated/Web", "ui_select"));

The runtime lane is different. AquaSynth should own Faust toolchain selection, compile cache identity, generated artifacts, parameter manifests, and dynamic patch compilation outside the realtime path. Aquarium Engine should load and host the finished artifact, bind controls, and schedule audio. Native Faust targets are the preferred shipping path when the platform allows them; C# output is convenient authoring machinery, not the ceiling.

AquaSynthPatchCompiler is the live runtime-facing version of that boundary: it owns native libfaust loading policy, script parsing, Faust emission, compile keys, DSP source artifacts, manifests, and compiled products. Engine callers keep their device and scheduling code, and ask AquaSynth for compiled/renderable synth products.

As a Verse service, AquaSynth accepts .aqua DSL and Weksa utterance handoff documents, compiles Faust-native instruments, returns live instrument handles, and exposes control/sample state through CultMesh. See docs/verse-service-contract.md.

See docs/faust-toolchain-boundary.md.

Status

The current center of gravity is the speech-learning lane: structured utterance metadata -> utterance embedding -> synth automation -> vocal-tract/rendered-loss parity. The first proof path uses tiny eSpeak NG fixtures, log-mel evidence, packed C# backprop, and compiled Faust speech controls so many candidate weights can be tested against generated speech references without recompiling topology. The named audible witness for that lane lives at tests/AquaSynth.Dsl.Tests/Fixtures/Speech/WetVoice01/: Weksa-owned structured utterance in, AquaSynth-owned automation/render receipts out, all inspectable enough to diff when the machine mutates.

The modular graph surface, SFXR atoms, DX7/Zyn reference work, script scoring, audio comparison, presets, Faust emission, native Faust compilation/rendering, and installed Faust validation remain active foundations. The broader reference-synth digestion project is paused unless it directly improves the speech harness or render-loss machinery. Migration coverage is tracked in docs/migration-checklist.md, because leaving important things behind in the old repo would be a very efficient way to become our own haunted house.

Reference-driven DSL growth is tracked in docs/reference-synth-roadmap.md. The vocal tract curriculum is tracked in docs/ipa-vocal-tract-roadmap.md, with prior-work notes in docs/utterance-parity-research.md. Agent handoff state lives in state/spine.yaml.

Building against CultLib

Builds are pinned to CultLib revision abd1a92eb24e1af3fc7cdd1bf98a88dbdebc2938 (#91); the build fails if the CultLib checkout differs or is dirty. Create a pinned worktree and point the build at it:

git -C <CultLib> worktree add --detach <path> abd1a92eb24e1af3fc7cdd1bf98a88dbdebc2938
dotnet build -p:CultLibRoot=<path>   # or set CULTLIB_ROOT=<path>

Without an override the sibling ..\CultLib checkout is used and must itself be at that revision.

Stores are one-way, and rolling back can lose data. Since the pin move (#35) list elements carry ids, and a store holding any element id is stamped with a newer header. What an older build does with it depends on the store kind:

  • Single-file stores (header v3 with ids): the patch catalog (patches/aquasynth-patch-cultcache.cc), the speech training store and the daemon store. Pins before cultlib-unity-v2.0.0 / caching-unity-v2.0.0, including NuGet cultlib-v1.0.32, read these without complaint, silently drop the ids, and can rewrite elements without them. Only v2.0.0 and later refuse by name.
  • Directory stores (header v5 with ids): the IPA trial results store (ipa-trial-results.cc, UseDirectoryStore). These are refused by name from cultlib-unity-v1.0.57 / caching-unity-v1.2.0.

So: take a copy of any store before the upgrade and restore from it if you roll back, never write with the new pin and then read with an old one, and upgrade every reader before any writer. Stores written before the move still open; ids are minted on load.