Thanks for your interest. Bug reports, DSP contributions and gradient-rule improvements are all welcome.
git clone https://github.com/DBraun/faustax
cd faustax
uv sync
uv run pytestuv sync is enough for the whole test suite. The generated NNX modules are
checked in, so you do not need the Faust compiler to work on Faustax — only
to change a .dsp file or to work on runtime compilation.
The tests that do need Faust are marked needs_faust and skip automatically
when no suitable build is found, so a plain uv run pytest is green either way.
If you expected those tests to run and they skipped, check:
uv run python -c "from faustax.compile import has_nnx_backend; print(has_nnx_backend())"The NNX backend lives in Faust's master-dev branch and is not in a tagged
release yet, so a Faust from Homebrew or apt will not have it. Build from
source:
git clone --branch master-dev --depth 1 https://github.com/grame-cncm/faust
cd faust && make && sudo make installVerify it — faust --version must list DSP to NNX:
$ faust --version
FAUST Version 2.87.0
Embedded backends:
DSP to C
DSP to C++
DSP to NNX
Faustax finds the compiler from FAUST_BIN, then $PATH, and supports both
layouts: a source checkout run out of its build tree
(<root>/build/bin/faust, libraries at <root>/libraries) and an installed
prefix (<prefix>/bin/faust, libraries at <prefix>/share/faust). Point at a
non-default build with:
export FAUST_BIN=/path/to/faust/build/bin/faust-
Write or edit
src/faustax/dsp/<name>.dsp. -
Regenerate the checked-in modules:
uv run python tools/generate.py
Commit the regenerated
src/faustax/_generated/<name>.pyalong with the.dspchange.tools/generate.pyrewrites the compiler's absolute paths to<faust>/<repo>placeholders, so the diff should not contain your home directory. If it does, runuv run python tools/generate.py --scrub-only. -
If the DSP pulls in a Faust library the repo has not used before, refresh the attribution table (see Licensing below).
-
Add a test under
tests/.
Faustax is MIT, but the generated modules and two of the source modules carry
third-party terms. NOTICE is the single place that records all of it, and CI
checks that it stays complete.
-
Adding a
.dspthat uses a new Faust library. The Faust compiler records every library and its per-function license declarations in each module's embeddedjson_metadata. Regenerate the attribution table and updateNOTICEsection 2:uv run python tools/collect_attribution.py # print the table uv run python tools/collect_attribution.py --check # what CI runs
-
Porting an algorithm from another project. Say so in the module docstring, naming the upstream project, its license and its copyright holder, and add an entry to
NOTICEsection 3.src/faustax/ops.pyis the worked example. -
Adding a dependency. Permissive licenses (MIT, BSD, Apache-2.0, ISC) can go in
dependenciesordev. A copyleft dependency must not be a required one; put it in its own optional group and document it inNOTICEsection 4, asdev-fdn/fdn_toolbox(GPL-3.0) is. -
Do not commit dataset audio, or audio rendered from it. CI fails on any committed
.wav,.mp3or.flac.
By contributing you agree that your contribution is licensed under this repository's MIT license.
Formatting and linting are handled by ruff via pre-commit. Install the hooks once and they run on every commit:
uv run pre-commit install
uv run pre-commit run --all-files # or check everything by handThe generated modules under _generated/ are excluded — never hand-edit them.
Beyond what the linter enforces:
- Type hints and Google-style docstrings on public functions.
- Explain what the code does now. Comments describing how it used to work belong in the commit message, not the source.
- Prefer letting errors surface over defaulting them away: raise
RuntimeErrorwith a message that says what to do, rather than silently substituting a fallback value.
uv run pytest # everything that needs no Faust build
uv run pytest -k vectorize # one area
uv run pytest --cov=faustax # with coverageNumerical changes need a test that pins the numbers. The vectorizer in
particular is required to be bitwise-identical to the scalar module; see
tests/test_vectorize.py for the comparison harness.