--[[ Description: Quick add FX or track template About: Adds FX or track templates to selected tracks or takes. Version: 1.50 Author: Neutronic Donation: https://paypal.me/SIXSTARCOS License: GNU GPL v3 Links: Neutronic's REAPER forum profile https://forum.cockos.com/member.php?u=66313 Script's forum thread https://forum.cockos.com/showthread.php?t=220800 Changelog: + option to clear master track FX chain before adding FX # open plugins inside FX Chains if chains are visible --]] --require("dev") function console() end local cur_os = reaper.GetOS() ---------- USER DEFINABLES ---------- local input_ovrd = "" -- put FX or track template query inside the quotes to hardcode it local fx_a = "VST2" local fx_b = "VST3" local fx_c = "JS" local fx_d = "CHAIN" local fx_e = "AU" local fx_type = {fx_d, fx_e, fx_a, fx_b, fx_c} -- the search order of FX types. Can be reordered ----- change the values below to true to activate the options or false to disable local search_track_name = false -- silently feed track names to the script local a_flag_reverse = false -- set it to "true" to reverse the behavior of the /a flag local keep_states = { -- what original track info to preserve when applying track templates GROUP_FLAGS = true, -- track group membership ISBUS = true, -- folder states (affects only templates containing a single track) ITEMS = true, -- track items LAYOUTS = true, -- track TCP + MCP layouts MAINSEND = true, -- master send / parent channels MUTESOLO = false, -- mute / solo NAME = false, -- track name REC = true, -- track record arm status / input / monitoring TRACKHEIGHT = true, -- track height VOLPAN = false -- volume / pan } ------------------------------------- keep_states.GROUP_FLAGS_HIGH = keep_states.GROUP_FLAGS local sel_tr_count = reaper.CountSelectedTracks() local sel_it_count = reaper.CountSelectedMediaItems() local m_track = reaper.GetMasterTrack() local is_m_sel = reaper.IsTrackSelected(m_track) local name, name_parts, part_match, l, input, undo_name, t_or_t, retval, data, js_name, v_s, dest, dest_count, fx_ch_list, fx_i, plugs, vst, au, sel_tr, track_1_sub, content, tracks, clear_fx local r_path = reaper.GetResourcePath() local dir_list = {} local file_list = {} local plugs_rel = {} local exact = "" local bit_vers = reaper.GetAppVersion():gsub(".+/", "") if bit_vers:gsub("%D", "") == "64" then vst = r_path .. "/reaper-vstplugins64.ini" if cur_os == "OSX64" then au = r_path .. "/reaper-auplugins64.ini" end else vst = r_path .. "/reaper-vstplugins.ini" end function close_undo() reaper.Undo_EndBlock("ReaScript: Run", -1) end function no_fx() reaper.MB("No FX matched your request.", "REASCRIPT Query", 0) end function add_fx() list_dir("FXChains", "RfxChain") fx_ch_list = file_list file_list = {} dir_list = {} match() if #plugs_rel == 0 then no_fx() return end for i = 1, #plugs_rel do local l if type(plugs_rel[i][1]) == "table" then l = plugs_rel[i][1][1] else l = plugs_rel[i][1] end console("Match " .. i .. ": " .. l, 1) end if not dest or dest == "/i" then reaper.PreventUIRefresh(1) add_track_fx() reaper.PreventUIRefresh(-1) elseif dest and dest == "/t" then reaper.PreventUIRefresh(1) add_item_fx() reaper.PreventUIRefresh(-1) end end function add_track_fx() local pass if sel_tr_count > 0 or is_m_sel then reaper.Undo_BeginBlock() is_input() track_fx() master_fx() if fx_i == -1 then return end track_or_tracks() if dest == "/i" then -- if input fx then reaper.Undo_EndBlock("Add input "..undo_name.." to selected "..t_or_t, -1) else reaper.Undo_EndBlock("Add "..undo_name.." to selected "..t_or_t, -1) end else local answ = reaper.MB("Select a track to put the fx on.", "REASCRIPT Query", 1) if answ == 1 then track_wait() else return end end end function flush_fx(object, kind) if kind < 3 then -- if not take FX if kind < 2 then -- if not track input FX local fx_count = reaper.TrackFX_GetCount(object) for i = 0, fx_count do reaper.TrackFX_SetOffline(object, 0, true) reaper.TrackFX_Delete(object, 0) end else -- if track input FX local fx_count = reaper.TrackFX_GetRecCount(object) for i = 0, fx_count do reaper.TrackFX_SetOffline(object, 0x1000000+0, true) reaper.TrackFX_Delete(object, 0x1000000+0) end end else -- if take FX local fx_count = reaper.TakeFX_GetCount(object) for i = 0, fx_count do reaper.TakeFX_SetOffline(object, 0, true) reaper.TakeFX_Delete(object, 0) end end end function template_single(i) track_1_sub = tracks[1] local tr = reaper.GetSelectedTrack(0, i) flush_fx(tr, 1) for k, v in pairs(sel_tr[i+1]["states"]) do -- recall states if tracks[1]:match(k) then track_1_sub = track_1_sub:gsub(k..".-\n", v, 1) else track_1_sub = track_1_sub:gsub(" 1 then return end local save_state = tr_chunk:match(state..".-\n") sel_tr[i+1]["states"][state] = save_state end function apply_template(template) local fn = string.gsub(template, "\\", "/") local file = io.open(fn) content = file:read("*a") file:close() local first_sel_tr_idx tracks = {} content = content:gsub("{.-}", "") repeat local track = content:match("((\n\n" table.insert(tracks, track) track = track:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0") content = content:gsub(track, "") end until not track table.insert(tracks, content) if content == "" or sel_tr_count == 0 then close_undo() return end if not search_track_name then first_sel_tr_idx = reaper.GetMediaTrackInfo_Value(reaper.GetSelectedTrack(0, 0), "IP_TRACKNUMBER") - 1 else first_sel_tr_idx = reaper.GetMediaTrackInfo_Value(reaper.GetSelectedTrack(0, pass), "IP_TRACKNUMBER") - 1 end first_sel_tr_idx = math.floor(first_sel_tr_idx) sel_tr = {} for i = 0, sel_tr_count -1 do local tr = reaper.GetSelectedTrack(0, i) sel_tr[i+1] = {states = {}} local tr_chunk = select(2, reaper.GetTrackStateChunk(tr, "", false)) if keep_states.ITEMS == true then sel_tr[i+1].items = {} for item in tr_chunk:gmatch("\n>") do table.insert(sel_tr[i+1].items, item) end end for k, v in pairs(keep_states) do if v == true then keepers(tracks, tr_chunk, k, i) end end end for i = 1, #tracks do -- fix sends tracks[i] = tracks[i]:gsub("(AUXRECV )(%d+)", function(a, b) b = tonumber(b) + first_sel_tr_idx return a..b end) end if not search_track_name and #tracks > 1 then template_multi(first_sel_tr, first_sel_tr_idx) elseif search_track_name then if #tracks > 1 then template_multi(first_sel_tr, first_sel_tr_idx) else template_single(pass) end if sel_tr_count - pass > 1 then pass = pass + 1 main() end else for i = 0, sel_tr_count - 1 do template_single(i) end end end function is_input() if dest == "/i" then input = true else input = false end end function plugs_rel_parse(v) if v.fx_type == "JS" then -- if JS name = v[1]:match(".+||"):gsub("|", "") if name ~= "Video processor" then name = v.fx_type..":"..v[1]:match(".+||"):gsub("|", "") end undo_name = v[1]:gsub(".+||", ""):gsub(" %(.+%)", "") elseif v.fx_type == "CHAIN" then name = [[]] .. v[1][2]:gsub(r_path .. "/FXChains/", "") .. v[1][1] .. [[]] .. ".RfxChain" undo_name = v[1][1] else -- if VST name = v.fx_type..":"..v[1]:gsub("!.+", "") undo_name = name:gsub("VST%d:", ""):gsub(" %(.+%)", "") end console("Plug-in name: " .. name .. "\nPlug-in undo name: " .. undo_name, 1) end function fxTrack_Float(track) if input then -- if input FX if not name:match("%.RfxChain") then -- if not chain local chunk = select(2, reaper.GetTrackStateChunk(track, "", false)) local is_fxc_vis = tonumber(chunk:match("