2 ["type"] = "EditorAction",
3 name = "Recall Mixer Settings",
4 author = "Mixbus Team",
7 Recalls mixer settings outined by files
8 created by Store Mixer Settings.
10 Allows for some room to change Source
16 function factory () return function ()
18 local user_cfg = ARDOUR.user_config_directory(-1)
19 local local_path = ARDOUR.LuaAPI.build_filename(Session:path(), 'mixer_settings')
20 local global_path = ARDOUR.LuaAPI.build_filename(user_cfg, 'mixer_settings')
25 local ok, err, code = os.rename(file, file)
27 if code == 13 then -- Permission denied, but it exists
34 if not pcall(function() local first_check = Session:get_mixbus(0) end) then
37 local second_check = Session:get_mixbus(11)
38 if second_check:isnil() then
47 return exists(path.."/")
50 function fetch_valid_settings_file(directory, fallback)
51 local i, t, popen = 0, {}, io.popen
52 local pfile = popen('ls "'..directory..'"')
53 for filename in pfile:lines() do
55 if string.find(filename, ".lua") then
63 function get_processor_by_name(track, name)
65 local proc = track:nth_processor(i)
67 if(proc:display_name() == name) then
72 proc = track:nth_processor(i)
76 function new_plugin(name)
78 local plugin = ARDOUR.LuaAPI.new_plugin(Session, name, x, "")
79 if not(plugin:isnil()) then return plugin end
83 function group_by_id(id)
84 local id = tonumber(id)
85 for g in Session:route_groups():iter() do
86 local group_id = tonumber(g:to_stateful():id():to_s())
87 if group_id == id then return g end
91 function group_by_name(name)
92 for g in Session:route_groups():iter() do
93 if g:name() == name then return g end
97 function route_groupid_interrogate(t)
99 for g in Session:route_groups():iter() do
100 for r in g:route_list():iter() do
101 if r:name() == t:name() then group = g:to_stateful():id():to_s() end
106 function route_group_interrogate(t)
107 for g in Session:route_groups():iter() do
108 for r in g:route_list():iter() do
109 if r:name() == t:name() then return g end
114 function recall(debug, path, dry_run)
115 local file = io.open(path, "r")
116 assert(file, "File not found!")
117 local bypass_routes = {}
120 for l in file:lines() do
123 local exec_line = dry_run["dothis-"..i]
124 local skip_line = false
125 if not(exec_line == nil) and not(exec_line) then
129 local plugin, route, group = false, false, false
133 print(i, string.sub(l, 0, 29), f)
138 if instance["route_id"] then route = true end
139 if instance["plugin_id"] then plugin = true end
140 if instance["group_id"] then group = true end
143 if skip_line then goto nextline end
145 local g_id = instance["group_id"]
146 local routes = instance["routes"]
147 local name = instance["name"]
148 local group = group_by_id(g_id)
150 local group = Session:new_route_group(name)
151 for _, v in pairs(routes) do
152 local rt = Session:route_by_id(PBD.ID(v))
153 if rt:isnil() then rt = Session:route_by_name(name) end
154 if not(rt:isnil()) then group:add(rt) end
160 local substitution = tonumber(dry_run["destination-"..i])
161 if skip_line or (substitution == 0) then
162 bypass_routes[#bypass_routes + 1] = instance["route_id"]
166 local old_order = ARDOUR.ProcessorList()
167 local route_id = instance["route_id"]
168 local r_id = PBD.ID(instance["route_id"])
169 local muted, soloed = instance["muted"], instance["soloed"]
170 local order = instance["order"]
171 local cache = instance["cache"]
172 local group = instance["group"]
173 local group_name = instance["group_name"]
174 local name = instance["route_name"]
175 local gc, tc, pc = instance["gain_control"], instance["trim_control"], instance["pan_control"]
177 if not(substitution == instance["route_id"]) then
178 print('SUBSTITUTION FOR: ', name, substitution, Session:route_by_id(PBD.ID(substitution)):name())
179 --bypass_routes[#bypass_routes + 1] = route_id
181 r_id = PBD.ID(substitution)
184 local rt = Session:route_by_id(r_id)
185 if rt:isnil() then rt = Session:route_by_name(name) end
186 if rt:isnil() then goto nextline end
188 local cur_group_id = route_groupid_interrogate(rt)
189 if not(group) and (cur_group_id) then
190 local g = group_by_id(cur_group_id)
191 if g then g:remove(rt) end
194 local rt_group = group_by_name(group_name)
195 if rt_group then rt_group:add(rt) end
197 well_known = {'PRE', 'Trim', 'EQ', 'Comp', 'Fader', 'POST'}
199 for k, v in pairs(order) do
200 local proc = Session:processor_by_id(PBD.ID(1))
201 if not(was_subbed) then
202 proc = Session:processor_by_id(PBD.ID(v))
205 for id, name in pairs(cache) do
207 proc = new_plugin(name)
208 for _, control in pairs(well_known) do
209 if name == control then
210 proc = get_processor_by_name(rt, control)
211 invalidate[v] = proc:to_stateful():id():to_s()
215 if not(proc) then goto nextproc end
216 if not(proc:isnil()) then
217 rt:add_processor_by_index(proc, 0, nil, true)
218 invalidate[v] = proc:to_stateful():id():to_s()
224 if proc and not(proc:isnil()) then old_order:push_back(proc) end
226 rt:reorder_processors(old_order, nil)
227 if muted then rt:mute_control():set_value(1, 1) else rt:mute_control():set_value(0, 1) end
228 if soloed then rt:solo_control():set_value(1, 1) else rt:solo_control():set_value(0, 1) end
229 rt:gain_control():set_value(gc, 1)
230 rt:trim_control():set_value(tc, 1)
231 if pc ~= false then rt:pan_azimuth_control():set_value(pc, 1) end
235 if skip_line then goto nextline end
237 --if the plugin is owned by a route
238 --we decided not to use, skip it
239 for _, v in pairs(bypass_routes) do
240 if instance["owned_by_route_id"] == v then
246 local params = instance["parameters"]
247 local p_id = instance["plugin_id"]
248 local act = instance["active"]
250 for k, v in pairs(invalidate) do --invalidate any deleted plugin's id
256 local proc = Session:processor_by_id(PBD.ID(p_id))
257 if proc:isnil() then goto nextline end
258 local plug = proc:to_insert():plugin(0)
260 for k, v in pairs(params) do
261 local label = plug:parameter_label(k)
262 if string.find(label, "Assign") or string.find(label, "Enable") then --@ToDo: Check Plugin type == LADSPA or VST?
263 enable[k] = v --queue any assignments/enables for after the initial parameter recalling to duck the 'in-on-change' feature
265 ARDOUR.LuaAPI.set_processor_param(proc, k, v)
268 for k, v in pairs(enable) do
269 ARDOUR.LuaAPI.set_processor_param(proc, k, v)
271 if act then proc:activate() else proc:deactivate() end
280 function dry_run(debug, path)
281 --returns a dialog-able table of
282 --everything we do (logically)
283 --in the recall function
284 local route_values = {['----'] = "0"}
285 for r in Session:get_routes():iter() do
286 route_values[r:name()] = r:to_stateful():id():to_s()
291 {type = "label", align="right", key="col-1-title", col=0, colspan=1, title = 'Source:'},
292 {type = "label", align="left", key="col-2-title", col=1, colspan=1, title = 'Destination:'},
294 local file = io.open(path, "r")
295 assert(file, "File not found!")
297 for l in file:lines() do
298 local do_plugin, do_route, do_group = false, false, false
302 print(i, string.sub(l, 0, 29), f)
307 if instance["route_id"] then do_route = true end
308 if instance["plugin_id"] then do_plugin = true end
309 if instance["group_id"] then do_group = true end
312 local group_id = instance["group_id"]
313 local group_name = instance["name"]
314 local dlg_title, action_title = "", ""
316 local group_ptr = group_by_id(group_id)
318 if not(group_ptr) then
319 new_group = Session:new_route_group(group_name)
320 dlg_title = string.format("(Group) %s.", group_name, new_group:name())
321 --action_title = "will create and use settings"
323 dlg_title = string.format("(Group) %s.", group_ptr:name())
324 --action_title = "will use group settings"
326 table.insert(dry_table, {
327 type = "label", align="right", key = "type-"..i , col = 0, colspan = 1, title = ""
329 table.insert(dry_table, {
330 type = "label", align="right", key = "group-"..i , col = 1, colspan = 1, title = dlg_title
335 local route_id = instance["route_id"]
336 local route_name = instance["route_name"]
339 local route_ptr = Session:route_by_id(PBD.ID(route_id))
341 if route_ptr:isnil() then
342 route_ptr = Session:route_by_name(route_name)
343 if not(route_ptr:isnil()) then
344 dlg_title = string.format("%s", route_ptr:name())
345 --action_title = "will use route settings"
347 dlg_title = string.format("%s", route_name)
348 --action_title = "will be ignored"
351 dlg_title = string.format("%s", route_ptr:name())
352 --action_title = "will use route settings"
354 if route_ptr:isnil() then name = route_name else name = route_ptr:name() end
356 table.insert(dry_table, {
357 type = "label", align="right", key = "route-"..i , col = 1, colspan = 1, title = dlg_title
359 table.insert(dry_table, {
360 type = "dropdown", align="left", key = "destination-"..i, col = 2, colspan = 1, title = "", values = route_values, default = name or "----"
368 local global_vs_local_dlg = {
369 { type = "label", col=0, colspan=20, align="left", title = "" },
371 type = "radio", col=0, colspan=20, align="left", key = "recall-dir", title = "", values =
373 ['Pick from Global Settings'] = 1, ['Pick from Local Settings'] = 2
375 default = 'Pick from Local Settings'
377 { type = "label", col=0, colspan=20, align="left", title = ""},
380 local recall_options = {
381 { type = "label", col=0, colspan=10, align="left", title = "" },
382 { type = "file", col=0, colspan=15, align="left", key = "file", title = "Select a Settings File:", path = ARDOUR.LuaAPI.build_filename(Session:path(), "export", "params.lua") },
383 { type = "label", col=0, colspan=10, align="left", title = "" },
386 local gvld = LuaDialog.Dialog("Recall Mixer Settings:", global_vs_local_dlg):run()
391 if gvld['recall-dir'] == 1 then
392 local global_ok = isdir(global_path)
393 local global_default_path = ARDOUR.LuaAPI.build_filename(global_path, fetch_valid_settings_file(global_path, string.format("FactoryDefault-%s.lua", whoami())))
394 print(global_default_path)
396 recall_options[2]['path'] = global_default_path
397 local rv = LuaDialog.Dialog("Recall Mixer Settings:", recall_options):run()
398 if not(rv) then return end
399 local dry_return = LuaDialog.Dialog("Mixer Store:", dry_run(false, rv['file'])):run()
401 recall(false, rv['file'], dry_return)
406 LuaDialog.Message ("Recall Mixer Settings:",
407 global_path .. ' does not exist!\nPlease run Store Mixer Settings first.',
408 LuaDialog.MessageType.Info, LuaDialog.ButtonType.Close):run()
412 if gvld['recall-dir'] == 2 then
413 local local_ok = isdir(local_path)
414 local local_default_path = ARDOUR.LuaAPI.build_filename(local_path, fetch_valid_settings_file(local_path))
415 print(local_default_path)
417 recall_options[2]['path'] = local_default_path
418 local rv = LuaDialog.Dialog("Recall Mixer Settings:", recall_options):run()
419 if not(rv) then return end
420 local dry_return = LuaDialog.Dialog("Mixer Store:", dry_run(false, rv['file'])):run()
422 recall(false, rv['file'], dry_return)
427 LuaDialog.Message ("Recall Mixer Settings:",
428 local_path .. 'does not exist!\nPlease run Store Mixer Settings first.',
429 LuaDialog.MessageType.Info, LuaDialog.ButtonType.Close):run()