+++ /dev/null
-ardour { ["type"] = "EditorAction", name = "Tom's Loop",
- license = "MIT",
- author = "Robin Gareus",
- email = "robin@gareus.org",
- site = "http://gareus.org",
- description = [[Bounce the loop-range of all non muted audio tracks, paste N times at playhead]]
-}
-
-function action_params ()
- return { ["times"] = { title = "Number of copies to add", default = "1"}, }
-end
-
-function factory (params) return function ()
- -- get options
- local p = params or {}
- local n_paste = tonumber (p["times"] or 1)
- assert (n_paste > 0)
-
- local proc = ARDOUR.LuaAPI.nil_proc () -- bounce w/o processing
- local itt = ARDOUR.InterThreadInfo () -- bounce progress info (unused)
-
- local loop = Session:locations ():auto_loop_location ()
- local playhead = Session:transport_frame ()
-
- -- make sure we have a loop, and the playhead (edit point) is after it
- if not loop then
- print ("A Loop range must be set.")
- goto errorout
- end
- assert (loop:start () < loop:_end ())
- if loop:_end () >= playhead then
- print ("The Playhead (paste point) needs to be after the loop.")
- goto errorout
- end
-
- -- prepare undo operation
- Session:begin_reversible_command ("Tom's Loop")
- local add_undo = false -- keep track if something has changed
-
- -- prefer solo'ed tracks
- local soloed_track_found = false
- for route in Session:get_tracks ():iter () do
- if route:soloed () then
- soloed_track_found = true
- break
- end
- end
-
- -- count regions that are bounced
- local n_regions_created = 0
-
- -- loop over all tracks in the session
- for route in Session:get_tracks ():iter () do
- if soloed_track_found then
- -- skip not soloed tracks
- if not route:soloed () then
- goto continue
- end
- end
-
- -- skip muted tracks (also applies to soloed + muted)
- if route:muted () then
- goto continue
- end
-
- -- at this point the track is either soloed (if at least one track is soloed)
- -- or not muted (if no track is soloed)
-
- -- test if bouncing is possible
- local track = route:to_track ()
- if not track:bounceable (proc, false) then
- goto continue
- end
-
- -- only audio tracks
- local playlist = track:playlist ()
- if playlist:data_type ():to_string () ~= "audio" then
- goto continue
- end
-
- -- check if there is at least one unmuted region in the loop-range
- local reg_unmuted_count = 0
- for reg in playlist:regions_touched (loop:start (), loop:_end ()):iter () do
- if not reg:muted() then
- reg_unmuted_count = reg_unmuted_count + 1
- end
- end
-
- if reg_unmuted_count < 1 then
- goto continue
- end
-
- -- clear existing changes, prepare "diff" of state for undo
- playlist:to_stateful ():clear_changes ()
-
- -- do the actual work
- local region = track:bounce_range (loop:start (), loop:_end (), itt, proc, false)
- playlist:add_region (region, playhead, n_paste, false)
-
- n_regions_created = n_regions_created + 1
-
- -- create a diff of the performed work, add it to the session's undo stack
- -- and check if it is not empty
- if not Session:add_stateful_diff_command (playlist:to_statefuldestructible ()):empty () then
- add_undo = true
- end
-
- ::continue::
- end
-
- --advance playhead so it's just after the newly added regions
- if n_regions_created > 0 then
- Session:request_locate((playhead + loop:length() * n_paste),false)
- end
-
- -- all done, commit the combined Undo Operation
- if add_undo then
- -- the 'nil' Command here mean to use the collected diffs added above
- Session:commit_reversible_command (nil)
- else
- Session:abort_reversible_command ()
- end
-
- print ("bounced " .. n_regions_created .. " regions from loop range (" .. loop:length() .. " frames) to playhead @ frame # " .. playhead)
-
- ::errorout::
-end end
+++ /dev/null
-ardour {
- ["type"] = "EditorAction",
- name = "Action Test",
- license = "MIT",
- author = "Robin Gareus",
- email = "robin@gareus.org",
- site = "http://gareus.org",
- description = [[ An Example Ardour Editor Action Plugin.]]
-}
-
-function factory (params)
- return function ()
- for n in pairs(_G) do print(n) end
- print ("----")
- end
-end
-ardour { ["type"] = "Snippet", name = "fader automation" }
+ardour { ["type"] = "Snippet", name = "Fader Automation" }
function factory () return function ()
local playhead = Session:transport_frame ()
local samplerate = Session:nominal_frame_rate ()
-- get selected tracks
- rl = Editor:get_selection().tracks:routelist()
+ rl = Editor:get_selection ().tracks:routelist ()
+
-- prepare undo operation
Session:begin_reversible_command ("Fancy Fade Out")
local add_undo = false -- keep track if something has changed
- -- iterate over selected tracks
- for r in rl:iter() do
- local ac = r:amp():gain_control() -- ARDOUR:AutomationControl
- local acl = ac:alist() -- ARDOUR:AutomationControlList (state, high-level)
- local cl = acl:list() -- Evoral:ControlList (actual events)
- ac:set_automation_state(ARDOUR.AutoState.Touch)
+ -- iterate over selected tracks
+ for r in rl:iter () do
+ local ac = r:amp ():gain_control () -- ARDOUR:AutomationControl
+ local al = ac:alist () -- ARDOUR:AutomationList (state, high-level)
+ local cl = al:list () -- Evoral:ControlList (actual events)
- if cl:isnil() then
+ if cl:isnil () then
goto out
end
+ -- set automation state to "Touch"
+ ac:set_automation_state (ARDOUR.AutoState.Touch)
+
-- query the value at the playhead position
- local g = cl:eval(playhead)
+ local g = cl:eval (playhead)
-- get state for undo
- local before = acl:get_state()
+ local before = al:get_state ()
-- delete all events after the playhead...
cl:truncate_end (playhead)
+
-- ...and generate some new ones.
for i=0,50 do
+ -- use a sqrt fade-out (the shape is recognizable, and otherwise
+ -- not be possible to achieve with existing ardour fade shapes)
cl:add (playhead + i * samplerate / 50,
- g * (1 - math.sqrt (i / 50)),
- false, true)
+ g * (1 - math.sqrt (i / 50)),
+ false, true)
end
+
-- remove dense events
- cl:thin(20)
+ cl:thin (20)
-- save undo
- local after = acl:get_state()
- Session:add_command (acl:memento_command(before, after))
+ local after = al:get_state ()
+ Session:add_command (al:memento_command (before, after))
add_undo = true
::out::
-ardour { ["type"] = "Snippet", name = "foreach track" }
+ardour { ["type"] = "Snippet", name = "Foreach Track" }
function factory () return function ()
for r in Session:get_tracks():iter() do
print (r:name())
-- see http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:Track
-- for available methods e.g.
- --
r:set_active (true, nil)
end
end end
-ardour { ["type"] = "Snippet", name = "plugin automation2" }
+ardour { ["type"] = "Snippet", name = "Plugin automation" }
function factory () return function ()
+ -- query playhead position and session sample-rate
local playhead = Session:transport_frame ()
local samplerate = Session:nominal_frame_rate ()
+ -- get Track/Bus with RID 3
local r = Session:route_by_remote_id(3)
- -- get AutomationControList, ControlList and ParameterDescriptor
- local acl, cl, pd = ARDOUR.LuaAPI.plugin_automation (r:nth_plugin (0), 0)
+ -- make sure the track object exists
+ assert (not r:isnil ())
- if not acl:isnil() then
+ -- get AutomationList, ControlList and ParameterDescriptor
+ -- of the first plugin's first parameter
+ -- see http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:LuaAPI
+ local al, cl, pd = ARDOUR.LuaAPI.plugin_automation (r:nth_plugin (0), 0)
+
+ if not al:isnil () then
print ("Parameter Range", pd.lower, pd.upper)
- print ("Current value", cl:eval(playhead))
+ print ("Current value", cl:eval (playhead))
-- prepare undo operation
Session:begin_reversible_command ("Automatix")
- local before = acl:get_state()
+ -- remember current AutomationList state
+ local before = al:get_state()
-- remove future automation
cl:truncate_end (playhead)
- -- add new data points after the playhead 1 sec min..max
+ -- add new data points after the playhead 1 sec, min..max
-- without guard-points, but with initial (..., false, true)
for i=0,10 do
cl:add (playhead + i * samplerate / 10,
end
-- save undo
- local after = acl:get_state()
- Session:add_command (acl:memento_command(before, after))
+ local after = al:get_state()
+ Session:add_command (al:memento_command(before, after))
Session:commit_reversible_command (nil)
end
end end
--- /dev/null
+ardour { ["type"] = "Snippet", name = "Editor Selection" }
+
+function factory () return function ()
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:Selection
+ -- the Ardour Selection can include multiple items
+ -- (regions, tracks, ranges, markers, automation, midi-notes etc)
+ local sel = Editor:get_selection ()
+
+ --
+ -- At the point of writing the following data items are available
+ --
+
+ -- Range selection, total span of all ranges (0, 0 if no time range is selected)
+ if sel.time:start () < sel.time:end_frame () then
+ print ("Total Range:", sel.time:start (), sel.time:end_frame ())
+ end
+
+ -- Range selection, individual ranges.
+ for ar in sel.time:iter () do
+ -- each of the items is a
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:AudioRange
+ print ("Range:", ar.id, ar.start, ar._end)
+ end
+
+ -- Track/Bus Selection
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:TrackSelection
+ for r in sel.tracks:routelist ():iter () do
+ -- each of the items is a
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:Route
+ print ("Route:", r:name ())
+ end
+
+ -- Region selection
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:RegionSelection
+ for r in sel.regions:regionlist ():iter () do
+ -- each of the items is a
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:Region
+ print ("Region:", r:name ())
+ end
+
+ -- Markers
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:MarkerSelection
+ -- Note: Marker selection is not cleared and currently (Ardour-4.7) points
+ -- to the most recently selected marker.
+ for m in sel.markers:iter () do
+ -- each of the items is a
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ARDOURUI::ArdourMarker
+ print ("Marker:", m:name (), m:position(), m:_type())
+ end
+
+ ----------------------------------------------------------
+ -- The total time extents of all selected regions and ranges
+ local ok, ext = Editor:get_selection_extents (0, 0)
+ if ok then
+ print ("Selection Extents:", ext[1], ext[2])
+ else
+ print ("No region or range is selected")
+ end
+
+end end
--- /dev/null
+ardour { ["type"] = "EditorAction", name = "Tom's Loop",
+ license = "MIT",
+ author = "Robin Gareus",
+ email = "robin@gareus.org",
+ site = "http://gareus.org",
+ description = [[Bounce the loop-range of all non muted audio tracks, paste N times at playhead]]
+}
+
+function action_params ()
+ return { ["times"] = { title = "Number of copies to add", default = "1"}, }
+end
+
+function factory (params) return function ()
+ -- get options
+ local p = params or {}
+ local n_paste = tonumber (p["times"] or 1)
+ assert (n_paste > 0)
+
+ local proc = ARDOUR.LuaAPI.nil_proc () -- bounce w/o processing
+ local itt = ARDOUR.InterThreadInfo () -- bounce progress info (unused)
+
+ local loop = Session:locations ():auto_loop_location ()
+ local playhead = Session:transport_frame ()
+
+ -- make sure we have a loop, and the playhead (edit point) is after it
+ if not loop then
+ print ("A Loop range must be set.")
+ goto errorout
+ end
+ assert (loop:start () < loop:_end ())
+ if loop:_end () >= playhead then
+ print ("The Playhead (paste point) needs to be after the loop.")
+ goto errorout
+ end
+
+ -- prepare undo operation
+ Session:begin_reversible_command ("Tom's Loop")
+ local add_undo = false -- keep track if something has changed
+
+ -- prefer solo'ed tracks
+ local soloed_track_found = false
+ for route in Session:get_tracks ():iter () do
+ if route:soloed () then
+ soloed_track_found = true
+ break
+ end
+ end
+
+ -- count regions that are bounced
+ local n_regions_created = 0
+
+ -- loop over all tracks in the session
+ for route in Session:get_tracks ():iter () do
+ if soloed_track_found then
+ -- skip not soloed tracks
+ if not route:soloed () then
+ goto continue
+ end
+ end
+
+ -- skip muted tracks (also applies to soloed + muted)
+ if route:muted () then
+ goto continue
+ end
+
+ -- at this point the track is either soloed (if at least one track is soloed)
+ -- or not muted (if no track is soloed)
+
+ -- test if bouncing is possible
+ local track = route:to_track ()
+ if not track:bounceable (proc, false) then
+ goto continue
+ end
+
+ -- only audio tracks
+ local playlist = track:playlist ()
+ if playlist:data_type ():to_string () ~= "audio" then
+ goto continue
+ end
+
+ -- check if there is at least one unmuted region in the loop-range
+ local reg_unmuted_count = 0
+ for reg in playlist:regions_touched (loop:start (), loop:_end ()):iter () do
+ if not reg:muted() then
+ reg_unmuted_count = reg_unmuted_count + 1
+ end
+ end
+
+ if reg_unmuted_count < 1 then
+ goto continue
+ end
+
+ -- clear existing changes, prepare "diff" of state for undo
+ playlist:to_stateful ():clear_changes ()
+
+ -- do the actual work
+ local region = track:bounce_range (loop:start (), loop:_end (), itt, proc, false)
+ playlist:add_region (region, playhead, n_paste, false)
+
+ n_regions_created = n_regions_created + 1
+
+ -- create a diff of the performed work, add it to the session's undo stack
+ -- and check if it is not empty
+ if not Session:add_stateful_diff_command (playlist:to_statefuldestructible ()):empty () then
+ add_undo = true
+ end
+
+ ::continue::
+ end
+
+ --advance playhead so it's just after the newly added regions
+ if n_regions_created > 0 then
+ Session:request_locate((playhead + loop:length() * n_paste),false)
+ end
+
+ -- all done, commit the combined Undo Operation
+ if add_undo then
+ -- the 'nil' Command here mean to use the collected diffs added above
+ Session:commit_reversible_command (nil)
+ else
+ Session:abort_reversible_command ()
+ end
+
+ print ("bounced " .. n_regions_created .. " regions from loop range (" .. loop:length() .. " frames) to playhead @ frame # " .. playhead)
+
+ ::errorout::
+end end