Pure-Rust, real-time-safe inference for Neural Amp Modeler (NAM) .nam models.
nam-rs loads a .nam model file and runs its neural-network forward pass — a whole
buffer at a time (WaveNet uses a cache-friendly block kernel) or one sample at a time —
with no heap allocation on the audio thread, suitable for use inside a JACK
callback, a VST3/CLAP process(), or any real-time audio graph.
Status: Both WaveNet and LSTM inference are implemented and tested — parser, forward pass, parity, and RT-safety harnesses all green. Build any
.namwith the architecture-agnosticModel::from_nam, which dispatches on the model's architecture.
- Parity with the reference. Output must equal the canonical Python/C++ NAM
implementations within float tolerance for the same model and input. Enforced by
tests/parity.rsagainst fixtures generated from Python NAM. - Real-time safety. The runtime's
process_buffer(for both WaveNet and LSTM, reached viaModel) performs zero heap allocation, locks, or syscalls; all scratch buffers are pre-allocated at construction. Enforced bytests/rt_safety.rsviaassert_no_alloc.
cargo add nam-rsuse nam_rs::{Model, NamModel};
// Off the audio thread: load + allocate. `Model::from_nam` dispatches on the
// model's architecture, so the same code runs WaveNet and LSTM `.nam` files.
let model = NamModel::from_file("twin_reverb.nam")?;
let mut amp = Model::from_nam(&model)?;
// On the audio thread: in-place, allocation-free. Call once per audio block;
// state carries across calls, so block-wise output matches one whole-buffer call.
let mut audio_buffer = vec![0.0_f32; 512]; // your host's block, filled with input
amp.process_buffer(&mut audio_buffer);For WaveNet models, the first WaveNet::receptive_field() output samples are a startup
transient (the dilated stack filling against zero-history) — the model's inherent
latency, the same convention NAM Core / NeuralAudio use. LSTM models have no such
warmup. Call Model::reset to return to silence.
Sample rate. A .nam expects audio at the rate it was captured
(NamModel::expected_sample_rate(), 48 kHz if the file omits it). nam-rs does not
resample: feed the model audio at that rate, or resample in your host first. A
mismatched rate produces silently wrong output, since the model's dilations and
recurrence are defined in samples, not seconds.
Processing boundary. nam-rs runs only the model's forward pass. The reference
NAM plugin additionally applies a DC blocker (high-pass) and, optionally, loudness
normalization on the output — those belong to the host's audio graph, not the model.
The calibration accessors (NamModel::loudness() etc.) give you the numbers for that
gain-staging.
cargo test # parser, parity, and RT-safety tests
cargo fmt --check
cargo clippy --all-targets -- -D warningsParity fixtures are committed under tests/fixtures/; regenerate them from Python NAM
with tests/fixtures/gen_fixtures.py (see tests/fixtures/README.md).
nam-rs is MIT-licensed (see LICENSE). It is a derivative work: the
algorithm and .nam weight layout are ported from the projects below. Their license
texts are reproduced in NOTICE.
| Project | Role | License |
|---|---|---|
| neural-amp-modeler | Reference trainer + .nam exporter (source of truth for weight/config layout) |
MIT |
| NeuralAmpModelerCore | Canonical C++ inference library | MIT |
| NeuralAudio | High-performance C++ NAM runtime; primary porting reference | MIT |
| waveny | Go port; conceptual cross-check only | Apache-2.0 |
.nam model files are licensed separately by whoever captured them; nam-rs ships
no model files.