2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "libardour-config.h"
26 #include "pbd/failed_constructor.h"
27 #include "pbd/xml++.h"
28 #include "pbd/types_convert.h"
30 #include "ardour/audio_buffer.h"
31 #include "ardour/automation_list.h"
32 #include "ardour/buffer_set.h"
33 #include "ardour/debug.h"
34 #include "ardour/event_type_map.h"
35 #include "ardour/ladspa_plugin.h"
36 #include "ardour/luaproc.h"
37 #include "ardour/plugin.h"
38 #include "ardour/plugin_insert.h"
39 #include "ardour/port.h"
42 #include "ardour/lv2_plugin.h"
45 #ifdef WINDOWS_VST_SUPPORT
46 #include "ardour/windows_vst_plugin.h"
50 #include "ardour/lxvst_plugin.h"
54 #include "ardour/mac_vst_plugin.h"
57 #ifdef AUDIOUNIT_SUPPORT
58 #include "ardour/audio_unit.h"
61 #include "ardour/session.h"
62 #include "ardour/types.h"
67 using namespace ARDOUR;
70 const string PluginInsert::port_automation_node_name = "PortAutomation";
72 PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug)
73 : Processor (s, (plug ? plug->name() : string ("toBeRenamed")))
74 , _sc_playback_latency (0)
75 , _sc_capture_latency (0)
76 , _plugin_signal_latency (0)
77 , _signal_analysis_collected_nframes(0)
78 , _signal_analysis_collect_nframes_max(0)
83 , _maps_from_state (false)
84 , _latency_changed (false)
85 , _bypass_port (UINT32_MAX)
88 /* the first is the master */
92 create_automatable_parameters ();
93 const ChanCount& sc (sidechain_input_pins ());
94 if (sc.n_audio () > 0 || sc.n_midi () > 0) {
95 add_sidechain (sc.n_audio (), sc.n_midi ());
100 PluginInsert::~PluginInsert ()
102 for (CtrlOutMap::const_iterator i = _control_outputs.begin(); i != _control_outputs.end(); ++i) {
103 boost::dynamic_pointer_cast<ReadOnlyControl>(i->second)->drop_references ();
108 PluginInsert::set_strict_io (bool b)
110 bool changed = _strict_io != b;
113 PluginConfigChanged (); /* EMIT SIGNAL */
118 PluginInsert::set_count (uint32_t num)
120 bool require_state = !_plugins.empty();
122 if (require_state && num > 1 && plugin (0)->get_info ()->type == ARDOUR::AudioUnit) {
123 // we don't allow to replicate AUs
127 /* this is a bad idea.... we shouldn't do this while active.
128 * only a route holding their redirect_lock should be calling this
133 } else if (num > _plugins.size()) {
134 uint32_t diff = num - _plugins.size();
136 for (uint32_t n = 0; n < diff; ++n) {
137 boost::shared_ptr<Plugin> p = plugin_factory (_plugins[0]);
141 XMLNode& state = _plugins[0]->get_state ();
142 p->set_state (state, Stateful::loading_state_version);
149 PluginConfigChanged (); /* EMIT SIGNAL */
151 } else if (num < _plugins.size()) {
152 uint32_t diff = _plugins.size() - num;
153 for (uint32_t n= 0; n < diff; ++n) {
156 PluginConfigChanged (); /* EMIT SIGNAL */
164 PluginInsert::set_sinks (const ChanCount& c)
167 /* no signal, change will only be visible after re-config */
171 PluginInsert::set_outputs (const ChanCount& c)
173 bool changed = (_custom_out != c) && _custom_cfg;
176 PluginConfigChanged (); /* EMIT SIGNAL */
181 PluginInsert::set_custom_cfg (bool b)
183 bool changed = _custom_cfg != b;
186 PluginConfigChanged (); /* EMIT SIGNAL */
191 PluginInsert::set_preset_out (const ChanCount& c)
193 bool changed = _preset_out != c;
195 if (changed && !_custom_cfg) {
196 PluginConfigChanged (); /* EMIT SIGNAL */
202 PluginInsert::add_sidechain (uint32_t n_audio, uint32_t n_midi)
204 // caller must hold process lock
208 std::ostringstream n;
209 if (n_audio == 0 && n_midi == 0) {
210 n << "TO BE RESET FROM XML";
211 } else if (owner()) {
212 n << "SC " << owner()->name() << "/" << name() << " " << Session::next_name_id ();
216 SideChain *sc = new SideChain (_session, n.str ());
217 _sidechain = boost::shared_ptr<SideChain> (sc);
218 _sidechain->activate ();
219 for (uint32_t n = 0; n < n_audio; ++n) {
220 _sidechain->input()->add_port ("", owner(), DataType::AUDIO); // add a port, don't connect.
222 for (uint32_t n = 0; n < n_midi; ++n) {
223 _sidechain->input()->add_port ("", owner(), DataType::MIDI); // add a port, don't connect.
225 PluginConfigChanged (); /* EMIT SIGNAL */
230 PluginInsert::del_sidechain ()
236 _sc_playback_latency = 0;
237 _sc_capture_latency = 0;
238 PluginConfigChanged (); /* EMIT SIGNAL */
243 PluginInsert::update_sidechain_name ()
249 std::ostringstream n;
253 n << owner()->name() << "/";
256 n << name() << " " << Session::next_name_id ();
258 _sidechain->set_name (n.str());
262 PluginInsert::control_list_automation_state_changed (Evoral::Parameter which, AutoState s)
264 if (which.type() != PluginAutomation)
267 boost::shared_ptr<AutomationControl> c
268 = boost::dynamic_pointer_cast<AutomationControl>(control (which));
271 _plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_sample()));
276 PluginInsert::output_streams() const
278 assert (_configured);
279 return _configured_out;
283 PluginInsert::input_streams() const
285 assert (_configured);
286 return _configured_in;
290 PluginInsert::internal_streams() const
292 assert (_configured);
293 return _configured_internal;
297 PluginInsert::internal_output_streams() const
299 assert (!_plugins.empty());
301 PluginInfoPtr info = _plugins.front()->get_info();
303 if (info->reconfigurable_io()) {
304 ChanCount out = _plugins.front()->output_streams ();
305 // DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, reconfigur(able) output streams = %1\n", out));
308 ChanCount out = info->n_outputs;
309 // DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, static output streams = %1 for %2 plugins\n", out, _plugins.size()));
310 out.set_audio (out.n_audio() * _plugins.size());
311 out.set_midi (out.n_midi() * _plugins.size());
317 PluginInsert::internal_input_streams() const
319 assert (!_plugins.empty());
323 PluginInfoPtr info = _plugins.front()->get_info();
325 if (info->reconfigurable_io()) {
326 in = _plugins.front()->input_streams();
331 DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, input streams = %1, match using %2\n", in, _match.method));
333 if (_match.method == Split) {
335 /* we are splitting 1 processor input to multiple plugin inputs,
336 so we have a maximum of 1 stream of each type.
338 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
339 if (in.get (*t) > 1) {
345 } else if (_match.method == Hide) {
347 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
348 in.set (*t, in.get (*t) - _match.hide.get (*t));
354 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
355 in.set (*t, in.get (*t) * _plugins.size ());
363 PluginInsert::natural_output_streams() const
366 if (is_channelstrip ()) {
367 return ChanCount::min (_configured_out, ChanCount (DataType::AUDIO, 2));
370 return _plugins[0]->get_info()->n_outputs;
374 PluginInsert::natural_input_streams() const
377 if (is_channelstrip ()) {
378 return ChanCount::min (_configured_in, ChanCount (DataType::AUDIO, 2));
381 return _plugins[0]->get_info()->n_inputs;
385 PluginInsert::sidechain_input_pins() const
387 return _cached_sidechain_pins;
391 PluginInsert::has_no_inputs() const
393 return _plugins[0]->get_info()->n_inputs == ChanCount::ZERO;
397 PluginInsert::has_no_audio_inputs() const
399 return _plugins[0]->get_info()->n_inputs.n_audio() == 0;
403 PluginInsert::plugin_latency () const {
404 return _plugins.front()->signal_latency ();
408 PluginInsert::is_instrument() const
410 PluginInfoPtr pip = _plugins[0]->get_info();
411 return (pip->is_instrument ());
415 PluginInsert::has_output_presets (ChanCount in, ChanCount out)
417 if (!_configured && _plugins[0]->get_info ()->reconfigurable_io ()) {
418 // collect possible configurations, prefer given in/out
419 _plugins[0]->can_support_io_configuration (in, out);
422 PluginOutputConfiguration ppc (_plugins[0]->possible_output ());
424 if (ppc.size () == 0) {
427 if (!strict_io () && ppc.size () == 1) {
431 if (strict_io () && ppc.size () == 1) {
432 // "stereo" is currently preferred default for instruments
433 if (ppc.find (2) != ppc.end ()) {
438 if (ppc.size () == 1 && ppc.find (0) != ppc.end () && !_plugins[0]->get_info ()->reconfigurable_io ()) {
439 // some midi-sequencer (e.g. QMidiArp) or other midi-out plugin
440 // pretending to be an "Instrument"
444 if (!is_instrument ()) {
451 PluginInsert::create_automatable_parameters ()
453 assert (!_plugins.empty());
455 boost::shared_ptr<Plugin> plugin = _plugins.front();
456 set<Evoral::Parameter> a = _plugins.front()->automatable ();
458 const uint32_t limit_automatables = Config->get_limit_n_automatables ();
460 for (uint32_t i = 0; i < plugin->parameter_count(); ++i) {
461 if (!plugin->parameter_is_control (i)) {
465 ParameterDescriptor desc;
466 plugin->get_parameter_descriptor(i, desc);
468 if (!plugin->parameter_is_input (i)) {
469 _control_outputs[i] = boost::shared_ptr<ReadOnlyControl> (new ReadOnlyControl (plugin, desc, i));
472 Evoral::Parameter param (PluginAutomation, 0, i);
474 const bool automatable = a.find(param) != a.end();
476 boost::shared_ptr<AutomationList> list(new AutomationList(param, desc));
477 boost::shared_ptr<AutomationControl> c (new PluginControl(this, param, desc, list));
478 if (!automatable || (limit_automatables > 0 && i > limit_automatables)) {
479 c->set_flags (Controllable::Flag ((int)c->flags() | Controllable::NotAutomatable));
482 plugin->set_automation_control (i, c);
486 const Plugin::PropertyDescriptors& pdl (plugin->get_supported_properties ());
487 for (Plugin::PropertyDescriptors::const_iterator p = pdl.begin(); p != pdl.end(); ++p) {
488 Evoral::Parameter param (PluginPropertyAutomation, 0, p->first);
489 const ParameterDescriptor& desc = plugin->get_property_descriptor(param.id());
490 if (desc.datatype != Variant::NOTHING) {
491 boost::shared_ptr<AutomationList> list;
492 if (Variant::type_is_numeric(desc.datatype)) {
493 list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
495 boost::shared_ptr<AutomationControl> c (new PluginPropertyControl(this, param, desc, list));
496 if (!Variant::type_is_numeric(desc.datatype)) {
497 c->set_flags (Controllable::Flag ((int)c->flags() | Controllable::NotAutomatable));
503 _bypass_port = plugin->designated_bypass_port ();
505 /* special case VST effSetBypass */
506 if (_bypass_port == UINT32_MAX -1) {
507 // emulate VST Bypass
508 Evoral::Parameter param (PluginAutomation, 0, _bypass_port);
509 ParameterDescriptor desc;
510 desc.label = _("Plugin Enable");
515 boost::shared_ptr<AutomationList> list(new AutomationList(param, desc));
516 boost::shared_ptr<AutomationControl> c (new PluginControl(this, param, desc, list));
520 if (_bypass_port != UINT32_MAX) {
521 boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, _bypass_port));
522 if (0 == (ac->flags () & Controllable::NotAutomatable)) {
523 ac->alist()->automation_state_changed.connect_same_thread (*this, boost::bind (&PluginInsert::bypassable_changed, this));
524 ac->Changed.connect_same_thread (*this, boost::bind (&PluginInsert::enable_changed, this));
527 plugin->PresetPortSetValue.connect_same_thread (*this, boost::bind (&PluginInsert::preset_load_set_value, this, _1, _2));
530 /** Called when something outside of this host has modified a plugin
531 * parameter. Responsible for propagating the change to two places:
533 * 1) anything listening to the Control itself
534 * 2) any replicated plugins that make up this PluginInsert.
536 * The PluginInsert is connected to the ParameterChangedExternally signal for
537 * the first (primary) plugin, and here broadcasts that change to any others.
539 * XXX We should probably drop this whole replication idea (Paul, October 2015)
540 * since it isn't used by sensible plugin APIs (AU, LV2).
543 PluginInsert::parameter_changed_externally (uint32_t which, float val)
545 boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, which));
547 /* First propagation: alter the underlying value of the control,
548 * without telling the plugin(s) that own/use it to set it.
555 boost::shared_ptr<PluginControl> pc = boost::dynamic_pointer_cast<PluginControl> (ac);
558 pc->catch_up_with_external_value (val);
561 /* Second propagation: tell all plugins except the first to
562 update the value of this parameter. For sane plugin APIs,
563 there are no other plugins, so this is a no-op in those
567 Plugins::iterator i = _plugins.begin();
569 /* don't set the first plugin, just all the slaves */
571 if (i != _plugins.end()) {
573 for (; i != _plugins.end(); ++i) {
574 (*i)->set_parameter (which, val);
580 PluginInsert::set_block_size (pframes_t nframes)
583 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
584 if ((*i)->set_block_size (nframes) != 0) {
592 PluginInsert::automation_run (samplepos_t start, pframes_t nframes, bool only_active)
594 // XXX does not work when rolling backwards
595 if (_loop_location && nframes > 0) {
596 const samplepos_t loop_start = _loop_location->start ();
597 const samplepos_t loop_end = _loop_location->end ();
598 const samplecnt_t looplen = loop_end - loop_start;
600 samplecnt_t remain = nframes;
601 samplepos_t start_pos = start;
604 if (start_pos >= loop_end) {
605 sampleoffset_t start_off = (start_pos - loop_start) % looplen;
606 start_pos = loop_start + start_off;
608 samplecnt_t move = std::min ((samplecnt_t)nframes, loop_end - start_pos);
610 Automatable::automation_run (start_pos, move, only_active);
616 Automatable::automation_run (start, nframes, only_active);
620 PluginInsert::find_next_event (double now, double end, Evoral::ControlEvent& next_event, bool only_active) const
622 bool rv = Automatable::find_next_event (now, end, next_event, only_active);
624 if (_loop_location && now < end) {
626 end = ceil (next_event.when);
628 const samplepos_t loop_end = _loop_location->end ();
629 assert (now < loop_end); // due to map_loop_range ()
630 if (end > loop_end) {
631 next_event.when = loop_end;
639 PluginInsert::activate ()
641 _timing_stats.reset ();
642 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
646 Processor::activate ();
647 /* when setting state e.g ProcessorBox::paste_processor_state ()
648 * the plugin is not yet owned by a route.
649 * but no matter. Route::add_processors() will call activate () again
654 if (_plugin_signal_latency != signal_latency ()) {
655 _plugin_signal_latency = signal_latency ();
661 PluginInsert::deactivate ()
664 if (is_nonbypassable ()) {
668 _timing_stats.reset ();
669 Processor::deactivate ();
671 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
674 if (_plugin_signal_latency != signal_latency ()) {
675 _plugin_signal_latency = signal_latency ();
681 PluginInsert::flush ()
683 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
689 PluginInsert::enable (bool yn)
691 if (_bypass_port == UINT32_MAX) {
698 if (!_pending_active) {
701 boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, _bypass_port));
702 const double val = yn ? 1.0 : 0.0;
703 ac->set_value (val, Controllable::NoGroup);
705 #ifdef ALLOW_VST_BYPASS_TO_FAIL // yet unused, see also vst_plugin.cc
706 /* special case VST.. bypass may fail */
707 if (_bypass_port == UINT32_MAX - 1) {
708 /* check if bypass worked */
709 if (ac->get_value () != val) {
710 warning << _("PluginInsert: VST Bypass failed, falling back to host bypass.") << endmsg;
711 // set plugin to enabled (not-byassed)
712 ac->set_value (1.0, Controllable::NoGroup);
713 // ..and use host-provided hard-bypass
728 PluginInsert::enabled () const
730 if (_bypass_port == UINT32_MAX) {
731 return Processor::enabled ();
733 boost::shared_ptr<const AutomationControl> ac = boost::const_pointer_cast<AutomationControl> (automation_control (Evoral::Parameter (PluginAutomation, 0, _bypass_port)));
734 return (ac->get_value () > 0 && _pending_active);
739 PluginInsert::bypassable () const
741 if (_bypass_port == UINT32_MAX) {
744 boost::shared_ptr<const AutomationControl> ac = boost::const_pointer_cast<AutomationControl> (automation_control (Evoral::Parameter (PluginAutomation, 0, _bypass_port)));
746 return !ac->automation_playback ();
751 PluginInsert::enable_changed ()
757 PluginInsert::bypassable_changed ()
759 BypassableChanged ();
763 PluginInsert::write_immediate_event (size_t size, const uint8_t* buf)
766 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
767 if (!(*i)->write_immediate_event (size, buf)) {
775 PluginInsert::preset_load_set_value (uint32_t p, float v)
777 boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter(PluginAutomation, 0, p));
782 if (ac->automation_state() & Play) {
787 ac->set_value (v, Controllable::NoGroup);
792 PluginInsert::inplace_silence_unconnected (BufferSet& bufs, const PinMappings& out_map, samplecnt_t nframes, samplecnt_t offset) const
794 // TODO optimize: store "unconnected" in a fixed set.
795 // it only changes on reconfiguration.
796 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
797 for (uint32_t out = 0; out < bufs.count().get (*t); ++out) {
799 if (*t == DataType::MIDI && out == 0 && has_midi_bypass ()) {
800 mapped = true; // in-place Midi bypass
802 for (uint32_t pc = 0; pc < get_count() && !mapped; ++pc) {
803 PinMappings::const_iterator i = out_map.find (pc);
804 if (i == out_map.end ()) {
807 const ChanMapping& outmap (i->second);
808 for (uint32_t o = 0; o < natural_output_streams().get (*t); ++o) {
810 uint32_t idx = outmap.get (*t, o, &valid);
811 if (valid && idx == out) {
818 bufs.get (*t, out).silence (nframes, offset);
825 PluginInsert::connect_and_run (BufferSet& bufs, samplepos_t start, samplepos_t end, double speed, pframes_t nframes, samplecnt_t offset, bool with_auto)
827 if (_mapping_changed) { // ToDo use a counter, increment until match
828 _no_inplace = check_inplace ();
829 _mapping_changed = false;
831 // TODO: atomically copy maps & _no_inplace
832 PinMappings in_map (_in_map); // TODO Split case below overrides, use const& in_map
833 PinMappings const& out_map (_out_map);
834 ChanMapping const& thru_map (_thru_map);
836 if (_latency_changed) {
837 /* delaylines are configured with the max possible latency (as reported by the plugin)
838 * so this won't allocate memory (unless the plugin lied about its max latency)
839 * It may still 'click' though, since the fixed delaylines are not de-clicked.
840 * Then again plugin-latency changes are not click-free to begin with.
842 * This is also worst case, there is currently no concept of per-stream latency.
844 * e.g. Two identical latent plugins:
845 * 1st plugin: process left (latent), bypass right.
846 * 2nd plugin: bypass left, process right (latent).
847 * -> currently this yields 2 times latency of the plugin,
849 _latency_changed = false;
850 _delaybuffers.set (ChanCount::max(bufs.count(), _configured_out), plugin_latency ());
853 if (_match.method == Split && !_no_inplace) {
854 // TODO: also use this optimization if one source-buffer
855 // feeds _all_ *connected* inputs.
856 // currently this is *first* buffer to all only --
857 // see PluginInsert::check_inplace
858 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
859 if (_configured_internal.get (*t) == 0) {
863 uint32_t first_idx = in_map.p(0).get (*t, 0, &valid);
864 assert (valid && first_idx == 0); // check_inplace ensures this
865 /* copy the first stream's buffer contents to the others */
866 for (uint32_t i = 1; i < natural_input_streams ().get (*t); ++i) {
867 uint32_t idx = in_map.p(0).get (*t, i, &valid);
870 bufs.get (*t, i).read_from (bufs.get (*t, first_idx), nframes, offset, offset);
874 /* the copy operation produces a linear monotonic input map */
875 in_map[0] = ChanMapping (natural_input_streams ());
878 bufs.set_count(ChanCount::max(bufs.count(), _configured_internal));
879 bufs.set_count(ChanCount::max(bufs.count(), _configured_out));
886 for (Controls::const_iterator li = controls().begin(); li != controls().end(); ++li, ++n) {
888 /* boost::dynamic_pointer_cast<> has significant overhead, since we know that
889 * all controls are AutomationControl and their lists - if any - are AutomationList,
890 * we can use static_cast<>. This yields a speedup of 2.8/4.6 over to the
891 * previous code (measuerd with VeeSeeVSTRack 10k parameters, optimized build) */
892 AutomationControl& c = static_cast<AutomationControl&> (*(li->second));
893 boost::shared_ptr<const Evoral::ControlList> clist (c.list());
894 if (clist && (static_cast<AutomationList const&> (*clist)).automation_playback ()) {
896 const float val = c.list()->rt_safe_eval (start, valid);
898 c.set_value_unchecked(val);
903 boost::shared_ptr<ControlList> cl = _automated_controls.reader ();
904 for (ControlList::const_iterator ci = cl->begin(); ci != cl->end(); ++ci) {
905 AutomationControl& c = *(ci->get());
906 boost::shared_ptr<const Evoral::ControlList> clist (c.list());
907 /* we still need to check for Touch and Latch */
908 if (clist && (static_cast<AutomationList const&> (*clist)).automation_playback ()) {
910 const float val = c.list()->rt_safe_eval (start, valid);
912 c.set_value_unchecked(val);
919 /* Calculate if, and how many samples we need to collect for analysis */
920 samplecnt_t collect_signal_nframes = (_signal_analysis_collect_nframes_max -
921 _signal_analysis_collected_nframes);
922 if (nframes < collect_signal_nframes) { // we might not get all samples now
923 collect_signal_nframes = nframes;
926 if (collect_signal_nframes > 0) {
928 //std::cerr << "collect input, bufs " << bufs.count().n_audio() << " count, " << bufs.available().n_audio() << " available" << std::endl;
929 //std::cerr << " streams " << internal_input_streams().n_audio() << std::endl;
930 //std::cerr << "filling buffer with " << collect_signal_nframes << " samples at " << _signal_analysis_collected_nframes << std::endl;
932 _signal_analysis_inputs.set_count (ChanCount (DataType::AUDIO, input_streams().n_audio()));
934 for (uint32_t i = 0; i < input_streams().n_audio(); ++i) {
935 _signal_analysis_inputs.get_audio(i).read_from (
937 collect_signal_nframes,
938 _signal_analysis_collected_nframes); // offset is for target buffer
943 if (is_channelstrip ()) {
944 if (_configured_in.n_audio() > 0) {
945 ChanMapping mb_in_map (ChanCount::min (_configured_in, ChanCount (DataType::AUDIO, 2)));
946 ChanMapping mb_out_map (ChanCount::min (_configured_out, ChanCount (DataType::AUDIO, 2)));
948 _plugins.front()->connect_and_run (bufs, start, end, speed, mb_in_map, mb_out_map, nframes, offset);
950 for (uint32_t out = _configured_in.n_audio (); out < bufs.count().get (DataType::AUDIO); ++out) {
951 bufs.get (DataType::AUDIO, out).silence (nframes, offset);
957 // TODO optimize -- build maps once.
959 BufferSet& inplace_bufs = _session.get_noinplace_buffers();
960 ARDOUR::ChanMapping used_outputs;
962 assert (inplace_bufs.count () >= natural_input_streams () + _configured_out);
964 /* build used-output map */
965 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
966 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
967 for (uint32_t out = 0; out < natural_output_streams().get (*t); ++out) {
969 uint32_t out_idx = out_map.p(pc).get (*t, out, &valid);
971 used_outputs.set (*t, out_idx, 1); // mark as used
976 /* copy thru data to outputs before processing in-place */
977 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
978 for (uint32_t out = 0; out < bufs.count().get (*t); ++out) {
980 uint32_t in_idx = thru_map.get (*t, out, &valid);
981 uint32_t m = out + natural_input_streams ().get (*t);
983 _delaybuffers.delay (*t, out, inplace_bufs.get (*t, m), bufs.get (*t, in_idx), nframes, offset, offset);
984 used_outputs.set (*t, out, 1); // mark as used
986 used_outputs.get (*t, out, &valid);
988 /* the plugin is expected to write here, but may not :(
989 * (e.g. drumgizmo w/o kit loaded)
991 inplace_bufs.get (*t, m).silence (nframes);
998 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
1000 ARDOUR::ChanMapping i_in_map (natural_input_streams());
1001 ARDOUR::ChanMapping i_out_map (out_map.p(pc));
1002 ARDOUR::ChanCount mapped;
1004 /* map inputs sequentially */
1005 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1006 for (uint32_t in = 0; in < natural_input_streams().get (*t); ++in) {
1008 uint32_t in_idx = in_map.p(pc).get (*t, in, &valid);
1009 uint32_t m = mapped.get (*t);
1011 inplace_bufs.get (*t, m).read_from (bufs.get (*t, in_idx), nframes, offset, offset);
1013 inplace_bufs.get (*t, m).silence (nframes, offset);
1015 mapped.set (*t, m + 1);
1019 /* outputs are mapped to inplace_bufs after the inputs */
1020 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1021 i_out_map.offset_to (*t, natural_input_streams ().get (*t));
1024 if ((*i)->connect_and_run (inplace_bufs, start, end, speed, i_in_map, i_out_map, nframes, offset)) {
1029 /* all instances have completed, now copy data that was written
1030 * and zero unconnected buffers */
1031 ARDOUR::ChanMapping nonzero_out (used_outputs);
1032 if (has_midi_bypass ()) {
1033 nonzero_out.set (DataType::MIDI, 0, 1); // Midi bypass.
1035 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1036 for (uint32_t out = 0; out < bufs.count().get (*t); ++out) {
1038 used_outputs.get (*t, out, &valid);
1040 nonzero_out.get (*t, out, &valid);
1042 bufs.get (*t, out).silence (nframes, offset);
1045 uint32_t m = out + natural_input_streams ().get (*t);
1046 bufs.get (*t, out).read_from (inplace_bufs.get (*t, m), nframes, offset, offset);
1051 /* in-place processing */
1053 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
1054 if ((*i)->connect_and_run(bufs, start, end, speed, in_map.p(pc), out_map.p(pc), nframes, offset)) {
1058 // now silence unconnected outputs
1059 inplace_silence_unconnected (bufs, _out_map, nframes, offset);
1062 if (collect_signal_nframes > 0) {
1064 //std::cerr << " output, bufs " << bufs.count().n_audio() << " count, " << bufs.available().n_audio() << " available" << std::endl;
1065 //std::cerr << " streams " << internal_output_streams().n_audio() << std::endl;
1067 _signal_analysis_outputs.set_count (ChanCount (DataType::AUDIO, output_streams().n_audio()));
1069 for (uint32_t i = 0; i < output_streams().n_audio(); ++i) {
1070 _signal_analysis_outputs.get_audio(i).read_from(
1072 collect_signal_nframes,
1073 _signal_analysis_collected_nframes); // offset is for target buffer
1076 _signal_analysis_collected_nframes += collect_signal_nframes;
1077 assert(_signal_analysis_collected_nframes <= _signal_analysis_collect_nframes_max);
1079 if (_signal_analysis_collected_nframes == _signal_analysis_collect_nframes_max) {
1080 _signal_analysis_collect_nframes_max = 0;
1081 _signal_analysis_collected_nframes = 0;
1083 AnalysisDataGathered(&_signal_analysis_inputs,
1084 &_signal_analysis_outputs);
1088 if (_plugin_signal_latency != signal_latency ()) {
1089 _plugin_signal_latency = signal_latency ();
1095 PluginInsert::bypass (BufferSet& bufs, pframes_t nframes)
1097 /* bypass the plugin(s) not the whole processor.
1098 * -> use mappings just like connect_and_run
1100 if (_mapping_changed) {
1101 _no_inplace = check_inplace ();
1102 _mapping_changed = false;
1104 // TODO: atomically copy maps & _no_inplace
1105 ChanMapping const& in_map (no_sc_input_map ());
1106 ChanMapping const& out_map (output_map ());
1108 bufs.set_count(ChanCount::max(bufs.count(), _configured_internal));
1109 bufs.set_count(ChanCount::max(bufs.count(), _configured_out));
1112 ChanMapping thru_map (_thru_map);
1114 BufferSet& inplace_bufs = _session.get_noinplace_buffers();
1116 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1117 for (uint32_t in = 0; in < _configured_internal.get (*t); ++in) {
1118 inplace_bufs.get (*t, in).read_from (bufs.get (*t, in), nframes, 0, 0);
1121 ARDOUR::ChanMapping used_outputs;
1123 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1124 for (uint32_t out = 0; out < _configured_out.get (*t); ++out) {
1126 uint32_t in_idx = thru_map.get (*t, out, &valid);
1128 bufs.get (*t, out).read_from (inplace_bufs.get (*t, in_idx), nframes, 0, 0);
1129 used_outputs.set (*t, out, 1); // mark as used
1133 // plugin no-op: assume every plugin has an internal identity map
1134 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1135 for (uint32_t out = 0; out < _configured_out.get (*t); ++out) {
1137 uint32_t src_idx = out_map.get_src (*t, out, &valid);
1141 uint32_t in_idx = in_map.get (*t, src_idx, &valid);
1145 bufs.get (*t, out).read_from (inplace_bufs.get (*t, in_idx), nframes, 0, 0);
1146 used_outputs.set (*t, out, 1); // mark as used
1149 // now silence all unused outputs
1150 if (has_midi_bypass ()) {
1151 used_outputs.set (DataType::MIDI, 0, 1); // Midi bypass.
1153 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1154 for (uint32_t out = 0; out < _configured_out.get (*t); ++out) {
1156 used_outputs.get (*t, out, &valid);
1158 bufs.get (*t, out).silence (nframes, 0);
1163 if (_match.method == Split) {
1164 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1165 if (_configured_internal.get (*t) == 0) {
1168 // copy/feeds _all_ *connected* inputs, copy the first buffer
1170 uint32_t first_idx = in_map.get (*t, 0, &valid);
1171 assert (valid && first_idx == 0); // check_inplace ensures this
1172 for (uint32_t i = 1; i < natural_input_streams ().get (*t); ++i) {
1173 uint32_t idx = in_map.get (*t, i, &valid);
1176 bufs.get (*t, i).read_from (bufs.get (*t, first_idx), nframes, 0, 0);
1182 // apply output map and/or monotonic but not identity i/o mappings
1183 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1184 for (uint32_t out = 0; out < _configured_out.get (*t); ++out) {
1186 uint32_t src_idx = out_map.get_src (*t, out, &valid);
1188 bufs.get (*t, out).silence (nframes, 0);
1191 uint32_t in_idx = in_map.get (*t, src_idx, &valid);
1193 bufs.get (*t, out).silence (nframes, 0);
1196 if (in_idx != src_idx) {
1197 bufs.get (*t, out).read_from (bufs.get (*t, in_idx), nframes, 0, 0);
1205 PluginInsert::silence (samplecnt_t nframes, samplepos_t start_sample)
1207 automation_run (start_sample, nframes, true); // evaluate automation only
1210 // XXX delaybuffers need to be offset by nframes
1214 _delaybuffers.flush ();
1216 const ChanMapping in_map (natural_input_streams ());
1217 const ChanMapping out_map (natural_output_streams ());
1218 ChanCount maxbuf = ChanCount::max (natural_input_streams (), natural_output_streams());
1220 if (is_channelstrip ()) {
1221 if (_configured_in.n_audio() > 0) {
1222 _plugins.front()->connect_and_run (_session.get_scratch_buffers (maxbuf, true), start_sample, start_sample + nframes, 1.0, in_map, out_map, nframes, 0);
1226 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
1227 (*i)->connect_and_run (_session.get_scratch_buffers (maxbuf, true), start_sample, start_sample + nframes, 1.0, in_map, out_map, nframes, 0);
1232 PluginInsert::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, double speed, pframes_t nframes, bool)
1235 // collect sidechain input for complete cycle (!)
1236 // TODO we need delaylines here for latency compensation
1237 _sidechain->run (bufs, start_sample, end_sample, speed, nframes, true);
1240 if (g_atomic_int_compare_and_exchange (&_stat_reset, 1, 0)) {
1241 _timing_stats.reset ();
1244 if (_pending_active) {
1245 #if defined MIXBUS && defined NDEBUG
1246 if (!is_channelstrip ()) {
1247 _timing_stats.start ();
1250 _timing_stats.start ();
1252 /* run as normal if we are active or moving from inactive to active */
1254 if (_session.transport_rolling() || _session.bounce_processing()) {
1255 automate_and_run (bufs, start_sample, end_sample, speed, nframes);
1257 Glib::Threads::Mutex::Lock lm (control_lock(), Glib::Threads::TRY_LOCK);
1258 connect_and_run (bufs, start_sample, end_sample, speed, nframes, 0, lm.locked());
1260 #if defined MIXBUS && defined NDEBUG
1261 if (!is_channelstrip ()) {
1262 _timing_stats.update ();
1265 _timing_stats.update ();
1269 _timing_stats.reset ();
1270 // XXX should call ::silence() to run plugin(s) for consistent load.
1271 // We'll need to change this anyway when bypass can be automated
1272 bypass (bufs, nframes);
1273 automation_run (start_sample, nframes, true); // evaluate automation only
1274 _delaybuffers.flush ();
1277 _active = _pending_active;
1279 /* we have no idea whether the plugin generated silence or not, so mark
1280 * all buffers appropriately.
1285 PluginInsert::automate_and_run (BufferSet& bufs, samplepos_t start, samplepos_t end, double speed, pframes_t nframes)
1287 Evoral::ControlEvent next_event (0, 0.0f);
1288 samplecnt_t offset = 0;
1290 Glib::Threads::Mutex::Lock lm (control_lock(), Glib::Threads::TRY_LOCK);
1293 connect_and_run (bufs, start, end, speed, nframes, offset, false);
1297 /* map start back into loop-range, adjust end */
1298 map_loop_range (start, end);
1300 if (!find_next_event (start, end, next_event) || _plugins.front()->requires_fixed_sized_buffers()) {
1302 /* no events have a time within the relevant range */
1304 connect_and_run (bufs, start, end, speed, nframes, offset, true);
1310 samplecnt_t cnt = min (((samplecnt_t) ceil (next_event.when) - start), (samplecnt_t) nframes);
1312 connect_and_run (bufs, start, start + cnt, speed, cnt, offset, true); // XXX (start + cnt) * speed
1318 map_loop_range (start, end);
1320 if (!find_next_event (start, end, next_event)) {
1325 /* cleanup anything that is left to do */
1328 connect_and_run (bufs, start, start + nframes, speed, nframes, offset, true);
1333 PluginInsert::default_parameter_value (const Evoral::Parameter& param)
1335 if (param.type() != PluginAutomation)
1338 if (_plugins.empty()) {
1339 fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
1341 abort(); /*NOTREACHED*/
1344 return _plugins[0]->default_value (param.id());
1349 PluginInsert::can_reset_all_parameters ()
1352 uint32_t params = 0;
1353 for (uint32_t par = 0; par < _plugins[0]->parameter_count(); ++par) {
1355 const uint32_t cid = _plugins[0]->nth_parameter (par, ok);
1357 if (!ok || !_plugins[0]->parameter_is_input(cid)) {
1361 boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter(PluginAutomation, 0, cid));
1367 if (ac->automation_state() & Play) {
1372 return all && (params > 0);
1376 PluginInsert::reset_parameters_to_default ()
1380 for (uint32_t par = 0; par < _plugins[0]->parameter_count(); ++par) {
1382 const uint32_t cid = _plugins[0]->nth_parameter (par, ok);
1384 if (!ok || !_plugins[0]->parameter_is_input(cid)) {
1388 const float dflt = _plugins[0]->default_value (cid);
1389 const float curr = _plugins[0]->get_parameter (cid);
1395 boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter(PluginAutomation, 0, cid));
1400 if (ac->automation_state() & Play) {
1405 ac->set_value (dflt, Controllable::NoGroup);
1410 boost::shared_ptr<Plugin>
1411 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
1413 boost::shared_ptr<LadspaPlugin> lp;
1414 boost::shared_ptr<LuaProc> lua;
1416 boost::shared_ptr<LV2Plugin> lv2p;
1418 #ifdef WINDOWS_VST_SUPPORT
1419 boost::shared_ptr<WindowsVSTPlugin> vp;
1421 #ifdef LXVST_SUPPORT
1422 boost::shared_ptr<LXVSTPlugin> lxvp;
1424 #ifdef MACVST_SUPPORT
1425 boost::shared_ptr<MacVSTPlugin> mvp;
1427 #ifdef AUDIOUNIT_SUPPORT
1428 boost::shared_ptr<AUPlugin> ap;
1431 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
1432 return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
1433 } else if ((lua = boost::dynamic_pointer_cast<LuaProc> (other)) != 0) {
1434 return boost::shared_ptr<Plugin> (new LuaProc (*lua));
1436 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
1437 return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
1439 #ifdef WINDOWS_VST_SUPPORT
1440 } else if ((vp = boost::dynamic_pointer_cast<WindowsVSTPlugin> (other)) != 0) {
1441 return boost::shared_ptr<Plugin> (new WindowsVSTPlugin (*vp));
1443 #ifdef LXVST_SUPPORT
1444 } else if ((lxvp = boost::dynamic_pointer_cast<LXVSTPlugin> (other)) != 0) {
1445 return boost::shared_ptr<Plugin> (new LXVSTPlugin (*lxvp));
1447 #ifdef MACVST_SUPPORT
1448 } else if ((mvp = boost::dynamic_pointer_cast<MacVSTPlugin> (other)) != 0) {
1449 return boost::shared_ptr<Plugin> (new MacVSTPlugin (*mvp));
1451 #ifdef AUDIOUNIT_SUPPORT
1452 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
1453 return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
1457 fatal << string_compose (_("programming error: %1"),
1458 X_("unknown plugin type in PluginInsert::plugin_factory"))
1460 abort(); /*NOTREACHED*/
1461 return boost::shared_ptr<Plugin> ((Plugin*) 0);
1465 PluginInsert::set_input_map (uint32_t num, ChanMapping m) {
1466 if (num < _in_map.size()) {
1467 bool changed = _in_map[num] != m;
1469 changed |= sanitize_maps ();
1471 PluginMapChanged (); /* EMIT SIGNAL */
1472 _mapping_changed = true;
1473 _session.set_dirty();
1479 PluginInsert::set_output_map (uint32_t num, ChanMapping m) {
1480 if (num < _out_map.size()) {
1481 bool changed = _out_map[num] != m;
1483 changed |= sanitize_maps ();
1485 PluginMapChanged (); /* EMIT SIGNAL */
1486 _mapping_changed = true;
1487 _session.set_dirty();
1493 PluginInsert::set_thru_map (ChanMapping m) {
1494 bool changed = _thru_map != m;
1496 changed |= sanitize_maps ();
1498 PluginMapChanged (); /* EMIT SIGNAL */
1499 _mapping_changed = true;
1500 _session.set_dirty();
1505 PluginInsert::pre_seed (const ChanCount& in, const ChanCount& out,
1506 const ChanMapping& im, const ChanMapping& om, const ChanMapping& tm)
1508 if (_configured) { return false; }
1509 _configured_in = in;
1510 _configured_out = out;
1514 _maps_from_state = in.n_total () > 0 && out.n_total () > 0;
1519 PluginInsert::input_map () const
1523 for (PinMappings::const_iterator i = _in_map.begin (); i != _in_map.end (); ++i, ++pc) {
1524 ChanMapping m (i->second);
1525 const ChanMapping::Mappings& mp ((*i).second.mappings());
1526 for (ChanMapping::Mappings::const_iterator tm = mp.begin(); tm != mp.end(); ++tm) {
1527 for (ChanMapping::TypeMapping::const_iterator i = tm->second.begin(); i != tm->second.end(); ++i) {
1528 rv.set (tm->first, i->first + pc * natural_input_streams().get(tm->first), i->second);
1537 PluginInsert::no_sc_input_map () const
1541 for (PinMappings::const_iterator i = _in_map.begin (); i != _in_map.end (); ++i, ++pc) {
1542 ChanMapping m (i->second);
1543 const ChanMapping::Mappings& mp ((*i).second.mappings());
1544 for (ChanMapping::Mappings::const_iterator tm = mp.begin(); tm != mp.end(); ++tm) {
1545 uint32_t ins = natural_input_streams().get(tm->first) - _cached_sidechain_pins.get(tm->first);
1546 for (ChanMapping::TypeMapping::const_iterator i = tm->second.begin(); i != tm->second.end(); ++i) {
1547 if (i->first < ins) {
1548 rv.set (tm->first, i->first + pc * ins, i->second);
1557 PluginInsert::output_map () const
1561 for (PinMappings::const_iterator i = _out_map.begin (); i != _out_map.end (); ++i, ++pc) {
1562 ChanMapping m (i->second);
1563 const ChanMapping::Mappings& mp ((*i).second.mappings());
1564 for (ChanMapping::Mappings::const_iterator tm = mp.begin(); tm != mp.end(); ++tm) {
1565 for (ChanMapping::TypeMapping::const_iterator i = tm->second.begin(); i != tm->second.end(); ++i) {
1566 rv.set (tm->first, i->first + pc * natural_output_streams().get(tm->first), i->second);
1570 if (has_midi_bypass ()) {
1571 rv.set (DataType::MIDI, 0, 0);
1578 PluginInsert::has_midi_bypass () const
1580 if (_configured_in.n_midi () == 1 && _configured_out.n_midi () == 1
1581 && natural_output_streams ().n_midi () == 0) {
1588 PluginInsert::has_midi_thru () const
1590 if (_configured_in.n_midi () == 1 && _configured_out.n_midi () == 1
1591 && natural_input_streams ().n_midi () == 0 && natural_output_streams ().n_midi () == 0) {
1599 PluginInsert::is_channelstrip () const {
1600 return _plugins.front()->is_channelstrip();
1603 PluginInsert::is_nonbypassable () const {
1604 return _plugins.front()->is_nonbypassable ();
1609 PluginInsert::check_inplace ()
1611 bool inplace_ok = !_plugins.front()->inplace_broken ();
1613 if (_thru_map.n_total () > 0) {
1614 // TODO once midi-bypass is part of the mapping, ignore it
1618 if (_match.method == Split && inplace_ok) {
1619 assert (get_count() == 1);
1620 assert (_in_map.size () == 1);
1621 if (!_out_map[0].is_monotonic ()) {
1624 if (_configured_internal != _configured_in) {
1625 /* no sidechain -- TODO we could allow this with
1626 * some more logic in PluginInsert::connect_and_run().
1628 * PluginInsert::reset_map() already maps it.
1633 for (DataType::iterator t = DataType::begin(); t != DataType::end() && inplace_ok; ++t) {
1634 if (_configured_internal.get (*t) == 0) {
1638 uint32_t first_idx = _in_map[0].get (*t, 0, &valid);
1639 if (!valid || first_idx != 0) {
1640 // so far only allow to copy the *first* stream's buffer to others
1643 for (uint32_t i = 1; i < natural_input_streams ().get (*t); ++i) {
1644 uint32_t idx = _in_map[0].get (*t, i, &valid);
1645 if (valid && idx != first_idx) {
1654 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: In Place Split Map\n", name()));
1659 for (uint32_t pc = 0; pc < get_count() && inplace_ok ; ++pc) {
1660 if (!_in_map[pc].is_monotonic ()) {
1663 if (!_out_map[pc].is_monotonic ()) {
1669 /* check if every output is fed by the corresponding input
1671 * this prevents in-port 1 -> sink-pin 2 || source-pin 1 -> out port 1, source-pin 2 -> out port 2
1672 * (with in-place, source-pin 1 -> out port 1 overwrites in-port 1)
1674 * but allows in-port 1 -> sink-pin 2 || source-pin 2 -> out port 1
1676 ChanMapping const& in_map (input_map ());
1677 const ChanMapping::Mappings out_m (output_map ().mappings ());
1678 for (ChanMapping::Mappings::const_iterator t = out_m.begin (); t != out_m.end () && inplace_ok; ++t) {
1679 for (ChanMapping::TypeMapping::const_iterator c = (*t).second.begin (); c != (*t).second.end () ; ++c) {
1680 /* src-pin: c->first, out-port: c->second */
1682 uint32_t in_port = in_map.get (t->first, c->first, &valid);
1683 if (valid && in_port != c->second) {
1691 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: %2\n", name(), inplace_ok ? "In-Place" : "No Inplace Processing"));
1692 return !inplace_ok; // no-inplace
1696 PluginInsert::sanitize_maps ()
1698 bool changed = false;
1699 /* strip dead wood */
1700 PinMappings new_ins;
1701 PinMappings new_outs;
1702 ChanMapping new_thru;
1704 for (uint32_t pc = 0; pc < get_count(); ++pc) {
1706 ChanMapping new_out;
1707 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1708 for (uint32_t i = 0; i < natural_input_streams().get (*t); ++i) {
1710 uint32_t idx = _in_map[pc].get (*t, i, &valid);
1711 if (valid && idx < _configured_internal.get (*t)) {
1712 new_in.set (*t, i, idx);
1715 for (uint32_t o = 0; o < natural_output_streams().get (*t); ++o) {
1717 uint32_t idx = _out_map[pc].get (*t, o, &valid);
1718 if (valid && idx < _configured_out.get (*t)) {
1719 new_out.set (*t, o, idx);
1723 if (_in_map[pc] != new_in || _out_map[pc] != new_out) {
1726 new_ins[pc] = new_in;
1727 new_outs[pc] = new_out;
1730 /* prevent dup output assignments */
1731 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1732 for (uint32_t o = 0; o < _configured_out.get (*t); ++o) {
1733 bool mapped = false;
1734 for (uint32_t pc = 0; pc < get_count(); ++pc) {
1736 uint32_t idx = new_outs[pc].get_src (*t, o, &valid);
1737 if (valid && mapped) {
1738 new_outs[pc].unset (*t, idx);
1746 /* remove excess thru */
1747 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1748 for (uint32_t o = 0; o < _configured_out.get (*t); ++o) {
1750 uint32_t idx = _thru_map.get (*t, o, &valid);
1751 if (valid && idx < _configured_internal.get (*t)) {
1752 new_thru.set (*t, o, idx);
1757 /* prevent out + thru, existing plugin outputs override thru */
1758 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1759 for (uint32_t o = 0; o < _configured_out.get (*t); ++o) {
1760 bool mapped = false;
1762 for (uint32_t pc = 0; pc < get_count(); ++pc) {
1763 new_outs[pc].get_src (*t, o, &mapped);
1764 if (mapped) { break; }
1766 if (!mapped) { continue; }
1767 uint32_t idx = new_thru.get (*t, o, &valid);
1769 new_thru.unset (*t, idx);
1774 if (has_midi_bypass ()) {
1775 // TODO: include midi-bypass in the thru set,
1776 // remove dedicated handling.
1777 new_thru.unset (DataType::MIDI, 0);
1780 if (_in_map != new_ins || _out_map != new_outs || _thru_map != new_thru) {
1784 _out_map = new_outs;
1785 _thru_map = new_thru;
1791 PluginInsert::reset_map (bool emit)
1793 const PinMappings old_in (_in_map);
1794 const PinMappings old_out (_out_map);
1798 _thru_map = ChanMapping ();
1800 /* build input map */
1801 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1802 uint32_t sc = 0; // side-chain round-robin (all instances)
1804 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
1805 const uint32_t nis = natural_input_streams ().get(*t);
1806 const uint32_t stride = nis - sidechain_input_pins().get (*t);
1808 /* SC inputs are last in the plugin-insert.. */
1809 const uint32_t sc_start = _configured_in.get (*t);
1810 const uint32_t sc_len = _configured_internal.get (*t) - sc_start;
1811 /* ...but may not be at the end of the plugin ports.
1812 * in case the side-chain is not the last port, shift connections back.
1813 * and connect to side-chain
1816 uint32_t ic = 0; // split inputs
1817 const uint32_t cend = _configured_in.get (*t);
1819 for (uint32_t in = 0; in < nis; ++in) {
1820 const Plugin::IOPortDescription& iod (_plugins[pc]->describe_io_port (*t, true, in));
1821 if (iod.is_sidechain) {
1822 /* connect sidechain sinks to sidechain inputs in round-robin fashion */
1823 if (sc_len > 0) {// side-chain may be hidden
1824 _in_map[pc].set (*t, in, sc_start + sc);
1825 sc = (sc + 1) % sc_len;
1829 if (_match.method == Split) {
1830 if (cend == 0) { continue; }
1831 if (_strict_io && ic + stride * pc >= cend) {
1834 /* connect *no* sidechain sinks in round-robin fashion */
1835 _in_map[pc].set (*t, in, ic + stride * pc);
1836 if (_strict_io && (ic + 1) == cend) {
1839 ic = (ic + 1) % cend;
1841 uint32_t s = in - shift;
1842 if (stride * pc + s < cend) {
1843 _in_map[pc].set (*t, in, s + stride * pc);
1851 /* build output map */
1853 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
1854 _out_map[pc] = ChanMapping (ChanCount::min (natural_output_streams(), _configured_out));
1855 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1856 _out_map[pc].offset_to(*t, pc * natural_output_streams().get(*t));
1861 if (old_in == _in_map && old_out == _out_map) {
1865 PluginMapChanged (); /* EMIT SIGNAL */
1866 _mapping_changed = true;
1867 _session.set_dirty();
1873 PluginInsert::configure_io (ChanCount in, ChanCount out)
1875 Match old_match = _match;
1877 ChanCount old_internal;
1881 old_pins = natural_input_streams();
1882 old_in = _configured_in;
1883 old_out = _configured_out;
1884 old_internal = _configured_internal;
1886 _configured_in = in;
1887 _configured_internal = in;
1888 _configured_out = out;
1891 /* TODO hide midi-bypass, and custom outs. Best /fake/ "out" here.
1892 * (currently _sidechain->configure_io always succeeds
1893 * since Processor::configure_io() succeeds)
1895 if (!_sidechain->configure_io (in, out)) {
1896 DEBUG_TRACE (DEBUG::ChanMapping, "Sidechain configuration failed\n");
1899 _configured_internal += _sidechain->input()->n_ports();
1901 // include (static_cast<Route*>owner())->name() ??
1902 _sidechain->input ()-> set_pretty_name (string_compose (_("SC %1"), name ()));
1905 /* get plugin configuration */
1906 _match = private_can_support_io_configuration (in, out);
1908 if (DEBUG_ENABLED(DEBUG::ChanMapping)) {
1910 DEBUG_STR_APPEND(a, string_compose ("%1: ", name()));
1911 DEBUG_STR_APPEND(a, _match);
1912 DEBUG_TRACE (DEBUG::ChanMapping, DEBUG_STR(a).str());
1916 /* set the matching method and number of plugins that we will use to meet this configuration */
1917 if (set_count (_match.plugins) == false) {
1918 PluginIoReConfigure (); /* EMIT SIGNAL */
1919 _configured = false;
1923 /* configure plugins */
1924 switch (_match.method) {
1927 if (_plugins.front()->configure_io (natural_input_streams(), out) == false) {
1928 PluginIoReConfigure (); /* EMIT SIGNAL */
1929 _configured = false;
1935 ChanCount din (_configured_internal);
1936 ChanCount dout (din); // hint
1938 if (_custom_sinks.n_total () > 0) {
1939 din = _custom_sinks;
1942 } else if (_preset_out.n_audio () > 0) {
1943 dout.set (DataType::AUDIO, _preset_out.n_audio ());
1944 } else if (dout.n_midi () > 0 && dout.n_audio () == 0) {
1945 dout.set (DataType::AUDIO, 2);
1947 if (out.n_audio () == 0) { out.set (DataType::AUDIO, 1); }
1949 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: Delegate lookup : %2 %3\n", name(), din, dout));
1950 bool const r = _plugins.front()->can_support_io_configuration (din, dout, &useins);
1952 if (useins.n_audio() == 0) {
1955 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: Delegate configuration: %2 %3\n", name(), useins, dout));
1957 if (_plugins.front()->configure_io (useins, dout) == false) {
1958 PluginIoReConfigure (); /* EMIT SIGNAL */
1959 _configured = false;
1963 _custom_sinks = din;
1968 if (_plugins.front()->configure_io (in, out) == false) {
1969 PluginIoReConfigure (); /* EMIT SIGNAL */
1970 _configured = false;
1976 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: cfg:%2 state:%3 chn-in:%4 chn-out:%5 inpin:%6 match:%7 cust:%8 size-in:%9 size-out:%10\n",
1978 _configured ? "Y" : "N",
1979 _maps_from_state ? "Y" : "N",
1980 old_in == in ? "==" : "!=",
1981 old_out == out ? "==" : "!=",
1982 old_pins == natural_input_streams () ? "==" : "!=",
1983 old_match.method == _match.method ? "==" : "!=",
1984 old_match.custom_cfg == _match.custom_cfg ? "==" : "!=",
1985 _in_map.size() == get_count () ? "==" : "!=",
1986 _out_map.size() == get_count () ? "==" : "!="
1989 bool mapping_changed = false;
1990 if (old_in == in && old_out == out
1992 && old_pins == natural_input_streams ()
1993 && old_match.method == _match.method
1994 && old_match.custom_cfg == _match.custom_cfg
1995 && _in_map.size() == _out_map.size()
1996 && _in_map.size() == get_count ()
1998 /* If the configuration has not changed, keep the mapping */
1999 mapping_changed = sanitize_maps ();
2000 } else if (_match.custom_cfg && _configured) {
2001 /* don't touch the map in manual mode */
2002 mapping_changed = sanitize_maps ();
2005 if (is_channelstrip ()) {
2006 /* fake channel map - for wire display */
2009 _thru_map = ChanMapping ();
2010 _in_map[0] = ChanMapping (ChanCount::min (_configured_in, ChanCount (DataType::AUDIO, 2)));
2011 _out_map[0] = ChanMapping (ChanCount::min (_configured_out, ChanCount (DataType::AUDIO, 2)));
2012 /* set "thru" map for in-place forward of audio */
2013 for (uint32_t i = 2; i < _configured_in.n_audio(); ++i) {
2014 _thru_map.set (DataType::AUDIO, i, i);
2016 /* and midi (after implicit 1st channel bypass) */
2017 for (uint32_t i = 1; i < _configured_in.n_midi(); ++i) {
2018 _thru_map.set (DataType::MIDI, i, i);
2022 if (_maps_from_state && old_in == in && old_out == out) {
2023 mapping_changed = true;
2026 /* generate a new mapping */
2027 mapping_changed = reset_map (false);
2029 _maps_from_state = false;
2032 if (mapping_changed) {
2033 PluginMapChanged (); /* EMIT SIGNAL */
2036 if (DEBUG_ENABLED(DEBUG::ChanMapping)) {
2039 DEBUG_STR_APPEND(a, "\n--------<<--------\n");
2040 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i, ++pc) {
2042 DEBUG_STR_APPEND(a, "----><----\n");
2044 DEBUG_STR_APPEND(a, string_compose ("Channel Map for %1 plugin %2\n", name(), pc));
2045 DEBUG_STR_APPEND(a, " * Inputs:\n");
2046 DEBUG_STR_APPEND(a, _in_map[pc]);
2047 DEBUG_STR_APPEND(a, " * Outputs:\n");
2048 DEBUG_STR_APPEND(a, _out_map[pc]);
2050 DEBUG_STR_APPEND(a, " * Thru:\n");
2051 DEBUG_STR_APPEND(a, _thru_map);
2052 DEBUG_STR_APPEND(a, "-------->>--------\n");
2053 DEBUG_TRACE (DEBUG::ChanMapping, DEBUG_STR(a).str());
2058 _no_inplace = check_inplace ();
2059 _mapping_changed = false;
2061 /* only the "noinplace_buffers" thread buffers need to be this large,
2062 * this can be optimized. other buffers are fine with
2063 * ChanCount::max (natural_input_streams (), natural_output_streams())
2064 * and route.cc's max (configured_in, configured_out)
2066 * no-inplace copies "thru" outputs (to emulate in-place) for
2067 * all outputs (to prevent overwrite) into a temporary space
2068 * which also holds input buffers (in case the plugin does process
2069 * in-place and overwrites those).
2071 * this buffers need to be at least as
2072 * natural_input_streams () + possible outputs.
2074 * sidechain inputs add a constraint on the input:
2075 * configured input + sidechain (=_configured_internal)
2077 * NB. this also satisfies
2078 * max (natural_input_streams(), natural_output_streams())
2079 * which is needed for silence runs
2081 _required_buffers = ChanCount::max (_configured_internal,
2082 natural_input_streams () + ChanCount::max (_configured_out, natural_output_streams () * get_count ()));
2084 if (old_in != in || old_out != out || old_internal != _configured_internal
2085 || old_pins != natural_input_streams ()
2086 || (old_match.method != _match.method && (old_match.method == Split || _match.method == Split))
2088 PluginIoReConfigure (); /* EMIT SIGNAL */
2091 _delaybuffers.configure (_configured_out, _plugins.front ()->max_latency ());
2092 _latency_changed = true;
2094 /* we don't know the analysis window size, so we must work with the
2095 * current buffer size here. each request for data fills in these
2096 * buffers and the analyser makes sure it gets enough data for the
2097 * analysis window. We also only analyze audio, so we can ignore
2100 ChanCount cc_analysis_in (DataType::AUDIO, in.n_audio());
2101 ChanCount cc_analysis_out (DataType::AUDIO, out.n_audio());
2103 session().ensure_buffer_set (_signal_analysis_inputs, cc_analysis_in);
2104 _signal_analysis_inputs.set_count (cc_analysis_in);
2106 session().ensure_buffer_set (_signal_analysis_outputs, cc_analysis_out);
2107 _signal_analysis_outputs.set_count (cc_analysis_out);
2109 // std::cerr << "set counts to i" << in.n_audio() << "/o" << out.n_audio() << std::endl;
2112 return Processor::configure_io (in, out);
2115 /** Decide whether this PluginInsert can support a given IO configuration.
2116 * To do this, we run through a set of possible solutions in rough order of
2119 * @param in Required input channel count.
2120 * @param out Filled in with the output channel count if we return true.
2121 * @return true if the given IO configuration can be supported.
2124 PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out)
2127 _sidechain->can_support_io_configuration (in, out); // never fails, sets "out"
2129 return private_can_support_io_configuration (in, out).method != Impossible;
2133 PluginInsert::private_can_support_io_configuration (ChanCount const& in, ChanCount& out) const
2135 if (!_custom_cfg && _preset_out.n_audio () > 0) {
2136 // preseed hint (for variable i/o)
2137 out.set (DataType::AUDIO, _preset_out.n_audio ());
2140 Match rv = internal_can_support_io_configuration (in, out);
2142 if (!_custom_cfg && _preset_out.n_audio () > 0) {
2143 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: using output preset: %2\n", name(), _preset_out));
2144 out.set (DataType::AUDIO, _preset_out.n_audio ());
2149 /** A private version of can_support_io_configuration which returns the method
2150 * by which the configuration can be matched, rather than just whether or not
2154 PluginInsert::internal_can_support_io_configuration (ChanCount const & inx, ChanCount& out) const
2156 if (_plugins.empty()) {
2161 if (is_channelstrip ()) {
2163 return Match (ExactMatch, 1);
2167 /* if a user specified a custom cfg, so be it. */
2169 PluginInfoPtr info = _plugins.front()->get_info();
2171 if (info->reconfigurable_io()) {
2172 return Match (Delegate, 1, _strict_io, true);
2174 return Match (ExactMatch, get_count(), _strict_io, true);
2178 /* try automatic configuration */
2179 Match m = PluginInsert::automatic_can_support_io_configuration (inx, out);
2181 PluginInfoPtr info = _plugins.front()->get_info();
2182 ChanCount inputs = info->n_inputs;
2183 ChanCount outputs = info->n_outputs;
2185 /* handle case strict-i/o */
2186 if (_strict_io && m.method != Impossible) {
2189 /* special case MIDI instruments */
2190 if (is_instrument ()) {
2191 // output = midi-bypass + at most master-out channels.
2192 ChanCount max_out (DataType::AUDIO, 2); // TODO use master-out
2193 max_out.set (DataType::MIDI, out.get(DataType::MIDI));
2194 out = ChanCount::min (out, max_out);
2195 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: special case strict-i/o instrument\n", name()));
2201 if (inx.n_audio () != out.n_audio ()) { // ignore midi bypass
2202 /* replicate processor to match output count (generators and such)
2203 * at least enough to feed every output port. */
2204 uint32_t f = 1; // at least one. e.g. control data filters, no in, no out.
2205 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2206 uint32_t nout = outputs.get (*t);
2207 if (nout == 0 || inx.get(*t) == 0) { continue; }
2208 f = max (f, (uint32_t) ceil (inx.get(*t) / (float)nout));
2211 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: special case strict-i/o for generator\n", name()));
2212 return Match (Replicate, f, _strict_io);
2223 if (m.method != Impossible) {
2227 ChanCount ns_inputs = inputs - sidechain_input_pins ();
2229 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: resolving 'Impossible' match...\n", name()));
2231 if (info->reconfigurable_io()) {
2234 if (out.n_midi () > 0 && out.n_audio () == 0) { out.set (DataType::AUDIO, 2); }
2235 if (out.n_audio () == 0) { out.set (DataType::AUDIO, 1); }
2236 bool const r = _plugins.front()->can_support_io_configuration (inx + sidechain_input_pins (), out, &useins);
2238 // houston, we have a problem.
2239 return Match (Impossible, 0);
2242 if (inx.n_midi () > 0 && out.n_midi () == 0) { out.set (DataType::MIDI, 1); }
2243 return Match (Delegate, 1, _strict_io);
2246 ChanCount midi_bypass;
2247 if (inx.get(DataType::MIDI) == 1 && outputs.get(DataType::MIDI) == 0) {
2248 midi_bypass.set (DataType::MIDI, 1);
2251 // add at least as many plugins so that output count matches input count (w/o sidechain pins)
2253 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2254 uint32_t nin = ns_inputs.get (*t);
2255 uint32_t nout = outputs.get (*t);
2256 if (nin == 0 || inx.get(*t) == 0) { continue; }
2257 // prefer floor() so the count won't overly increase IFF (nin < nout)
2258 f = max (f, (uint32_t) floor (inx.get(*t) / (float)nout));
2260 if (f > 0 && outputs * f >= _configured_out) {
2261 out = outputs * f + midi_bypass;
2262 return Match (Replicate, f, _strict_io);
2265 // add at least as many plugins needed to connect all inputs (w/o sidechain pins)
2267 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2268 uint32_t nin = ns_inputs.get (*t);
2269 if (nin == 0 || inx.get(*t) == 0) { continue; }
2270 f = max (f, (uint32_t) ceil (inx.get(*t) / (float)nin));
2273 out = outputs * f + midi_bypass;
2274 return Match (Replicate, f, _strict_io);
2277 // add at least as many plugins needed to connect all inputs
2279 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2280 uint32_t nin = inputs.get (*t);
2281 if (nin == 0 || inx.get(*t) == 0) { continue; }
2282 f = max (f, (uint32_t) ceil (inx.get(*t) / (float)nin));
2284 out = outputs * f + midi_bypass;
2285 return Match (Replicate, f, _strict_io);
2288 /* this is the original Ardour 3/4 behavior, mainly for backwards compatibility */
2290 PluginInsert::automatic_can_support_io_configuration (ChanCount const & inx, ChanCount& out) const
2292 if (_plugins.empty()) {
2296 PluginInfoPtr info = _plugins.front()->get_info();
2297 ChanCount in; in += inx;
2298 ChanCount midi_bypass;
2300 if (info->reconfigurable_io()) {
2301 /* Plugin has flexible I/O, so delegate to it
2302 * pre-seed outputs, plugin tries closest match
2305 if (out.n_midi () > 0 && out.n_audio () == 0) { out.set (DataType::AUDIO, 2); }
2306 if (out.n_audio () == 0) { out.set (DataType::AUDIO, 1); }
2307 bool const r = _plugins.front()->can_support_io_configuration (in + sidechain_input_pins (), out);
2309 return Match (Impossible, 0);
2312 if (in.n_midi () > 0 && out.n_midi () == 0) { out.set (DataType::MIDI, 1); }
2313 return Match (Delegate, 1);
2316 ChanCount inputs = info->n_inputs;
2317 ChanCount outputs = info->n_outputs;
2318 ChanCount ns_inputs = inputs - sidechain_input_pins ();
2320 if (in.get(DataType::MIDI) == 1 && outputs.get(DataType::MIDI) == 0) {
2321 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: bypassing midi-data\n", name()));
2322 midi_bypass.set (DataType::MIDI, 1);
2324 if (in.get(DataType::MIDI) == 1 && inputs.get(DataType::MIDI) == 0) {
2325 DEBUG_TRACE (DEBUG::ChanMapping, string_compose ("%1: hiding midi-port from plugin\n", name()));
2326 in.set(DataType::MIDI, 0);
2329 // add internally provided sidechain ports
2330 ChanCount insc = in + sidechain_input_ports ();
2332 bool no_inputs = true;
2333 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2334 if (inputs.get (*t) != 0) {
2341 /* no inputs so we can take any input configuration since we throw it away */
2342 out = outputs + midi_bypass;
2343 return Match (NoInputs, 1);
2346 /* Plugin inputs match requested inputs + side-chain-ports exactly */
2347 if (inputs == insc) {
2348 out = outputs + midi_bypass;
2349 return Match (ExactMatch, 1);
2352 /* Plugin inputs matches without side-chain-pins */
2353 if (ns_inputs == in) {
2354 out = outputs + midi_bypass;
2355 return Match (ExactMatch, 1);
2358 /* We may be able to run more than one copy of the plugin within this insert
2359 to cope with the insert having more inputs than the plugin.
2360 We allow replication only for plugins with either zero or 1 inputs and outputs
2361 for every valid data type.
2365 bool can_replicate = true;
2366 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2368 // ignore side-chains
2369 uint32_t nin = ns_inputs.get (*t);
2371 // No inputs of this type
2372 if (nin == 0 && in.get(*t) == 0) {
2376 if (nin != 1 || outputs.get (*t) != 1) {
2377 can_replicate = false;
2381 // Potential factor not set yet
2383 f = in.get(*t) / nin;
2386 // Factor for this type does not match another type, can not replicate
2387 if (f != (in.get(*t) / nin)) {
2388 can_replicate = false;
2393 if (can_replicate && f > 0) {
2394 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2395 out.set (*t, outputs.get(*t) * f);
2398 return Match (Replicate, f);
2401 /* If the processor has exactly one input of a given type, and
2402 the plugin has more, we can feed the single processor input
2403 to some or all of the plugin inputs. This is rather
2404 special-case-y, but the 1-to-many case is by far the
2405 simplest. How do I split thy 2 processor inputs to 3
2406 plugin inputs? Let me count the ways ...
2409 bool can_split = true;
2410 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2412 bool const can_split_type = (in.get (*t) == 1 && ns_inputs.get (*t) > 1);
2413 bool const nothing_to_do_for_type = (in.get (*t) == 0 && inputs.get (*t) == 0);
2415 if (!can_split_type && !nothing_to_do_for_type) {
2421 out = outputs + midi_bypass;
2422 return Match (Split, 1);
2425 /* If the plugin has more inputs than we want, we can `hide' some of them
2426 by feeding them silence.
2429 bool could_hide = false;
2430 bool cannot_hide = false;
2431 ChanCount hide_channels;
2433 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
2434 if (inputs.get(*t) > in.get(*t)) {
2435 /* there is potential to hide, since the plugin has more inputs of type t than the insert */
2436 hide_channels.set (*t, inputs.get(*t) - in.get(*t));
2438 } else if (inputs.get(*t) < in.get(*t)) {
2439 /* we definitely cannot hide, since the plugin has fewer inputs of type t than the insert */
2444 if (could_hide && !cannot_hide) {
2445 out = outputs + midi_bypass;
2446 return Match (Hide, 1, false, false, hide_channels);
2449 return Match (Impossible, 0);
2454 PluginInsert::state ()
2456 XMLNode& node = Processor::state ();
2458 node.set_property("type", _plugins[0]->state_node_name());
2459 node.set_property("unique-id", _plugins[0]->unique_id());
2460 node.set_property("count", (uint32_t)_plugins.size());
2462 /* remember actual i/o configuration (for later placeholder
2463 * in case the plugin goes missing) */
2464 node.add_child_nocopy (* _configured_in.state (X_("ConfiguredInput")));
2465 node.add_child_nocopy (* _custom_sinks.state (X_("CustomSinks")));
2466 node.add_child_nocopy (* _configured_out.state (X_("ConfiguredOutput")));
2467 node.add_child_nocopy (* _preset_out.state (X_("PresetOutput")));
2469 /* save custom i/o config */
2470 node.set_property("custom", _custom_cfg);
2471 for (uint32_t pc = 0; pc < get_count(); ++pc) {
2473 snprintf (tmp, sizeof(tmp), "InputMap-%d", pc);
2474 node.add_child_nocopy (* _in_map[pc].state (tmp));
2475 snprintf (tmp, sizeof(tmp), "OutputMap-%d", pc);
2476 node.add_child_nocopy (* _out_map[pc].state (tmp));
2478 node.add_child_nocopy (* _thru_map.state ("ThruMap"));
2481 node.add_child_nocopy (_sidechain->get_state ());
2484 _plugins[0]->set_insert_id(this->id());
2485 node.add_child_nocopy (_plugins[0]->get_state());
2487 for (Controls::iterator c = controls().begin(); c != controls().end(); ++c) {
2488 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> ((*c).second);
2490 node.add_child_nocopy (ac->get_state());
2498 PluginInsert::set_control_ids (const XMLNode& node, int version)
2500 const XMLNodeList& nlist = node.children();
2501 XMLNodeConstIterator iter;
2502 set<Evoral::Parameter>::const_iterator p;
2504 for (iter = nlist.begin(); iter != nlist.end(); ++iter) {
2505 if ((*iter)->name() == Controllable::xml_node_name) {
2507 uint32_t p = (uint32_t)-1;
2510 if ((*iter)->get_property (X_("symbol"), str)) {
2511 boost::shared_ptr<LV2Plugin> lv2plugin = boost::dynamic_pointer_cast<LV2Plugin> (_plugins[0]);
2513 p = lv2plugin->port_index(str.c_str());
2517 if (p == (uint32_t)-1) {
2518 (*iter)->get_property (X_("parameter"), p);
2521 if (p != (uint32_t)-1) {
2523 /* this may create the new controllable */
2525 boost::shared_ptr<Evoral::Control> c = control (Evoral::Parameter (PluginAutomation, 0, p));
2527 #ifndef NO_PLUGIN_STATE
2531 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (c);
2533 ac->set_state (**iter, version);
2542 PluginInsert::set_state(const XMLNode& node, int version)
2544 XMLNodeList nlist = node.children();
2545 XMLNodeIterator niter;
2546 XMLPropertyList plist;
2547 ARDOUR::PluginType type;
2550 if (!node.get_property ("type", str)) {
2551 error << _("XML node describing plugin is missing the `type' field") << endmsg;
2555 if (str == X_("ladspa") || str == X_("Ladspa")) { /* handle old school sessions */
2556 type = ARDOUR::LADSPA;
2557 } else if (str == X_("lv2")) {
2559 } else if (str == X_("windows-vst")) {
2560 type = ARDOUR::Windows_VST;
2561 } else if (str == X_("lxvst")) {
2562 type = ARDOUR::LXVST;
2563 } else if (str == X_("mac-vst")) {
2564 type = ARDOUR::MacVST;
2565 } else if (str == X_("audiounit")) {
2566 type = ARDOUR::AudioUnit;
2567 } else if (str == X_("luaproc")) {
2570 error << string_compose (_("unknown plugin type %1 in plugin insert state"), str) << endmsg;
2574 XMLProperty const * prop = node.property ("unique-id");
2577 #ifdef WINDOWS_VST_SUPPORT
2578 /* older sessions contain VST plugins with only an "id" field. */
2579 if (type == ARDOUR::Windows_VST) {
2580 prop = node.property ("id");
2584 #ifdef LXVST_SUPPORT
2585 /*There shouldn't be any older sessions with linuxVST support.. but anyway..*/
2586 if (type == ARDOUR::LXVST) {
2587 prop = node.property ("id");
2594 error << _("Plugin has no unique ID field") << endmsg;
2599 boost::shared_ptr<Plugin> plugin = find_plugin (_session, prop->value(), type);
2600 bool any_vst = false;
2602 /* treat VST plugins equivalent if they have the same uniqueID
2603 * allow to move sessions windows <> linux */
2604 #ifdef LXVST_SUPPORT
2605 if (plugin == 0 && (type == ARDOUR::Windows_VST || type == ARDOUR::MacVST)) {
2606 type = ARDOUR::LXVST;
2607 plugin = find_plugin (_session, prop->value(), type);
2608 if (plugin) { any_vst = true; }
2612 #ifdef WINDOWS_VST_SUPPORT
2613 if (plugin == 0 && (type == ARDOUR::LXVST || type == ARDOUR::MacVST)) {
2614 type = ARDOUR::Windows_VST;
2615 plugin = find_plugin (_session, prop->value(), type);
2616 if (plugin) { any_vst = true; }
2620 #ifdef MACVST_SUPPORT
2621 if (plugin == 0 && (type == ARDOUR::Windows_VST || type == ARDOUR::LXVST)) {
2622 type = ARDOUR::MacVST;
2623 plugin = find_plugin (_session, prop->value(), type);
2624 if (plugin) { any_vst = true; }
2628 if (plugin == 0 && type == ARDOUR::Lua) {
2629 /* unique ID (sha1 of script) was not found,
2630 * load the plugin from the serialized version in the
2631 * session-file instead.
2633 boost::shared_ptr<LuaProc> lp (new LuaProc (_session.engine(), _session, ""));
2634 XMLNode *ls = node.child (lp->state_node_name().c_str());
2636 lp->set_script_from_state (*ls);
2642 error << string_compose(
2643 _("Found a reference to a plugin (\"%1\") that is unknown.\n"
2644 "Perhaps it was removed or moved since it was last used."),
2650 // The name of the PluginInsert comes from the plugin, nothing else
2651 _name = plugin->get_info()->name;
2655 // Processor::set_state() will set this, but too late
2656 // for it to be available when setting up plugin
2657 // state. We can't call Processor::set_state() until
2658 // the plugins themselves are created and added.
2662 if (_plugins.empty()) {
2663 /* if we are adding the first plugin, we will need to set
2664 up automatable controls.
2666 add_plugin (plugin);
2667 create_automatable_parameters ();
2668 set_control_ids (node, version);
2671 node.get_property ("count", count);
2673 if (_plugins.size() != count) {
2674 for (uint32_t n = 1; n < count; ++n) {
2675 add_plugin (plugin_factory (plugin));
2679 Processor::set_state (node, version);
2681 PBD::ID new_id = this->id();
2682 PBD::ID old_id = this->id();
2684 node.get_property ("id", old_id);
2686 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2688 /* find the node with the type-specific node name ("lv2", "ladspa", etc)
2689 and set all plugins to the same state.
2692 if ( ((*niter)->name() == plugin->state_node_name())
2693 || (any_vst && ((*niter)->name() == "lxvst" || (*niter)->name() == "windows-vst" || (*niter)->name() == "mac-vst"))
2696 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
2697 /* Plugin state can include external files which are named after the ID.
2699 * If regenerate_xml_or_string_ids() is set, the ID will already have
2700 * been changed, so we need to use the old ID from the XML to load the
2701 * state and then update the ID.
2703 * When copying a plugin-state, route_ui takes care of of updating the ID,
2704 * but we need to call set_insert_id() to clear the cached plugin-state
2705 * and force a change.
2707 if (!regenerate_xml_or_string_ids ()) {
2708 (*i)->set_insert_id (new_id);
2710 (*i)->set_insert_id (old_id);
2713 (*i)->set_state (**niter, version);
2715 if (regenerate_xml_or_string_ids ()) {
2716 (*i)->set_insert_id (new_id);
2720 /* when copying plugin state, notify UI */
2721 for (Controls::const_iterator li = controls().begin(); li != controls().end(); ++li) {
2722 boost::shared_ptr<PBD::Controllable> c = boost::dynamic_pointer_cast<PBD::Controllable> (li->second);
2724 c->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
2732 if (version < 3000) {
2734 /* Only 2.X sessions need a call to set_parameter_state() - in 3.X and above
2735 this is all handled by Automatable
2738 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2739 if ((*niter)->name() == "Redirect") {
2740 /* XXX do we need to tackle placement? i think not (pd; oct 16 2009) */
2741 Processor::set_state (**niter, version);
2746 set_parameter_state_2X (node, version);
2749 node.get_property (X_("custom"), _custom_cfg);
2751 uint32_t in_maps = 0;
2752 uint32_t out_maps = 0;
2753 XMLNodeList kids = node.children ();
2754 for (XMLNodeIterator i = kids.begin(); i != kids.end(); ++i) {
2755 if ((*i)->name() == X_("ConfiguredInput")) {
2756 _configured_in = ChanCount(**i);
2758 if ((*i)->name() == X_("CustomSinks")) {
2759 _custom_sinks = ChanCount(**i);
2761 if ((*i)->name() == X_("ConfiguredOutput")) {
2762 _custom_out = ChanCount(**i);
2763 _configured_out = ChanCount(**i);
2765 if ((*i)->name() == X_("PresetOutput")) {
2766 _preset_out = ChanCount(**i);
2768 if (strncmp ((*i)->name ().c_str(), X_("InputMap-"), 9) == 0) {
2769 long pc = atol (&((*i)->name().c_str()[9]));
2770 if (pc >= 0 && pc <= (long) get_count()) {
2771 _in_map[pc] = ChanMapping (**i);
2775 if (strncmp ((*i)->name ().c_str(), X_("OutputMap-"), 10) == 0) {
2776 long pc = atol (&((*i)->name().c_str()[10]));
2777 if (pc >= 0 && pc <= (long) get_count()) {
2778 _out_map[pc] = ChanMapping (**i);
2782 if ((*i)->name () == "ThruMap") {
2783 _thru_map = ChanMapping (**i);
2786 // sidechain is a Processor (IO)
2787 if ((*i)->name () == Processor::state_node_name) {
2789 if (regenerate_xml_or_string_ids ()) {
2790 add_sidechain_from_xml (**i, version);
2795 if (!regenerate_xml_or_string_ids ()) {
2796 _sidechain->set_state (**i, version);
2798 update_sidechain_name ();
2803 if (in_maps == out_maps && out_maps >0 && out_maps == get_count()) {
2804 _maps_from_state = true;
2807 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
2811 (*i)->deactivate ();
2815 PluginConfigChanged (); /* EMIT SIGNAL */
2820 PluginInsert::update_id (PBD::ID id)
2823 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
2824 (*i)->set_insert_id (id);
2829 PluginInsert::set_owner (SessionObject* o)
2831 Processor::set_owner (o);
2832 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
2833 (*i)->set_owner (o);
2838 PluginInsert::set_state_dir (const std::string& d)
2840 // state() only saves the state of the first plugin
2841 _plugins[0]->set_state_dir (d);
2845 PluginInsert::set_parameter_state_2X (const XMLNode& node, int version)
2847 XMLNodeList nlist = node.children();
2848 XMLNodeIterator niter;
2850 /* look for port automation node */
2852 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2854 if ((*niter)->name() != port_automation_node_name) {
2859 XMLNodeConstIterator iter;
2863 cnodes = (*niter)->children ("port");
2865 for (iter = cnodes.begin(); iter != cnodes.end(); ++iter){
2869 if (!child->get_property("number", port_id)) {
2870 warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
2874 if (port_id >= _plugins[0]->parameter_count()) {
2875 warning << _("PluginInsert: Auto: port id out of range") << endmsg;
2879 boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl>(
2880 control(Evoral::Parameter(PluginAutomation, 0, port_id), true));
2882 if (c && c->alist()) {
2883 if (!child->children().empty()) {
2884 c->alist()->set_state (*child->children().front(), version);
2887 error << string_compose (_("PluginInsert: automatable control %1 not found - ignored"), port_id) << endmsg;
2897 boost::shared_ptr<ReadOnlyControl>
2898 PluginInsert::control_output (uint32_t num) const
2900 CtrlOutMap::const_iterator i = _control_outputs.find (num);
2901 if (i == _control_outputs.end ()) {
2902 return boost::shared_ptr<ReadOnlyControl> ();
2909 PluginInsert::describe_parameter (Evoral::Parameter param)
2911 if (param.type() == PluginAutomation) {
2912 return _plugins[0]->describe_parameter (param);
2913 } else if (param.type() == PluginPropertyAutomation) {
2914 boost::shared_ptr<AutomationControl> c(automation_control(param));
2915 if (c && !c->desc().label.empty()) {
2916 return c->desc().label;
2919 return Automatable::describe_parameter(param);
2923 PluginInsert::signal_latency() const
2925 if (!_pending_active) {
2928 if (_user_latency) {
2929 return _user_latency;
2932 return _plugins[0]->signal_latency ();
2936 PluginInsert::type ()
2938 return plugin()->get_info()->type;
2941 PluginInsert::PluginControl::PluginControl (PluginInsert* p,
2942 const Evoral::Parameter& param,
2943 const ParameterDescriptor& desc,
2944 boost::shared_ptr<AutomationList> list)
2945 : AutomationControl (p->session(), param, desc, list, p->describe_parameter(param))
2950 list->set_interpolation(Evoral::ControlList::Discrete);
2955 /** @param val `user' value */
2958 PluginInsert::PluginControl::actually_set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
2960 /* FIXME: probably should be taking out some lock here.. */
2962 for (Plugins::iterator i = _plugin->_plugins.begin(); i != _plugin->_plugins.end(); ++i) {
2963 (*i)->set_parameter (_list->parameter().id(), user_val);
2966 boost::shared_ptr<Plugin> iasp = _plugin->_impulseAnalysisPlugin.lock();
2968 iasp->set_parameter (_list->parameter().id(), user_val);
2971 AutomationControl::actually_set_value (user_val, group_override);
2975 PluginInsert::PluginControl::catch_up_with_external_value (double user_val)
2977 AutomationControl::actually_set_value (user_val, Controllable::NoGroup);
2981 PluginInsert::PluginControl::get_state ()
2983 XMLNode& node (AutomationControl::get_state());
2984 node.set_property (X_("parameter"), parameter().id());
2986 boost::shared_ptr<LV2Plugin> lv2plugin = boost::dynamic_pointer_cast<LV2Plugin> (_plugin->_plugins[0]);
2988 node.set_property (X_("symbol"), lv2plugin->port_symbol (parameter().id()));
2995 /** @return `user' val */
2997 PluginInsert::PluginControl::get_value () const
2999 boost::shared_ptr<Plugin> plugin = _plugin->plugin (0);
3005 return plugin->get_parameter (_list->parameter().id());
3008 PluginInsert::PluginPropertyControl::PluginPropertyControl (PluginInsert* p,
3009 const Evoral::Parameter& param,
3010 const ParameterDescriptor& desc,
3011 boost::shared_ptr<AutomationList> list)
3012 : AutomationControl (p->session(), param, desc, list)
3018 PluginInsert::PluginPropertyControl::actually_set_value (double user_val, Controllable::GroupControlDisposition gcd)
3020 /* Old numeric set_value(), coerce to appropriate datatype if possible.
3021 This is lossy, but better than nothing until Ardour's automation system
3022 can handle various datatypes all the way down. */
3023 const Variant value(_desc.datatype, user_val);
3024 if (value.type() == Variant::NOTHING) {
3025 error << "set_value(double) called for non-numeric property" << endmsg;
3029 for (Plugins::iterator i = _plugin->_plugins.begin(); i != _plugin->_plugins.end(); ++i) {
3030 (*i)->set_property(_list->parameter().id(), value);
3035 AutomationControl::actually_set_value (user_val, gcd);
3039 PluginInsert::PluginPropertyControl::get_state ()
3041 XMLNode& node (AutomationControl::get_state());
3042 node.set_property (X_("property"), parameter().id());
3043 node.remove_property (X_("value"));
3049 PluginInsert::PluginPropertyControl::get_value () const
3051 return _value.to_double();
3054 boost::shared_ptr<Plugin>
3055 PluginInsert::get_impulse_analysis_plugin()
3057 boost::shared_ptr<Plugin> ret;
3058 if (_impulseAnalysisPlugin.expired()) {
3059 // LV2 in particular uses various _session params
3060 // during init() -- most notably block_size..
3062 ret = plugin_factory(_plugins[0]);
3063 ChanCount out (internal_output_streams ());
3064 if (ret->get_info ()->reconfigurable_io ()) {
3065 // populate get_info ()->n_inputs and ->n_outputs
3067 ret->can_support_io_configuration (internal_input_streams (), out, &useins);
3068 assert (out == internal_output_streams ());
3070 ret->configure_io (internal_input_streams (), out);
3071 ret->set_owner (_owner);
3072 _impulseAnalysisPlugin = ret;
3074 ret = _impulseAnalysisPlugin.lock();
3081 PluginInsert::collect_signal_for_analysis (samplecnt_t nframes)
3083 // called from outside the audio thread, so this should be safe
3084 // only do audio as analysis is (currently) only for audio plugins
3085 _signal_analysis_inputs.ensure_buffers (DataType::AUDIO, input_streams().n_audio(), nframes);
3086 _signal_analysis_outputs.ensure_buffers (DataType::AUDIO, output_streams().n_audio(), nframes);
3088 _signal_analysis_collected_nframes = 0;
3089 _signal_analysis_collect_nframes_max = nframes;
3092 /** Add a plugin to our list */
3094 PluginInsert::add_plugin (boost::shared_ptr<Plugin> plugin)
3096 plugin->set_insert_id (this->id());
3097 plugin->set_owner (_owner);
3099 if (_plugins.empty()) {
3100 /* first (and probably only) plugin instance - connect to relevant signals */
3102 plugin->ParameterChangedExternally.connect_same_thread (*this, boost::bind (&PluginInsert::parameter_changed_externally, this, _1, _2));
3103 plugin->StartTouch.connect_same_thread (*this, boost::bind (&PluginInsert::start_touch, this, _1));
3104 plugin->EndTouch.connect_same_thread (*this, boost::bind (&PluginInsert::end_touch, this, _1));
3105 _custom_sinks = plugin->get_info()->n_inputs;
3106 // cache sidechain port count
3107 _cached_sidechain_pins.reset ();
3108 const ChanCount& nis (plugin->get_info()->n_inputs);
3109 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
3110 for (uint32_t in = 0; in < nis.get (*t); ++in) {
3111 const Plugin::IOPortDescription& iod (plugin->describe_io_port (*t, true, in));
3112 if (iod.is_sidechain) {
3113 _cached_sidechain_pins.set (*t, 1 + _cached_sidechain_pins.n(*t));
3118 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
3119 boost::shared_ptr<VSTPlugin> vst = boost::dynamic_pointer_cast<VSTPlugin> (plugin);
3121 vst->set_insert (this, _plugins.size ());
3125 _plugins.push_back (plugin);
3129 PluginInsert::add_sidechain_from_xml (const XMLNode& node, int version)
3131 if (version < 3000) {
3135 XMLNodeList nlist = node.children();
3137 if (nlist.size() == 0) {
3144 XMLNodeConstIterator it = nlist.front()->children().begin();
3145 for ( ; it != nlist.front()->children().end(); ++ it) {
3146 if ((*it)->name() == "Port") {
3147 DataType type(DataType::NIL);
3148 (*it)->get_property ("type", type);
3149 if (type == DataType::AUDIO) {
3151 } else if (type == DataType::MIDI) {
3157 ChanCount in_cc = ChanCount();
3158 in_cc.set (DataType::AUDIO, audio);
3159 in_cc.set (DataType::MIDI, midi);
3161 add_sidechain (audio, midi);
3165 PluginInsert::load_preset (ARDOUR::Plugin::PresetRecord pr)
3168 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
3169 if (! (*i)->load_preset (pr)) {
3177 PluginInsert::realtime_handle_transport_stopped ()
3179 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
3180 (*i)->realtime_handle_transport_stopped ();
3185 PluginInsert::realtime_locate ()
3187 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
3188 (*i)->realtime_locate ();
3193 PluginInsert::monitoring_changed ()
3195 for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
3196 (*i)->monitoring_changed ();
3201 PluginInsert::latency_changed ()
3203 // this is called in RT context, LatencyChanged is emitted after run()
3204 _latency_changed = true;
3205 // XXX This also needs a proper API not an owner() hack.
3207 static_cast<Route*>(owner ())->processor_latency_changed (); /* EMIT SIGNAL */
3211 PluginInsert::start_touch (uint32_t param_id)
3213 boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id));
3215 // ToDo subtract _plugin_signal_latency from audible_sample() when rolling, assert > 0
3216 ac->start_touch (session().audible_sample());
3221 PluginInsert::end_touch (uint32_t param_id)
3223 boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id));
3225 // ToDo subtract _plugin_signal_latency from audible_sample() when rolling, assert > 0
3226 ac->stop_touch (session().audible_sample());
3231 PluginInsert::provides_stats () const
3233 #if defined MIXBUS && defined NDEBUG
3234 if (is_channelstrip () || !display_to_user ()) {
3242 PluginInsert::get_stats (uint64_t& min, uint64_t& max, double& avg, double& dev) const
3244 /* TODO: consider taking a try/lock: Don't run concurrently with
3245 * TimingStats::update, TimingStats::reset.
3247 return _timing_stats.get_stats (min, max, avg, dev);
3251 PluginInsert::clear_stats ()
3253 g_atomic_int_set (&_stat_reset, 1);
3256 std::ostream& operator<<(std::ostream& o, const ARDOUR::PluginInsert::Match& m)
3259 case PluginInsert::Impossible: o << "Impossible"; break;
3260 case PluginInsert::Delegate: o << "Delegate"; break;
3261 case PluginInsert::NoInputs: o << "NoInputs"; break;
3262 case PluginInsert::ExactMatch: o << "ExactMatch"; break;
3263 case PluginInsert::Replicate: o << "Replicate"; break;
3264 case PluginInsert::Split: o << "Split"; break;
3265 case PluginInsert::Hide: o << "Hide"; break;
3267 o << " cnt: " << m.plugins
3268 << (m.strict_io ? " strict-io" : "")
3269 << (m.custom_cfg ? " custom-cfg" : "");
3270 if (m.method == PluginInsert::Hide) {
3271 o << " hide: " << m.hide;