Skip to content

Audio Input

Resonon can capture audio from microphones, instruments, and other input devices. Route inputs to tracks, monitor in real time with effects, record multi-track takes, and save recordings to disk.

Use audio_devices() to list all audio devices on your system. Each entry is a dict with these fields:

FieldTypeDescription
nameStringDevice name
input_channelsNumberNumber of input channels
output_channelsNumberNumber of output channels
sample_rateNumberDefault sample rate (Hz)
is_defaultBooleanWhether this is the system default
let devices = audio_devices();
for d in devices {
if d.input_channels > 0 {
PRINT d.name + " (" + d.input_channels + " inputs)";
}
}

For projects that use a fixed recording setup, define named input channels in your configuration file (~/.config/resonon/config.toml):

[audio.input]
device = "Focusrite Scarlett 2i2"
[audio.input.channels]
mic = [0]
vocals = [0, 1]
guitar = [2]

Channel mapping rules:

  • Single-element array (e.g. [0]) — mono input from that channel
  • Two-element array (e.g. [0, 1]) — stereo input from those channels

Once configured, use the channel name with .input() instead of the device name:

let vox = AudioTrack("vocals");
vox = vox.input("vocals"); // Resolves to channels [0, 1] on the Scarlett

Use .input(name) on an AudioTrack to route an audio input:

let mic = AudioTrack("mic_track");
mic = mic.input("MacBook Pro Microphone");

The argument can be either a device name or a named channel from your [audio.input.channels] configuration. The method is chainable — it returns the AudioTrack.

Arm a track for recording with .arm(). The track must have an input source configured via .input() first — calling .arm() without one produces an error. Only armed tracks capture audio when RECORD is triggered. Disarm with .disarm().

mic = mic.arm();
// ... record ...
mic = mic.disarm();

Control whether the input signal is heard through the output with .monitor(mode):

ModeBehavior
"in"Always hear input through output
"auto"Hear input only when the track is armed or recording
"off"Input is not monitored (silent)
mic = mic.monitor("in"); // Always hear the microphone
mic = mic.monitor("auto"); // Hear only when armed/recording
mic = mic.monitor("off"); // Silence monitoring

Starts playback and begins capturing audio on all armed tracks simultaneously:

RECORD;

Stops playback and recording. Tracks remain armed and ready to record again:

PAUSE;

Stops recording, disarms all tracks (armed and recording), and resets the transport to the beginning:

STOP;
CommandStops playbackStops recordingDisarms tracksResets transport
PAUSEYesYesNoNo
STOPYesYesYesYes

A typical recording session in the REPL:

mic = mic.arm();
mic = mic.monitor("auto");
RECORD;
// ... play or sing ...
PAUSE;

Arm multiple tracks to record from different inputs simultaneously. RECORD captures on all armed tracks at once:

let vocals = AudioTrack("vocals");
vocals = vocals.input("mic").arm().monitor("auto");
let guitar = AudioTrack("guitar");
guitar = guitar.input("guitar").arm().monitor("auto");
RECORD;
// ... perform ...
PAUSE;
// Each track has its own independent recording
let vocal_take = vocals.take();
let guitar_take = guitar.take();

There are two ways to get recordings from a track:

Returns a RecordedAudio object for inspection and saving, or NUL if nothing was captured. Consumes the buffer — calling .take() again returns NUL until a new recording is made.

let take1 = mic.take();
if take1 != NUL {
PRINT take1.duration();
take1.save("take1.wav");
}

Saves the recording directly to a WAV file and returns the AudioTrack (chainable). Also consumes the buffer.

mic.save("takes/vocals_01.wav");

Both approaches consume the recording buffer, so use one or the other — not both for the same take.

Monitored input flows through the track’s effect chain before reaching the output. This means you can apply effects to a live input signal:

let vox = AudioTrack("vocals");
vox = vox.input("mic");
vox = vox.load_effect(Reverb(0.3, 0.5));
vox = vox.load_effect(Compressor(-18, 4, 0.01, 0.1));
vox = vox.monitor("in");
// Now hear your voice with reverb and compression in real time

Live effects also work with routing. Use .send_to() to route processed input to other tracks:

let reverb_bus = AudioTrack("reverb_bus");
reverb_bus = reverb_bus.load_effect(Reverb(0.5, 0.7));
let vox = AudioTrack("vocals");
vox = vox.input("mic").monitor("in");
vox = vox.send_to(reverb_bus, 0.4); // Send 40% to reverb bus
MethodReturnsDescription
.input(name)AudioTrackRoute an input device or named channel
.arm()AudioTrackArm track for recording
.disarm()AudioTrackDisarm track
.monitor(mode)AudioTrackSet monitor mode: "in", "auto", or "off"
.take()RecordedAudio / NULRetrieve recording (consumes buffer)
.save(path)AudioTrackSave recording to WAV file (consumes buffer)
.is_armed()BooleanTrue if the track is armed or recording
.is_recording()BooleanTrue if the track is actively recording
MethodReturnsDescription
.duration()NumberLength of the recording in seconds
.samples()NumberTotal sample count
.sample_rate()NumberSample rate in Hz
.save(path)RecordedAudioSave to a WAV file (chainable)
let take1 = mic.take();
if take1 != NUL {
PRINT take1.duration();
PRINT take1.samples();
PRINT take1.sample_rate();
take1.save("recording.wav");
}

Chaining example — save and continue using the recording:

let take1 = mic.take();
if take1 != NUL {
take1.save("backup.wav").save("archive/backup_copy.wav");
}
// 1. Discover input devices
let devices = audio_devices();
for d in devices {
if d.input_channels > 0 {
PRINT d.name;
}
}
// 2. Create tracks with different inputs
let vocals = AudioTrack("vocals");
vocals = vocals.input("mic");
vocals = vocals.load_effect(Compressor(-18, 4, 0.01, 0.1));
let guitar = AudioTrack("guitar");
guitar = guitar.input("guitar");
guitar = guitar.load_effect(Reverb(0.2, 0.4));
// 3. Arm and enable auto monitoring
vocals = vocals.arm().monitor("auto");
guitar = guitar.arm().monitor("auto");
// 4. Record
RECORD;
// ... perform ...
PAUSE;
// 5. Retrieve and save recordings
let vocal_take = vocals.take();
if vocal_take != NUL {
PRINT "Vocals: " + vocal_take.duration() + "s";
vocal_take.save("takes/vocals_01.wav");
}
guitar.save("takes/guitar_01.wav");
// 6. Disarm (or use STOP to disarm all at once)
vocals = vocals.disarm();
guitar = guitar.disarm();