Write CC automation to MIDI region via Lua

Hi everyone,

I am trying to write CC automation data to a MIDI region via a Lua script with full undo support. I was looking into the midi_cc_to_automation.lua and lfo_automation.lua scripts bundled with Ardour for guidance. I am already able to delete stuff from an existing midi region’s cc parameters via midi_region:control (EvoralParameter (...)): list() and its methods, but I struggle to add undo support for the script (the Control type’s list() doesn’t have a get_state() method).

The scripts linked above use the plugin_automation() utility function of the track the region in question belongs to to get access to an AutomationControl type which offers undo/redo functionality via the get_state() method, but I struggle to find an equivalent for generic MIDI CC automation.

I was trying to do the following:

local automation_list = track:nth_processor (0):to_automatable (): automation_control (
    Evoral.Parameter (ARDOUR.AutomationType.MidiCCAutomation, midi_channel, midi_cc),
    false):alist ()

but this only results in a shared_ptr is nil error.

I guess that I might have not yet fully grasped the scripting interface, and guess that I am likely poking at the wrong end. Can anybody tell me what to do in order to achieve what I want?

Ardour’s GUI shows MIDI CC events in a similar way as parameter automation, even though these are MIDI events in a MIDI region.

There is no automatable control port for MIDI. To add/remove CCs, you have to edit the MIDI region of the given track, using the control-list of the MIDI region.

local sel = Editor:get_selection ()
for r in sel.regions:regionlist ():iter () do
  local mr = r:to_midiregion ()
  if mr:isnil () then goto next end

  local midi_channel = 0 -- MIDI channel [0 .. 15]
  local cc_param = 1 -- CC-1 (modulation)  [0 .. 127]
  local ec = mr:control (Evoral.Parameter (ARDOUR.AutomationType.MidiCCAutomation, midi_channel, cc_param), true)
  if ec:isnil () then goto next end
  local cl = ec:list (); -- get control list for control

  -- specify time in samples, here two points at 0, at 48000, converting them to MIDI beat-unit:
  local bfc = ARDOUR.DoubleBeatsSamplesConverter (Session:tempo_map (), r:start ())
  cl:editor_add (bfc:from (0 + r:start ()), 1, false)
  cl:editor_add (bfc:from (48000 + r:start ()), 127, false)  

  ::next::
end

At this point in time it is not possible to save an undo command, I’ve just git pushed a call to cast the ControlList into an AutomationList so that this will be possible staring with the next relase like this:

  local al = cl:to_automationlist();
  local before = al:get_state() -- save previous state (for undo)
  -- ...
  cl:editor_add (bfc:from (0 + r:start ()), 1, false)
  -- ...
  Session:begin_reversible_command ("Edit CC")
  Session:add_command (al:memento_command(before, al:get_state()))
  Session:commit_reversible_command(nil)
1 Like

Thank you very much, Robin, for adding adding the cast to AutomationList! I’m looking forward to the next release. Until then I can live without undo when altering MIDI regions via Lua scripting.