From f40c7c45beb9a069a0aeefee5ce496603fb0ee8a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 26 Sep 2011 18:07:02 +0000 Subject: [PATCH] Somewhat experimental patch to hide plugin inputs if the preceding processor doesn't offer outputs for them. Fixes #4330. git-svn-id: svn://localhost/ardour2/branches/3.0@10126 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/plugin_insert.h | 23 ++++++-- libs/ardour/plugin_insert.cc | 88 +++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 31 deletions(-) diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index e860dbd331..0e530c5d8e 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -120,7 +120,7 @@ class PluginInsert : public Processor void collect_signal_for_analysis (framecnt_t nframes); bool splitting () const { - return _matching_method == Split; + return _match.method == Split; } PBD::Signal2 AnalysisDataGathered; @@ -134,9 +134,10 @@ class PluginInsert : public Processor Impossible, ///< we can't Delegate, ///< we are delegating to the plugin, and it can handle it NoInputs, ///< plugin has no inputs, so anything goes - ExactMatch, ///< the insert's inputs are the same as the plugin's + ExactMatch, ///< our insert's inputs are the same as the plugin's Replicate, ///< we have multiple instances of the plugin - Split, ///< we copy one of the insert's inputs to multiple plugin inputs + Split, ///< we copy one of our insert's inputs to multiple plugin inputs + Hide, ///< we `hide' some of the plugin's inputs by feeding them silence }; private: @@ -161,10 +162,20 @@ class PluginInsert : public Processor BufferSet _signal_analysis_inputs; BufferSet _signal_analysis_outputs; - std::pair private_can_support_io_configuration (ChanCount const &, ChanCount &) const; + /** Description of how we can match our plugin's IO to our own insert IO */ + struct Match { + Match () : method (Impossible), plugins (0) {} + Match (MatchingMethod m, int32_t p, ChanCount h = ChanCount ()) : method (m), plugins (p), hide (h) {} + + MatchingMethod method; ///< method to employ + int32_t plugins; ///< number of copies of the plugin that we need + ChanCount hide; ///< number of channels to hide + }; - /** matching method currently being used */ - MatchingMethod _matching_method; + Match private_can_support_io_configuration (ChanCount const &, ChanCount &) const; + + /** details of the match currently being used */ + Match _match; 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/plugin_insert.cc b/libs/ardour/plugin_insert.cc index 068606a41a..b44f1d01fc 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -69,7 +69,6 @@ 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) - , _matching_method (Impossible) { /* the first is the master */ @@ -151,7 +150,7 @@ PluginInsert::input_streams() const { ChanCount in = _plugins[0]->get_info()->n_inputs; - if (_matching_method == Split) { + if (_match.method == Split) { /* we are splitting 1 processor input to multiple plugin inputs, so we have a maximum of 1 stream of each type. @@ -163,14 +162,22 @@ PluginInsert::input_streams() const } return in; + } else if (_match.method == Hide) { + + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + in.set (*t, in.get (*t) - _match.hide.get (*t)); + } + return in; + } else if (in == ChanCount::INFINITE) { return _plugins[0]->input_streams (); - + } else { - in.set_audio (in.n_audio() * _plugins.size()); - in.set_midi (in.n_midi() * _plugins.size()); + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + in.set (*t, in.get (*t) * _plugins.size ()); + } return in; } @@ -308,21 +315,33 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of collect_signal_nframes = nframes; } - ChanMapping in_map(input_streams()); - ChanMapping out_map(output_streams()); + ChanCount const in_streams = input_streams (); + ChanCount const out_streams = output_streams (); - if (_matching_method == Split) { + ChanMapping in_map (in_streams); + ChanMapping out_map (out_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 ()); /* 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) { + for (uint32_t i = in_streams.n_audio(); i < natural_input_streams().n_audio(); ++i) { memcpy (bufs.get_audio (in_map.get (DataType::AUDIO, i)).data (offset), mono, sizeof (Sample) * nframes); } } + if (_match.method == Hide) { + /* Silence the hidden input buffers */ + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + for (uint32_t i = in_streams.get(*t); i < (in_streams.get(*t) + _match.hide.get(*t)); ++i) { + bufs.get(*t, i).silence (nframes); + } + } + } + /* Note that we've already required that plugins be able to handle in-place processing. */ @@ -412,7 +431,7 @@ PluginInsert::silence (framecnt_t nframes) ChanMapping in_map(input_streams()); ChanMapping out_map(output_streams()); - if (_matching_method == Split) { + 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 ()); } @@ -615,23 +634,23 @@ PluginInsert::plugin_factory (boost::shared_ptr other) bool PluginInsert::configure_io (ChanCount in, ChanCount out) { - MatchingMethod old_matching_method = _matching_method; + Match old_match = _match; /* set the matching method and number of plugins that we will use to meet this configuration */ - pair const r = private_can_support_io_configuration (in, out); - _matching_method = r.first; - if (set_count (r.second) == false) { + _match = private_can_support_io_configuration (in, out); + if (set_count (_match.plugins) == false) { return false; } /* a signal needs emitting if we start or stop splitting */ - if (old_matching_method != _matching_method && (old_matching_method == Split || _matching_method == Split)) { + if (old_match.method != _match.method && (old_match.method == Split || _match.method == Split)) { SplittingChanged (); /* EMIT SIGNAL */ } /* configure plugins */ - switch (_matching_method) { + switch (_match.method) { case Split: + case Hide: if (_plugins.front()->configure_io (_plugins.front()->get_info()->n_inputs, out)) { return false; } @@ -670,24 +689,24 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) bool PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) const { - return private_can_support_io_configuration (in, out).first != Impossible; + return private_can_support_io_configuration (in, out).method != Impossible; } /** A private version of can_support_io_configuration which returns the method * by which the configuration can be matched, rather than just whether or not * it can be. */ -pair +PluginInsert::Match PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCount& out) const { if (_plugins.front()->reconfigurable_io()) { /* Plugin has flexible I/O, so delegate to it */ bool const r = _plugins.front()->can_support_io_configuration (in, out); if (!r) { - return make_pair (Impossible, 0); + return Match (Impossible, 0); } - return make_pair (Delegate, 1); + return Match (Delegate, 1); } ChanCount inputs = _plugins[0]->get_info()->n_inputs; @@ -704,13 +723,13 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo if (no_inputs) { /* no inputs so we can take any input configuration since we throw it away */ out = outputs; - return make_pair (NoInputs, 1); + return Match (NoInputs, 1); } /* Plugin inputs match requested inputs exactly */ if (inputs == in) { out = outputs; - return make_pair (ExactMatch, 1); + return Match (ExactMatch, 1); } /* We may be able to run more than one copy of the plugin within this insert @@ -751,7 +770,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { out.set (*t, outputs.get(*t) * f); } - return make_pair (Replicate, f); + return Match (Replicate, f); } /* If the processor has exactly one input of a given type, and @@ -775,10 +794,29 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo if (can_split) { out = outputs; - return make_pair (Split, 1); + return Match (Split, 1); } - return make_pair (Impossible, 0); + /* If the plugin has more inputs than we want, we can `hide' some of them + by feeding them silence. + */ + + bool can_hide = false; + ChanCount hide_channels; + + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + if (inputs.get(*t) > in.get(*t)) { + hide_channels.set (*t, inputs.get(*t) - in.get(*t)); + can_hide = true; + } + } + + if (can_hide) { + out = outputs; + return Match (Hide, 1, hide_channels); + } + + return Match (Impossible, 0); } XMLNode&