fix stuck solo w/sidechain (when using port, not send, connections)
[ardour.git] / scripts / tomsloop.lua
index 2a7880111e949c781c263b4571ac598c51c805fe..f1bca82068981aa94f956b96316a7c0ce6103321 100644 (file)
@@ -1,4 +1,4 @@
-ardour { ["type"] = "Snippet", name = "Tom's Loop",
+ardour { ["type"] = "EditorAction", name = "Tom's Loop",
        license     = "MIT",
        author      = "Robin Gareus",
        email       = "robin@gareus.org",
@@ -6,16 +6,15 @@ ardour { ["type"] = "Snippet", name = "Tom's Loop",
        description = [[Bounce the loop-range of all non muted audio tracks, paste N times at playhead]]
 }
 
--- unused ;  cfg parameter for ["type"] = "EditorAction"
 function action_params ()
        return { ["times"]   = { title = "Number of copies to add", default = "1"}, }
 end
 
-function factory () return function ()
+function factory (params) return function ()
        -- get options
        local p = params or {}
-       local npaste   = p["times"] or 1
-       assert (npaste > 0)
+       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)
@@ -24,8 +23,6 @@ function factory () return function ()
        local playhead = Session:transport_frame ()
 
        -- make sure we have a loop, and the playhead (edit point) is after it
-       -- TODO: only print an error and return
-       -- TODO: use the edit-point (not playhead) ? maybe.
        if not loop then
                print ("A Loop range must be set.")
                goto errorout
@@ -40,35 +37,67 @@ function factory () return function ()
        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
-               -- skip muted tracks
+               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 are any regions in the loop-range of this track
-               local range = Evoral.Range (loop:start (), loop:_end ())
-               if playlist:regions_with_start_within (range):empty ()
-                       and playlist:regions_with_end_within (range):empty () then
+               -- 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
+               -- 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, npaste, 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
@@ -78,12 +107,21 @@ function factory () return function ()
 
                ::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' Commend here mean to use the collected diffs added above
+               -- 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