858bb4294d
Two main problems are addressed by this commit. First, storage of parameters was broken because the index for values was set by the parameter count, not the control port count which set_processor_param() expects. Second, the value was not clamped to pd.upper and pd.lower causing some parameters to fail when set. This invalidates previous mixer store files.
482 lines
14 KiB
Lua
482 lines
14 KiB
Lua
ardour {
|
|
["type"] = "EditorAction",
|
|
name = "Recall Mixer Settings",
|
|
author = "Mixbus Team",
|
|
description = [[
|
|
|
|
Recalls mixer settings outined by files
|
|
created by Store Mixer Settings.
|
|
|
|
Allows for some room to change Source
|
|
and Destination.
|
|
|
|
]]
|
|
}
|
|
|
|
function factory ()
|
|
|
|
local acoraida_monicas_last_used_recall_file
|
|
|
|
return function ()
|
|
|
|
local user_cfg = ARDOUR.user_config_directory(-1)
|
|
local local_path = ARDOUR.LuaAPI.build_filename(Session:path(), 'mixer_settings')
|
|
local global_path = ARDOUR.LuaAPI.build_filename(user_cfg, 'mixer_settings')
|
|
|
|
local invalidate = {}
|
|
|
|
function exists(file)
|
|
local ok, err, code = os.rename(file, file)
|
|
if not ok then
|
|
if code == 13 then -- Permission denied, but it exists
|
|
return true
|
|
end
|
|
end return ok, err
|
|
end
|
|
|
|
function whoami()
|
|
if not pcall(function() local first_check = Session:get_mixbus(0) end) then
|
|
return "Ardour"
|
|
else
|
|
local second_check = Session:get_mixbus(11)
|
|
if second_check:isnil() then
|
|
return "Mixbus"
|
|
else
|
|
return "32C"
|
|
end
|
|
end
|
|
end
|
|
|
|
function isdir(path)
|
|
return exists(path.."/")
|
|
end
|
|
|
|
function get_processor_by_name(track, name)
|
|
local i = 0
|
|
local proc = track:nth_processor(i)
|
|
repeat
|
|
if(proc:display_name() == name) then
|
|
return proc
|
|
else
|
|
i = i + 1
|
|
end
|
|
proc = track:nth_processor(i)
|
|
until proc:isnil()
|
|
end
|
|
|
|
function new_plugin(name, type)
|
|
local plugin = ARDOUR.LuaAPI.new_plugin(Session, name, type, "")
|
|
if not(plugin:isnil()) then return plugin end
|
|
end
|
|
|
|
function group_by_id(id)
|
|
local id = tonumber(id)
|
|
for g in Session:route_groups():iter() do
|
|
local group_id = tonumber(g:to_stateful():id():to_s())
|
|
if group_id == id then return g end
|
|
end
|
|
end
|
|
|
|
function group_by_name(name)
|
|
for g in Session:route_groups():iter() do
|
|
if g:name() == name then return g end
|
|
end
|
|
end
|
|
|
|
function route_groupid_interrogate(t)
|
|
local group = false
|
|
for g in Session:route_groups():iter() do
|
|
for r in g:route_list():iter() do
|
|
if r:name() == t:name() then group = g:to_stateful():id():to_s() end
|
|
end
|
|
end return group
|
|
end
|
|
|
|
function route_group_interrogate(t)
|
|
for g in Session:route_groups():iter() do
|
|
for r in g:route_list():iter() do
|
|
if r:name() == t:name() then return g end
|
|
end
|
|
end
|
|
end
|
|
|
|
function recall(debug, path, dry_run)
|
|
local file = io.open(path, "r")
|
|
assert(file, "File not found!")
|
|
local bypass_routes = {}
|
|
|
|
local i = 0
|
|
for l in file:lines() do
|
|
--print(i, l)
|
|
|
|
local create_groups = dry_run["create_groups"]
|
|
local skip_line = false
|
|
|
|
local plugin, route, group = false, false, false
|
|
local f = load(l)
|
|
|
|
if debug then
|
|
--print('create_groups ' .. tostring(create_groups))
|
|
print(i, string.sub(l, 0, 29), f)
|
|
end
|
|
|
|
if f then f() end
|
|
|
|
if instance["route_id"] then route = true end
|
|
if instance["plugin_id"] then plugin = true end
|
|
if instance["group_id"] then group = true end
|
|
|
|
if group then
|
|
local g_id = instance["group_id"]
|
|
local routes = instance["routes"]
|
|
local name = instance["name"]
|
|
local group = group_by_id(g_id)
|
|
if not(group) then
|
|
if create_groups then
|
|
local group = Session:new_route_group(name)
|
|
for _, v in pairs(routes) do
|
|
local rt = Session:route_by_id(PBD.ID(v))
|
|
if rt:isnil() then rt = Session:route_by_name(name) end
|
|
if not(rt:isnil()) then group:add(rt) end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if route then
|
|
local substitution = tonumber(dry_run["destination-"..i])
|
|
if substitution == 0 then
|
|
bypass_routes[#bypass_routes + 1] = instance["route_id"]
|
|
goto nextline
|
|
end
|
|
|
|
local old_order = ARDOUR.ProcessorList()
|
|
local route_id = instance["route_id"]
|
|
local r_id = PBD.ID(instance["route_id"])
|
|
local muted, soloed = instance["muted"], instance["soloed"]
|
|
local order = instance["order"]
|
|
local cache = instance["cache"]
|
|
local group = instance["group"]
|
|
local group_name = instance["group_name"]
|
|
local name = instance["route_name"]
|
|
local gc, tc, pc = instance["gain_control"], instance["trim_control"], instance["pan_control"]
|
|
local sends = instance["sends"]
|
|
|
|
if not(substitution == instance["route_id"]) then
|
|
print('SUBSTITUTION FOR: ', name, substitution, Session:route_by_id(PBD.ID(substitution)):name())
|
|
--bypass_routes[#bypass_routes + 1] = route_id
|
|
was_subbed = true
|
|
r_id = PBD.ID(substitution)
|
|
end
|
|
|
|
local rt = Session:route_by_id(r_id)
|
|
if rt:isnil() then rt = Session:route_by_name(name) end
|
|
if rt:isnil() then goto nextline end
|
|
|
|
if sends then
|
|
for i, data in pairs(sends) do
|
|
i = i-1
|
|
for j, ctrl in pairs({
|
|
rt:send_level_controllable(i),
|
|
rt:send_enable_controllable(i),
|
|
rt:send_pan_azimuth_controllable(i),
|
|
rt:send_pan_azimuth_enable_controllable(i),
|
|
}) do
|
|
if not(ctrl:isnil()) then
|
|
local value = data[j]
|
|
if value then
|
|
if debug then
|
|
print("Setting " .. ctrl:name() .. " to value " .. value)
|
|
end
|
|
ctrl:set_value(value, PBD.GroupControlDisposition.NoGroup)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local cur_group_id = route_groupid_interrogate(rt)
|
|
if not(group) and (cur_group_id) then
|
|
local g = group_by_id(cur_group_id)
|
|
if g then g:remove(rt) end
|
|
end
|
|
|
|
local rt_group = group_by_name(group_name)
|
|
if rt_group then rt_group:add(rt) end
|
|
|
|
well_known = {'PRE', 'Trim', 'EQ', 'Comp', 'Fader', 'POST'}
|
|
protected_instrument = false
|
|
for k, v in pairs(order) do
|
|
local proc = Session:processor_by_id(PBD.ID(1))
|
|
if not(was_subbed) then
|
|
proc = Session:processor_by_id(PBD.ID(v))
|
|
end
|
|
if proc:isnil() then
|
|
for id, sub_tbl in pairs(cache) do
|
|
local name = sub_tbl[1]
|
|
local type = sub_tbl[2]
|
|
if v == id then
|
|
proc = new_plugin(name, type)
|
|
for _, control in pairs(well_known) do
|
|
if name == control then
|
|
proc = get_processor_by_name(rt, control)
|
|
invalidate[v] = proc:to_stateful():id():to_s()
|
|
goto nextproc
|
|
end
|
|
end
|
|
if not(proc) then goto nextproc end
|
|
if not(proc:isnil()) then
|
|
rt:add_processor_by_index(proc, 0, nil, true)
|
|
invalidate[v] = proc:to_stateful():id():to_s()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
::nextproc::
|
|
if proc and not(proc:isnil()) then old_order:push_back(proc) end
|
|
if not(old_order:empty()) and not(protected_instrument) then
|
|
if not(rt:to_track():to_midi_track():isnil()) then
|
|
if not(rt:the_instrument():isnil()) then
|
|
protected_instrument = true
|
|
old_order:push_back(rt:the_instrument())
|
|
end
|
|
end
|
|
end
|
|
end
|
|
rt:reorder_processors(old_order, nil)
|
|
if muted then rt:mute_control():set_value(1, 1) else rt:mute_control():set_value(0, 1) end
|
|
if soloed then rt:solo_control():set_value(1, 1) else rt:solo_control():set_value(0, 1) end
|
|
rt:gain_control():set_value(gc, 1)
|
|
rt:trim_control():set_value(tc, 1)
|
|
if pc ~= false and not(rt:is_master()) then rt:pan_azimuth_control():set_value(pc, 1) end
|
|
end
|
|
|
|
if plugin then
|
|
--if the plugin is owned by a route
|
|
--we decided not to use, skip it
|
|
for _, v in pairs(bypass_routes) do
|
|
if instance["owned_by_route_id"] == v then
|
|
goto nextline
|
|
end
|
|
end
|
|
|
|
local enable = {}
|
|
local params = instance["parameters"]
|
|
local p_id = instance["plugin_id"]
|
|
local act = instance["active"]
|
|
|
|
for k, v in pairs(invalidate) do --invalidate any deleted plugin's id
|
|
if p_id == k then
|
|
p_id = v
|
|
end
|
|
end
|
|
|
|
local proc = Session:processor_by_id(PBD.ID(p_id))
|
|
if proc:isnil() then goto nextline end
|
|
local plug = proc:to_insert():plugin(0)
|
|
|
|
local ctl = 0
|
|
for j = 0, plug:parameter_count() - 1 do
|
|
if plug:parameter_is_control(j) then
|
|
local label = plug:parameter_label(j)
|
|
value = params[ctl]
|
|
if value then
|
|
if string.find(label, "Assign") or string.find(label, "Enable") then --@ToDo: Check Plugin type == LADSPA or VST?
|
|
enable[ctl] = value -- Queue enable assignment for later
|
|
goto skip_param
|
|
end
|
|
if not(ARDOUR.LuaAPI.set_processor_param(proc, ctl, value)) then
|
|
print("Could not set ctrl port " .. ctl .. " to " .. value)
|
|
end
|
|
end
|
|
::skip_param::
|
|
ctl = ctl + 1
|
|
end
|
|
end
|
|
|
|
for k, v in pairs(enable) do
|
|
ARDOUR.LuaAPI.set_processor_param(proc, k, v)
|
|
end
|
|
|
|
if act then proc:activate() else proc:deactivate() end
|
|
end
|
|
|
|
::nextline::
|
|
i = i + 1
|
|
|
|
end
|
|
end
|
|
|
|
function dry_run(debug, path)
|
|
--returns a dialog-able table of
|
|
--everything we do (logically)
|
|
--in the recall function
|
|
local route_values = {['----'] = "0"}
|
|
for r in Session:get_routes():iter() do
|
|
route_values[r:name()] = r:to_stateful():id():to_s()
|
|
end
|
|
|
|
local i = 0
|
|
local dry_table = {
|
|
{type = "label", align="right", key="col-1-title", col=0, colspan=1, title = 'Source:'},
|
|
{type = "label", align="left", key="col-2-title", col=1, colspan=1, title = 'Destination:'},
|
|
}
|
|
local file = io.open(path, "r")
|
|
assert(file, "File not found!")
|
|
pad = 0
|
|
for l in file:lines() do
|
|
local do_plugin, do_route, do_group = false, false, false
|
|
local f = load(l)
|
|
|
|
if debug then
|
|
print(i, string.sub(l, 0, 29), f)
|
|
end
|
|
|
|
if f then f() end
|
|
|
|
if instance["route_id"] then do_route = true end
|
|
if instance["plugin_id"] then do_plugin = true end
|
|
if instance["group_id"] then do_group = true end
|
|
|
|
if do_group then
|
|
local group_id = instance["group_id"]
|
|
local group_name = instance["name"]
|
|
local dlg_title, action_title = "", ""
|
|
|
|
local group_ptr = group_by_id(group_id)
|
|
|
|
if not(group_ptr) then
|
|
dlg_title = string.format("(Group) %s.", group_name)
|
|
--action_title = "will create and use settings"
|
|
else
|
|
dlg_title = string.format("(Group) %s.", group_ptr:name())
|
|
--action_title = "will use group settings"
|
|
end
|
|
table.insert(dry_table, {
|
|
order=pad, type = "label", align="right", key = "group-"..i , col = 0, colspan = 1, title = dlg_title
|
|
})
|
|
pad = pad + 1
|
|
end
|
|
|
|
if do_route then
|
|
local route_id = instance["route_id"]
|
|
local route_name = instance["route_name"]
|
|
local dlg_title = ""
|
|
|
|
local route_ptr = Session:route_by_id(PBD.ID(route_id))
|
|
|
|
if route_ptr:isnil() then
|
|
route_ptr = Session:route_by_name(route_name)
|
|
if not(route_ptr:isnil()) then
|
|
dlg_title = string.format("%s", route_ptr:name())
|
|
--action_title = "will use route settings"
|
|
else
|
|
dlg_title = string.format("%s", route_name)
|
|
--action_title = "will be ignored"
|
|
end
|
|
else
|
|
dlg_title = string.format("%s", route_ptr:name())
|
|
--action_title = "will use route settings"
|
|
end
|
|
if route_ptr:isnil() then name = route_name else name = route_ptr:name() end
|
|
|
|
table.insert(dry_table, {
|
|
order=instance['pi_order']+pad, type = "label", align="right", key = "route-"..i , col = 0, colspan = 1, title = dlg_title
|
|
})
|
|
table.insert(dry_table, {
|
|
type = "dropdown", align="left", key = "destination-"..i, col = 1, colspan = 1, title = "", values = route_values, default = name or "----"
|
|
})
|
|
end
|
|
i = i + 1
|
|
end
|
|
table.insert(dry_table, {
|
|
type = "checkbox", col=0, colspan=2, align="left", key = "create_groups", default = true, title = "Create Groups if necessary?"
|
|
})
|
|
return dry_table
|
|
end
|
|
|
|
local global_vs_local_dlg = {
|
|
{ type = "label", col=0, colspan=20, align="left", title = "" },
|
|
{
|
|
type = "radio", col=0, colspan=20, align="left", key = "recall-dir", title = "", values =
|
|
{
|
|
['Pick from Global Settings'] = 1, ['Pick from Local Settings'] = 2, ['Last Used Recall File'] = 3,
|
|
},
|
|
default = 'Last Used Recall File'
|
|
},
|
|
{ type = "label", col=0, colspan=20, align="left", title = ""},
|
|
}
|
|
|
|
local recall_options = {
|
|
{ type = "label", col=0, colspan=10, align="left", title = "" },
|
|
{ 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") },
|
|
{ type = "label", col=0, colspan=10, align="left", title = "" },
|
|
}
|
|
|
|
local gvld = LuaDialog.Dialog("Recall Mixer Settings:", global_vs_local_dlg):run()
|
|
|
|
if not(gvld) then
|
|
return
|
|
else
|
|
if gvld['recall-dir'] == 1 then
|
|
local global_ok = isdir(global_path)
|
|
local global_default_path = ARDOUR.LuaAPI.build_filename(global_path, string.format("FactoryDefault-%s.lua", whoami()))
|
|
print(global_default_path)
|
|
if global_ok then
|
|
recall_options[2]['path'] = global_default_path
|
|
local rv = LuaDialog.Dialog("Recall Mixer Settings:", recall_options):run()
|
|
if not(rv) then return end
|
|
local dry_return = LuaDialog.Dialog("Recall Mixer Settings:", dry_run(false, rv['file'])):run()
|
|
if dry_return then
|
|
acoraida_monicas_last_used_recall_file = rv['file']
|
|
recall(false, rv['file'], dry_return)
|
|
else
|
|
return
|
|
end
|
|
else
|
|
LuaDialog.Message ("Recall Mixer Settings:",
|
|
global_path .. ' does not exist!\nPlease run Store Mixer Settings first.',
|
|
LuaDialog.MessageType.Info, LuaDialog.ButtonType.Close):run()
|
|
end
|
|
end
|
|
|
|
if gvld['recall-dir'] == 2 then
|
|
local local_ok = isdir(local_path)
|
|
local local_default_path = ARDOUR.LuaAPI.build_filename(local_path, 'asdf')
|
|
print(local_default_path)
|
|
if local_ok then
|
|
recall_options[2]['path'] = local_default_path
|
|
local rv = LuaDialog.Dialog("Recall Mixer Settings:", recall_options):run()
|
|
if not(rv) then return end
|
|
local dry_return = LuaDialog.Dialog("Recall Mixer Settings:", dry_run(false, rv['file'])):run()
|
|
if dry_return then
|
|
acoraida_monicas_last_used_recall_file = rv['file']
|
|
recall(true, rv['file'], dry_return)
|
|
else
|
|
return
|
|
end
|
|
else
|
|
LuaDialog.Message ("Recall Mixer Settings:",
|
|
local_path .. 'does not exist!\nPlease run Store Mixer Settings first.',
|
|
LuaDialog.MessageType.Info, LuaDialog.ButtonType.Close):run()
|
|
end
|
|
end
|
|
|
|
if gvld['recall-dir'] == 3 then
|
|
if acoraida_monicas_last_used_recall_file then
|
|
local dry_return = LuaDialog.Dialog("Recall Mixer Settings:", dry_run(false, acoraida_monicas_last_used_recall_file)):run()
|
|
if dry_return then
|
|
recall(true, acoraida_monicas_last_used_recall_file, dry_return)
|
|
else
|
|
return
|
|
end
|
|
else
|
|
LuaDialog.Message ("Script has no record of last used file:",
|
|
'Please pick a recall file and then this option will be available',
|
|
LuaDialog.MessageType.Info, LuaDialog.ButtonType.Close):run()
|
|
end
|
|
end
|
|
end
|
|
|
|
end end
|