Skip to content

Hello, Sound

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

Let’s make our first sounds. This page quickly covers the live-evaluation model and walks you through your first drum beat and melody.

The common way to run Resonon code and hear changes live is using the select-and-execute workflow in Visual Studio Code. You write Resonon code in a .non file, select (highlight) it, and press Cmd+Enter to execute it.

The first time you do this, the extension will automatically start a new Resonon runtime with active server. Then it will send the highlighted code to the server to run. Subsequent code execution then uses that same runtime, so Resonon “remembers” what was exected before.

Alternatively you can use the Resonon extension menu in the sidebar to start a server-runtime and connect to it, before running any Resonon code.

As a first test write the line below into a new .non file, select it and press Cmd+Enter. The output appears in VSCode’s Output panel (select “RESONON” from the dropdown).

PRINT "Hello, RESONON!";

Each evaluation shares the same session, so any state is “remembered” by the runtime and accessible in the code that gets evaluated after. To see this, select and execute the two following lines one by one. The first line defines a new greeting string and assigns the message. The second line the prints the previously defined greeting to the console.

let greeting = "Hello";
PRINT greeting;

You can highlight and execute an arbitrary amount of Resonon code at once - Just make sure the highlighted code is valid.

Resonon has a built-in sample engine. Let’s use it to play a simple drum rhythm. Execute the following code and you should hear it play. We will go over the example line by line afterwards.

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

You don’t have to understand all new concepts in their entirety just now. Tracks, instruments and patterns are all deep topics that can be explored as you progress in your Resonon journey. Check the relevant docs pages if you want to read more about anything unknown you encounter. The following guides will explain things in more detail.

Here is a quick explanation of what each line does:

  • use "std/instruments" { Sampler, Kit };

    Imports Sampler and Kit from the Resonon standard library, so we can use them in our program. Note that AudioTrack is an elementary feature of the language and thus needs no import.

  • let drums = AudioTrack("drums");

    Creates a new audio track called “drums”. Think of a tracks like in regular DAW. They have volume and pan, you can load an instrument and a chain of effects onto them, and their output is default-routed to the master output. More on this later.

  • let sampler = Sampler(Kit("cr78"));

    Creates a new Sampler instrument instance using the CR-78 drum sample Kit. Instruments can be loaded onto audio tracks, and then sent notes via patterns for playback. The Sampler is a Resonon built-in instrument used for non-melodic sample playback (mainly drums). We will later learn about the SamplerMelodic for sampling melodic instruments, as well as loading any VST3 or CLAP plugin instrument, and even writing your own instruments fully within the Resonon lanuguage.

  • drums.load_instrument(sampler);

    Loads the sampler instrument we just created onto the audio track. Any track can have exactly one instrument loaded onto it. If we then send notes to the track, it will automatically forward them to the loaded instrument. Of course, it is also possible to load effects onto a track, but for now let’s keep things simple.

  • drums << [bd sd bd sd];

    Assigns a pattern to the drums track for playback. The bd (bass drum) and sd (snare drum) are sample names from the CR-78 kit. Patterns are the heart of musical composition and sequencing in Resonon. The following guide will dive deeper into how patterns work. For now, just note that patterns are repeating and have a fixed length called the cycle-time. This is then divided by the number of events present in the pattern to determine their length. Per default, the cycle-time in resonon is set to 120bpm at 4 beats per cycle, so 2 seconds. In the above pattern we have 4 total events, so each drum hit gets exactly one beat of time - or 0.5 seconds.

    If you ever worked with the legendary Alex McLean’s TidalCycles or its newer cousin strudel.cc, you will see many parallels in how Resonon patterns work. We`re standing on the shoulders of giants here.

  • PLAY;

    Starts playback, so you hear the sequenced sounds.

Sample names like bd and sd are defined by the loaded kit. The CR-78 kit includes the following (and more):

NameSound
bdBass drum
sdSnare drum
hhHi-hat
cyCymbal
cpClap
cbCowbell
rsRimshot

Now try a slightly more interesting beat. What do you hear?

drums << [bd _ sd _, hh hh hh hh];

The comma creates a stack — both layers play simultaneously. The kick-snare rhythm plays alongside steady hi-hats. (More on patterns in the following guide.)

Use _ (underscore) for silence:

drums << [bd _ _ sd, hh _ hh _];

Rests take up the same time as a note — they create space in the pattern.

Patterns can contain pitched notes using scientific pitch notation. C4 is middle C (MIDI note 60):

use "std/instruments" { SamplerMelodic, Kit };
let keys = AudioTrack("keys");
keys.load_instrument(SamplerMelodic(Kit("epiano")));
keys << [C4 E4 G4 C5];
NotationMIDIDescription
C460Middle C
D462D above middle C
C#4 / Db461Sharps and flats
C572One octave up
6060MIDI number directly

Notes and numbers can be mixed freely: [C4 62 E4 67].

Control the playback speed with setbpm:

setbpm(140); // 140 BPM, 4 beats per cycle (default)

A cycle is the fundamental time unit — patterns repeat every cycle. With 4 beats per cycle at 120 BPM, one cycle lasts 2 seconds. A pattern with 4 elements gives each element one beat:

setbpm(120); // 2 seconds per cycle
drums << [bd sd bd sd]; // Each hit = 1 beat = 0.5 seconds

Use the second argument when your patterns have more or fewer than 4 beats:

setbpm(120, 8); // 8 beats per cycle (4 seconds per cycle)
ActionCodeKeybinding
PlayPLAY;F5
PausePAUSE;F5 (toggle)
Stop & resetShift+F5
Reset sessionCtrl+Shift+F5

Apply built-in effects to any audio track:

use "std/effects" { Delay, Lowpass };
drums.load_effect(Delay(0.25, 0.5)); // 250ms delay, 50% feedback
drums.load_effect(Lowpass(2000)); // Cut frequencies above 2kHz

Effects chain in the order you load them. Re-evaluating with different parameters replaces the existing effect by name:

drums.load_effect(Delay(0.125, 0.3)); // Replaces the previous Delay

Beyond built-in effects, Resonon lets you write custom DSP effects and synthesizers directly in the language — no plugins or external tools needed:

dsp instrument SineOsc {
voice state phase: 0.0;
fn render(note, velocity, gate) -> (out_l, out_r) {
let freq = mtof(note);
phase = fract(phase + freq * INV_SR);
let sample = sin(phase * TWOPI) * velocity * gate;
return (sample, sample);
}
}
let synth = AudioTrack("synth");
synth.load_instrument(SineOsc());
synth << [C4 E4 G4 C5];

This is a complete polyphonic synthesizer in 8 lines of DSP code. The Custom DSP page covers effects, instruments, parameters, and filters in detail.

You’ve played samples, applied effects, and heard a custom synth. Next, learn how patterns work in depth and how to send them to external synthesizers via MIDI: