neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
Faust programming language website.
Translation pending
Developer toolsRust · FaustGitHub @grame-cncmOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Functional programming language for signal processing and sound synthesis
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Rust workspace for the Faust compiler port. ⚠️ Experimental — work in progress. faust-rs is a research port of the Faust compiler to Rust. It is not ready for production use, and its APIs and behavior may change at any time. Use cargo run -p xtask -- golden-check-cpp for the long-run C++ parity target when tests/golden/cpp/ is expected to match the current Rust output. The wasm-ffi crate packages the Faust compiler itself as a raw WebAssembly module. This is different from faust-rs -lang wasm, which compiles one Faust DSP to WebAssembly.Read the full README ↗
Rust workspace for the Faust compiler port.
⚠️ Experimental — work in progress. faust-rs is a research port of the Faust compiler to Rust. It is not ready for production use, and its APIs and behavior may change at any time.
# Entire workspace
cargo build --workspace
# Entire workspace (release)
cargo build --workspace --release
# Compiler binary crate only
cargo build -p compiler
# Compiler binary crate only (release)
cargo build -p compiler --release
# Raw Rust compiler module for faustwasm embedded-compiler mode
cargo run -p xtask -- build-faustwasm-compiler-module
Recommended local checks before committing:
cargo check --workspace --all-targets
cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets
cargo run -p xtask -- golden-check
Use cargo run -p xtask -- golden-check-cpp for the long-run C++ parity target
when tests/golden/cpp/ is expected to match the current Rust output.
The wasm-ffi crate packages the Faust compiler itself as a raw WebAssembly
module. This is different from faust-rs -lang wasm, which compiles one Faust
DSP to WebAssembly.
Install the Rust target and run the verified packaging workflow:
rustup target add wasm32-unknown-unknown
cargo run -p xtask -- build-faustwasm-compiler-module
The release module is published as:
target/wasm32-unknown-unknown/release/libfaust-rs.wasm
The workflow builds the module with a 16 MiB WebAssembly stack, renames Cargo's
crate-normalized faust_wasm_ffi.wasm artifact to libfaust-rs.wasm, and
verifies the exported compiler ABI. The equivalent unverified manual build and
rename is:
cargo build -p wasm-ffi --target wasm32-unknown-unknown --release
mv target/wasm32-unknown-unknown/release/faust_wasm_ffi.wasm \
target/wasm32-unknown-unknown/release/libfaust-rs.wasm
A Web host can load libfaust-rs.wasm with the standard WebAssembly API and
call its handle-based faust_wasm_* exports to compile Faust source strings to
DSP WebAssembly and JSON artifacts. See the
wasm-ffi guide for the raw allocation, result,
and lifetime contract, plus options for embedding Faust libraries.
libfaust-rs from C and C++A host reaches the compiler through one of two contracts: the C API of
libfaust-rs, Rust code exported with C linkage that mirrors libfaust's, and
the Rust API of the faust crate, a safe layer over the same entry points.
Which one to bind depends on the language the host is written in:
Rust application, or a binding written in Rust (py-faust-rs, ...) -> faust Rust API
C or C++ application, Cython, cffi, ctypes -> libfaust-rs C API
faustwasm -> wasm-ffi WASM ABI
A binding written in Rust could use the C API too, and would pay for it in
unsafe code, a rebuilt control walk and f32 interpreter samples. The four
layers and these costs are in Embedding faust-rs
(French).
The faust-ffi crate builds one unified C ABI library named libfaust-rs, with
C++ wrappers over the same ABI. It exports the factory and DSP APIs for both the
bytecode Interpreter and the experimental native Cranelift JIT backend:
cargo run -p xtask -- build-libfaust --release
This produces the platform static library (libfaust-rs.a or faust-rs.lib)
and dynamic library (libfaust-rs.dylib, libfaust-rs.so, or faust-rs.dll) under
target/release/. The C++ headers are
crates/interp-ffi/include/interpreter-dsp.h and
crates/cranelift-ffi/include/cranelift-dsp.h; the corresponding C headers are
interpreter-dsp-c.h and cranelift-dsp-c.h in the same directories. The C++
wrappers also use the standard Faust architecture headers, so add the Faust
architecture/ directory to the include path. For example:
c++ -std=c++17 app.cpp \
-I crates/interp-ffi/include \
-I crates/cranelift-ffi/include \
-I /path/to/faust/architecture \
-L target/release -lfaust-rs \
-Wl,-rpath,"$PWD/target/release" \
-o app
Create an interpreter_dsp_factory from a Faust source file or string, create a
standard Faust dsp instance from it, then initialize and process audio:
#include "interpreter-dsp.h"
#include <array>
#include <iostream>
#include <memory>
#include <string>
int main()
{
std::string error;
auto* factory = createInterpreterDSPFactoryFromString(
"gain", "process = _ * 0.5;", 0, nullptr, error);
if (!factory) {
std::cerr << error << '\n';
return 1;
}
{
std::unique_ptr<dsp> processor(factory->createDSPInstance());
if (!processor) {
deleteInterpreterDSPFactory(factory);
return 1;
}
processor->init(48000);
std::array<FAUSTFLOAT, 64> input{};
std::array<FAUSTFLOAT, 64> output{};
FAUSTFLOAT* inputs[] = {input.data()};
FAUSTFLOAT* outputs[] = {output.data()};
processor->compute(64, inputs, outputs);
} // Destroy the DSP instance before its factory.
deleteInterpreterDSPFactory(factory);
}
Use createInterpreterDSPFactoryFromFile(...) to compile a .dsp file. The
Interpreter API also provides readInterpreterDSPFactoryFromBitcodeFile(...)
and writeInterpreterDSPFactoryToBitcodeFile(...) for .fbc files.
The Cranelift wrapper exposes the same dsp lifecycle, so only the header and
factory functions change in the example above:
#include "cranelift-dsp.h"
#include <iostream>
#include <memory>
#include <string>
int main()
{
std::string error;
auto* factory = createCraneliftDSPFactoryFromString(
"gain", "process = _ * 0.5;", 0, nullptr, error, 2);
if (!factory) {
std::cerr << error << '\n';
return 1;
}
{
std::unique_ptr<dsp> processor(factory->createDSPInstance());
if (!processor) {
deleteCraneliftDSPFactory(factory);
return 1;
}
processor->init(48000);
// Use processor->compute(...) exactly as in the Interpreter example.
} // Destroy the DSP instance before its factory.
deleteCraneliftDSPFactory(factory);
}
The final opt_level argument is optional and defaults to 0; values 1 and
2 currently select speed optimization, while values of 3 or more select
speed-and-size optimization. createCraneliftDSPFactoryFromFile(...) is the
file-based equivalent.
crates/faust is the supported way to embed faust-rs from
Rust: one model over the interpreter and the Cranelift JIT, with the lifecycle
of the C API and none of its raw pointers. A Factory is a compiled program,
cheap to clone; Factory::create_dsp_instance(sample_rate) gives a Dsp that owns a
reference to its factory, so it can be stored, moved, sent to another thread
and shared (Send + Sync) with no lifetime parameter and no unsafe on the
host's side. Controls
are addressed by their /group/label paths, as with MapUI and OSC:
use faust::{Backend, CompileOptions, Factory};
let options = CompileOptions { backend: Backend::Cranelift, ..Default::default() };
let factory = Factory::from_source("gain", r#"process = _ * hslider("gain", 0.5, 0, 1, 0.01);"#, &options)?;
let mut dsp = factory.create_dsp_instance(48_000)?;
dsp.set_param_value("/gain/gain", 0.25)?; // or its shortname or label, "gain"
let input = [1.0_f32; 64];
let mut output = [0.0_f32; 64];
dsp.compute(64, &[&input], &mut [&mut output])?;
The methods carry the names of the C++ dsp class (dsp.h) in snake case:
get_num_inputs, instance_init, instance_clear, compute(count, inputs, outputs)... compute accepts f32 or f64 buffers and converts when they
are not the compiled precision: a -double program run over f64 buffers
sees its samples unrounded, on both backends. This crate and the C API
below are the two contracts of faust-rs; the other crates of the workspace are
implementation details and may change without notice.
The C API uses opaque factory and instance pointers and does not require the Faust architecture headers. This complete Interpreter example follows the same factory-before-instance destruction order as the C++ example:
#include "interpreter-dsp-c.h"
#include <stdio.h>
int main(void)
{
char error[4096] = {0};
interpreter_dsp_factory* factory =
createCInterpreterDSPFactoryFromString(
"gain", "process = _ * 0.5;", 0, NULL, error);
if (factory == NULL) {
fprintf(stderr, "%s\n", error);
return 1;
}
interpreter_dsp* processor = createCInterpreterDSPInstance(factory);
if (processor == NULL) {
deleteCInterpreterDSPFactory(factory);
return 1;
}
initCInterpreterDSPInstance(processor, 48000);
FAUSTFLOAT input[64] = {0};
FAUSTFLOAT output[64] = {0};
FAUSTFLOAT* inputs[] = {input};
FAUSTFLOAT* outputs[] = {output};
computeCInterpreterDSPInstance(processor, 64, inputs, outputs);
deleteCInterpreterDSPInstance(processor);
deleteCInterpreterDSPFactory(factory);
}
Compile it against the same unified library:
cc -std=c11 app.c \
-I crates/interp-ffi/include \
-L target/release -lfaust-rs \
-Wl,-rpath,"$PWD/target/release" \
-o app
The Cranelift C API has the same lifecycle with backend-specific names:
| Operation | Interpreter C API | Cranelift C API |
|---|---|---|
| Header | interpreter-dsp-c.h | cranelift-dsp-c.h |
| Factory from string | createCInterpreterDSPFactoryFromString(..., error) | createCCraneliftDSPFactoryFromString(..., error, opt_level) |
| Factory from file | createCInterpreterDSPFactoryFromFile(..., error) | createCCraneliftDSPFactoryFromFile(..., error, opt_level) |
| Create instance | createCInterpreterDSPInstance(factory) | createCCraneliftDSPInstance(factory) |
| Initialize | initCInterpreterDSPInstance(dsp, sample_rate) | initCCraneliftDSPInstance(dsp, sample_rate) |
| Process | computeCInterpreterDSPInstance(...) | computeCCraneliftDSPInstance(...) |
| Delete instance | deleteCInterpreterDSPInstance(dsp) | deleteCCraneliftDSPInstance(dsp) |
| Delete factory | deleteCInterpreterDSPFactory(factory) | deleteCCraneliftDSPFactory(factory) |
Unlike the C++ wrapper, the Cranelift C constructor always takes the
opt_level argument. Returned strings such as factory JSON or serialized
factory data are owned by libfaust-rs and must be released with freeCMemory()
when the corresponding header says so.
When a program does not compile, the C++ wrappers put the compiler's complete
diagnostic in their std::string& error, so the std::cerr << error of the
examples above prints the location, the source line and the suggested fix:
parse failed for gain: errors=1, recoveries=0, diagnostics=1
gain:1:21: error [FRS-PARSE-0001] Parsing error at line 1 column 21. Repair sequences found:
1: Insert RPAR
1 | process = _ : *(0.5 ;
| ^ unexpected token
| ^ `(` opened here
= fix (machine-applicable): insert `)`
the parser found only this insertion repair
In C, error is a buffer the caller allocates and whose size the library is
never told: 4096 bytes, as in libfaust, and it cannot grow without overflowing
existing hosts. It receives the first line above, the summary. The complete text
is read from the library, one function per API:
| Header | Entry points | Complete text of their last error | Its typed form (JSON) |
|---|---|---|---|
interpreter-dsp-c.h | Interpreter factories, expansion, auxiliary files | getCCompleteInterpreterDSPFactoryError() | getCInterpreterDSPFactoryErrorDiagnostics() |
cranelift-dsp-c.h | Cranelift factories, expansion, auxiliary files | getCCompleteCraneliftDSPFactoryError() | getCCraneliftDSPFactoryErrorDiagnostics() |
libfaust-c.h | expandCDSP*, generateCAuxFiles* | getCCompleteDSPError() | getCDSPErrorDiagnostics() |
libfaust-box-c.h | CDSPToBoxes, CboxesToSignals*, CcreateSourceFromBoxes | getCCompleteBoxError() | getCBoxErrorDiagnostics() |
libfaust-signal-c.h | CcreateSourceFromSignals | getCCompleteSignalError() | none: no failure of this API is typed |
char error[4096] = {0};
interpreter_dsp_factory* factory =
createCInterpreterDSPFactoryFromString("gain", source, 0, NULL, error);
if (factory == NULL) {
/* `error` has the summary; the complete text adds the diagnostic. */
const char* complete = getCCompleteInterpreterDSPFactoryError();
fprintf(stderr, "%s\n", complete ? complete : error);
return 1;
}
The contract is the same for the five, and is that of dlerror:
error received, never cut at 4096 bytes, followed
by the rendered diagnostics when the failure came from the compiler; an
error that has none (a missing file, a null pointer, an unsupported target)
is its message;freeCMemory() included;The text is for a person. The typed form of the same failure is the
compiler's diagnostics-v2 JSON report: for each diagnostic its code, its
labels with byte ranges in each of sources[], its facts, notes and
help, and its fixes with their edits and their applicability, so that a
host (an editor, an agent) applies a machine-applicable fix without reading
prose:
const char* report = getCInterpreterDSPFactoryErrorDiagnostics();
if (report != NULL) {
/* {"schema_version": 2, "status": "failed", "request": {"backend": "interpreter"},
"diagnostics": [{"code": "FRS-PARSE-0001", ...,
"fixes": [{"applicability": "machine_applicable", "title": "insert `)`",
"edits": [{"range": {"source_id": 0, "start": 20, "end": 20}, "replacement": ")"}]}]}]} */
}
Same contract, with one difference that follows from what it is: the pointer
is null when the last error carried no typed diagnostics (a null pointer, a
missing file), even if an earlier one did, so that a report never outlives the
failure it describes. The document carries its own schema_version (2 today)
and names the surface in request.backend; fields may be added within a
version, so read what you know and check the version. It is the complete
report, the one the WebAssembly bindings return, a superset of what faust-rs --error-format json prints. The C++ wrappers return it as a std::string,
empty when there is none: getInterpreterDSPFactoryErrorDiagnostics(),
getCraneliftDSPFactoryErrorDiagnostics(), getDSPErrorDiagnostics().
These functions are additions of libfaust-rs; the reference libfaust has no
equivalent. The text is the one the faust-rs command prints under
--error-format human; see the diagnostics guide
for how to read it, and for the report's fields.
Cranelift support is experimental: native JIT execution works for the currently
supported compiler/FIR subset, but full runtime parity and its serialized
factory format are not yet final. Always check the returned factory and report
the error. See the detailed
Interpreter C/C++ API guide and
Cranelift C/C++ API guide, as well as the
corresponding *-dsp-c.h headers when calling libfaust-rs from C.
# Install the `faust-rs` binary into Cargo's bin directory
cargo install --path crates/compiler
# Show the CLI without installation (from the repository)
cargo run -p compiler -- --help
# Show the installed binary's CLI
faust-rs --help
# Build/run the optional native HTTP(S) source support (still runtime-off by default)
cargo run -p compiler --features network-imports -- \
--allow-network-imports -lang cpp https://example.test/main.dsp
The feature and the CLI flag are deliberately separate opt-ins: compiling with
network-imports does not enable network access by itself. Once enabled, the
CLI accepts a direct HTTP(S) DSP source, explicit URL imports, relative imports
inside a remote source graph, and a remote main architecture passed with -a.
Requests and redirects are bounded and URL credentials are rejected. Server or
embedded hosts should inject their own fetcher and URL authorization policy
instead of using the unrestricted native convenience transport. See the
compiler HTTP(S) API documentation
and the --allow-network-imports CLI reference.
The browser compiler module remains network-free but accepts asynchronously
prefetched URL/source graphs as documented in the
wasm-ffi README.
DSP compilation examples:
# Use the project-local Faust libraries (optimizers.lib and interleave.lib)
faust-rs -I libraries -lang cpp foo.dsp
# Generate AssemblyScript
faust-rs -lang asc foo.dsp
# Generate C
faust-rs -lang c foo.dsp
# Generate a scalar Cmajor processor
faust-rs -lang cmajor foo.dsp -o foo.cmajor
# Generate RNBO codebox source
faust-rs -lang codebox foo.dsp -o foo.codebox
# Generate codebox with the RNBO wrapper's `RB_` parameter names
faust-rs -lang codebox-test foo.dsp -o foo.codebox
# Generate C++
faust-rs -lang cpp foo.dsp
# Generate C++ with mode-zero host-managed buffers plus layout/cost JSON
faust-rs -lang cpp -mem0 -json foo.dsp -o foo.cpp
# The same scalar mode is available for C and native Cranelift
faust-rs -lang c -mem0 foo.dsp -o foo.c
faust-rs -lang cranelift -mem0 -json foo.dsp -o foo.cranelift
# Generate experimental Cranelift backend report
faust-rs -lang cranelift foo.dsp
# Generate interpreter bytecode (.fbc)
faust-rs -lang interp foo.dsp -o foo.fbc
# Dump FIR text IR
faust-rs -lang fir foo.dsp
# Generate Julia source
faust-rs -lang julia foo.dsp -o foo.jl
# Generate Rust source
faust-rs -lang rust foo.dsp -o foo.rs
# Generate WebAssembly plus companion JSON
faust-rs -lang wasm foo.dsp -o foo.wasm
# Generate textual WAT/WAST from the same WASM backend
faust-rs -lang wast foo.dsp -o foo.wat
# Emit strict Faust JSON description
faust-rs --json foo.dsp
# Emit a backend artifact plus companion JSON next to the output path
faust-rs -lang cpp --json foo.dsp -o foo.cpp
# Generate block-diagram SVG files
faust-rs -svg foo.dsp
# Write output to a file
faust-rs -lang cpp foo.dsp -o foo.cpp
faust-rs -lang interp foo.dsp -o foo.fbc
-mem, -mem0, --memory-manager, and --memory-manager0 are equivalent.
Only mode zero is currently supported, for scalar C, C++, and Cranelift. Its
JSON companion includes a versioned target layout and compute_cost; see the
-mem0 custom memory manager guide for how to
write a custom allocator against it, the
porting analysis
for the full design rationale, and the
Cranelift C/C++ API guide.
Scheduling and vector code generation:
# Select a scheduling strategy in scalar or vector mode.
faust-rs -ss 0 foo.dsp # depth-first (default)
faust-rs --scheduling-strategy 1 foo.dsp # breadth-first
faust-rs -ss 2 foo.dsp # special/interleaved
faust-rs -ss 3 foo.dsp # reverse breadth-first
# Request checked vector lowering with 64-sample chunks.
faust-rs -vec -vs 64 -lv 0 foo.dsp
faust-rs -vec -vs 64 -lv 1 foo.dsp
# Execution options (c/cpp/rust/fir/asc backends): external control and
# one-sample processing, as C++ Faust.
faust-rs -ec foo.dsp # separate host-scheduled control() function
faust-rs -os foo.dsp # one-sample frame(inputs, outputs) API
faust-rs -ec -os foo.dsp # control() once, then frame() per sample
faust-rs -ec -vec foo.dsp # external control with vector compute
The RNBO codebox target is inherently external-control and one-sample: its
output is identical with or without -ec and -os. It rejects -vec.
-lang codebox-test changes only parameter names to the RB_ convention used
by Faust's rnbo-dsp.h wrapper for manual RNBO round-trips. The backend has
in-tree structural and numeric tests; the RNBO import/export validation remains
manual because the RNBO SDK is not part of this workspace.
The scalar cmajor target has the same intrinsic execution shape: event-based
external control and one sample per processor tick, independent of -ec and
-os; it rejects -vec. It supports the default single precision and
-double, -cn, UI events,
rate-limited bargraphs, tables, --json, and -a architecture wrapping.
Polyphonic and Cmajor SDK application tooling remain deferred.
-ss accepts non-negative integers: 0, 1, and 2 select the strategies
shown above, while 3 and greater select reverse breadth-first. Missing,
negative, and non-integer values are hard errors; this is deliberately stricter
than the C++ compiler's atoi fallback. -vec defaults to -vs 32 -lv 0;
the supported loop variants are -lv 0 (constant-trip main loop plus scalar
remainder) and -lv 1 (runtime-bounded chunk loop).
faust-rs deliberately applies the same default -ss 0 depth-first policy in
both scalar and vector modes. This differs from the C++ vector default, which
uses CodeLoop::sortGraph; -ss 3 is the closest faust-rs match for that C++
levelization policy.
Built-in FIR backend fixtures (for backend debugging / bring-up):
# List internal FIR fixtures
faust-rs --list-fir-fixtures
# Dump a built-in FIR fixture
faust-rs --fir-fixture sine_phasor -lang fir
# Generate backend output directly from a built-in FIR fixture
faust-rs --fir-fixture control_flow -lang c
faust-rs --fir-fixture gain_bias_ui_meta -lang cpp
faust-rs --fir-fixture sine_phasor -lang interp
faust-rs --fir-fixture gain_bias_ui_meta -lang cranelift
faust-rs --fir-fixture sine_phasor -lang julia
faust-rs --fir-fixture gain_bias_ui_meta -lang codebox
faust-rs --fir-fixture gain_bias_ui_meta -lang wasm
Notes:
--fir-fixture bypasses the Faust front-end pipeline and feeds a hand-written
FIR module from codegen::fixtures directly into the selected backend.If your installed command is named faust (for example via a symlink/wrapper),
the same model applies:
faust -lang asc foo.dsp
faust -lang c foo.dsp
faust -lang cmajor foo.dsp
faust -lang codebox foo.dsp
faust -lang codebox-test foo.dsp
faust -lang cpp foo.dsp
faust -lang cranelift foo.dsp
faust -lang fir foo.dsp
faust -lang interp foo.dsp
faust -lang julia foo.dsp
faust -lang rust foo.dsp
faust -lang wasm foo.dsp
faust -lang wast foo.dsp
Without installation (equivalent):
cargo run -p compiler -- -lang asc foo.dsp
cargo run -p compiler -- -lang c foo.dsp
cargo run -p compiler -- -lang cmajor foo.dsp
cargo run -p compiler -- -lang codebox foo.dsp
cargo run -p compiler -- -lang codebox-test foo.dsp
cargo run -p compiler -- -lang cpp foo.dsp
cargo run -p compiler -- -lang cranelift foo.dsp
cargo run -p compiler -- -lang fir foo.dsp
cargo run -p compiler -- -lang interp foo.dsp
cargo run -p compiler -- -lang julia foo.dsp
cargo run -p compiler -- -lang rust foo.dsp
cargo run -p compiler -- -lang wasm foo.dsp
cargo run -p compiler -- -lang wast foo.dsp
faust-rs adds clock-domain and automatic-differentiation primitives to the
Faust language. They are compiler extensions: do not expect the C++ Faust
reference compiler to accept them.
ondemand(C) (OD) runs C only when its clock input fires; it holds the
last computed value between firings.upsampling(C) (US) runs C at an increased local rate.downsampling(C) (DS) runs C at a reduced local rate.fad(expr, seeds) emits every primal output followed by one forward-mode
tangent per seed lane. It is useful when a local derivative is consumed
directly inside the DSP.rad(expr, seeds) emits the primal outputs followed by reverse-mode
gradients for the sum of the primals. Delays and recursion use a
block-local reverse sweep, which is particularly useful for host-driven
optimization.Inside a US or DS block, ma.SR is adapted automatically to the local
clock domain: an upsampling factor H makes the block observe SR * H, while
a downsampling factor H makes it observe SR / H. Filters, oscillators, and
other algorithms that derive their coefficients from ma.SR therefore use the
effective sample rate of the block without requiring a manual correction.
There is currently one practical limitation in the Faust libraries:
platform.lib defines ma.SR with an upper and lower clamp equivalent to
min(192000, max(1, fSamplingFreq)). The compiler adapts the sample-rate value
inside US/DS, but the generated expression retains that surrounding
min/max. Consequently, a large US factor can still clamp the effective
local rate to 192 kHz—for example, US(8) at 48 kHz should observe 384 kHz but
currently observes 192 kHz through this definition. The ma.SR definition in
platform.lib must therefore be relaxed or redesigned before large
upsampling factors can expose their full local sample rate.
See the clock-domain note for OD/US/DS timing and rate semantics, and the FAD/RAD synthesis for output layouts, examples, and current limits.
Project-local Faust helpers live in libraries/. Add
that directory to the import path with -I libraries when a DSP imports
optimizers.lib or loads interleave.lib.
libraries/interleave.lib combines frame serialization with ondemand so an
N-point FFT, spectral effect, and inverse FFT run once per frame or hop rather
than once per audio sample. This supports analysis-only FFTs, spectral masks,
fast convolution, overlap-add STFT effects, phase-vocoder state, and
differentiable spectral losses in ordinary Faust graphs.
The current compiler expands the FFT into a specialized scalar butterfly graph: this works well for small and medium transforms, but large FFTs increase compilation time, generated-code size, instruction-cache pressure, and the worst-case work performed on a frame tick. See the clock-domain and spectral-processing note for executable DSP examples, framing semantics, and a comparison with optimized FFT implementations.
Use the following variables to increase the evaluation depth stack:
export FAUST_RS_STRUCTURAL_HARD_MAX_DEPTH=XX (default: 4096)export FAUST_RS_DEFAULT_EVAL_MAX_DEPTH=XX (default: 1024)-mem0 custom memory manager guideondemand/upsampling/downsampling): English / Frenchfad/rad): English / FrenchPull requests are welcome, including contributions developed with AI assistance. Human-authored and AI-assisted changes are held to the same standards, and contributors remain responsible for the correctness, maintainability, tests, and documentation of the submitted work.
Every pull request must follow Commit and Documentation Hygiene. In particular, keep the Git history linear, submit small and coherent commits, update the README and porting journal when required, and keep documentation concise, factual, and implementation-oriented.
The workspace follows a one-way dependency rule:
compiler core <- FFI adapters <- distribution, the distribution crates being
what a host links: faust-ffi (libfaust-rs), wasm-ffi and faust (the
Rust API). Run cargo run -p xtask -- ffi-boundary-check to verify that no
dependency points rightward and that unsafe-code opt-ins remain confined to
the explicit FFI boundary, the faust crate over it, and the foreign-call
runtime bridge. Embedding faust-rs describes
the layers from a host's side.
| Crate | Role |
|---|---|
tlib | Hash-consed tree arena, symbols, lists, recursive tree helpers |
diagnostics | Structured diagnostic reports, stable codes, labels, and bundles |
interval | Interval arithmetic |
algebra | Shared algebra/rewrite scaffold |
graph | Shared graph algorithms scaffold |
boxes | Faust box IR builders and matchers |
parser | Faust source parser and import handling |
signals | Faust signal IR builders, matchers, extended math nodes, and shared local RAD rule helpers |
ui | Grouped UI IR |
eval | Box-level evaluator and pattern matcher |
propagate | Box-to-signal propagation, including FAD/RAD expansion |
normalize | Signal normalization and preparation helpers |
sigtype | Signal type lattice and inference |
transform | Signal preparation and signal-to-FIR lowering |
fir | Faust Intermediate Representation |
foreign-call | Raw C ABI foreign-function invocation bridge |
codegen | AssemblyScript, C, C++, Cmajor, Codebox (RNBO), Rust, interpreter, Cranelift, WASM, and Julia backend generation |
draw | SVG block-diagram rendering |
doc | Documentation/reporting scaffold |
compiler | Top-level compiler facade and CLI |
| Crate | Role |
|---|---|
ffi-common | Shared ABI, marshalling, allocation, and factory-cache support for FFI adapters |
tree-ffi | Shared opaque tree-handle support for Box and Signal C APIs |
box-ffi | Box manipulation C/C++ API |
signal-ffi | Signal manipulation C/C++ API |
interp-ffi | Interpreter backend C/C++ API |
cranelift-ffi | Experimental Cranelift backend C/C++ API; also hosts the impulse-cranelift and faustprobe binaries, which drive its runtime |
libfaust-ffi | Backend-agnostic libfaust C/C++ API (expandDSP*, generateAuxFiles*, generateSHA1) |
| Crate | Role |
|---|---|
impulse-runner | Interpreter-backed scalar impulse-test runner |
faustprobe | Binary of cranelift-ffi: set controls, render offline, measure (see below) |
xtask | Developer and CI automation |
faust-ffi | Unified libfaust-rs distribution crate |
wasm-ffi | Raw WASM ABI for faustwasm embedded compiler mode |
faust | Supported Rust API: Factory and Dsp over interpreter and Cranelift |
faustprobeThe two impulse runners answer did the behaviour change? — a fixed protocol
compared against a stored reference. faustprobe answers is the behaviour
correct?, by setting controls to a chosen operating point and reporting what
comes out:
# What can be set, with ranges
cargo run --release -p cranelift-ffi --bin faustprobe -- filter.dsp -I lib --list-params
# Steady-state level of a 1 kHz sine through a filter, transient excluded
cargo run --release -p cranelift-ffi --bin faustprobe -- filter.dsp -I lib \
--set cutoff=1000 --set resonance=0 \
--sr 48000 -n 96000 --skip 48000 --in sine:1000 --quiet
# Build faustprobe to be installed
cargo build --release -p cranelift-ffi --bin faustprobe
Per-frame CSV goes to stdout and the statistics to stderr, so a dump stays
pipeable. --skip applies to both, which matters: statistics taken over a
window that includes the startup transient will disagree with theory on any
strongly attenuated signal.
A control is addressable by full path or by any trailing fragment that is
unambiguous (cutoff for /filter/cutoff); an ambiguous fragment is reported
with its candidates rather than resolved arbitrarily. Addresses follow the same
rule as C++ MapUI, so they match what other Faust hosts report for the same
DSP.
Full reference: docs/faustprobe-user-guide-en.md.
Design and phases:
porting/faustprobe-generic-test-tool-design-2026-08-14-en.md.
Generate Rustdoc for workspace crates only (recommended):
cargo doc --workspace --no-deps
Generate Rustdoc including dependencies:
cargo doc --workspace
Open the generated HTML entry point:
open target/doc/index.html
Crate-specific entry point example:
target/doc/compiler/index.htmlStatus and scope:
Architecture contracts and design notes:
Formal specifications (Lean; see the usage methodology):
History and process:
*-plan-YYYY-MM-DD-en.md)