Skip to content

Instantly share code, notes, and snippets.

@ryrun
Created December 29, 2025 16:53
Show Gist options
  • Select an option

  • Save ryrun/1ddcb236206bd10333f19c3f6aadb462 to your computer and use it in GitHub Desktop.

Select an option

Save ryrun/1ddcb236206bd10333f19c3f6aadb462 to your computer and use it in GitHub Desktop.
protoplug LUA Midi Mono Mode (Monoplay)
require "include/protoplug"
local TARGET_CH = 1
local RETRIGGER_VELOCITY = nil
local held = {}
local currentOut = -1
local function isNoteOn(ev)
return ev:isNoteOn() and ev:getVel() > 0
end
local function isNoteOff(ev)
return ev:isNoteOff() or (ev:isNoteOn() and ev:getVel() == 0)
end
local function highestHeldNote()
for n = 127, 0, -1 do
if held[n] ~= nil then
return n
end
end
return -1
end
function plugin.processBlock(samples, smax, midiBuf)
local out = {}
for ev in midiBuf:eachEvent() do
if not (ev:isNoteOn() or ev:isNoteOff()) then
table.insert(out, ev)
elseif ev:getChannel() ~= TARGET_CH then
table.insert(out, ev)
else
local t = ev.time or 0
local note = ev:getNote()
local vel = ev:getVel()
if isNoteOn(ev) then
held[note] = vel
if currentOut == -1 then
currentOut = note
table.insert(out, midi.Event.noteOn(TARGET_CH, note, vel, t))
elseif note > currentOut then
table.insert(out, midi.Event.noteOff(TARGET_CH, currentOut, 0, t))
currentOut = note
table.insert(out, midi.Event.noteOn(TARGET_CH, note, vel, t))
end
elseif isNoteOff(ev) then
held[note] = nil
if note == currentOut then
table.insert(out, midi.Event.noteOff(TARGET_CH, currentOut, 0, t))
currentOut = -1
local nextNote = highestHeldNote()
if nextNote ~= -1 then
local nextVel = held[nextNote]
if RETRIGGER_VELOCITY ~= nil then
nextVel = RETRIGGER_VELOCITY
end
currentOut = nextNote
table.insert(out, midi.Event.noteOn(TARGET_CH, nextNote, nextVel, t))
end
end
end
end
end
midiBuf:clear()
for i = 1, #out do
midiBuf:addEvent(out[i])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment