Skip to content

Plugins

Resonon supports CLAP and VST3 audio plugins for effects processing and virtual instruments. Most built-in effects (delay, filters, overdrive) are native DSP — no plugins needed. Two reverb plugins are bundled; third-party plugins require a scan step.

Resonon ships with two built-in reverb plugins. These are embedded in the binary and auto-extracted on first use — no scan required.

Plugin NameFilenamePlugin ID
RESONON Reverbresonon-reverbcom.resonon.reverb
RESONON Plate Reverbresonon-reverb-platecom.resonon.reverb-plate
// Bundled plugins load instantly -- no plugin_scan() needed
let reverb = Effect("resonon-reverb");
let plate = Effect("resonon-reverb-plate");

Scan standard CLAP and VST3 directories for installed third-party plugins and cache the results. Returns the total number of plugins found:

let count = plugin_scan();
show(count); // e.g. 42

The scan searches OS-specific directories in priority order:

OSFormatSearch Paths (highest priority first)
macOSCLAP/Library/Audio/Plug-Ins/CLAP, ~/Library/Audio/Plug-Ins/CLAP, ~/.clap
macOSVST3/Library/Audio/Plug-Ins/VST3, ~/Library/Audio/Plug-Ins/VST3
LinuxCLAP/usr/lib/clap, /usr/local/lib/clap, ~/.clap
LinuxVST3/usr/lib/vst3, /usr/local/lib/vst3, ~/.vst3
WindowsCLAPC:\Program Files\Common Files\CLAP, C:\Program Files (x86)\Common Files\CLAP
WindowsVST3C:\Program Files\Common Files\VST3, C:\Program Files (x86)\Common Files\VST3

Results are written to a JSON cache file so that subsequent plugin_list() calls and name-based loading are fast.

List all discovered plugins from the cache, deduped by name. Plugins available in both CLAP and VST3 are shown once with format tags. Returns the number of unique plugins:

let count = plugin_list();
// 5 plugins:
// RESONON Delay — Resonon [CLAP]
// RESONON Filter — Resonon [CLAP]
// Surge XT — Surge Synth Team [CLAP, VST3]
// Valhalla Room — Valhalla DSP [VST3]
// ...

If no cache exists, run plugin_scan() first.

Load an effect plugin (CLAP or VST3). The format is auto-detected — by default CLAP is tried first, then VST3. You can override this globally or per-plugin in config.toml. The name argument is resolved in this order:

  1. Full path — if the name ends in .clap/.vst3 or points to an existing file
  2. Filename — search OS plugin directories for a matching .clap or .vst3 file
  3. Registry name — look up by display name in the scan cache
  4. Error with suggestions — list available plugins
let reverb = Effect("resonon-reverb"); // By filename (bundled)
let shimmer = Effect("Valhalla Shimmer"); // By display name (after scan)
let fx = Effect("/path/to/plugin.clap"); // By full path
let room = Effect("ValhallaRoom"); // Auto-detects CLAP or VST3

For plugins that contain multiple effect types in a single bundle, specify the plugin ID as the second argument:

let chorus = Effect("Multi-FX", "com.vendor.multi-fx.chorus");

If you omit the plugin ID for a multi-plugin bundle, Resonon lists the available IDs.

Instrument(name) / Instrument(name, plugin_id)

Section titled “Instrument(name) / Instrument(name, plugin_id)”

Load an instrument plugin (CLAP or VST3). Format auto-detection, name resolution, and config-based preference follow the same rules as Effect():

let synth = Instrument("Surge XT");
let lead = AudioTrack("lead");
lead.load_instrument(synth);
lead << [C4 E4 G4 C5];

When a plugin cannot be found, Resonon shows which paths were searched and lists available plugins:

Plugin not found: 'Surge'
Searched locations:
- /Library/Audio/Plug-Ins/CLAP/Surge.clap
- ~/Library/Audio/Plug-Ins/CLAP/Surge.clap
- /Library/Audio/Plug-Ins/VST3/Surge.vst3
- ~/Library/Audio/Plug-Ins/VST3/Surge.vst3
Available plugins:
- resonon-reverb
- resonon-reverb-plate
...
Tip: Run plugin_scan() to discover installed plugins.

If multiple plugins share the same display name, Resonon asks you to disambiguate with a plugin ID:

// Specify the exact plugin ID
let delay = Effect("Delay", "com.resonon.delay");
MethodArgsReturnsDescription
.name()StringPlugin display name
.params()NulPrint all parameters as a table
.params(filter)StringNulPrint parameters matching the filter substring
.param(path)StringNumberRead a parameter’s current value
.set_param(path, value)String, NumberSelfSet a parameter value (chainable)
.set_param_norm(path, value)String, NumberSelfSet a parameter using normalized 0–1 value (chainable)
.supports_gui()BooleanWhether the plugin has a GUI
.show_gui()NulOpen the plugin GUI window
.hide_gui()NulClose the plugin GUI window
.save_state(path)StringSelfSave full plugin state to a file (chainable)
.load_state(path)StringSelfLoad plugin state from a file (chainable)

.params() prints all parameters with their ranges, defaults, and current values:

let reverb = Effect("resonon-reverb");
reverb.params();

Output is a formatted table:

Parameter Range Default Value
─────────────────────────────────────────────────
Room [0.0-1.0] 0.5 0.5
Damp [0.0-1.0] 0.5 0.5
Width [0.0-1.0] 1.0 1.0
Mix [0.0-1.0] 0.33 0.33

.params(filter) accepts a substring to narrow results. This is useful for plugins with many parameters:

let synth = Instrument("Surge XT");
synth.params("osc"); // Only show oscillator-related parameters
synth.params("filter"); // Only show filter parameters

.param(path) returns a parameter’s current value:

show(delay.param("Time")); // 0.25
show(filter.param("Cutoff")); // 1000.0

.set_param(path, value) sets a parameter and returns the plugin for chaining:

delay.set_param("Time", 0.3)
.set_param("Feedback", 0.6)
.set_param("Mix", 0.8);

.set_param_norm(path, value) sets a parameter using a normalized 0–1 value. The value is mapped to the parameter’s actual range (including non-linear curves for VST3 plugins):

delay.set_param_norm("Time", 0.5) // midpoint of the Time range
.set_param_norm("Mix", 1.0); // maximum mix

Dot-access with the parameter name and << provides a concise syntax:

filter.Cutoff << 2000;
filter.Resonance << 3.0;

This shorthand also accepts signals for continuous modulation:

filter.Cutoff << Sine(2).range_exp(400, 4000);
filter.Resonance << Tri(0.5).range(0.5, 4.0);

See Signals & Automation for the full set of signal generators.

.name() returns the plugin’s display name:

let reverb = Effect("resonon-reverb");
show(reverb.name()); // "RESONON Reverb"

Some CLAP and VST3 plugins provide a graphical interface for editing parameters.

let synth = Instrument("Surge XT");
show(synth.supports_gui()); // true or false
synth.show_gui(); // Open the plugin window
synth.hide_gui(); // Close it
plugin_scan();
let synth = Instrument("Surge XT");
let lead = AudioTrack("lead");
lead.load_instrument(synth);
// Open the GUI to design a sound
if synth.supports_gui() {
synth.show_gui();
}
// Save the preset for later
synth.save_state("presets/lead_patch.preset");
lead << [C4 E4 G4 C5];
PLAY;

Save the full plugin state (all parameters and internal state) to a file. Returns the plugin for chaining:

delay.save_state("presets/my_delay.preset");

Load a previously saved state into a plugin instance. Returns the plugin for chaining:

let reverb2 = Effect("resonon-reverb");
reverb2.load_state("presets/my_reverb.preset");

If the preset was saved by a different plugin, a warning is printed but the state is still loaded:

warning: preset 'presets/my_delay.preset' was saved for 'RESONON Delay', loading into 'RESONON Filter'

Both methods are chainable:

let reverb = Effect("resonon-reverb");
reverb.set_param("Room", 0.8)
.save_state("presets/big_room.preset")
.set_param("Room", 0.3);
drums.load_effect(delay);
drums.load_effect(filter);

Effects chain in the order they are loaded. See Effects for the full effect management API.

let synth = Instrument("Surge XT");
let lead = AudioTrack("lead");
lead.load_instrument(synth);

Drums through a filter and delay (native DSP) into a reverb (bundled plugin):

use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");
drums.load_instrument(Sampler(Kit("cr78")));
drums << [bd sd [bd bd] sd];
// Native DSP effects
let lp = Lowpass(3000, 2.0);
let echo = Delay(0.2, 0.4);
// Bundled reverb plugin
let verb = Reverb(0.6, 0.4, 1.0, 0.3);
drums.load_effect(lp);
drums.load_effect(echo);
drums.load_effect(verb);
PLAY;

Scan for plugins, load an external synth, and configure it:

plugin_scan();
let synth = Instrument("Surge XT");
let lead = AudioTrack("lead");
lead.load_instrument(synth);
// Discover parameters
synth.params("osc");
// Set parameters
synth.set_param("osc/type", 1)
.set_param("osc/pitch", 0);
lead << [C4 _ E4 _ | G4 _ C5 _ | E5 _ G5 _ | C6 _ _ _];
PLAY;

Design a sound with the plugin GUI, save it, and recall it later:

plugin_scan();
let synth = Instrument("Surge XT");
let lead = AudioTrack("lead");
lead.load_instrument(synth);
// Open GUI to design the patch
if synth.supports_gui() {
synth.show_gui();
}
// Play a pattern while tweaking
lead << [C4 E4 G4 C5];
PLAY;
// Save the result
synth.save_state("presets/my_lead.preset");
// Later, in another script:
let synth2 = Instrument("Surge XT");
synth2.load_state("presets/my_lead.preset");