Skip to content

Effects

This content is for v0.7. Switch to the latest version for up-to-date documentation.

use "std/effects" { Delay };
use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");
drums.load_instrument(Sampler(Kit("cr78")));
drums << [bd sd bd sd];
drums.load_effect(Delay(0.25, 0.5));
PLAY;

Echo/repeat effect.

let echo = Delay(time, feedback);
ParameterRangeDefaultDescription
timeseconds0.25Delay time
feedback0.0—1.00.5How much signal feeds back
let echo = Delay(0.25, 0.5); // 250ms delay, 50% feedback

All filters accept an optional resonance (Q) parameter. Default is 0.707 (Butterworth response, flat passband). Higher values create a narrower, more resonant peak.

Cuts high frequencies.

let warm = Lowpass(cutoff, resonance);
ParameterRangeDefaultDescription
cutoffHz1000.0Cutoff frequency
resonance0.707—100.707Filter Q
let warm = Lowpass(800); // Gentle warmth
let resonant = Lowpass(800, 3.0); // Resonant peak

Cuts low frequencies.

let thin = Highpass(500);

Keeps a frequency band, cuts above and below.

let focused = Bandpass(1000);
let narrow = Bandpass(1000, 8.0); // Narrow Q

Removes a frequency band (opposite of bandpass).

let de_hum = Notch(60);
let surgical = Notch(2000, 8.0);

Phase shift at cutoff frequency (phaser building block).

let phase = Allpass(500, 5.0);

Bell emphasis around a center frequency.

let presence = Peak(3000);

Freeverb room/hall reverb.

let hall = Reverb(room, damp, width, mix);
ParameterRangeDefaultDescription
room0.0—1.00.5Room size
damp0.0—1.00.5High-freq damping
width0.0—1.01.0Stereo width
mix0.0—1.00.33Dry/wet mix
let hall = Reverb(0.8, 0.3); // Large room, low damping

Dattorro plate reverb with a lush, diffuse character.

let plate = PlateReverb(size, damping, diffusion, predelay, mix);
ParameterRangeDefaultDescription
size0.0—1.00.5Tank size
damping0.0—1.00.5High-freq damping
diffusion0.0—1.00.7Diffusion amount
predelay0.0—1.00.0Pre-delay
mix0.0—1.00.33Dry/wet mix
let plate = PlateReverb(0.7, 0.4, 0.8);

Symmetrical/tube-style clipping.

let od = Overdrive(drive, tone);
ParameterRangeDefaultDescription
drive0.0—1.00.5Distortion intensity
tone0.0—1.00.7Post-distortion brightness
let warm_drive = Overdrive(0.2, 0.5);
let heavy = Overdrive(0.9, 0.8);

Asymmetrical/transistor-style clipping.

let dist = Distortion(drive, tone);
ParameterRangeDefaultDescription
drive0.0—1.00.5Distortion intensity
tone0.0—1.00.7Post-distortion brightness
let gritty = Distortion(0.3, 0.4);
let crushed = Distortion(1.0, 0.9);

Effects are loaded onto tracks with load_effect() and process in the order they are added:

drums.load_effect(Delay(0.25, 0.5));
drums.load_effect(Lowpass(800));
// Signal: drums -> delay -> lowpass -> output

Bulk loading with load_effects():

let fx = #[Highpass(2000), Delay(0.125, 0.3)];
hats.load_effects(fx);

Set effect parameters with .set_param() (chainable) or <<:

echo.set_param("Time", 0.4).set_param("Feedback", 0.3);
// Or with << syntax
echo.Time << 0.15;
echo.Feedback << 0.6;

Route a signal to an effect parameter for continuous modulation:

filter.Cutoff << Sine(2).range_exp(400, 4000);
delay.Time << Sine(0.25).range(0.1, 0.4);

Use .modulate() or << with automation() for envelope-style control:

filter.Cutoff << automation(#[0, 0.0], #[4, 1.0]).range_exp(200, 4000);

See Signals & Automation for full details.

Every effect carries a slot name (defaults to the constructor name like "Delay", "Lowpass"). When you load_effect, if an effect with the same slot name already exists, it is replaced in-place rather than accumulated. This makes live coding idempotent — re-executing a line updates the effect instead of stacking duplicates.

// Re-executing this line replaces the Delay, not adds another
drums.load_effect(Delay(0.25, 0.5));
// Custom name for multiple effects of the same type
drums.load_effect(Delay(0.125, 0.2, "short_echo"));
drums.load_effect(Delay(0.5, 0.4, "long_echo"));
// Retrieve by name
drums.get_effect("short_echo").set_param("Time", 0.2);
// Rename an effect's slot
let verb = Reverb(0.5).set_name("my_verb");
FunctionDescription
load_effect(fx)Load effect by slot name (replaces if exists)
load_effects(arr)Load multiple effects (each replaces by slot)
effects()Return array of effects on the track
get_effect(name)Get an effect by its slot name
swap_effects(i, j)Swap two effects by index
remove_effect(i)Remove and return the effect at index i
clear_effects()Remove all effects from the track
drums.swap_effects(0, 1); // Reorder
let removed = drums.remove_effect(0); // Remove first
drums.clear_effects().load_effects(new_chain); // Replace all

Load effects on master to process the entire mix:

master.load_effect(Lowpass(8000));
master.get_effect("Lowpass").set_param("Cutoff", 4000);

Write audio effects directly in Resonon using dsp effect blocks. The identifier after dsp effect names the effect type:

dsp effect Gain {
param level: 1.0 range(0, 2);
fn process(left, right) -> (out_l, out_r) {
return (left * level, right * level);
}
}
let gain = Gain();
drums.load_effect(gain);

dsp effect is a top-level definition. Instantiate it with call syntax (Name()) to get a value you can load onto tracks. The name also serves as the slot name for idempotent loading. You can rename after creation with .set_name("NewName").

By default, DSP effects are stereo in/out. Use input and output declarations for custom layouts:

dsp effect SidechainComp {
input main: stereo;
input sidechain: mono;
output: stereo;
param threshold: 0.5 range(0, 1);
state env: 0.0;
fn process(main_l, main_r, sc) -> (out_l, out_r) {
let level = abs(sc);
if level > threshold {
env = env + (level - env) * 0.01;
} else {
env = env + (level - env) * 0.001;
}
let gain = 1.0 / (1.0 + env);
return (main_l * gain, main_r * gain);
}
}
let comp = SidechainComp();

Process function parameters map to declared inputs in order:

  • input main: stereo provides 2 parameters (main_l, main_r)
  • input sidechain: mono provides 1 parameter (sc)

Channel types: mono (1 channel) or stereo (2 channels).

Connect another track’s audio to a sidechain input with connect_input():

let drums = AudioTrack("drums");
let bass = AudioTrack("bass");
drums.load_effect(comp);
comp.connect_input("sidechain", bass);

The source track is automatically processed before the destination. Mono sidechain ports receive a downmixed (L + R) / 2 signal from stereo sources.

See Routing for more details on sidechain routing.

Declare fixed-size arrays in effect state with buffer:

dsp effect BufferEcho {
param time: 0.25 range(0.001, 1.0);
param feedback: 0.5 range(0, 0.99);
buffer buf(48000);
state wp: 0;
fn process(left, right) -> (out_l, out_r) {
let delay_samples = time * sr;
let rp = wp - delay_samples;
if rp < 0 { rp = rp + 48000; }
let delayed = buf[rp];
buf[wp] = left + delayed * feedback;
wp = (wp + 1) % 48000;
return (left + delayed * 0.5, right + delayed * 0.5);
}
}
let echo = BufferEcho();
  • buffer name(size) allocates size f64 values, initialized to zero
  • Access elements with name[index] (read) and name[index] = value (write)
  • Indices wrap with modulo, so out-of-range access is safe
  • Useful for delay lines, circular buffers, and wavetables

DSP effects can define local helper functions to break complex processing into reusable pieces. Any fn that is not process is a local helper:

dsp fn softclip(x) -> out {
return x / (1.0 + abs(x));
}
dsp effect WarmDrive {
param drive: 2.0 range(1, 10);
fn apply_drive(x) -> out {
return softclip(x * drive);
}
fn process(left, right) -> (out_l, out_r) {
return (apply_drive(left), apply_drive(right));
}
}

Local helpers can access the effect’s state, buffer, and param variables. Top-level dsp fn and dsp object declarations let you share helpers across multiple effects. See DSP Functions & Objects for the full reference.

plugin_scan();
let shimmer = Effect("Valhalla Shimmer");
let reverb = Effect("resonon-reverb"); // bundled reverb plugin
let synth = Instrument("Surge XT");
let lead = AudioTrack("lead");
lead.load_instrument(synth);

plugin_scan() searches the standard CLAP and VST3 directories for your operating system and caches the results.

reverb.params(); // Print parameter table
reverb.param("Room"); // Read current value
reverb.set_param("Room", 0.8); // Set value (chainable)
reverb.set_param_norm("Room", 0.5); // Set by normalized 0-1 value
reverb.Room << 0.8; // Shorthand
plugin_scan();
plugin_list(); // Prints all discovered plugins

The built-in Sampler() and SamplerMelodic() constructors wrap Resonon’s CLAP sampler plugin internally.

reverb.save_state("presets/my_reverb.preset");
reverb.load_state("presets/my_reverb.preset");

Both methods are chainable.

External plugins require plugin_scan() to discover third-party plugins. Bundled Resonon reverbs are always available.

use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");
drums.load_instrument(Sampler(Kit("cr78")));
drums << [bd sd bd sd];
let dub = Delay(0.3, 0.7);
dub.Feedback << Sine(0.25).range(0.3, 0.8);
drums.load_effect(dub);
drums.load_effect(Lowpass(2000));
let drums = AudioTrack("drums");
drums.load_instrument(Sampler(Kit("cr78")));
drums << [bd sd bd sd];
let filter = Lowpass(2000);
drums.load_effect(filter);
filter.Cutoff << automation(#[0, 0.0], #[4, 1.0]).range_exp(200, 4000);