MIDI I/O
Resonon isn’t a closed world — it speaks MIDI, so it can drive a hardware synth, sequence a DAW, or take notes and knob-turns from a controller. In this chapter you’ll connect an output port, send a pattern to it, read a controller, and map a knob to a parameter with MIDI learn.
Sending MIDI
Section titled “Sending MIDI”Connecting a Port
Section titled “Connecting a Port”First, see what’s out there. midi_ports() returns the output ports your system
exposes; midi_connect opens one:
let ports = midi_ports();PRINT ports; // ["IAC Driver Bus 1", "Prophet Rev2", ...]
midi_connect("IAC Driver Bus 1");On macOS the IAC Driver is the usual way to pipe MIDI into a DAW — enable it in Audio MIDI Setup → MIDI Studio. On Windows, a tool like loopMIDI gives you the same kind of virtual port.
Sending Notes
Section titled “Sending Notes”A MidiTrack is the MIDI counterpart to the AudioTrack you’ve been using — but
instead of feeding an instrument, its notes go out the port on a chosen channel.
Send it a pattern with <<, exactly like an audio track:
midi_connect("IAC Driver Bus 1");
let melody = MidiTrack(1); // channel 1melody << [C4 E4 G4 E4];
PLAY;Point a software or hardware instrument at channel 1 and you’ll hear your pattern. Everything you know about patterns — chords, rests, Euclidean rhythms — works unchanged; only the destination is different.
Routing to Several Destinations
Section titled “Routing to Several Destinations”Give each connection an alias and you can fan tracks out to different ports and channels — your DAW on one, a hardware synth on another:
midi_connect("IAC Driver Bus 1", "daw");midi_connect("Prophet Rev2", "synth");
let drums = MidiTrack(10, 110, "daw"); // to the DAW, channel 10, velocity 110let bass = MidiTrack(1, 90, "synth"); // to hardware, channel 1let pad = MidiTrack(3, 80, "synth"); // to hardware, channel 3
drums << [bd _ sd _, ch ch ch ch];bass << [C2 _ C2 G2];pad << [C4, E4, G4];
PLAY;MidiTrack(channel, velocity, alias) — the velocity and alias are optional and
default to 100 and "default". Re-route a track at any time with .output:
bass.output("daw", 1); // move bass onto the DAW, channel 1When you lose track of what’s going where, midi_routing() prints the whole
picture — every output, input, track route, and the clock state.
Receiving MIDI
Section titled “Receiving MIDI”Input mirrors output. midi_input_ports() lists controllers; midi_input_connect
opens one under an alias:
let in_ports = midi_input_ports();PRINT in_ports; // ["Arturia KeyStep 37", ...]
midi_input_connect("KeyStep", "kb");Route that input into a track with .input, and choose how it monitors — whether
incoming notes pass straight through to the output:
midi_input_connect("KeyStep", "kb");midi_connect("IAC Driver Bus 1", "daw");
let keys = MidiTrack(1, 100) .input("kb") .monitor("in") .output("daw");
PLAY;Now the KeyStep plays through Resonon and out to your DAW. The monitor modes:
| Mode | Behavior |
|---|---|
"off" | No pass-through (the default) |
"in" | Always pass input straight to output |
"auto" | Pass through only while no pattern is playing on the track |
You can narrow input down to one channel, or open it up to everything:
let bass = MidiTrack(2, 100).input("kb", 1); // only channel 1 from "kb"let omni = MidiTrack(3, 80).input("all"); // every port, every channelMapping Knobs with CC
Section titled “Mapping Knobs with CC”Controller knobs and faders send CC (control-change) messages, and Resonon
hands them to you as signals — the same signals you can route into any parameter.
Cc(n) reads CC n from any channel; Cc(channel, n) pins it to one channel
(channels are 0–15):
let cutoff = Cc(74); // CC 74, any channellet mod_wheel = Cc(0, 1); // CC 1 on channel 0A CC arrives normalized to 0.0–1.0. Shape it and send it into a parameter with
<<, just like an LFO:
use "std/effects" { Lowpass, Delay };
let filter = Lowpass(2000);let delay = Delay(0.25, 0.5);drums.load_effect(filter);drums.load_effect(delay);
filter.param("Cutoff") << Cc(74).smooth(50).range_exp(200, 8000);delay.param("Feedback") << Cc(71).smooth(30).range(0.1, 0.6);.smooth(ms) irons out the zipper noise of stepped 7-bit values, and .range /
.range_exp map the 0–1 signal onto a useful span — reach for range_exp on
anything frequency-like, where your ear hears ratios rather than steps.
MIDI Learn
Section titled “MIDI Learn”Don’t know which CC a knob sends? Let Resonon listen. Cc_learn() waits up to ten
seconds for the first CC message, then returns a signal bound to it:
let knob = Cc_learn();// "Waiting for CC input... (10s timeout)"// ...twist a knob on your controller...// "Learned: Cc(0, 74)"Once you know the number, hard-code it so your script doesn’t pause to learn every time:
let knob = Cc(0, 74);Syncing to a Clock
Section titled “Syncing to a Clock”To lock tempo with external gear, either send MIDI clock to your outputs or follow a clock coming in:
midi_clock_send(true); // become the clock mastersetbpm(120);PLAY;midi_input_connect("DAW Output", "daw");midi_clock_follow("daw"); // follow an incoming clock insteadSending and following are two ends of the same wire — a session is either the master or a follower, not both. If notes and clock drift against your gear, nudge them into line:
midi_delay(15); // delay all MIDI output by 15 msmidi_clock_offset(-5); // send clock 5 ms ahead of the notesNext Steps
Section titled “Next Steps”That’s the whole round trip — out to your gear, back from a controller, and locked to a shared clock. The MIDI chapters go deeper on each piece:
- MIDI Output — full track API, microtonal tuning, MPE, export
- MIDI Input & CC — channel filtering, monitor modes, CC in custom DSP
- Clock Sync — virtual ports and DAW configuration per platform
- MIDI Reference — every MIDI function and method