X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=scripts%2Ftomsloop.lua;h=4c04d32fbddf333031039cddbfb25d7e8e647292;hb=244313f43fc3178fb8f58b01fc6ba125115062ad;hp=882815d26c4818d614e2ad2314dfd3803728b584;hpb=f4751f1018b1464f7d9556170c08a600e50b0be9;p=ardour.git diff --git a/scripts/tomsloop.lua b/scripts/tomsloop.lua index 882815d26c..4c04d32fbd 100644 --- a/scripts/tomsloop.lua +++ b/scripts/tomsloop.lua @@ -5,130 +5,14 @@ ardour { ["type"] = "EditorAction", name = "Tom's Loop", } -- for minimal configuration in dialogue --- ============================================================================ function action_params () return { ["times"] = { title = "Number of copies to add", default = "1"}, } end -- main method, every custom (i.e. non-ardour) method must be defined *inside* factory() --- ============================================================================ 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_help(); - print ("Error: A Loop range must be set.") - goto errorout - end - assert (loop:start () < loop:_end ()) - if loop:_end () >= playhead then - print_help(); - print ("Error: 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, 0) - - 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 -- for all routes - - --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) -- when this script is called as an action, the output will be printed to the ardour log window --- ============================================================================ function print_help() print("") print("---------------------------------------------------------------------") @@ -275,7 +159,161 @@ function factory (params) return function () print("") print("See also: Lua Action Bounce+Replace Regions") print("") + print("") end -- print_help() + + -- 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_help(); + print ("Error: A Loop range must be set.") + goto errorout + end + assert (loop:start () < loop:_end ()) + if loop:_end () >= playhead then + print_help(); + print ("Error: 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, 0, 0, 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 -- for all routes + + --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 -- factory() -end -- end of lua script +end -- end of anonymous action script function +end -- end of script factory + + +function icon (params) return function (ctx, width, height) + local x = width * .5 + local y = height * .5 + local r = math.min (x, y) + + ctx:set_line_width (1) + + function stroke_outline () + ctx:set_source_rgba (0, 0, 0, 1) + ctx:stroke_preserve () + ctx:set_source_rgba (1, 1, 1, 1) + ctx:fill () + end + + ctx:rectangle (x - r * .6, y - r * .05, r * .6, r * .3) + stroke_outline () + + ctx:arc (x, y, r * .61, math.pi, 0.2 * math.pi) + ctx:arc_negative (x, y, r * .35, 0.2 * math.pi, math.pi); + stroke_outline () + + function arc_arrow (rad, ang) + return x - rad * math.sin (ang * 2.0 * math.pi), y - rad * math.cos (ang * 2.0 * math.pi) + end + + ctx:move_to (arc_arrow (r * .36, .72)) + ctx:line_to (arc_arrow (r * .17, .72)) + ctx:line_to (arc_arrow (r * .56, .60)) + ctx:line_to (arc_arrow (r * .75, .72)) + ctx:line_to (arc_arrow (r * .62, .72)) + + ctx:set_source_rgba (0, 0, 0, 1) + ctx:stroke_preserve () + ctx:close_path () + ctx:set_source_rgba (1, 1, 1, 1) + ctx:fill () +end end