Skip to content

MIDI Input

Route MIDI from external keyboards, controllers, and instruments into Resonon tracks.

midi_input_ports() returns an array of available MIDI input port names:

let in_ports = midi_input_ports();
PRINT in_ports;
// ["IAC Driver Resonon", "USB MIDI Keyboard"]

midi_input_connect(port, alias) opens a connection and assigns it an alias for later reference:

midi_input_connect("IAC Driver Resonon", "iac");

The alias is a short name you choose. Use it when routing input to tracks.

The port name does not need to be exact. Resonon tries an exact match first, then falls back to substring matching:

// Full port name is "Arturia KeyStep 37"
midi_input_connect("KeyStep", "kb");

If multiple ports contain the substring, the first match is used. Use a more specific substring or the full name to avoid ambiguity.

Each alias must be unique. Connecting a second port with the same alias produces an error:

Input port alias 'kb' already connected

Disconnect the existing alias first if you need to reuse it.

.input(alias) routes all MIDI channels from the named input to the track:

let keys = MidiTrack(1, 100).input("iac");

.input(alias, channel) filters to a single MIDI channel:

let bass = MidiTrack(2, 100).input("iac", 1);

The special alias "all" listens to every connected input port:

let omni = MidiTrack(3, 80).input("all");

Monitor mode controls whether incoming MIDI is passed through to the track’s output.

ModeBehavior
"off"No pass-through (default)
"in"Always pass input through to output
"auto"Pass through only when no pattern is playing
// Always hear the keyboard
let keys = MidiTrack(1, 100).input("iac").monitor("in");
// Hear keyboard only when the track is idle
let keys_auto = MidiTrack(1, 100).input("iac").monitor("auto");
// Silent monitoring (record only)
let keys_off = MidiTrack(1, 100).input("iac").monitor("off");

When monitor mode is "in" or "auto", incoming MIDI events are forwarded to the track’s output port. Several things happen during thru-play:

Incoming MIDI is remapped to the track’s output channel. If your keyboard sends on channel 1 but the track outputs on channel 5, the forwarded notes arrive on channel 5. This keeps thru-play consistent with pattern output.

If an input port and output port form a loop (for example, both connected to the same IAC bus), events can circulate endlessly. Resonon detects this automatically: if thru-play exceeds the rate limit, it is temporarily suppressed. You will see a warning in the console:

[resonon] MIDI feedback loop detected on ch1 — thru-play suppressed (will retry after 1000ms cooldown)

After a brief cooldown, thru-play re-enables automatically. To avoid feedback loops, use separate ports for input and output, or set monitor mode to "off".

Incoming CC messages are automatically captured and made available as Cc() signal sources. For example, if your controller sends CC 1 (mod wheel), that value is immediately usable in patterns and modulation. See MIDI CC for details on using CC signals.

Chain .with_input(), .with_monitor(), and .with_output() in a single expression for a complete input-to-output routing:

let thru = MidiTrack(1, 100)
.with_input("iac")
.with_monitor("in")
.with_output("iac");

This creates a track that receives from the "iac" input, monitors everything, and sends to the "iac" output.

midi_clock_send(true) enables 24 PPQ clock output to all connected MIDI output ports. Resonon becomes the clock master, sending Start, Stop, and Continue transport messages alongside clock ticks.

midi_connect("IAC Driver Bus 1", "daw");
midi_clock_send(true);
setbpm(120);
PLAY;

Disable with midi_clock_send(false).

Clock send and clock follow are mutually exclusive — enabling one disables the other.

midi_clock_follow(alias) syncs Resonon’s tempo and transport to an external MIDI clock source arriving on the named input port:

midi_input_connect("DAW Output", "daw");
midi_clock_follow("daw");

When clock follow is active:

  • Tempo is derived by averaging 24 ticks (one quarter note)
  • Start resets playback to the beginning
  • Stop pauses playback
  • Continue resumes from the current position
  • A soft PLL applies phase correction (up to ~1ms per quarter note) to stay tightly locked

Disable clock follow by passing false:

midi_clock_follow(false);

midi_delay(ms) adds a global delay (in milliseconds) to all outgoing MIDI — notes and clock. This is useful for compensating audio output latency so that MIDI and audio stay aligned.

midi_delay(15); // delay all MIDI output by 15ms
PRINT midi_delay(); // getter: prints 15

midi_clock_offset(ms) adds an offset (in milliseconds) applied only to clock ticks. Positive values delay ticks, negative values send them earlier.

midi_clock_offset(-5); // send clock ticks 5ms early
PRINT midi_clock_offset(); // getter: prints -5

Clock offset is independent of midi_delay(). The total delay on clock ticks is midi_delay() + midi_clock_offset():

midi_delay(15); // all MIDI delayed 15ms
midi_clock_offset(-5); // clock ticks shifted 5ms earlier
// Effective clock delay: 15 + (-5) = 10ms
// Effective note delay: 15ms
FunctionDescription
midi_clock_send(true)Enable 24 PPQ clock output (master mode)
midi_clock_send(false)Disable clock output
midi_clock_follow(alias)Sync to external clock on input port
midi_clock_follow(false)Disable clock follow
midi_delay(ms)Set global MIDI output delay (notes + clock)
midi_delay()Get current output delay in ms
midi_clock_offset(ms)Set clock-only offset (positive = later, negative = earlier)
midi_clock_offset()Get current clock offset in ms

midi_routing() prints a summary of all MIDI connections, active slots, and clock state:

midi_routing();

Example output:

MIDI Routing
Output Ports:
"daw" -> "IAC Driver Bus 1"
"synth" -> "Prophet Rev2"
Input Ports:
"kb" -> "Arturia KeyStep 37"
Active Slots:
ch1 -> "daw" (ch 1)
synth:ch1 -> "synth" (ch 1)
Clock:
mode: follower (from "kb")

In master mode, the clock section shows the send state:

Clock:
mode: master (sending)

If nothing is connected, it shows (no MIDI connections).

midi_input_disconnect(alias) closes the named input connection:

midi_input_disconnect("iac");

On disconnect, Resonon sends All Notes Off (CC 123) to any output ports that were receiving thru-play from the disconnected input. This prevents stuck notes when you unplug or disconnect a controller mid-performance.

A full workflow: list ports, connect with substring matching, create a track with input and monitoring, inspect routing, play, and clean up:

// List available ports
PRINT midi_input_ports();
PRINT midi_ports();
// Connect ports (substring match)
midi_input_connect("KeyStep", "kb");
midi_connect("IAC Driver Bus 1", "daw");
// Create a pass-through track
let keys = MidiTrack("keys", 1, 100)
.with_input("kb")
.with_monitor("in")
.with_output("daw");
// Check the routing
midi_routing();
PLAY;
// ... play your MIDI keyboard ...
PAUSE;
// Clean up
midi_input_disconnect("kb");
midi_disconnect("daw");
ErrorCauseFix
Input port alias '...' already connectedAlias already in useDisconnect the alias first, or choose a different alias
No MIDI input connected with alias '...'Clock follow with unrecognized aliasConnect the input port with midi_input_connect() first
Port not foundPort name not recognizedCheck midi_input_ports() for available names
MIDI feedback loop detected on ch...Thru-play forming a loopUse separate ports for input and output, or set monitor to "off"
// List available input ports
PRINT midi_input_ports();
// Show full MIDI routing state
midi_routing();