Add test synth to debug capture alignment
[ardour.git] / scripts / tomsloop.lua
index 882815d26c4818d614e2ad2314dfd3803728b584..420eb5ae1e73ec847dcea6f9a9e7f070751cc25d 100644 (file)
 ardour { ["type"] = "EditorAction", name = "Tom's Loop",
        license     = "MIT",
        author      = "Ardour Team",
-       description = [[Bounce the loop-range of all non muted audio tracks, paste N times at playhead]]
+       description = [[Bounce the loop-range of all non muted audio tracks, paste at playhead]]
 }
 
--- 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()
+               printf("See source for help.")
+---[[
                print("")
                print("---------------------------------------------------------------------")
                print("")
@@ -275,7 +156,160 @@ function factory (params) return function ()
                print("")
                print("See also: Lua Action Bounce+Replace Regions")
                print("")
+               print("")
+--]]
        end -- print_help()
+
+       local n_paste  = 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_sample ()
+
+       -- 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,5) --TRS_UI
+       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() ..  " samples) to playhead @ sample # " .. 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