Skip to content

Commit fecbcea

Browse files
authored
Release Copy - Paste the selected or all the FX from the focused FX chain to all the selected items or tracks v1.00 (ReaTeam#1368)
1 parent 3fbee63 commit fecbcea

1 file changed

+241
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
-- @description Copy - Paste the selected or all the FX from the focused FX chain to all the selected items or tracks
2+
-- @author amagalma
3+
-- @version 1.00
4+
-- @link https://forum.cockos.com/showthread.php?t=290715
5+
-- @screenshot https://i.ibb.co/SQRQDhw/Show.gif
6+
-- @donation https://www.paypal.me/amagalma
7+
-- @about
8+
-- Copies and pastes the selected (or all the FX in chain, if there is not a selection) from the focused FX chain to all the selected items or tracks.
9+
--
10+
-- - Requires js_ReaScriptAPI and ReaImGui
11+
12+
13+
if not reaper.ImGui_GetBuiltinPath then
14+
return reaper.MB('ReaImGui is not installed or too old.', 'Error!', 0)
15+
end
16+
package.path = reaper.ImGui_GetBuiltinPath() .. '/?.lua'
17+
local ImGui = require 'imgui' '0.9.0.2'
18+
19+
20+
21+
local function GetSelectedListItems( windowTitle )
22+
local FX_win = reaper.JS_Window_Find( windowTitle, true )
23+
if not FX_win then return end
24+
local sel_FX = {}
25+
local list = reaper.JS_Window_FindChildByID( FX_win, 1076 )
26+
local sel_nr, sel_fx = reaper.JS_ListView_ListAllSelItems( list )
27+
local fx_cnt = 0
28+
if sel_nr ~= 0 then
29+
for i in sel_fx:gmatch("%d+") do
30+
sel_FX[fx_cnt+1] = tonumber(i)
31+
fx_cnt = fx_cnt + 1
32+
end
33+
else -- if none selected, consider as all selected
34+
fx_cnt = reaper.JS_ListView_GetItemCount( list )
35+
for i = 1, fx_cnt do
36+
sel_FX[i] = i-1
37+
end
38+
end
39+
return sel_FX, fx_cnt
40+
end
41+
42+
43+
local function GetInfo()
44+
local retval, trackidx, itemidx, takeidx = reaper.GetTouchedOrFocusedFX( 1 )
45+
if retval == false then return end
46+
local what, sel_FX, fx_cnt
47+
local isMaster = trackidx == -1
48+
local track = isMaster and reaper.GetMasterTrack( 0 ) or reaper.GetTrack( 0, trackidx )
49+
local GUIDS = {}
50+
if takeidx ~= -1 then -- Item
51+
local item = reaper.GetTrackMediaItem( track, itemidx )
52+
local take = reaper.GetTake( item, takeidx )
53+
local name = reaper.GetTakeName( take )
54+
local search = string.format("FX: Item%s", name == "" and "" or (' "' .. name .. '"'))
55+
sel_FX, fx_cnt = GetSelectedListItems( search )
56+
for i = 1, fx_cnt do
57+
GUIDS[reaper.TakeFX_GetFXGUID( take, sel_FX[i] )] = true
58+
end
59+
return {what = "Take", obj = take, fx = GUIDS, cnt = fx_cnt}
60+
else
61+
if isMaster then
62+
sel_FX, fx_cnt = GetSelectedListItems( "FX: Master Track" )
63+
else -- normal Track
64+
local _, name = reaper.GetSetMediaTrackInfo_String( track, "P_NAME", "", false )
65+
local search = string.format("FX: Track %i%s", trackidx+1, name == "" and "" or (' "' .. name .. '"'))
66+
sel_FX, fx_cnt = GetSelectedListItems( search )
67+
for i = 1, fx_cnt do
68+
GUIDS[reaper.TrackFX_GetFXGUID( track, sel_FX[i] )] = true
69+
end
70+
return {what = "Track", obj = track, fx = GUIDS}
71+
end
72+
end
73+
end
74+
75+
76+
local data = GetInfo()
77+
if not data then
78+
return reaper.MB( "Could not get the focused FX chain.\nPlease, click it to focus and run again.",
79+
"Aborting..", 0 )
80+
end
81+
82+
83+
local open, visible -- Needed up here for the NotValid() to be able to affect the ImGui window
84+
85+
86+
local function Undo( func, descchange, flags )
87+
reaper.Undo_BeginBlock2( 0 )
88+
reaper.PreventUIRefresh( 1 )
89+
func()
90+
reaper.PreventUIRefresh( -1 )
91+
reaper.Undo_EndBlock2( 0 , descchange, flags )
92+
end
93+
94+
95+
local function NotValid(ptr)
96+
if not reaper.ValidatePtr2( 0, data.obj, ptr ) then
97+
open = false
98+
reaper.MB("The source FX are no longer valid!", "Quitting..", 0)
99+
return true
100+
end
101+
end
102+
103+
104+
local function FromTrackToItem()
105+
if NotValid("MediaTrack*") then return end
106+
for i = 0, reaper.CountSelectedMediaItems(0)-1 do
107+
local item = reaper.GetSelectedMediaItem( 0, i )
108+
local take = reaper.GetActiveTake( item )
109+
if not take then return end
110+
local fx_cnt = reaper.TakeFX_GetCount( take ) - 1
111+
local c = 0
112+
for j = 0, reaper.TrackFX_GetCount( data.obj ) - 1 do
113+
local GUID = reaper.TrackFX_GetFXGUID( data.obj, j )
114+
if data.fx[GUID] then
115+
c = c + 1
116+
reaper.TrackFX_CopyToTake( data.obj, j, take, fx_cnt + c, false )
117+
end
118+
end
119+
end
120+
end
121+
122+
123+
local function FromTrackToTrack()
124+
if NotValid("MediaTrack*") then return end
125+
for i = 0, reaper.CountSelectedTracks2(0, true)-1 do
126+
local track = reaper.GetSelectedTrack2( 0, i, true )
127+
local fx_cnt = reaper.TrackFX_GetCount( track ) - 1
128+
local c = 0
129+
for j = 0, reaper.TrackFX_GetCount( data.obj ) - 1 do
130+
local GUID = reaper.TrackFX_GetFXGUID( data.obj, j )
131+
if data.fx[GUID] then
132+
c = c + 1
133+
reaper.TrackFX_CopyToTrack( data.obj, j, track, fx_cnt + c, false )
134+
end
135+
end
136+
end
137+
end
138+
139+
140+
local function FromItemToItem()
141+
if NotValid("MediaItem_Take*") then return end
142+
for i = 0, reaper.CountSelectedMediaItems(0)-1 do
143+
local item = reaper.GetSelectedMediaItem( 0, i )
144+
local take = reaper.GetActiveTake( item )
145+
if not take then return end
146+
local fx_cnt = reaper.TakeFX_GetCount( take ) - 1
147+
local c = 0
148+
for j = 0, reaper.TakeFX_GetCount( data.obj ) - 1 do
149+
local GUID = reaper.TakeFX_GetFXGUID( data.obj, j )
150+
if data.fx[GUID] then
151+
c = c + 1
152+
reaper.TakeFX_CopyToTake( data.obj, j, take, fx_cnt + c, false )
153+
end
154+
end
155+
end
156+
end
157+
158+
159+
local function FromItemToTrack()
160+
if NotValid("MediaItem_Take*") then return end
161+
for i = 0, reaper.CountSelectedTracks2(0, true)-1 do
162+
local track = reaper.GetSelectedTrack2( 0, i, true )
163+
local fx_cnt = reaper.TrackFX_GetCount( track ) - 1
164+
local c = 0
165+
for j = 0, reaper.TakeFX_GetCount( data.obj ) - 1 do
166+
local GUID = reaper.TakeFX_GetFXGUID( data.obj, j )
167+
if data.fx[GUID] then
168+
c = c + 1
169+
reaper.TakeFX_CopyToTrack( data.obj, j, track, fx_cnt + c, false )
170+
end
171+
end
172+
end
173+
end
174+
175+
176+
-----------------------------------------------------------------------------------------------------
177+
178+
179+
local ctx = ImGui.CreateContext('Copy/Paste selected FX', ImGui.ConfigFlags_NoSavedSettings)
180+
local sans_serif = ImGui.CreateFont('sans-serif', 16)
181+
ImGui.Attach(ctx, sans_serif)
182+
183+
184+
local text = 'Choose the items or tracks where\nyou want to paste the selected FX'
185+
local text2 = "Paste to:"
186+
local timer, indent = 0, 0
187+
188+
189+
local function myWindow()
190+
ImGui.Text( ctx, text )
191+
ImGui.Spacing( ctx )
192+
ImGui.Separator( ctx )
193+
if timer ~= 2 then
194+
timer = timer + 1
195+
indent = (ImGui.GetContentRegionAvail(ctx) - ImGui.CalcTextSize( ctx, text2 ))/2
196+
end
197+
ImGui.Indent( ctx, indent )
198+
ImGui.Text( ctx, text2 )
199+
ImGui.Unindent( ctx, indent )
200+
ImGui.Spacing( ctx )
201+
if ImGui.Button(ctx, 'Selected Items') then
202+
if data.what == "Take" then
203+
Undo( FromItemToItem, "Copy TakeFX to Items", 4 )
204+
else
205+
Undo( FromTrackToItem, "Copy TrackFX to Items", 4 )
206+
end
207+
end
208+
ImGui.SameLine(ctx)
209+
if ImGui.Button(ctx, 'Selected Tracks') then
210+
if data.what == "Take" then
211+
Undo( FromItemToTrack, "Copy TakeFX to Tracks", 2 )
212+
else
213+
Undo( FromTrackToTrack, "Copy TrackFX to Tracks", 2 )
214+
end
215+
end
216+
ImGui.Spacing( ctx )
217+
end
218+
219+
220+
local window_flags = ImGui.WindowFlags_NoCollapse|ImGui.WindowFlags_NoDocking|
221+
ImGui.WindowFlags_NoResize|ImGui.WindowFlags_NoSavedSettings|ImGui.WindowFlags_TopMost
222+
local x, y = reaper.GetMousePosition()
223+
ImGui.SetNextWindowPos( ctx, x, y, 0, 0.5, 0)
224+
local window_name = 'Paste copied ' .. data.what .. " FX"
225+
226+
227+
local function loop()
228+
ImGui.PushFont(ctx, sans_serif)
229+
visible, open = ImGui.Begin(ctx, window_name, true, window_flags)
230+
if visible then
231+
myWindow()
232+
ImGui.End(ctx)
233+
end
234+
ImGui.PopFont(ctx)
235+
236+
if open then
237+
reaper.defer(loop)
238+
end
239+
end
240+
241+
reaper.defer(loop)

0 commit comments

Comments
 (0)