Skip to content

Instantly share code, notes, and snippets.

@ssj71
Last active October 26, 2022 19:31
Show Gist options
  • Save ssj71/0e839f99e5163804ad005773827fc71b to your computer and use it in GitHub Desktop.
Save ssj71/0e839f99e5163804ad005773827fc71b to your computer and use it in GitHub Desktop.
moony.lv2 random note drop
-- MIDI Note Event random dropper
---
-- This is an example that randomly doesn't let notes through.
-- affected MIDI channels
-- 0..15 or set to -1 to apply to events on all channels
local filter_chan = -1
-- affected note range(s)
-- string with comma-separated list of single MIDI note numbers or
-- ranges (min-max separated by a dash, whitespace is ignored)
-- example: local note_ranges = "0-12, 36,48, 60 - 96"
local note_ranges = "0-127"
-- whether to pass non-note events or note events outside of affected range(s)
local pass_other = true
-- the probability (percent) that the note is dropped
local drop_prob = 20
-- NO NEED TO CHANGE ANYTHING BELOW
-- http://rosettacode.org/wiki/Range_expansion#Lua
function range(i, j)
local t = {}
for n = i, j, i<j and 1 or -1 do
t[#t+1] = n
end
return t
end
function expand_ranges(rspec)
local ptn = "([-+]?%d+)%s?-%s?([-+]?%d+)"
local t = {}
for v in string.gmatch(rspec, '[^,]+') do
local s, e = v:match(ptn)
if s == nil then
t[tonumber(v)] = true
else
for _, n in ipairs(range(tonumber(s), tonumber(e))) do
t[n] = true
end
end
end
return t
end
local c --random number storage
local function send_note()
if random.value(c,100) > drop_prob then
return true
else
return false
end
end
-- note responder function factory
local function note_responder(cmd)
return function(self, frames, forge, chan, note, vel)
local pass = pass_other
if (filter_chan == -1 or chan == filter_chan) and filter_notes[note] ~= nil then
if cmd == MIDI.NoteOn then
pass = send_note(vel)
else
pass = true
end
end
if pass then
-- send event
forge:time(frames):midi(cmd | chan, note, vel)
end
end
end
function once(n, control, notify, seq, forge)
filter_notes = expand_ranges(note_ranges)
c = random.new()
-- define a MIDIResponder object to handle note-on and note-off events
midiR = MIDIResponder({
[MIDI.NoteOn] = note_responder(MIDI.NoteOn),
[MIDI.NoteOff] = note_responder(MIDI.NoteOff)
}, pass_other)
end
function run(n, control, notify, seq, forge)
-- iterate over incoming events
for frames, atom in seq:foreach() do
-- call responder for event
local handled = midiR(frames, forge, atom)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment