Skip to content

Sampler & Sample

Sampling in Resonon has three layers. A Kit is metadata: it describes a folder of WAV files and their note mapping. A Sampler (drums) or SamplerMelodic (pitched) is an instrument that loads a kit and plays on a track. A Sample is a single hit inside a pattern — bd, sd — that you can transform per-event with methods like .vel() and .pitch().

The constructors live in the standard library: use "std/instruments" { Sampler, SamplerMelodic, Kit };. Most methods return their receiver, so calls chain freely.

Kit methodReturnsMeaning
samples()ArraySample names in the kit
sample_info()Array[name, note, file] rows, sorted by note
name()StringKit display name
mode()String"oneshot" or "melodic"
author()StringAuthor from kit.toml, or ""
info()NulPrint a formatted kit table
Sampler (drum) methodReturnsMeaning
samples()ArrayLoaded sample names
sample_info()Array[name, note, file] rows, sorted by note
note_for(name)NumberMIDI note a sample is mapped to
name()StringSampler name (= kit name)
get(name)SampleExtract a standalone Sample copy
slot(name_or_note)DrumSampleRefHandle to a live sample slot
set_note(name, note)SamplerRemap a sample to a new MIDI note
choke_group(id, names)SamplerSamples that cut each other off
load_kit(kit)SamplerSwap in a different kit
param(path)ParamRefModulatable parameter handle
param_get(path)NumberRead a parameter value
param_set(path, value)SamplerSet a parameter (native range)
param_set_norm(path, value)SamplerSet a parameter (normalized 0–1)
params(filter?)NulPrint available parameters
DrumSampleRef methodReturnsMeaning
param(name)ParamRefModulatable slot parameter handle
param_get(name)NumberRead a slot parameter
param_set(name, value)DrumSampleRefSet a slot parameter
params(filter?)NulPrint slot parameters
envelope(a, d, s, r)DrumSampleRefSet ADSR (milliseconds, sustain 0–1)
name()StringSlot’s sample name
note()NumberSlot’s MIDI note
SamplerMelodic methodReturnsMeaning
load_sample(name, root?)SamplerMelodicLoad a sample by name
root(note)SamplerMelodicOverride the root note
envelope(a, d, s, r)SamplerMelodicSet ADSR (milliseconds, sustain 0–1)
set_loop(start, end)SamplerMelodicLoop points in seconds
set_loop_normalized(start, end)SamplerMelodicLoop points 0–1; reversed = ping-pong
samples() / sample_info() / root_for(name)Array / Array / NumberInspection
get(name)SampleExtract a standalone Sample copy
load_kit(kit)SamplerMelodicSwap in a different kit
param(path) / param_get / param_set / param_set_norm / params(filter?)Parameter access (as drum sampler)
Sample method (in patterns)ReturnsMeaning
vel(v)SampleVelocity, 0.0 and up
pitch(semitones)SamplePitch shift in semitones
pan(position)SampleStereo position, -1.0 to 1.0
slice(start, end)SamplePlay a region, 0.0–1.0 normalized
reverse()SamplePlay backwards

Load kit metadata by name. Without an argument, loads the built-in "CR-78". Kits are looked up in your project’s kits/ folder, in kit paths from your configuration, and in installed packages (qualified as "package/kit"). A folder without a kit.toml works too — every WAV inside is auto-detected.

use "std/instruments" { Kit };
let kit = Kit("CR-78");
PRINT kit.name(); // "CR-78"
PRINT kit.mode(); // "oneshot"
PRINT kit.samples(); // sample names
let custom = Kit("mykit"); // kits/mykit/ in your project
let packaged = Kit("drumlib/808"); // kit from an installed package

samples() / sample_info() / name() / mode() / author() / info()

Section titled “samples() / sample_info() / name() / mode() / author() / info()”

Inspection getters. samples() returns the sample names; sample_info() returns [name, note, file] rows sorted by MIDI note; mode() is "oneshot" (drums) or "melodic" (pitched); info() prints a formatted table.

for entry in kit.sample_info() {
PRINT f"{entry[0]} note={entry[1]}";
}
PRINT kit.author();
kit.info();

Create a drum sampler instrument from a Kit. One-shot playback with a 64-voice pool shared across all samples; when the pool is full, the quietest releasing voice is stolen first. Without an argument, creates an empty sampler — load a kit later with load_kit(). Passing a string is an error: wrap it as Sampler(Kit("name")).

use "std/instruments" { Sampler, Kit };
use "std/signals" { Sine };
let kit = Sampler(Kit("CR-78"));
let drums = AudioTrack("drums");
drums.load_instrument(kit);
drums << [bd sd bd sd];

samples() / sample_info() / note_for(name) / name()

Section titled “samples() / sample_info() / note_for(name) / name()”

Inspection mirrors the Kit getters, but reflects the sampler’s live state (after set_note() or load_kit()). note_for() returns the MIDI note a sample name is mapped to — patterns accept either form: [bd 42 sd 42].

PRINT kit.samples();
PRINT kit.note_for("bd"); // 36
PRINT kit.name(); // "CR-78"

Extract a sample as a standalone Sample value — an independent copy of the audio data, unlike slot(), which controls the live plugin slot. The result supports all sample methods.

let kick = kit.get("bd");
let reversed = kick.reverse().pitch(-5);

Remap a sample to a different MIDI note. Accepts a note name ("C2") or number. Returns the sampler, so remappings chain.

kit.set_note("bd", 60).set_note("sd", "D4");
kit.set_note("bd", 36).set_note("sd", 38); // restore

Put samples into a choke group (id 1–255): triggering any member releases the others’ voices — the classic closed-hat-cuts-open-hat behavior. Calls accumulate; groups are reset when a new kit is loaded.

kit.choke_group(1, #["hh", "cy"]);
drums << [cy _ _ _ hh _ _ _]; // hh chokes the ringing cymbal

Replace all samples with another kit, keeping the same plugin instance (and its place on the track).

kit.load_kit(Kit("TR-808"));
drums << [bd sd bd sd];

param(path) / param_get(path) / param_set(path, value) / param_set_norm(path, value) / params(filter?)

Section titled “param(path) / param_get(path) / param_set(path, value) / param_set_norm(path, value) / params(filter?)”

Path-based parameter access using slot_N/name paths, e.g. "slot_0/gain". param() returns a modulatable handle for <<; param_set_norm() takes a normalized 0–1 value. params() prints the full table, optionally filtered by substring. For everyday use, prefer the name-based slot() API below.

kit.params("gain");
kit.param_set("slot_0/gain", 0.8);
PRINT kit.param_get("slot_0/gain");

Return a DrumSampleRef — a handle to one live sample slot, addressed by sample name or MIDI note. This is the main API for per-sample sound shaping.

let bd_ref = kit.slot("bd");
PRINT bd_ref.name(); // "bd"
PRINT bd_ref.note(); // 36
kit.slot(38); // by MIDI note

param(name) / param_get(name) / param_set(name, value) / params(filter?)

Section titled “param(name) / param_get(name) / param_set(name, value) / params(filter?)”

Per-slot parameter access by plain name. param() returns a modulatable handle — bind a value or a signal with <<. Available parameters:

ParameterRangeMeaning
gain0.0 and upSlot amplitude
pan-1.0 to 1.0Stereo position
attack / decay / releasemsADSR times
sustain0.0–1.0ADSR sustain level
slice_start / slice_end0.0–1.0Playback region
reverse0 or 1Reverse playback
kit.slot("bd").param("gain") << 0.8;
kit.slot("bd").param("pan") << Sine(0.5).range(-0.5, 0.5);
kit.slot("sd").param("slice_end") << 0.5;

Set the slot’s ADSR in one call. Times are in milliseconds (0–5000); sustain is a level from 0.0 to 1.0.

kit.slot("bd").envelope(5, 0, 1.0, 50); // punchy
kit.slot("sd").envelope(5, 100, 0.8, 200); // natural

Create a pitched sampler from a melodic-mode kit: incoming notes transpose each sample relative to its root note. 32-voice pool; retriggering the same note releases the previous voice, different notes overlap freely. Without an argument, creates an empty sampler.

use "std/instruments" { SamplerMelodic, Kit };
use "std/signals" { Sine };
let keys = SamplerMelodic(Kit("keys"));
let track = AudioTrack("keys");
track.load_instrument(keys);
track << [C3 E3 G3 C4];

Load a sample by name from the current kit. The root note comes from the explicit second argument (name or number), or falls back to the kit.toml root field.

keys.load_sample("sound1");
keys.load_sample("sound2", "C3");

Override the root note of the most recently loaded sample. Accepts a note name or MIDI number.

keys.root("C4");

Set the amplitude ADSR. Times are in milliseconds (0–5000); sustain is 0.0–1.0.

keys.envelope(10, 100, 0.8, 200);

set_loop(start, end) / set_loop_normalized(start, end)

Section titled “set_loop(start, end) / set_loop_normalized(start, end)”

Set sustain-loop points — in seconds, or normalized 0.0–1.0 relative to the sample length. With start > end the loop plays ping-pong, reversing direction at each boundary. Loop points from kit.toml (loop_start/loop_end) are applied automatically. The loop is also modulatable via the LoopStart/LoopEnd parameters.

keys.set_loop_normalized(0.2, 0.8);
keys.set_loop_normalized(0.6, 0.3); // ping-pong
keys.param("LoopStart") << Sine(0.5).range(0.1, 0.4);

samples() / sample_info() / root_for(name) / get(name) / name() / load_kit(kit)

Section titled “samples() / sample_info() / root_for(name) / get(name) / name() / load_kit(kit)”

Inspection and management, analogous to the drum sampler. sample_info() rows are [name, root, file]; root_for() returns a sample’s root note (or NUL if unset); get() extracts a standalone Sample; load_kit() swaps the kit.

PRINT keys.samples();
PRINT keys.root_for("sound1"); // 60 (C4)
let s = keys.get("sound1");
keys.load_kit(Kit("keys"));

The five param* methods work exactly as on the drum sampler, including param_set_norm().

Sample events in patterns take methods directly: [bd.vel(0.5) sd]. Each method returns a new Sample, so they chain — the original is never mutated.

use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");
drums.load_instrument(Sampler(Kit("CR-78")));
drums << [bd sd bd sd];

Set the hit’s velocity: 1.0 is full strength, below is softer, above boosts. Clamped at 0.

drums << [bd sd.vel(0.3) sd.vel(0.3) sd.vel(1.0)]; // ghost notes

Pitch-shift the hit by semitones, positive or negative. Repeated calls in a chain accumulate.

drums << [bd bd.pitch(12) bd.pitch(-12)];
drums << [cb cb.pitch(2) cb.pitch(4) cb.pitch(7)]; // pitched cowbell melody

Place the hit in the stereo field: -1.0 hard left, 0.0 center, 1.0 hard right.

drums << [bd.pan(-1) sd.pan(1)];

Play only a region of the sample, with start and end normalized to 0.0–1.0 (start < end required).

drums << [bd.slice(0.0, 0.5) sd bd.slice(0.5, 1.0) sd];

Play the hit backwards. Calling it again on the same chain toggles back to forward playback.

drums << [bd.reverse() sd];
drums << [bd.slice(0.3, 0.8).reverse().vel(1.2).pan(-0.5)]; // chaining

Three kits ship with Resonon and are always available — docs and examples rely on them.

The default kit, with round-robin variations per sample.

NameNoteSoundNameNoteSound
bdC2 (36)Bass drumcbG#2 (44)Cowbell
rsC#2 (37)RimshotmaA2 (45)Maracas
sdD2 (38)SnaretbC3 (48)Tambourine
cpD#2 (39)ClapguC#3 (49)Guiro
hhF#2 (42)Hi-hathbD3 (50)High bongo
cyA#2 (46)CymballbD#3 (51)Low bongo
meB2 (47)Metal beatlcE3 (52)Low conga
clG#3 (56)Clave
NameNoteSoundNameNoteSound
bdC2 (36)Bass drumlcA#2 (46)Low conga
rsC#2 (37)RimshotmcB2 (47)Mid conga
sdD2 (38)SnarehcC3 (48)High conga
cpD#2 (39)ClapcbC#3 (49)Cowbell
chE2 (40)Closed hatclD3 (50)Clave
ohF2 (41)Open hatmaD#3 (51)Maracas
cyF#2 (42)CymballtG2 (43)Low tom
mtG#2 (44)Mid tomhtA2 (45)High tom

Two pitched samples for SamplerMelodic: sound1 (root C4) and sound2 (root C3).

A kit is a folder with WAV files and an optional kit.toml. Without the file, every WAV is auto-detected and mapped. With it, you control names, notes, and playback details:

[kit]
name = "My Kit" # display name (defaults to the folder name)
author = "Your Name" # optional
mode = "oneshot" # "oneshot" (drums) or "melodic" (pitched)
[defaults]
bd = "C2" # fallback note for samples without an explicit one
[samples]
bd = { files = ["kick_1.wav", "kick_2.wav"], note = "C2", choke_group = 1, velocity = 1.0 }
sd = { file = "snare.wav", note = 38 }
# melodic mode uses root instead of note, plus optional loop points
pad = { file = "pad.wav", root = "C4", loop_start = 0.3, loop_end = 0.9 }

files with multiple entries enables round-robin playback. When a sample has no explicit note, resolution falls back through [defaults], then the General MIDI drum mapping by name, then sequential assignment from C2. See the samplers chapter for a guided walkthrough of building custom kits.