From 6c3bad48f9318d5b343e33b6dbc6311b84e0e332 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 31 Jan 2011 15:28:15 +0000 Subject: [PATCH] Allow plugins with >1 input to be inserted into mono tracks; the input is passed to each plugin input equally (#3746). git-svn-id: svn://localhost/ardour2/branches/3.0@8628 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/plugin_insert.h | 3 + libs/ardour/lv2_plugin.cc | 2 +- libs/ardour/plugin_insert.cc | 94 +++++++++++++++++++++++++----- 3 files changed, 82 insertions(+), 17 deletions(-) diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index a83f75ed3e..392bedb343 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -133,6 +133,9 @@ class PluginInsert : public Processor BufferSet _signal_analysis_inputs; BufferSet _signal_analysis_outputs; + /** true if we are splitting one processor input to >1 plugin inputs */ + bool _splitting; + void automation_run (BufferSet& bufs, pframes_t nframes); void connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t offset, bool with_auto, framepos_t now = 0); diff --git a/libs/ardour/lv2_plugin.cc b/libs/ardour/lv2_plugin.cc index be44dab105..d71fd50c00 100644 --- a/libs/ardour/lv2_plugin.cc +++ b/libs/ardour/lv2_plugin.cc @@ -620,7 +620,7 @@ LV2Plugin::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t offset) { Plugin::connect_and_run (bufs, in_map, out_map, nframes, offset); - + cycles_t then = get_cycles (); uint32_t audio_in_index = 0; diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index 16c8cce47d..25f700b7ca 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -66,6 +66,7 @@ PluginInsert::PluginInsert (Session& s, boost::shared_ptr plug) : Processor (s, (plug ? plug->name() : string ("toBeRenamed"))) , _signal_analysis_collected_nframes(0) , _signal_analysis_collect_nframes_max(0) + , _splitting (false) { /* the first is the master */ @@ -147,7 +148,19 @@ PluginInsert::input_streams() const { ChanCount in = _plugins[0]->get_info()->n_inputs; - if (in == ChanCount::INFINITE) { + if (_splitting) { + + /* we are splitting 1 processor input to multiple plugin inputs, + so we have a maximum of 1 stream of each type. + */ + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + if (in.get (*t) > 1) { + in.set (*t, 1); + } + } + return in; + + } else if (in == ChanCount::INFINITE) { return _plugins[0]->input_streams (); } else { in.set_audio (in.n_audio() * _plugins.size()); @@ -275,6 +288,18 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of ChanMapping in_map(input_streams()); ChanMapping out_map(output_streams()); + if (_splitting) { + /* 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 */ + Sample const * mono = bufs.get_audio (in_map.get (DataType::AUDIO, 0)).data (offset); + for (uint32_t i = input_streams().n_audio(); i < natural_input_streams().n_audio(); ++i) { + memcpy (bufs.get_audio (in_map.get (DataType::AUDIO, i)).data() + offset, mono + offset, sizeof (Sample) * (nframes - offset)); + } + } + /* Note that we've already required that plugins be able to handle in-place processing. */ @@ -357,13 +382,20 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of void PluginInsert::silence (framecnt_t nframes) { + if (!active ()) { + return; + } + ChanMapping in_map(input_streams()); ChanMapping out_map(output_streams()); - if (active()) { - for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { - (*i)->connect_and_run (_session.get_silent_buffers ((*i)->get_info()->n_inputs), in_map, out_map, nframes, 0); - } + if (_splitting) { + /* fix the input mapping so that we have maps for each of the plugin's inputs */ + in_map = ChanMapping (natural_input_streams ()); + } + + for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + (*i)->connect_and_run (_session.get_silent_buffers ((*i)->get_info()->n_inputs), in_map, out_map, nframes, 0); } } @@ -540,15 +572,16 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) return false; } - /* if we're running replicated plugins, each plugin has - the same i/o configuration and we may need to announce how many - output streams there are. - - if we running a single plugin, we need to configure it. - */ - - if (_plugins.front()->configure_io (in, out) == false) { - return false; + if (_plugins.front()->get_info()->n_inputs <= in) { + if (_plugins.front()->configure_io (in, out) == false) { + return false; + } + } else { + /* we must be splitting a single processor input to + multiple plugin inputs + */ + _plugins.front()->configure_io (_plugins.front()->get_info()->n_inputs, out); + _splitting = true; } // we don't know the analysis window size, so we must work with the @@ -620,9 +653,33 @@ PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) out.set (*t, outputs.get(*t) * f); } return true; - } else { - return false; } + + /* If the processor has exactly one input of a given type, and + the plugin has more, we can feed the single processor input + to some or all of the plugin inputs. This is rather + special-case-y, but the 1-to-many case is by far the + simplest. How do I split thy 2 processor inputs to 3 + plugin inputs? Let me count the ways ... + */ + + bool can_split = true; + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + + bool const can_split_type = (in.get (*t) == 1 && inputs.get (*t) > 1); + bool const nothing_to_do_for_type = (in.get (*t) == 0 && inputs.get (*t) == 0); + + if (!can_split_type && !nothing_to_do_for_type) { + can_split = false; + } + } + + if (can_split) { + out = outputs; + return true; + } + + return false; } /* Number of plugin instances required to support a given channel configuration. @@ -659,6 +716,11 @@ PluginInsert::count_for_configuration (ChanCount in, ChanCount /*out*/) const return 1; } + if (inputs > in) { + /* more plugin inputs than processor inputs, so we are splitting */ + return 1; + } + // assumes in is valid, so we must be replicating if (inputs.n_total() < in.n_total() && (in.n_total() % inputs.n_total() == 0)) {