Skip to content

cucuwritescode/adac

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ADAC

Automatic Differentiable Audio Compilation

Python 3.10+ License: MIT Tests Status

from differentiable audio research to efficient real-time DSP


the problem

researchers design and optimise audio processors in differentiable frameworks such as FLAMO, but deploying them as real-time plugins requires manual reimplementation. this is error-prone and creates a gap between research prototypes and usable tools. the worked example throughout is the feedback delay network (FDN), which exercises every part of the compiler.

before:   FLAMO model (PyTorch)  →  ???  →  real-time plugin
                                     ↑
                                manual rewrite

after:    FLAMO model (PyTorch)  →  adac  →  FAUST  →  plugin

how it works

┌──────────────┐       ┌──────────────┐       ┌──────────────┐
│    FLAMO     │  ───▶ │     JSON     │  ───▶ │    FAUST     │
│    model     │  ◀─── │    config    │       │    code      │
│  (PyTorch)   │       │              │       │   (.dsp)     │
└──────────────┘       └──────────────┘       └──────────────┘
       flamo_to_json() ──▶     json_to_faust() ──▶
       json_to_flamo() ◀──
         ╰───────────── flamo_to_faust() ──────────────╯

the pipeline traverses a FLAMO model graph, extracts all parameters (delays, gains, matrices, filters), serialises them to a JSON intermediate representation, and generates valid FAUST DSP code. extraction is map-aware: matrix types with non-identity maps (orthogonal, hadamard, householder) serialise the effective matrix the model applies, with the raw trainable weights preserved for round-tripping. json_to_flamo reconstructs the original model from the config.

on top of the codegen core:

  • HotReload republishes the model to a running FAUST plugin during training, so you hear the optimisation while it runs
  • macro-controls (rt60, dry_wet, pre_delay) add performance knobs to the generated plugin without touching the trained parameters
  • certify computes a stability certificate for every feedback loop, written as .cert.json next to the .dsp
  • export_juce turns a config into an installed VST3/AU plugin in one call

installation

pip install -e .

for full FLAMO model support (requires PyTorch):

pip install -e ".[full]"

building plugins additionally requires the FAUST distribution and JUCE.

quick start

import adac

#given a trained FLAMO model and sample rate
faust_code = adac.flamo_to_faust(model, fs=48000, name="MyReverb")

#write to file
with open("reverb.dsp", "w") as f:
    f.write(faust_code)

or use the two-step pipeline for inspection:

config = adac.flamo_to_json(model, fs=48000, name="MyReverb")
faust_code = adac.json_to_faust(config, controls={"rt60": True, "dry_wet": True})

hear it while it trains

live = adac.HotReload(fs=48000, name="MyReverb", controls={"rt60": True})
for step in range(n_steps):
    loss = criterion(model(x), target)
    loss.backward()
    optimiser.step()
    live.update(model)
live.update(model, force=True)

the hot-reload CLAP plugin (FAUST interpreter plus file watcher) lives in faust/architecture/clap/. reloads take about 100 ms and knob positions survive them. full script: examples/live_training.py.

ship it

adac.export_juce(
    adac.flamo_to_json(model, fs=48000, name="MyReverb"),
    "exported/", name="MyReverb",
    controls={"rt60": True, "dry_wet": True, "pre_delay": True},
    juce_modules="~/JUCE/modules",
    build=True,
)

one call: FAUST generation, stability certificate, JUCE project, release build, install into the user plugin folders (macOS). the export refuses to build a model whose certificate says unstable or not-certified; pass strict=False to override. full script: examples/export_plugin.py.

certify

cert = adac.certify(config)
print(cert["verdict"])

the criterion is small-gain: the product of per-element spectral norms around each feedback loop must stay below one at every frequency, evaluated on the parameter values as emitted (single precision). verdicts are certified-stable, marginally-stable, indeterminate, not-certified, unstable. a lossless prototype is marginally stable; with the rt60 control it is certified at any knob position.

equivalence

generated FAUST matches FLAMO sample-exactly, direct paths included. the energy decay of the compiled plugin follows the FLAMO reference throughout, and the underlying impulse responses agree to within single-precision arithmetic noise. all four stereo paths match identically; the suite pins them.

the rt60 macro-control on the compiled plugin, measured by Schroeder integration, follows the ideal decay for the slider value:

regenerate the figures with python examples/make_plots.py.

supported modules

FLAMO module FAUST output description
parallelDelay @(n) / de.fdelay integer or fractional sample delays
Gain / Matrix sum-of-products function mixing matrices (hoisted, map-aware)
HouseholderMatrix sum-of-products function emitted as the effective matrix
parallelGain *(g) per-channel diagonal gains
parallelSOSFilter fi.tf2(...) cascaded biquad filters
Series : sequential composition
Parallel , / :> side-by-side or summing
Recursion ~ feedback loops (FDN core)
Biquad / SVF fi.tf2 / fi.svf.* single-channel filters
Shell (unwrapped) FFT wrapper skipped

testing

#unit tests (no external dependencies)
pytest tests/ -q --ignore=tests/integration

#integration tests (requires flamo venv + faust compiler)
pytest tests/integration/ -v

200 unit tests validate the full pipeline: map-aware parameter extraction, delay quantisation, SOS normalisation, gain classification, graph traversal, code generation, macro-control wiring, multichannel arities, hot-reload publishing, certificate verdicts, and export orchestration.

integration tests compare impulse responses between FLAMO (frequency domain) and generated FAUST (time domain) sample-by-sample.

project structure

src/adac/
  codegen/
    flamo_to_json.py     parameter extraction and graph traversal
    json_to_faust.py     FAUST code generation and macro-controls
    json_to_flamo.py     model reconstruction from JSON config
    flamo_to_faust.py    convenience wrapper (both steps)
  hotreload.py           training-time live publishing
  certificate.py         small-gain stability certificate
  export.py              JUCE plugin export
examples/
    live_training.py
    export_plugin.py
    make_plots.py
tests/
    test_flamo_to_json.py
    test_json_to_faust.py
    test_flamo_to_faust.py
    test_param_extraction.py
    test_hotreload.py
    test_certificate.py
    test_export.py
    integration/
        test_ir_comparison.py
        generate_flamo_ir.py

related projects

  • FLAMO — differentiable audio processing framework
  • pyFDN — python feedback delay networks
  • FAUST — functional audio stream

licence

MIT — see LICENSE for details.

About

Automatic Differentiable Audio Compilation: differentiable audio graphs to real-time DSP

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages