Skip to content

MIDI Data Access

Read MIDI notes from regions, write notes back, create new MIDI regions, and send real-time MIDI.

local notes = pl.get_midi_notes(trackId, regionId)

Returns an array of MIDI note events, or nil if the region is not found.

FieldTypeDescription
pitchnumberMIDI note (0–127)
velocitynumberVelocity (0.0–1.0)
ticknumberStart position in ticks (PPQ=960)
durationnumberDuration in ticks
channelnumberMIDI channel (0–15)
local notes = pl.get_midi_notes(0, "region-abc")
if notes then
for _, n in ipairs(notes) do
pl.log(string.format("pitch=%d vel=%.2f tick=%d", n.pitch, n.velocity, n.tick))
end
end

pl.set_midi_notes(trackId, regionId, notes)

Replaces all MIDI notes in a region. The command is deferred to the next frame.

pl.set_midi_notes(0, "region-abc", {
{ pitch = 60, velocity = 0.8, tick = 0, duration = 480, channel = 0 },
{ pitch = 64, velocity = 0.7, tick = 480, duration = 480, channel = 0 },
{ pitch = 67, velocity = 0.9, tick = 960, duration = 480, channel = 0 },
})

pl.create_midi_region(trackId, tick, duration)

Creates an empty MIDI region on the given track. Deferred to next frame.

-- Create a 4-bar MIDI region at bar 1
pl.create_midi_region(0, 0, 960 * 4 * 4)

pl.send_midi(note, velocity, channel?)

Sends a MIDI note-on (velocity > 0) or note-off (velocity = 0) in real time. Channel defaults to 0.

-- Play middle C
pl.send_midi(60, 100)
pl.sleep(500)
pl.send_midi(60, 0) -- note off

-- Generate a random melody
local notes = {}
local scale = { 60, 62, 64, 65, 67, 69, 71, 72 }
for i = 0, 15 do
local pitch = scale[math.random(#scale)]
table.insert(notes, {
pitch = pitch,
velocity = 0.5 + math.random() * 0.4,
tick = i * 240,
duration = 200,
channel = 0,
})
end
local regions = pl.get_regions(0)
if #regions > 0 then
pl.set_midi_notes(0, regions[1].id, notes)
end