MIDI
Plinken supports full MIDI recording, editing, and playback with a built-in synthesizer and routing to external instrument plugins (AU, CLAP, VST3). MIDI data is stored in regions on tracks and processed at tick-level precision (960 PPQ).
MIDI Module Properties
Section titled “MIDI Module Properties”| Property | Type | Default | Description |
|---|---|---|---|
track_count | i64 | 0 | Number of MIDI tracks |
recording | bool | false | Whether MIDI recording is active |
selected_track_id | i64 | -1 | Currently selected MIDI track (−1 = none) |
synth_volume | f64 | — | Built-in synth master volume (0.0–1.0) |
synth_attack | f64 | — | Synth ADSR attack time (seconds) |
synth_decay | f64 | — | Synth ADSR decay time (seconds) |
synth_sustain | f64 | — | Synth ADSR sustain level (0.0–1.0) |
synth_release | f64 | — | Synth ADSR release time (seconds) |
-- Read MIDI module statelocal count = plinken.get("midi", "track_count")local recording = plinken.get("midi", "recording")local selected = plinken.get("midi", "selected_track_id")Recording MIDI
Section titled “Recording MIDI”Step by Step
Section titled “Step by Step”- Create or select a MIDI track
- Arm the track for recording
- Press R to arm transport recording
- Press Space to start — play your MIDI controller
- Press Space to stop — the recorded MIDI becomes a region on the track
Recording Modes
Section titled “Recording Modes”| Mode | Description |
|---|---|
| Replace | Punch holes in existing regions within the recording range, then add new regions |
| Merge | Layer new recordings on top of existing regions |
Recording Commands
Section titled “Recording Commands”| Command | Description |
|---|---|
midi:start-recording | Start recording MIDI on armed tracks |
midi:stop-recording | Stop recording and create MIDI regions |
midi:process-recording | Process MIDI recording buffer (called internally each frame) |
Recording Architecture
Section titled “Recording Architecture”MIDI recording uses a lock-free ring buffer architecture for glitch-free capture:
- Audio thread — Pushes
RecordingEventto ring buffer (~100ns, lock-free) - Background thread — Drains events and builds notes incrementally (matching note-on/off pairs)
- Main thread — Calls
stop_recording()to finalize regions
-- Start MIDI recording (usually triggered by transport)pl.cmd("midi:start-recording")
-- Stop and create regionspl.cmd("midi:stop-recording")Recording Counter
Section titled “Recording Counter”Each track maintains a persistent recording counter. Successive recordings on the same track produce incrementing names: Piano_1, Piano_2, Piano_3, etc.
MIDI Playback
Section titled “MIDI Playback”MIDI playback routes note events to either:
- The track’s instrument plugin (AU, CLAP, or VST3) — if assigned
- The built-in synthesizer — as fallback when no plugin is assigned
Playback Events
Section titled “Playback Events”| Event Type | Description |
|---|---|
NoteOn | Start a note (track, channel, pitch, velocity) |
NoteOff | End a note (track, channel, pitch) |
ControlChange | CC event (track, channel, cc, value) |
PitchBend | Pitch bend (track, channel, value as i16) |
AllNotesOff | Panic — silence all notes on a track |
MIDI Tracks
Section titled “MIDI Tracks”Each MIDI track has its own properties independent of timeline tracks:
| Property | Type | Default | Description |
|---|---|---|---|
id | u8 | auto | Unique track ID |
name | string | — | Track name |
arm | bool | false | Armed for recording |
mute | bool | false | Muted |
solo | bool | false | Soloed |
volume | f64 | 1.0 | Track volume (0.0–2.0) |
pan | f64 | 0.0 | Track pan (−1.0 to +1.0) |
MIDI Editor
Section titled “MIDI Editor”Open the MIDI Editor from View > Editor. The editor provides multiple views:
Piano Editor (Piano Roll)
Section titled “Piano Editor (Piano Roll)”The piano roll shows MIDI notes on a grid with pitch on the vertical axis and time on the horizontal axis. Click to create notes, drag to move or resize them. Velocity is shown as note color intensity.
Drum Editor
Section titled “Drum Editor”A grid-based view optimized for drum patterns. Each row represents a drum sound (mapped to MIDI notes), and you toggle hits on the grid.
List Editor
Section titled “List Editor”A tabular view showing all MIDI events as a sortable, editable list. Useful for precise numeric editing of:
- Note positions (tick)
- Pitches (MIDI note number)
- Velocities (0–127)
- Durations (ticks)
Automation Editor
Section titled “Automation Editor”Edit MIDI CC (Continuous Controller) data as curves. Draw and modify automation shapes for expression, modulation, sustain, and other controllers.
MIDI Regions
Section titled “MIDI Regions”MIDI regions contain note events and CC data:
| Property | Type | Description |
|---|---|---|
start_tick | i64 | Region start position in ticks |
length | i64 | Region length in ticks (min: 240) |
clip_offset | i64 | Offset into source clip |
events | EventTuple[] | Original MIDI note events |
events_quantized | EventTuple[] | Quantized events (used for playback) |
cc_events | CCEventTuple[] | CC automation events |
Quantization
Section titled “Quantization”MIDI regions support quantization. The events array holds the original recorded notes, while events_quantized holds the quantized version used during playback. This allows non-destructive quantization — you can always revert to the original timing.
Music Keys
Section titled “Music Keys”Open the virtual MIDI keyboard with the Music Keys panel. This lets you play notes using your computer keyboard when no MIDI controller is connected.
Built-in Synthesizer
Section titled “Built-in Synthesizer”Plinken includes a built-in polyphonic synthesizer as the default sound source for MIDI tracks without an assigned plugin instrument.
Synth Properties
Section titled “Synth Properties”| Property | Type | Range | Description |
|---|---|---|---|
synth_volume | f32 | 0.0–1.0 | Master volume |
synth_attack | f32 | ≥ 0.0 | ADSR attack time (seconds) |
synth_decay | f32 | ≥ 0.0 | ADSR decay time (seconds) |
synth_sustain | f32 | 0.0–1.0 | ADSR sustain level |
synth_release | f32 | ≥ 0.0 | ADSR release time (seconds) |
-- Adjust built-in synth ADSRplinken.set("midi", "synth_attack", 0.01)plinken.set("midi", "synth_decay", 0.2)plinken.set("midi", "synth_sustain", 0.6)plinken.set("midi", "synth_release", 0.3)
-- Set synth volumeplinken.set("midi", "synth_volume", 0.8)MIDI Device Routing
Section titled “MIDI Device Routing”Configure MIDI input and output devices in Settings > MIDI. Each device can be independently enabled for different protocol types.
Device Routing Properties
Section titled “Device Routing Properties”| Property | Type | Description |
|---|---|---|
device_id | string | System device identifier |
name | string | Human-readable device name |
midi | bool | Route standard MIDI messages |
mc | bool | Route MIDI Clock |
mtc | bool | Route MIDI Time Code |
mmc | bool | Route MIDI Machine Control |
Input Filtering
Section titled “Input Filtering”Each track can filter which MIDI input device and channel it listens to:
| Property | Type | Default | Description |
|---|---|---|---|
midi_input_filter | string | "all" | "all", "none", or a specific device_id |
midi_channel_filter | u8 | 0 | 0 = All channels, 1–16 = specific channel |
-- Set track to listen only to a specific devicepl.cmd("track:set-midi-input-filter", { track_id = 1, filter = "Arturia KeyLab 61"})
-- Filter to MIDI channel 1 onlypl.cmd("track:set-midi-channel-filter", { track_id = 1, channel = 1})MIDI Sync Output
Section titled “MIDI Sync Output”Plinken can send MIDI synchronization to external hardware:
| Protocol | Description | Command |
|---|---|---|
| MTC (MIDI Time Code) | Positional sync — sends SMPTE timecode | transport:toggle-mtc |
| MC (MIDI Clock) | Tempo sync — sends 24 ppqn clock | transport:toggle-mc |
Per-device sync routing is configured in the MIDI device settings. You can enable MTC or MC independently for each output device.
-- Check which devices have MTC enabledlocal mtc = plinken.get("transport", "mtc_enabled")
-- Toggle MTC outputpl.cmd("transport:toggle-mtc")Practical Examples
Section titled “Practical Examples”Record a MIDI Part
Section titled “Record a MIDI Part”-- Set up: arm track, arm transport, playpl.cmd("track:toggle-record", { track_id = 1 })pl.cmd("transport:toggle-record")pl.cmd("transport:toggle-play")
-- ... play your MIDI controller ...
-- Stop recordingpl.cmd("transport:toggle-play")Route MIDI to Plugin Instrument
Section titled “Route MIDI to Plugin Instrument”-- Assign an AU instrument to track 1pl.cmd("track:set-instrument", { track_id = 1, plugin_id = "com.apple.DLSSynth", format = "AU"})Adjust Synth Envelope for Pad Sound
Section titled “Adjust Synth Envelope for Pad Sound”-- Slow attack, long release padplinken.set("midi", "synth_attack", 0.5)plinken.set("midi", "synth_decay", 0.3)plinken.set("midi", "synth_sustain", 0.7)plinken.set("midi", "synth_release", 1.5)See Also
Section titled “See Also”- Transport — Recording, tempo, and MIDI sync controls
- Timeline > Regions — Working with MIDI regions on the timeline
- Timeline > Automation — Automation recording and CC events
- Mixer — Track levels and effects
- Plugins > Instruments — Instrument plugin management
- Settings > MIDI — MIDI device configuration
- Synth — Built-in synthesizer details