cue:midi — MIDI Note Output
midi(...) sends a MIDI note-on (and optional note-off) when triggered.
It is event-based, not continuous. It turns drawn objects into discrete MIDI note events, delivered via a virtual MIDI port (or a chosen hardware port) that any DAW, synthesiser, or MIDI-capable application can receive.
It works especially well with propagate() — a scatter of shapes in
Inkscape becomes a chord or melodic phrase with pitch derived from each
element's Y position.
BASIC FORM
midi(ch:
Parameters:
Key Meaning
ch MIDI channel 1–16 (default 1)
pitch Pitch source: y maps Y position to note range (see below)
vel Velocity source: size maps element size to 1–127
dur Duration in seconds — triggers note-off after this delay
lo Lowest MIDI note for pitch:y mapping (default 36 = C2)
hi Highest MIDI note for pitch:y mapping (default 84 = C6)
MIDI OUTPUT
Oscilla opens a virtual MIDI port named Oscilla on startup.
Connect any DAW, synth plugin host, or hardware bridge to this port:
- macOS — visible in GarageBand, Logic, Ableton, etc. as "Oscilla"
- Linux — appears as an ALSA MIDI source; use a2jmidid for JACK
- Windows — use a virtual MIDI cable (e.g. loopMIDI) to route it
To target a hardware port instead of the virtual port:
node server.js --midi-port-index 0
Run node server.js once to see available port indices in the console.
PITCH MAPPING
pitch:y — position-to-note
Y position is mapped linearly to a MIDI note range.
Use lo: and hi: to set the range:
midi(ch:1, pitch:y, vel:size) # default lo:36 hi:84 midi(ch:1, pitch:y, lo:48, hi:96, vel:size) # C3–C7 midi(ch:1, pitch:y, lo:60, hi:72, vel:size) # C4–C5 (one octave)
Top of viewport = highest note. Bottom = lowest note.
Fixed note
midi(ch:1, note:60, vel:size) # always middle C
VELOCITY MAPPING
vel:size element visual size → 1–127 vel:64 fixed velocity (integer value, 1–127)
NOTE DURATION
Without dur:, only a note-on is sent. The receiving instrument sustains
until it receives its own note-off (or you handle release externally).
With dur:, a note-off is sent automatically after the given time:
midi(ch:1, pitch:y, vel:size, dur:0.5)
TRIGGERS
Key Meaning
trig:auto Send immediately (default)
trig:playhead Fire when playhead crosses the element
trig:click Fire on user click
USE WITH propagate()
propagate() expands one cue template to every child element in a group,
sampling each element's visual properties independently at trigger time.
propagate( midi(ch:1, pitch:y, vel:size, dur:0.3, trig:playhead) )
A cluster of circles becomes a chord. A diagonal scatter becomes a melodic phrase. Vertical position controls pitch; element size controls velocity.
Multiple channels
propagate(midi(ch:1, pitch:y, vel:size, dur:4, trig:playhead)) propagate(midi(ch:2, pitch:y, lo:24, hi:48, vel:size, dur:4, trig:playhead))
Use different channels to route to separate instruments in your DAW.
CLICK BUTTONS
midi(ch:10, note:36, vel:100, trig:click) # kick on ch10
Combined with a visible SVG rectangle, this creates a clickable pad that fires a MIDI note on demand.
MIDI MESSAGE FORMAT
Each trigger sends one or two raw MIDI messages:
Note-on: [0x90 | (ch-1), note, velocity] Note-off: [0x80 | (ch-1), note, 0] (only when dur: is set)
Note and velocity are clamped to 0–127.
SERVER FLAGS
| Flag | Default | Description |
|---|---|---|
--midi-port-index <n> |
— | Open hardware port by index instead of virtual |
MIDI_PORT_NAME env var |
Oscilla |
Name of the virtual port |
SUMMARY
midi()converts visual positions into MIDI note events, routing through a virtual port that any DAW or instrument can receive — with pitch from Y position and velocity from element size.
Tip: use ← → or ↑ ↓ to navigate the docs