Skip to content

Instantly share code, notes, and snippets.

@ssj71
Last active October 26, 2022 19:31
Show Gist options
  • Select an option

  • Save ssj71/0e839f99e5163804ad005773827fc71b to your computer and use it in GitHub Desktop.

Select an option

Save ssj71/0e839f99e5163804ad005773827fc71b to your computer and use it in GitHub Desktop.

Revisions

  1. ssj71 revised this gist Oct 26, 2022. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions note_drop.lua
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    -- MIDI Note Event random dropper
    ---
    -- This is an example, that randomly doesn't let notes through.
    -- 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
    @@ -13,7 +13,7 @@ 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 = 50
    local drop_prob = 20

    -- NO NEED TO CHANGE ANYTHING BELOW

  2. ssj71 revised this gist Oct 26, 2022. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions note_drop.lua
    Original file line number Diff line number Diff line change
    @@ -44,8 +44,9 @@ function expand_ranges(rspec)
    return t
    end

    local c --random number storage
    local function send_note()
    if math.random(1,100) > drop_prob then
    if random.value(c,100) > drop_prob then
    return true
    else
    return false
    @@ -66,14 +67,14 @@ local function note_responder(cmd)

    if pass then
    -- send event
    forge:time(frames):midi(cmd | chan, note, vel_new)
    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),
  3. ssj71 revised this gist Oct 25, 2022. 1 changed file with 8 additions and 99 deletions.
    107 changes: 8 additions & 99 deletions note_drop.lua
    Original file line number Diff line number Diff line change
    @@ -13,103 +13,7 @@ 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 = 10


    -- MIDI Velocity Scaling for Note Range
    -- MIDI Velocity Scaling for Note Range

    -- 0..15 or set to -1 to apply to events on all channels
    local filter_chan = -1
    -- whether to pass non-note events
    local pass_other = true
    -- 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"

    -- scale incoming velocity values by this factor
    -- (affects note-on and note-off events)
    local vel_scale = 0.9
    -- offset value to add to velocity after scaling
    local vel_offset = 0
    -- clamp resulting velocity to this range
    local vel_min = 0
    local vel_max = 127

    -- 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 function scale_velocity(val)
    -- round to lower integer
    val = math.floor(val * vel_scale) + vel_offset
    -- clamp to [vel_min, vel_max]
    return val < vel_min and vel_min or (val > vel_max and vel_max or val)
    end

    -- note responder function factory
    local function note_responder(cmd)
    return function(self, frames, forge, chan, note, vel)
    local vel_new
    if (filter_chan == -1 or chan == filter_chan) and filter_notes[note] ~= nil then
    vel_new = scale_velocity(vel)
    else
    vel_new = vel
    end

    -- set absolute minimum velocity value for NoteOn events to 1
    if vel and (cmd == MIDI.NoteOn and vel_new == 0) then
    vel_new = 1
    end
    -- send event
    forge:time(frames):midi(cmd | chan, note, vel_new)
    end
    end

    function once(n, control, notify, seq, forge)
    filter_notes = expand_ranges(note_ranges)

    -- 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
    local drop_prob = 50

    -- NO NEED TO CHANGE ANYTHING BELOW

    @@ -140,19 +44,24 @@ function expand_ranges(rspec)
    return t
    end

    local function drop_note()
    local function send_note()
    if math.random(1,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
    pass = drop_note(vel)
    if cmd == MIDI.NoteOn then
    pass = send_note(vel)
    else
    pass = true
    end
    end

    if pass then
  4. ssj71 revised this gist Oct 25, 2022. 1 changed file with 114 additions and 27 deletions.
    141 changes: 114 additions & 27 deletions note_drop.lua
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,6 @@
    -- MIDI Note Event Filter/Processor
    -- MIDI Note Event random dropper
    ---
    -- This is an example, which passes all events unfiltered / unaltered.
    -- Change the 'do_filter' function to customize the filter.
    -- 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
    @@ -17,14 +16,103 @@ local pass_other = true
    local drop_prob = 10


    -- MIDI Velocity Scaling for Note Range
    -- MIDI Velocity Scaling for Note Range

    -- 0..15 or set to -1 to apply to events on all channels
    local filter_chan = -1
    -- whether to pass non-note events
    local pass_other = true
    -- 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"

    -- scale incoming velocity values by this factor
    -- (affects note-on and note-off events)
    local vel_scale = 0.9
    -- offset value to add to velocity after scaling
    local vel_offset = 0
    -- clamp resulting velocity to this range
    local vel_min = 0
    local vel_max = 127

    -- NO NEED TO CHANGE ANYTHING BELOW

    local _filter_notes
    -- 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 function scale_velocity(val)
    -- round to lower integer
    val = math.floor(val * vel_scale) + vel_offset
    -- clamp to [vel_min, vel_max]
    return val < vel_min and vel_min or (val > vel_max and vel_max or val)
    end

    -- note responder function factory
    local function note_responder(cmd)
    return function(self, frames, forge, chan, note, vel)
    local vel_new
    if (filter_chan == -1 or chan == filter_chan) and filter_notes[note] ~= nil then
    vel_new = scale_velocity(vel)
    else
    vel_new = vel
    end

    -- set absolute minimum velocity value for NoteOn events to 1
    if vel and (cmd == MIDI.NoteOn and vel_new == 0) then
    vel_new = 1
    end
    -- send event
    forge:time(frames):midi(cmd | chan, note, vel_new)
    end
    end

    function once(n, control, notify, seq, forge)
    filter_notes = expand_ranges(note_ranges)

    local function clamp(val, min, max)
    return val < min and min or (val > max and max or val)
    -- 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

    -- NO NEED TO CHANGE ANYTHING BELOW

    -- http://rosettacode.org/wiki/Range_expansion#Lua
    function range(i, j)
    local t = {}
    @@ -44,51 +132,50 @@ function expand_ranges(rspec)
    if s == nil then
    t[tonumber(v)] = true
    else
    for i, n in ipairs(range(tonumber(s), tonumber(e))) do
    t[] = true
    for _, n in ipairs(range(tonumber(s), tonumber(e))) do
    t[n] = true
    end
    end
    end
    return t
    end

    local function do_filter(frames, forge, chan, note, vel)
    -- decide randomly whether to drop the note
    if math.random() > drop_prob then
    return true, clamp(chan, 0, 16), clamp(note, 0, 127), clamp(vel, 0, 127)
    local function drop_note()
    if math.random(1,100) > drop_prob then
    return true
    else
    return false, 0, 0, 0
    return false
    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] then
    pass, chan, note, vel = do_filter(frames, forge, chan, note, vel)
    if (filter_chan == -1 or chan == filter_chan) and filter_notes[note] ~= nil then
    pass = drop_note(vel)
    end
    if (pass)

    if pass then
    -- send event
    forge:time(frames):midi(cmd | chan, note, vel)
    forge:time(frames):midi(cmd | chan, note, vel_new)
    end
    end
    end

    function once(n, control, notify, seq, forge)
    _filter_notes = expand_ranges(note_ranges)
    math.randomseed(os.time())

    -- 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)
    filter_notes = expand_ranges(note_ranges)

    -- 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)
    local handled = midiR(frames, forge, atom)
    end
    end
    end
  5. ssj71 created this gist Oct 25, 2022.
    94 changes: 94 additions & 0 deletions note_drop.lua
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,94 @@
    -- MIDI Note Event Filter/Processor
    ---
    -- This is an example, which passes all events unfiltered / unaltered.
    -- Change the 'do_filter' function to customize the filter.

    -- 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 = 10


    -- NO NEED TO CHANGE ANYTHING BELOW

    local _filter_notes

    local function clamp(val, min, max)
    return val < min and min or (val > max and max or val)
    end

    -- 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 i, n in ipairs(range(tonumber(s), tonumber(e))) do
    t[] = true
    end
    end
    end
    return t
    end

    local function do_filter(frames, forge, chan, note, vel)
    -- decide randomly whether to drop the note
    if math.random() > drop_prob then
    return true, clamp(chan, 0, 16), clamp(note, 0, 127), clamp(vel, 0, 127)
    else
    return false, 0, 0, 0
    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] then
    pass, chan, note, vel = do_filter(frames, forge, chan, note, vel)
    end
    if (pass)
    -- 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)
    math.randomseed(os.time())

    -- 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