Architecture¶
A visual overview of how gen-dsp turns a gen~ export (or a Python/JSON graph) into a buildable plugin project. For the prose version and conventions, see the project's CLAUDE.md; for the library API, see the Core API guide.
Pipeline data flow¶
Two front ends feed a single, front-end-agnostic intermediate representation (the Manifest), which every platform backend consumes. The gen~ path is zero-dependency; the graph path requires pydantic.
flowchart TD
subgraph gen["gen~ export path (zero-dependency)"]
E[gen~ export dir] --> P["core/parser.py"]
P --> EI[ExportInfo]
EI --> MB["manifest_from_export_info()"]
end
subgraph graph["graph frontend path (requires pydantic)"]
G["Graph (Python / JSON)"] --> CO["graph/compile.py"]
CO --> CPP["standalone C++"]
CPP --> AD["graph/adapter.py"]
end
MB --> MAN[["Manifest IR<br/>(I/O, params, buffers)"]]
AD --> MAN
MAN --> PG["core/project.py<br/>ProjectGenerator"]
PG --> PROJ["project dir<br/>(templates + manifest.json + .gen-dsp.json)"]
PROJ --> BLD["core/builder.py<br/>Builder"]
BLD --> PB["Platform.build()"]
PB --> OUT([built plugin / firmware])
CLI orchestration¶
cli.py wires the pipeline into subcommands. The graph subcommands are only available when the [graph] extra is installed.
flowchart LR
CLI["cli.py"]
CLI --> INIT["init<br/>(generate project)"]
CLI --> BUILD["build<br/>(compile)"]
CLI --> DETECT["detect<br/>(analyze export)"]
CLI --> MANI["manifest<br/>(emit JSON IR)"]
CLI --> LIST["list<br/>(platforms / boards)"]
CLI --> CACHE["cache<br/>(show / prune SDKs)"]
CLI --> GRP["graph: compile / validate / viz / simulate"]
INIT --> PG["ProjectGenerator"]
BUILD --> BL["Builder"]
GRP -. requires pydantic .-> GP["gen_dsp.graph"]
Platform registry¶
platforms/__init__.py holds PLATFORM_REGISTRY, mapping a string key to a Platform subclass. Adding a platform is a single-module change plus a registry entry. Backends group by build system:
flowchart TD
REG[["PLATFORM_REGISTRY"]]
REG --> CM["CMake + FetchContent"]
REG --> CMX["CMake (Xcode)"]
REG --> MK["Make"]
REG --> EM["Make (emcc)"]
CM --> CM1["au · clap · vst3 · lv2 · sc · max"]
CMX --> CMX1["auv3"]
MK --> MK1["pd · chuck · vcvrack · daisy · circle · standalone · csound"]
EM --> EM1["webaudio"]
Each Platform implements generate_project(), build(), clean(), find_output(), and get_build_instructions(). SDKs for CMake/FetchContent and several Make backends are auto-downloaded into a shared cache.
Header isolation pattern¶
Generated projects keep host-API code and genlib code in separate translation units that never include each other's headers. They communicate only through a small C interface (_ext*.h) over an opaque GenState* pointer, so the genlib sources compile without the host SDK and vice versa.
flowchart LR
API["host-API .cpp<br/>(CLAP / VST3 / ... headers only)"]
H["_ext*.h<br/>C interface · opaque GenState*"]
EXT["_ext*.cpp<br/>(genlib headers only)"]
API -->|"calls"| H
H -->|"implemented by"| EXT