Samplers
Resonon includes a built-in sample engine for drum machines and melodic instruments. Audio tracks host sampler instruments that respond to patterns.
Quick Start
Section titled “Quick Start”use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.load_instrument(Sampler(Kit("cr78")));drums << [bd sd bd sd];PLAY;Audio Tracks
Section titled “Audio Tracks”Audio tracks are channels for audio output. The name is used for identification and rendering.
let drums = AudioTrack("drums");let bass = AudioTrack("bass");let hats = AudioTrack("hats");Each track needs an instrument loaded before it can produce sound.
Track Controls
Section titled “Track Controls”drums.volume << 0.8; // Set volume to 80%drums.pan << -0.5; // Pan leftLoading Instruments
Section titled “Loading Instruments”Sampler()
Section titled “Sampler()”Sampler() loads a drum kit where each sample is mapped to a name or MIDI note.
Constructor forms
Section titled “Constructor forms”Sampler() // Empty sampler (no kit)Sampler(Kit("name")) // With local kitSampler(Kit("package/kit")) // With package-qualified kit| Parameter | Type | Description |
|---|---|---|
kit | Kit | Kit value (optional, creates empty sampler if omitted) |
Examples
Section titled “Examples”let kit = Sampler(Kit("cr78"));drums.load_instrument(kit);
// Package-qualified namelet kit = Sampler(Kit("drumlib/808"));drums.load_instrument(kit);SamplerMelodic()
Section titled “SamplerMelodic()”SamplerMelodic() is for pitched instruments (bass, keys, pads). Notes in patterns are mapped across the keyboard relative to a root note.
Constructor forms
Section titled “Constructor forms”SamplerMelodic() // Empty sampler (no kit)SamplerMelodic(Kit("name")) // With local kitSamplerMelodic(Kit("package/kit")) // With package-qualified kit| Parameter | Type | Description |
|---|---|---|
kit | Kit | Kit value (optional, creates empty sampler if omitted) |
The workflow for melodic samplers is: create the sampler, load a sample with its root note, optionally set an envelope, then load onto a track.
Examples
Section titled “Examples”let bass = SamplerMelodic(Kit("bass"));bass.load_sample("sub_bass", "C1");bass.envelope(10, 100, 1.0, 200);
let bass_track = AudioTrack("bass");bass_track.load_instrument(bass);bass_track << [C1 _ C1 _ | E1 _ E1 _ | G1 _ G1 _ | A1 _ A1 _];Playing Patterns with <<
Section titled “Playing Patterns with <<”The << operator sends a pattern to a track. Reassigning replaces the current pattern.
drums << [bd sd bd sd];drums << [bd*4]; // Replaces the previous patternLayered patterns use commas for parallel voices:
drums << [bd _ bd _, _ sd _ sd, hh*8];CR-78 Kit
Section titled “CR-78 Kit”The built-in CR-78 drum machine kit includes the following samples:
| Abbreviation | Sample | MIDI Note |
|---|---|---|
bd | Bass drum | 36 (C2) |
sd | Snare | 38 (D2) |
hh | Hi-hat | 42 (F#2) |
cy | Cymbal | 46 (A#2) |
cp | Clap | 39 (D#2) |
rs | Rimshot | 37 (C#2) |
cb | Cowbell | 56 |
cl | Clave | 75 |
ma | Maracas | 70 |
tb | Tambourine | 54 |
gu | Guiro | 73 |
hb | High bongo | 60 |
lb | Low bongo | 61 |
lc | Low conga | 64 |
me | Metal beat | 80 |
You can use MIDI note numbers instead of names, or mix both:
drums << [36 42 38 42]; // MIDI numbersdrums << [bd 42 sd 42]; // MixedSample Methods
Section titled “Sample Methods”Velocity
Section titled “Velocity”| Method | Velocity | Description |
|---|---|---|
.ghost | 0.3 | Subtle ghost note |
.soft | 0.5 | Half velocity |
.loud | 1.0 | Full velocity |
.accent | 1.0 | Emphasis |
.vel(n) | Custom | Explicit 0.0—1.0 |
drums << [bd.loud sd.soft bd.loud sd.soft];drums << [bd sd.ghost sd.ghost sd.ghost sd.accent];.pitch(semitones) shifts sample pitch. Positive values go higher, negative go lower.
drums << [bd bd.pitch(5) bd bd.pitch(-5)];drums << [bd bd.pitch(12) bd.pitch(-12)]; // Octave shiftsPanning
Section titled “Panning”.pan(position) sets stereo position from -1 (full left) to 1 (full right).
drums << [bd.pan(-1) sd.pan(1) bd.pan(-1) sd.pan(1)];drums << [hh.pan(-0.3) hh.pan(0.3) hh.pan(-0.3) hh.pan(0.3)];Method Chaining
Section titled “Method Chaining”Combine multiple methods on a single sample:
drums << [bd.loud.pan(-0.3) sd.soft.pitch(2)];drums << [bd.loud.pitch(-2).pan(-0.5) sd.accent.pitch(1).pan(0.5)];Volume Control
Section titled “Volume Control”Track volume is set with the .volume property:
drums.volume << 0.8;drums.volume << Sine(2).range(0.6, 1.0); // Tremolo effectKit Inspection
Section titled “Kit Inspection”Kit() loads kit metadata without creating a sampler plugin. Use it to inspect a kit before loading.
| Method | Args | Returns | Description |
|---|---|---|---|
.name() | — | String | Kit display name |
.mode() | — | String | "oneshot" or "melodic" |
.author() | — | String | Kit author (empty string if not set) |
.samples() | — | Array | List of sample names |
.sample_info() | — | Array | [name, note, file] entries sorted by note |
.info() | — | Nul | Print formatted kit table |
Examples
Section titled “Examples”let k = Kit("cr78");show(k); // Formatted sample table
k.name(); // "CR-78"k.mode(); // "oneshot"k.author(); // ""k.samples(); // ["bd", "rs", "sd", "cp", ...]k.sample_info(); // [[bd, 36, "samples/BD_1.wav"], ...]k.info(); // Print formatted table to consoleSampler (Drum) Methods
Section titled “Sampler (Drum) Methods”Once a drum sampler is loaded, it exposes methods for inspection, sample selection, envelope editing, note remapping, and parameter access.
Method Overview
Section titled “Method Overview”| Method | Args | Returns | Description |
|---|---|---|---|
.slot(name) | String or Number | DrumSampleRef | Get a reference to a sample slot |
.samples() | — | Array | List of sample names |
.sample_info() | — | Array | [name, note, file] entries |
.note_for(name) | String | Number | MIDI note for a sample name |
.get(name) | String | Sample | Extract sample as standalone value |
.select(name_or_note) | String or Number | Sampler | Select a slot for editing |
.selected() | — | Number | Currently selected note |
.set_note(name, note) | String, Number/String | Sampler | Remap a sample to a new note |
.choke_group(id, names) | Number, Array | Sampler | Assign samples to a choke group |
.envelope(...) | 4 or 5 args | Sampler | Set ADSR envelope |
.name() | — | String | Kit name |
.param(path) | String | Number | Read a parameter value |
.set_param(path, value) | String, Number | Sampler | Set a parameter value |
.set_param_norm(path, value) | String, Number | Sampler | Set a parameter using normalized 0–1 value |
.params() | — | Nul | Print all parameters |
.params(filter) | String | Nul | Print parameters matching filter |
Inspection
Section titled “Inspection”let drums = Sampler(Kit("cr78"));drums.samples(); // ["bd", "rs", "sd", "cp", ...]drums.sample_info(); // [[bd, 36, "samples/BD_1.wav"], ...]drums.note_for("bd"); // 36drums.name(); // "cr78".get(name) extracts a sample as a standalone Sample value:
let kick = drums.get("bd");Sample Selection and Envelope
Section titled “Sample Selection and Envelope”There are two ways to set an envelope on a drum sample:
5-argument form — specify the sample name directly:
drums.envelope("bd", 5, 50, 0.8, 100);Select-then-4-argument form — select a slot first, then apply:
drums.select("bd");drums.envelope(5, 50, 0.8, 100);drums.selected(); // 36 (the MIDI note of the selected slot)Envelope Parameters
Section titled “Envelope Parameters”| Parameter | Type | Range | Default | Description |
|---|---|---|---|---|
attack | Number | 0—5000 ms | — | Attack time in milliseconds |
decay | Number | 0—5000 ms | — | Decay time in milliseconds |
sustain | Number | 0.0—1.0 | — | Sustain level (amplitude) |
release | Number | 0—5000 ms | — | Release time in milliseconds |
Note Remapping
Section titled “Note Remapping”.set_note(name, note) reassigns a sample to a different MIDI note. The note can be a number or a note name:
drums.set_note("bd", 48); // Remap bass drum to C3drums.set_note("bd", "C3"); // Same, using note nameChoke Groups
Section titled “Choke Groups”.choke_group(id, names) assigns samples to a choke group from code. Samples in the same group cut each other off (e.g., open hi-hat chokes closed hi-hat). The group id must be 1—255.
let drums = Sampler(Kit("cr78"));drums.choke_group(1, ["hh", "cy"]); // Group 1: hh and cy choke each otherdrums.choke_group(2, ["hb", "lb"]); // Group 2: bongos — group 1 is preservedMultiple calls accumulate — each call adds to the existing overrides without removing previous ones. This is useful for prototyping choke configurations before committing them to kit.toml.
Parameter Access
Section titled “Parameter Access”Use .params() to list all available parameters, and .param() / .set_param() to read and write them:
drums.params(); // Print all parametersdrums.params("bd"); // Print parameters for bass drum onlydrums.param("slot_0/gain"); // Read a parameterdrums.set_param("slot_0/gain", 0.5); // Set a parameterParameters are addressed by path. After selecting a slot, legacy names like "Gain", "Pan", "Attack", etc. are also accepted:
drums.select("bd");drums.set_param("Gain", 0.8);DrumSampleRef
Section titled “DrumSampleRef”The .slot() method on a drum sampler returns a DrumSampleRef, a reference to a specific sample slot. This is the most ergonomic way to edit individual drum samples.
Creating a DrumSampleRef
Section titled “Creating a DrumSampleRef”let drums = Sampler(Kit("cr78"));drums.load_instrument(drums);
let kick = drums.slot("bd"); // DrumSampleRef for bass drumlet snare = drums.slot("sd"); // DrumSampleRef for snarePass any sample name as a string, or a MIDI note number:
drums.slot("hh") // hi-hat (by name)drums.slot("cp") // clapdrums.slot(36) // kick (by MIDI note)Because names are strings, you can use variables:
for s in drums.samples() { drums.slot(s).gain << 0.7;}Methods
Section titled “Methods”| Method | Args | Returns | Description |
|---|---|---|---|
.envelope(a, d, s, r) | 4 Numbers | DrumSampleRef | Set ADSR envelope |
.name() | — | String | Sample name |
.note() | — | Number | MIDI note number |
drums.slot("bd").name(); // "bd"drums.slot("bd").note(); // 36drums.slot("bd").envelope(5, 50, 0.8, 100);Properties
Section titled “Properties”DrumSampleRef properties return automatable parameter references. You can assign values directly with <<, or modulate them with signals.
| Property | Description |
|---|---|
.gain | Sample gain |
.pan | Stereo position |
.attack | Attack time (ms) |
.decay | Decay time (ms) |
.sustain | Sustain level |
.release | Release time (ms) |
.slice_start | Sample start point |
.slice_end | Sample end point |
.reverse | Reverse playback |
Setting values
Section titled “Setting values”drums.slot("bd").gain << 0.8;drums.slot("bd").pan << -0.3;drums.slot("sd").attack << 10;drums.slot("sd").release << 200;Signal modulation
Section titled “Signal modulation”drums.slot("hh").pan << Sine(0.5).range(-1, 1); // Auto-pan hi-hatdrums.slot("bd").gain << Sine(2).range(0.6, 1.0); // Pulsing kickSamplerMelodic Methods
Section titled “SamplerMelodic Methods”Melodic samplers provide methods for loading samples, setting envelopes, loop control, and inspection.
Method Overview
Section titled “Method Overview”| Method | Args | Returns | Description |
|---|---|---|---|
.load_sample(name) | String | Sampler | Load sample, root from kit.toml |
.load_sample(name, root) | String, String/Number | Sampler | Load sample with explicit root |
.envelope(a, d, s, r) | 4 Numbers | Sampler | Set ADSR envelope |
.root(note) | String or Number | Sampler | Override root note |
.set_loop(start, end) | 2 Numbers | Sampler | Set loop points in seconds |
.set_loop_normalized(start, end) | 2 Numbers | Sampler | Set loop points (0.0—1.0) |
.samples() | — | Array | List of sample names in the kit |
.sample_info() | — | Array | [name, root_or_nil, file] entries |
.root_for(name) | String | Number or Nul | Root note for a sample |
.get(name) | String | Sample | Extract sample as standalone value |
.name() | — | String | Plugin name |
.param(path) | String | Number | Read a parameter value |
.set_param(path, value) | String, Number | Sampler | Set a parameter value |
.set_param_norm(path, value) | String, Number | Sampler | Set a parameter using normalized 0–1 value |
.params() | — | Nul | Print all parameters |
.params(filter) | String | Nul | Print parameters matching filter |
Loading Samples
Section titled “Loading Samples”.load_sample() loads a sample from the kit and prepares it for pitched playback.
1-argument form — root note comes from kit.toml:
let keys = SamplerMelodic(Kit("keys"));keys.load_sample("sound1"); // Root C4 from kit.toml2-argument form — explicit root note:
keys.load_sample("sound1", "C4");keys.load_sample("sound1", 60); // Same, using MIDI numberRoot Note Override
Section titled “Root Note Override”.root(note) changes the root note after loading, without reloading the sample:
keys.load_sample("sound1", "C4");keys.root("C3"); // Shift root down an octavekeys.root(48); // Same, using MIDI numberEnvelope
Section titled “Envelope”.envelope(attack, decay, sustain, release) sets the ADSR envelope.
| Parameter | Type | Range | Default | Description |
|---|---|---|---|---|
attack | Number | 0—5000 ms | — | Attack time in milliseconds |
decay | Number | 0—5000 ms | — | Decay time in milliseconds |
sustain | Number | 0.0—1.0 | — | Sustain level (amplitude) |
release | Number | 0—5000 ms | — | Release time in milliseconds |
keys.envelope(10, 100, 0.8, 200); // 10ms attack, 100ms decay, 0.8 sustain, 200ms releaseLoop Points
Section titled “Loop Points”.set_loop(start_secs, end_secs) sets loop points in seconds. The values are converted to normalized positions using the loaded sample’s duration.
keys.set_loop(0.5, 2.0); // Loop from 0.5s to 2.0s.set_loop_normalized(start, end) sets loop points directly as normalized positions (0.0—1.0):
keys.set_loop_normalized(0.3, 0.9); // Loop over the middle 60% of the sampleWhen start > end, reverse (ping-pong) looping is enabled:
keys.set_loop_normalized(0.9, 0.3); // Reverse loopInspection
Section titled “Inspection”let keys = SamplerMelodic(Kit("keys"));keys.samples(); // ["sound1", "sound2"]keys.sample_info(); // [["sound1", 60, "/path/to/sound1.wav"], ...]keys.root_for("sound1"); // 60 (C4)keys.name(); // Plugin namekeys.params(); // Print all parametersFull Example
Section titled “Full Example”let pad = SamplerMelodic(Kit("keys"));pad.load_sample("sound1", "C4");pad.envelope(200, 300, 0.7, 500);pad.set_loop_normalized(0.2, 0.8);
let pad_track = AudioTrack("pad");pad_track.load_instrument(pad);pad_track.volume << 0.6;
pad_track << [C3 _ E3 _ | G3 _ C4 _ | E4 _ G4 _ | C5 _ _ _];Custom Kits
Section titled “Custom Kits”Place your own samples in a kits/ folder:
kits/mykit/ kit.toml (optional metadata) kick.wav snare.wav hihat.wavkit.toml Format
Section titled “kit.toml Format”A kit.toml file has three sections: [kit] for metadata, [defaults] for default note mappings, and [samples] for sample definitions.
[kit] Section
Section titled “[kit] Section”[kit]name = "My Kit"author = "Your Name"mode = "oneshot" # "oneshot" (drum) or "melodic"| Field | Type | Description |
|---|---|---|
name | String | Display name (falls back to directory name) |
author | String | Kit author |
mode | String | "oneshot" for drums, "melodic" for pitched instruments |
[defaults] Section
Section titled “[defaults] Section”Default note mappings for sample names. Values can be note names or MIDI numbers:
[defaults]bd = "C2"sd = "D2"hh = 42[samples] Section
Section titled “[samples] Section”Each sample has a key (the name used in patterns) and a configuration table:
| Field | Type | Description |
|---|---|---|
files | Array | WAV file paths (relative to kit directory). Multiple files enable round-robin. |
file | String | Single file path (backward compatibility, prefer files) |
note | Number or String | MIDI note that triggers this sample |
root | Number or String | Root note for melodic samples (original pitch of the recording) |
choke_group | Number | Samples in the same group cut each other off |
velocity | Number | Default velocity (0.0—1.0), defaults to 1.0 |
loop_start | Number | Loop start position (0.0—1.0, normalized) |
loop_end | Number | Loop end position (0.0—1.0, normalized) |
Drum Kit Example
Section titled “Drum Kit Example”[kit]name = "CR-78"mode = "oneshot"
[samples]bd = { files = ["samples/BD_1.wav", "samples/BD_2.wav"], note = "C2" }sd = { files = ["samples/SD_1.wav", "samples/SD_2.wav"], note = "D2" }hh = { files = ["samples/HH_1.wav"], note = "F#2", choke_group = 1 }hh_open = { files = ["samples/HH_open.wav"], note = "A#2", choke_group = 1 }Melodic Kit Example
Section titled “Melodic Kit Example”[kit]name = "keys"mode = "melodic"
[samples]sound1 = { files = ["samples/sound1.wav"], root = "C4" }sound2 = { files = ["samples/sound2.wav"], root = "C3", loop_start = 0.3, loop_end = 0.9 }Note Resolution Order
Section titled “Note Resolution Order”When a sample’s MIDI note is not explicitly set, it is resolved in this order:
- Explicit
notefield in the sample config - Default from the
[defaults]section - GM drum mapping based on the sample name (e.g.,
bdmaps to C2) - Sequential assignment starting from C2 (36)
Auto-Detection
Section titled “Auto-Detection”If kit.toml is omitted, Resonon auto-detects WAV files in the kit directory. Each file becomes a sample named after the filename (without extension), with notes assigned sequentially.
let custom = Sampler(Kit("mykit"));Package-Qualified Kit Names
Section titled “Package-Qualified Kit Names”Kits from installed packages use the "package/kit" syntax:
let drums = Sampler(Kit("drumlib/808"));let pad = SamplerMelodic(Kit("synthpack/pads"));The search path for package kits is:
~/.config/resonon/lib/{package}/kits/{kit}/See Package Management for details on installing and managing packages.
CLAP Instruments
Section titled “CLAP Instruments”External CLAP instrument plugins can also be loaded onto audio tracks. See Plugins for details on loading and controlling CLAP instruments.
let synth = Instrument("Surge XT");let lead = AudioTrack("lead");lead.load_instrument(synth);lead << [C4 E4 G4 C5];Retrieving the Loaded Instrument
Section titled “Retrieving the Loaded Instrument”Use get_instrument() to retrieve the instrument loaded on a track. This returns the original Sampler, SamplerMelodic, or Instrument value — a shared reference, so any parameter changes affect the live instrument.
let drums = AudioTrack("drums");drums.load_instrument(Sampler(Kit("cr78")));
// Later, retrieve and tweak parameterslet kit = drums.get_instrument();kit.slot("bd").envelope(2, 80, 0.3, 60);kit.slot("hh").release << Sine(0.25).range(40, 180);This is especially useful in multi-file projects where tracks are created in one module and used in another:
let drums = tracks.drums();let kit = drums.get_instrument();kit.slot("bd").gain << 0.8;Returns NUL if no instrument has been loaded.