Skip to content

Live Workflow

Live coding in resonon is a conversation with a running session. You start with a blank runtime and build it up: set up a track, load an instrument, send it a pattern, hit play. Then you keep going — swap the pattern, add a layer, tweak a parameter — and hear each change without ever stopping the music. This page is about that loop: how edits land in time, how the transport behaves, and how to keep an eye on what’s playing.

If your editor isn’t connected yet, set that up first in VSCode Extension. Everything here works the same from the editor’s Cmd+Enter or the REPL.

Here’s a whole starting point — a track, an instrument, a beat, and playback:

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

The runtime remembers all of this. The next time you evaluate code, drums still exists — you don’t redefine it, you talk to it. That persistence is the whole point of the live workflow: you grow a piece one evaluation at a time instead of re-running a file from scratch.

Now change the beat. With the session still playing, evaluate a new pattern for the same track:

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

You won’t hear the swap happen mid-bar. A new pattern takes effect at the next cycle boundary — the current cycle finishes, then the new one starts. This is what keeps live edits musical: you can evaluate whenever you like and trust that the change lands on the downbeat, in time, never halfway through a note.

Because the swap is quantized and the session persists, the everyday rhythm of live coding is: tweak the line, evaluate, listen, repeat. Layer more tracks the same way — each is just another AudioTrack you send patterns to.

Patterns aren’t the only thing you can swap mid-session. A track’s structure — its instrument, its effect chain, where it routes — is described the same declarative way, so re-evaluating the lines that build it makes the live graph match what you just wrote:

use "std/effects" { Lowpass, Delay };
drums.fx(#[Lowpass("lowpass", 4000)]);
drums.fx(#[Lowpass("lowpass", 4000), Delay("delay", 0.25, 0.4)]); // delay inserted, filter untouched

Add an effect to the array and it’s inserted; delete one and it’s removed; move one and the chain reorders. Effects you left alone keep their live instances, so their parameter values and any running modulation survive the edit. The same holds for the track itself and for its instrument: AudioTrack("drums") returns the track you already have, and re-attaching the instrument you already loaded preserves it.

The upshot is that structural edits belong in the same loop as pattern edits. You don’t need RESET; to add a plugin or re-order a chain — that’s the point of writing the rig as a layout.

Transport is the session-wide play head. You can drive it from code or, in the editor, from the keyboard.

ActionCodeKeybinding
PlayPLAY;F5
PausePAUSE;F5 (toggle)
StopSTOP;Shift+F5
ResetRESET;Ctrl+Shift+F5
PLAY; // resume playback from where the play head sits
PAUSE; // pause where you are — sound stops, position is kept
STOP; // stop and return to the start; a third STOP kills all sound
RESET; // wipe the whole session and start from a blank runtime

The four differ in how much they tear down:

  • PLAY resumes playback. The play head picks up wherever it was paused, and cycle-based code is primed so it’s ready the instant the transport rolls.
  • PAUSE stops playback but keeps your position, so the next PLAY continues from the same spot. Sounding notes are released (all-notes-off) so nothing hangs.
  • STOP is a harder stop: playback halts and the play head returns to the start. It stops the transport, not the sound — a reverb or delay still ringing goes on ringing, the same way it does in a DAW, and your master fader stays exactly where you put it. Your session — tracks, instruments, patterns — is untouched, so PLAY brings it all back.
  • STOP again, and a third time, is the panic. Once the transport is already stopped, further stops escalate: the master fades to silence over a few milliseconds, every instrument and effect is flushed — reverb tanks, delay lines, sounding voices — and playback comes back from a genuinely clean graph. Nothing about your session is destroyed; only what was still making noise.
  • RESET is the big one. It throws the entire session away — every variable, track, instrument, and effect — and gives you a fresh runtime. Reach for it when you want a clean slate, not when you just want silence.

Two more transport commands cover deeper ground:

  • RECORD; resumes playback like PLAY, but also starts capturing audio on any armed tracks. With nothing armed it just plays. Arming tracks, choosing inputs, and pulling takes off disk are covered in Recording & Input.
  • SEEK <expr>; jumps the play head to a cycle position — SEEK 16; moves to cycle 16. It comes into its own with timed arrangements; see Arrangements.

While you play, you’ll want to see what’s going on — levels, routing, MIDI, plugin editors. Resonon gives you a few windows onto a running session.

Plugin editors. A third-party instrument or effect with a graphical editor opens its own window with .show_gui() (and .hide_gui() to close it):

let synth = Instrument("Surge XT");
let lead = AudioTrack("lead");
lead.instrument(synth);
if synth.supports_gui() {
synth.show_gui();
}

Built-in DSP effects have no GUI — you drive those with .params() and param_set. See Plugins.

TUI views. From a terminal, resonon view <name> opens a text-mode panel connected to a running server:

Terminal window
resonon view mixer # track levels and the master
resonon view routing # how audio and MIDI are wired
resonon view scope # an oscilloscope on the output
resonon view console # server output and shortcut hints
resonon view midi_monitor # live MIDI messages

In the editor these are the same panels under the sidebar’s Views section. The mixer, routing, and scope views are also the quickest way to see a swap or a new layer take hold. For every option, see the CLI Reference.

Visuals. If your piece drives shaders, open the native render window with the Open Visuals button (or screen.show_window()) once resonon server is running. The visuals system itself is covered in Audioreactive Shaders.

You can build, swap, and steer a session live. Next, share that session — or learn when to drop the live loop entirely and render to a file.