Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Linux gets the plug-in and the JACK standalone; Windows gets the plug-in.

NAMp panel

namp-standalone: the NAMp panel above the rack in node view, with hosted VST3 and LV2 plug-in editors open around it

Above: the rack in Nodes view — two pedals before the amp, a delay and a reverb after it — with each plug-in's own editor open beside it. Two are VST3 and two are LV2; the rack hosts both and does not care which is which.

NAMp

A whole folder of Neural Amp Modeler captures under one knob — a raw VST3 plug-in for Linux and Windows.

A .nam capture freezes an amplifier at one knob position. Load one and you have a voice, not an amp: no matter what else you change, the gain stage is whatever it was on the day of the capture. Loading a second capture means swapping the model, which clicks.

NAMp takes a directory of up to 64 captures and puts the whole set under one Capture knob, which moves through them continuously and without a click. Nothing is reloaded when you turn it; every capture in the folder is already in memory and playable.

The knob is a gain knob when you feed it a gain-stacked set — the same amp captured at ascending gain settings, named 1, 2, … MAX. Then turning it feels like turning the amp's own gain control, because the marks it moves between are the amp's own, and every position in between is a real blend rather than a jump. That is what NAMp was built for and it is still the best thing to point it at.

It is also just a capture browser you can play. Point it at any folder — a pack of different amps, a set of cabinet or mic variations, everything you own by one modeller — and the knob steps through it in filename order with no reload, no click, and no dialog. Sweeping between two unrelated amps blends them, which is a legitimate sound, but it is not what a gain stack gives you.

It is a plug-in written directly against the Steinberg VST3 SDK — no JUCE, no iPlug2, no VSTGUI. The editor is an IPlugView embedded in the host's own window and painted by hand with Cairo and FreeType: an X11 child window driven by the host's IRunLoop on Linux, a WS_CHILD HWND driven by the host's message pump on Windows. MIT licensed, and every dependency in the include graph is MIT, BSD, Apache-2.0, MPL-2.0, zlib or OFL.

Why it doesn't click, and why it doesn't cost ten models

Two facts, both verified in the DSP core rather than assumed.

The models are strictly feed-forward. These captures route to the A2 fast-path WaveNet, which holds per-layer convolution history rings and no recurrent state anywhere. Its output at sample t is a pure function of the input window [t-6345, t], so a model that has been fed live input for one receptive field — 6346 samples, 132 ms at 48 kHz — is bit-identical to one that had been running since the session began. Priming an incoming model therefore costs nothing special: feed it while you fade to it, and by the time it is at full weight it is exact.

The knob is a position, not an index. The Capture knob is a continuous position p in [0, N-1]; the sounding output is entry floor(p) at weight 1-f mixed with entry floor(p)+1 at weight f. Every integer crossing therefore happens when one branch's weight is exactly zero, so a branch swap has no discontinuity to mask — a click is structurally impossible rather than hidden under a fade curve.

Peak cost is exactly two models, and only while the knob is moving: 300 ms after it stops, p glides to the nearest capture over 200 ms and collapses to a single branch. At rest NAMp costs the same as any single-capture NAM plug-in.

Measured

Numbers here are measured or read out of source, never estimated. On an i7-12700F at 48 kHz:

max abs(crossfade − fully-primed reference) after the fade 0.0 — bit-identical
the same test with a fade shorter than the receptive field 1.24e-02, fails — so the test has teeth
priming error below −40 dB after 33.0 ms of a 132.2 ms receptive field
mix law, worst deviation: a + b = 1 0.12 dB
mix law, worst deviation: a² + b² = 1 3.07 dB (6.35 dB at the widest gain gap)
cost resting on a capture RTF 0.0536 — one model
cost while sweeping RTF 0.1056 — two models, exactly 2×
allocations on the audio path 0, including through the resampler at 44.1 kHz
60 s live capture sweep, 128-frame JACK buffer 0 xruns

Adjacent captures of the same amp fed the same input are strongly correlated, which is why the mix is amplitude-complementary (a + b = 1) and not equal-power: equal-power puts a +3 dB bump in the middle of every fade.

Using it

Point the first loader box at a directory of .nam files. Everything in it up to 64 captures is loaded, in this order:

  1. anything with a number in its name, by that number — the last run of digits in the name, so GAIN 2 sorts before GAIN 10 and a year or a channel count earlier in the name does not interfere;
  2. then anything ending in MAX, which is a gain marking rather than a number and belongs at the top;
  3. then everything with no number at all, alphabetically.

As a gain knob

This is what NAMp is for. Capture your amp at each mark of its gain control and name the files so the mark is the last thing in the name:

MyAmp - crunch - GAIN 1.nam
MyAmp - crunch - GAIN 2.nam
...
MyAmp - crunch - GAIN MAX.nam

Ten of those give you the amp's gain control back, at the amp's own spacing, with every position between two marks a real blend of them. (The gain field in a capture's metadata is not used for this: the trainer defines it as a measured compression statistic, not a knob position.)

As a capture browser

A folder does not have to be one amp. Point it at a pack of different amps, a set of cabinet or mic variations, or everything you own from one modeller, and the knob walks the folder — up to 64 captures, all resident, no reload and no dialog between them. Rest on one and you are playing that capture exactly; positions in between blend the two either side, which across unrelated amps is a sound in its own right rather than a gain control.

Whichever way you use it, one click of the mouse wheel on the Capture knob is exactly one capture, so the wheel detents onto real captures rather than landing between them. The Capture knob has no number under it — it does not select a level — and the loader row names the capture that is sounding, in green, beside the folder and its capture count. A single .nam file still loads on its own: click the file itself in the picker instead of using "use this folder", and the knob then has nothing to move through.

Two things about a large folder are worth knowing, and both are properties of the design rather than limits that could be tuned away. Past 64 captures the highest-sorting files are dropped, with a warning on stderr naming where the cut fell — the bound is what keeps a directory of untrusted input from costing unbounded memory, at about 0.94 MB per capture. And crossing from one capture to the next can never take less than one receptive field, 132 ms at 48 kHz, so slamming the knob from end to end of a full 64-capture bank takes about 8.3 seconds. That rate limit is exactly what makes the move click-free; it does not apply to anything except full-travel sweeps.

The rest of the panel is a normal amp front end: input and output gain, a noise gate, a bass / middle / treble tone stack, an impulse-response loader with previous/next arrows that step through the IRs in the loaded one's folder, and a Slim control that trades model size for CPU. The editor is host-resizable and aspect-locked; the settings card behind the gear icon holds the output mode and input calibration.

Captures must be feed-forward (WaveNet or ConvNet). An LSTM capture has unbounded memory, so no finite fade can prime it exactly; NAMp detects those and refuses them rather than accepting them silently.

Building

Dependencies: cairo (+ cairo-ft, cairo-xlib), freetype2, fontconfig, libX11, and — for the standalone only — JACK, plus lv2 ≥ 1.18, lilv ≥ 0.24 and suil ≥ 0.10, which it hosts LV2 plug-ins through. Plus CMake ≥ 3.25, Ninja and a C++20 compiler.

JACK is optional and its absence only skips the standalone; the LV2 trio is not, and configuring without it fails outright. On Debian/Devuan/Ubuntu:

sudo apt install build-essential cmake ninja-build pkg-config \
    libcairo2-dev libfreetype-dev libfontconfig1-dev libx11-dev \
    libjack-jackd2-dev lv2-dev liblilv-dev libsuil-dev

GCC 12 and older need -fpermissive to compile AudioDSPTools' resampler, which CMake adds by itself on those versions — see the note beside it in CMakeLists.txt.

git submodule update --init --recursive NeuralAmpModelerCore AudioDSPTools eigen
git submodule update --init vst3sdk
git -C vst3sdk submodule update --init base cmake pluginterfaces public.sdk

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build

The VST3 SDK is a superproject and only four of its modules are needed; VSTGUI is deliberately left uninitialised, since the editor is drawn directly. Each dependency tree can be pointed elsewhere with -DVST3_SDK_DIR, -DNAM_CORE_DIR, -DAUDIO_DSP_TOOLS_DIR or -DEIGEN_DIR.

scripts/makedist-linux.sh builds from clean and packages dist/NAMp-<version>-linux-<arch>.tar.gz with the bundle, the standalone and the licence files.

Windows

Cross-compiled from Linux with MinGW-w64. No Windows machine and no VM are involved in building it; Wine is the local test rig.

sudo apt install g++-mingw-w64-x86-64-posix gcc-mingw-w64-x86-64-posix \
                 binutils-mingw-w64-x86-64 mingw-w64-x86-64-dev mingw-w64-tools

scripts/build-win-deps.sh     # builds zlib, libpng, pixman, freetype and cairo
                              # into a private static sysroot — Debian packages
                              # no MinGW build of any of them

cmake -S . -B build-win -G Ninja -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-mingw-w64.cmake
cmake --build build-win

The posix thread variant of the toolchain is required, not merely preferred: Debian's -win32 variant is built without _GLIBCXX_HAS_GTHREADS, so std::thread, std::mutex and std::condition_variable do not exist there — and the model loader needs all three.

scripts/makedist-windows.sh builds, strips, runs the SDK validator under Wine, generates moduleinfo.json, and packages dist/NAMp-<version>-windows-x86_64.zip. It refuses to package a bundle that imports anything but system DLLs, or that exports anything other than the three VST3 entry points — the plug-in statically links cairo, FreeType, libpng, zlib and the GCC runtime, so there is nothing to install beside it and nothing of anyone else's leaking out of it.

The same script also builds NAMp-install.exe from installer/namp.nsi and puts it in the ZIP beside the bundle. makensis is a native Linux binary — it links one of NSIS's prebuilt PE stubs and appends the compressed payload — so the installer is produced by the same run, with no Wine step and nothing from the cross compiler. Install NSIS with sudo apt install nsis, or unpack it without root and point $NAMP_NSIS_DIR at the prefix (bin/makensis plus share/nsis/, which is what apt-get download nsis nsis-common and dpkg-deb -x give you); the default is ~/third_party/nsis. NAMP_SKIP_INSTALLER=1 packages the bundle without it.

To install, either run NAMp-install.exe, or copy the whole NAMp.vst3 folder to one of the two places hosts search, in this order:

  1. %LOCALAPPDATA%\Programs\Common\VST3\ — just for you, no administrator rights
  2. C:\Program Files\Common Files\VST3\ — every user, needs administrator

The installer picks between those two by whether it is running elevated, shows which it picked, and lets you change it; it registers an uninstall entry and offers to remove a copy left in the other location, which a host would otherwise list twice. It is not code-signed, so SmartScreen warns about it — that is why the plain bundle stays in the ZIP as well.

Standalone

namp-standalone is a JACK application and a real VST3 host — and a single self-contained file. The plug-in is linked in, the art and fonts are linked in beside it, and scanning other people's plug-ins re-execs this same binary rather than a helper next to it. Nothing has to be installed, and it cannot end up playing an older installed plug-in than the one it was built from.

./build/namp-standalone --bank /path/to/captures --ir cab.wav

It remembers what it was last playing in ~/.config/NAMp/standalone.state. Passing the path to a .vst3 bundle hosts that plug-in instead of the built-in one, which is how a packaged build is compared against the current tree.

--sweep SECONDS is the live acceptance test: it walks the Capture knob across the whole bank and back, resting long enough at each end for the auto-detent to collapse, and reports the xrun count the JACK server observed. That is the honest answer to "will two neural models crossfading fit in my audio callback at this buffer size" on a particular machine.

./build/namp-standalone --bank /path/to/captures --sweep 60

Tools

namp_fadecheck the offline proof — renders the fade against a fully primed reference and asserts convergence, with a hard-switch control that must fail
namp_offline headless host: loads the built bundle the way a DAW does and renders a test signal
namp_rtcheck counts allocations on the audio path using the DSP core's own interception harness
panelrender renders the editor panel to a PNG with no X11 and no host, and fails if any art asset or font is missing

Credits and licence

NAMp is MIT. It builds on Steven Atkinson's Neural Amp ModelerNeuralAmpModelerCore and AudioDSPTools are used directly, and the signal chain follows NeuralAmpModelerPlugin. The VST3 SDK is Steinberg's, MIT since 3.7.10. See NOTICE for the full per-dependency attribution, including the one dependency whose licence status has to be re-checked on every update.

About

Load multiple nam captures and change between them in real time. Linux and Windows versions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages