#include "ardour/debug.h"
#include "ardour/event_type_map.h"
#include "ardour/ladspa_plugin.h"
+#include "ardour/luaproc.h"
#include "ardour/plugin.h"
#include "ardour/plugin_insert.h"
: Processor (s, (plug ? plug->name() : string ("toBeRenamed")))
, _signal_analysis_collected_nframes(0)
, _signal_analysis_collect_nframes_max(0)
+ , _no_inplace (false)
+ , _pending_no_inplace (false)
+ , _strict_io (false)
+ , _strict_io_configured (false)
{
/* the first is the master */
PluginInfoPtr info = _plugins.front()->get_info();
- if (info->reconfigurable_io()) {
+ if (_strict_io_configured) {
+ return _configured_in; // XXX, check initial configuration
+ }
+ else if (info->reconfigurable_io()) {
ChanCount out = _plugins.front()->output_streams ();
// DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, reconfigur(able) output streams = %1\n", out));
return out;
can_automate (param);
boost::shared_ptr<AutomationList> list(new AutomationList(param, desc));
- add_control (boost::shared_ptr<AutomationControl> (new PluginControl(this, param, desc, list)));
+ boost::shared_ptr<AutomationControl> c (new PluginControl(this, param, desc, list));
+ add_control (c);
+ _plugins.front()->set_automation_control (i->id(), c);
} else if (i->type() == PluginPropertyAutomation) {
Evoral::Parameter param(*i);
const ParameterDescriptor& desc = _plugins.front()->get_property_descriptor(param.id());
void
PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t offset, bool with_auto, framepos_t now)
{
+ _no_inplace = _pending_no_inplace;
// Calculate if, and how many frames we need to collect for analysis
framecnt_t collect_signal_nframes = (_signal_analysis_collect_nframes_max -
_signal_analysis_collected_nframes);
ChanCount const in_streams = input_streams ();
ChanCount const out_streams = output_streams ();
- ChanMapping in_map (in_streams);
- ChanMapping out_map (out_streams);
- bool valid;
if (_match.method == Split) {
+ assert (_in_map.size () == 1);
/* fix the input mapping so that we have maps for each of the plugin's inputs */
- in_map = ChanMapping (natural_input_streams ());
/* copy the first stream's buffer contents to the others */
/* XXX: audio only */
- uint32_t first_idx = in_map.get (DataType::AUDIO, 0, &valid);
+ bool valid;
+ uint32_t first_idx = _in_map[0].get (DataType::AUDIO, 0, &valid);
if (valid) {
for (uint32_t i = in_streams.n_audio(); i < natural_input_streams().n_audio(); ++i) {
- bufs.get_audio(in_map.get (DataType::AUDIO, i, &valid)).read_from(bufs.get_audio(first_idx), nframes, offset, offset);
+ bufs.get_audio(_in_map[0].get (DataType::AUDIO, i, &valid)).read_from(bufs.get_audio(first_idx), nframes, offset, offset);
}
}
}
}
- for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
- (*i)->connect_and_run(bufs, in_map, out_map, nframes, offset);
- for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
- in_map.offset_to(*t, natural_input_streams().get(*t));
- out_map.offset_to(*t, natural_output_streams().get(*t));
+ if (_no_inplace) {
+ BufferSet& inplace_bufs = _session.get_noinplace_buffers();
+
+ uint32_t pc = 0;
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
+
+ ARDOUR::ChanMapping in_map (natural_input_streams());
+ ARDOUR::ChanMapping out_map;
+ ARDOUR::ChanCount mapped;
+ ARDOUR::ChanCount backmap;
+
+ // map inputs sequentially
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ for (uint32_t in = 0; in < natural_input_streams().get (*t); ++in) {
+ bool valid;
+ uint32_t in_idx = _in_map[pc].get (*t, in, &valid);
+ uint32_t m = mapped.get (*t);
+ if (valid) {
+ inplace_bufs.get (*t, m).read_from (bufs.get (*t, in_idx), nframes, offset, offset);
+ } else {
+ inplace_bufs.get (*t, m).silence (nframes, offset);
+ }
+ mapped.set (*t, m + 1);
+ }
+ }
+
+ // TODO use map_offset_to() instead ??
+ backmap = mapped;
+
+ // map outputs
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ for (uint32_t out = 0; out < natural_output_streams().get (*t); ++out) {
+ uint32_t m = mapped.get (*t);
+ inplace_bufs.get (*t, m).silence (nframes, offset);
+ out_map.set (*t, out, m);
+ mapped.set (*t, m + 1);
+ }
+ }
+
+ if ((*i)->connect_and_run(inplace_bufs, in_map, out_map, nframes, offset)) {
+ deactivate ();
+ }
+
+ // clear output buffers
+ // TODO only clear buffers that are not connected, but configured
+ bufs.silence (nframes, offset);
+
+ // copy back outputs
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ for (uint32_t out = 0; out < natural_output_streams().get (*t); ++out) {
+ uint32_t m = backmap.get (*t);
+ bool valid;
+ uint32_t out_idx = _out_map[pc].get (*t, out, &valid);
+ if (valid) {
+ bufs.get (*t, out_idx).read_from (inplace_bufs.get (*t, m), nframes, offset, offset);
+ }
+ backmap.set (*t, m + 1);
+ }
+ }
+ }
+
+ } else {
+ uint32_t pc = 0;
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
+ if ((*i)->connect_and_run(bufs, _in_map[pc], _out_map[pc], nframes, offset)) {
+ deactivate ();
+ }
}
}
return;
}
- ChanMapping in_map(input_streams());
- ChanMapping out_map(output_streams());
-
- if (_match.method == Split) {
- /* fix the input mapping so that we have maps for each of the plugin's inputs */
- in_map = ChanMapping (natural_input_streams ());
- }
+ ChanMapping in_map (natural_input_streams ());
+ ChanMapping out_map (natural_output_streams ());
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
(*i)->connect_and_run (_session.get_scratch_buffers ((*i)->get_info()->n_inputs, true), in_map, out_map, nframes, 0);
return;
}
- if (!find_next_event (now, end, next_event) || requires_fixed_sized_buffers()) {
+ if (!find_next_event (now, end, next_event) || _plugins.front()->requires_fixed_sized_buffers()) {
/* no events have a time within the relevant range */
PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
{
boost::shared_ptr<LadspaPlugin> lp;
+ boost::shared_ptr<LuaProc> lua;
#ifdef LV2_SUPPORT
boost::shared_ptr<LV2Plugin> lv2p;
#endif
if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
+ } else if ((lua = boost::dynamic_pointer_cast<LuaProc> (other)) != 0) {
+ return boost::shared_ptr<Plugin> (new LuaProc (*lua));
#ifdef LV2_SUPPORT
} else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
break;
}
+ // TODO make configurable
+ uint32_t pc = 0;
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
+ if (_match.method == Split) {
+ /* TODO see PluginInsert::connect_and_run, channel replication */
+ _in_map[pc] = ChanMapping (natural_input_streams ());
+ } else {
+ _in_map[pc] = ChanMapping (input_streams ());
+ }
+ _out_map[pc] = ChanMapping (output_streams());
+
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ _in_map[pc].offset_to(*t, pc * natural_input_streams().get(*t));
+ _out_map[pc].offset_to(*t, pc * natural_output_streams().get(*t));
+ }
+ }
+
+
if ( (old_match.method != _match.method && (old_match.method == Split || _match.method == Split))
|| old_in != in
|| old_out != out
PluginInsert::Match
PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanCount& out)
{
+ _strict_io_configured = false;
if (_plugins.empty()) {
return Match();
}
return Match (Impossible, 0);
}
+ if (_strict_io && in.n_audio() < out.n_audio()) {
+ DEBUG_TRACE (DEBUG::Processors, string_compose ("hiding output ports of reconfigurable %1\n", name()));
+ out.set (DataType::AUDIO, in.get (DataType::AUDIO));
+ }
+
return Match (Delegate, 1);
}
}
/* Plugin inputs match requested inputs exactly */
- if (inputs == in) {
+ if (inputs == in && (!_strict_io || outputs.n_audio() == inputs.n_audio())) {
out = outputs + midi_bypass;
return Match (ExactMatch, 1);
}
plugin inputs? Let me count the ways ...
*/
- bool can_split = true;
+ bool can_split = !_strict_io;
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
bool const can_split_type = (in.get (*t) == 1 && inputs.get (*t) > 1);
}
if (could_hide && !cannot_hide) {
- out = outputs + midi_bypass;
+ if (_strict_io /*&& inputs.get (DataType::AUDIO) == outputs.get (DataType::AUDIO)*/) {
+ _strict_io_configured = true;
+ outputs = inputs;
+ } else {
+ out = outputs + midi_bypass;
+ }
return Match (Hide, 1, hide_channels);
}
type = ARDOUR::LXVST;
} else if (prop->value() == X_("audiounit")) {
type = ARDOUR::AudioUnit;
+ } else if (prop->value() == X_("luaproc")) {
+ type = ARDOUR::Lua;
} else {
error << string_compose (_("unknown plugin type %1 in plugin insert state"),
prop->value())
return -1;
}
+ if (type == ARDOUR::Lua) {
+ XMLNode *ls = node.child (plugin->state_node_name().c_str());
+ // we need to load the script to set the name and parameters.
+ boost::shared_ptr<LuaProc> lp = boost::dynamic_pointer_cast<LuaProc>(plugin);
+ if (ls && lp) {
+ lp->set_script_from_state (*ls);
+ }
+ }
+
// The name of the PluginInsert comes from the plugin, nothing else
_name = plugin->get_info()->name;