ardour { ["type"] = "EditorAction", name = "Brutalize MIDI", license = "MIT", author = "Ardour Team", description = [[Randomize MIDI Note position (de-quantize) of selected MIDI regions.]] } function factory () return function () -- Ask user about max randomness to introduce local dialog_options = { { type = "label", align="left", title = "Brutalize MIDI" }, { type = "dropdown", key = "divisor", title="Max randomness to introduce:", values = { ["8th note"] = 2, ["16th note"] = 4, ["16th triplett (1/24)"] = 6, ["32nd"] = 8, ["32nd triplett (1/48)"] = 12, ["64th"] = 16 }, default = "16th note" }, { type = "dropdown", key = "rand", title="Move Notes..", values = { ["only forward in time"] = function () return math.random() end, -- 0 .. +1 ["only backward in time"] = function () return math.random() - 2; end, -- -1 .. 0 ["either way"] = function () return 2 * math.random() - 1; end -- -1 .. +1 }, default = "either way" } } local rv = LuaDialog.Dialog ("Select Automation State", dialog_options):run() if not rv then return end -- calculate max distance in 'ticks' local ticks_per_beat = Temporal.Beats (1, 0):to_ticks (); local max_distance = ticks_per_beat / rv['divisor'] -- iterate over all selected regions local sel = Editor:get_selection () for r in sel.regions:regionlist ():iter () do local mr = r:to_midiregion () -- skip non MIDI regions if mr:isnil () then goto continue end -- get MIDI Model of the region local mm = mr:midi_source(0):model () -- Prepare Undo command local midi_command = mm:new_note_diff_command ("MIDI Note Brutalize") -- Iterate over all notes of the MIDI region for note in ARDOUR.LuaAPI.note_list (mm):iter () do -- note is-a https://manual.ardour.org/lua-scripting/class_reference/#Evoral:NotePtr -- get current position .. local old_pos = note:time () -- ..generate random offset.. local tickdiff = math.floor (rv['rand']() * max_distance); --print (old_pos:get_beats (), old_pos:get_ticks (), tickdiff) -- .. and calculate new position. local new_pos = Temporal.Beats (old_pos:get_beats (), old_pos:get_ticks () + tickdiff) -- now modify the note (but don't allow to move a note before the session start [1|1|0]) if old_pos ~= new_pos and new_pos > Temporal.Beats (0, 0) then local new_note = ARDOUR.LuaAPI.new_noteptr (note:channel (), new_pos, note:length (), note:note (), note:velocity ()) midi_command:remove (note) midi_command:add (new_note) end end -- apply changes, and save undo mm:apply_command (Session, midi_command) ::continue:: end end end