2 ["type"] = "EditorAction",
4 author = "Ardour Lua Taskforce",
5 description = [[Stores the current Mixer state as a file that can be recalled arbitrarily.
6 Supports: processor settings, gain, trim, pan and processor ordering plus some fancy voodoo magic for re-adding deleted plugins.]]
9 function factory() return function()
11 function new_plugin(name)
14 plugin = ARDOUR.LuaAPI.new_plugin(Session, name, x, "")
15 if not(plugin:isnil()) then break end
19 function group_by_id(id)
21 for g in Session:route_groups():iter() do
22 local group_id = tonumber(g:to_stateful():id():to_s())
23 if group_id == id then group = g end
27 local path = ARDOUR.LuaAPI.build_filename(Session:path(), "export", "params.lua")
30 local file = io.open(path, "w")
31 file:write("") --empty current file from last run
34 local g_route_str, group_str = "", ""
36 for g in Session:route_groups():iter() do
37 group_str = "instance = {group_id = " .. g:to_stateful():id():to_s() .. ", routes = {"
38 for t in g:route_list():iter() do
39 g_route_str = g_route_str .."[".. i .."] = " .. t:to_stateful():id():to_s() .. ","
42 group_str = group_str .. g_route_str .. "}}"
45 if not(group_str == "") then --sometimes there are no groups in the session
46 file = io.open(path, "a")
47 file:write(group_str, "\r\n")
51 for r in Session:get_routes():iter() do
52 if r:is_monitor () or r:is_auditioner () then goto nextroute end -- skip special routes
54 local order = ARDOUR.ProcessorList()
57 local proc = r:nth_processor(x)
58 if not proc:isnil() then
64 local route_str, proc_order_str, cache_str = "", "", ""
65 local rid = r:to_stateful():id():to_s()
66 local pan = r:pan_azimuth_control()
67 if pan:isnil() then pan = false else pan = pan:get_value() end --sometimes a route doesn't have pan, like the master.
70 for p in order:iter() do
71 local pid = p:to_stateful():id():to_s()
72 proc_order_str = proc_order_str .. "[" .. on .. "] = " .. pid ..","
73 if not(string.find(p:display_name(), "latcomp")) then
74 cache_str = cache_str .. "[" .. pid .. "] = " .. "\"" .. p:display_name() .. "\"" ..","
79 route_str = "instance = {route_id = " .. rid .. ", gain_control = " .. r:gain_control():get_value() .. ", trim_control = " .. r:trim_control():get_value() .. ", pan_control = " .. tostring(pan) .. ", order = {" .. proc_order_str .."}, cache = {" .. cache_str .. "}" .. "}"
80 file = io.open(path, "a")
81 file:write(route_str, "\r\n")
87 local proc_str, params_str = "", ""
88 local proc = r:nth_plugin (i)
89 if proc:isnil () then break end
90 local active = proc:active()
91 local id = proc:to_stateful():id():to_s()
92 local plug = proc:to_insert ():plugin (0)
93 local n = 0 -- count control-ports
94 for j = 0, plug:parameter_count () - 1 do -- iterate over all plugin parameters
95 if plug:parameter_is_control (j) then
96 local label = plug:parameter_label (j)
97 if plug:parameter_is_input (j) and label ~= "hidden" and label:sub (1,1) ~= "#" then
98 local _, _, pd = ARDOUR.LuaAPI.plugin_automation(proc, n)
99 local val = ARDOUR.LuaAPI.get_processor_param(proc, j, true)
106 for k, v in pairs(params) do
107 params_str = params_str .. "[".. k .."] = " .. v .. ","
109 proc_str = "instance = {plugin_id = " .. id .. ", parameters = {" .. params_str .. "}, active = " .. tostring(active) .. "}"
110 file = io.open(path, "a")
111 file:write(proc_str, "\r\n")
117 local invalidate = {}
119 local file = io.open(path, "r")
120 assert(file, "File not found!")
121 for l in file:lines() do
124 local plugin, route, group = false, false, false
128 if instance["route_id"] ~= nil then route = true end
129 if instance["plugin_id"] ~= nil then plugin = true end
130 if instance["group_id"] ~= nil then group = true end
133 local g_id = instance["group_id"]
134 local routes = instance["routes"]
135 local group = group_by_id(g_id)
136 if group == nil then goto nextline end
137 for k, v in pairs(routes) do
138 local rt = Session:route_by_id(PBD.ID(v))
139 if not(rt:isnil()) then group:add(rt) end
144 local old_order = ARDOUR.ProcessorList()
145 local r_id = PBD.ID(instance["route_id"])
146 local order = instance["order"]
147 local cache = instance["cache"]
148 local gc, tc, pc = instance["gain_control"], instance["trim_control"], instance["pan_control"]
150 local rt = Session:route_by_id(r_id)
151 if rt:isnil() then goto nextline end
153 for k, v in pairs(order) do
154 local proc = Session:processor_by_id(PBD.ID(v))
156 for id, name in pairs(cache) do
158 proc = new_plugin(name)
159 rt:add_processor_by_index(proc, 0, nil, true)
160 invalidate[v] = proc:to_stateful():id():to_s()
164 if not(proc:isnil()) then old_order:push_back(proc) end
166 rt:gain_control():set_value(gc, 1)
167 rt:trim_control():set_value(tc, 1)
168 if pc ~= false then rt:pan_azimuth_control():set_value(pc, 1) end
169 rt:reorder_processors(old_order, nil)
174 local params = instance["parameters"]
175 local p_id = instance["plugin_id"]
176 local act = instance["active"]
178 for k, v in pairs(invalidate) do --invalidate any deleted plugin's id
184 local proc = Session:processor_by_id(PBD.ID(p_id))
185 if proc:isnil() then goto nextline end
186 local plug = proc:to_insert():plugin(0)
188 for k, v in pairs(params) do
189 local label = plug:parameter_label(k)
190 if string.find(label, "Assign") or string.find(label, "Enable") then --@ToDo: Check Plugin type == LADSPA or VST?
191 enable[k] = v --queue any assignments/enables for after the initial parameter recalling to duck the 'in-on-change' feature
193 ARDOUR.LuaAPI.set_processor_param(proc, k, v)
196 for k, v in pairs(enable) do
197 ARDOUR.LuaAPI.set_processor_param(proc, k, v)
199 if act then proc:activate() else proc:deactivate() end
205 local dialog_options = {
206 { type = "label", colspan= 10, title = "" },
207 { type = "radio", colspan= 10, key = "select", title = "", values ={ ["1. Mark"] = "mark", ["2. Recall"] = "recall" }, default = "1. Mark"},
208 { type = "label", colspan= 10, title = "" },
211 local rv = LuaDialog.Dialog("Mixer Store:", dialog_options):run()
212 assert(rv, 'Dialog box was canceled or is ' .. type(rv))
213 local c = rv["select"]
214 if c == "mark" then mark() end
215 if c == "recall" then recall() end