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.
22 #include <sigc++/bind.h>
24 #include <pbd/failed_constructor.h>
25 #include <pbd/xml++.h>
27 #include <ardour/insert.h>
28 #include <ardour/plugin.h>
29 #include <ardour/port.h>
30 #include <ardour/route.h>
31 #include <ardour/ladspa_plugin.h>
34 #include <ardour/lv2_plugin.h>
38 #include <ardour/vst_plugin.h>
41 #ifdef HAVE_AUDIOUNITS
42 #include <ardour/audio_unit.h>
45 #include <ardour/audioengine.h>
46 #include <ardour/session.h>
47 #include <ardour/types.h>
52 using namespace ARDOUR;
55 Insert::Insert(Session& s, string name, Placement p)
56 : Redirect (s, name, p)
60 Insert::Insert(Session& s, string name, Placement p, int imin, int imax, int omin, int omax)
61 : Redirect (s, name, p, imin, imax, omin, omax)
65 /***************************************************************
66 Plugin inserts: send data through a plugin
67 ***************************************************************/
69 const string PluginInsert::port_automation_node_name = "PortAutomation";
71 PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placement placement)
72 : Insert (s, plug->name(), placement)
74 /* the first is the master */
76 _plugins.push_back (plug);
78 _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
82 if (_plugins[0]->fixed_io()) {
83 Glib::Mutex::Lock em (_session.engine().process_lock());
84 IO::MoreOutputs (output_streams ());
87 RedirectCreated (this); /* EMIT SIGNAL */
90 PluginInsert::PluginInsert (Session& s, const XMLNode& node)
91 : Insert (s, "will change", PreFader)
93 if (set_state (node)) {
94 throw failed_constructor();
99 _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
101 if (_plugins[0]->fixed_io()) {
102 Glib::Mutex::Lock em (_session.engine().process_lock());
103 IO::MoreOutputs (output_streams());
107 PluginInsert::PluginInsert (const PluginInsert& other)
108 : Insert (other._session, other.plugin()->name(), other.placement())
110 uint32_t count = other._plugins.size();
112 /* make as many copies as requested */
113 for (uint32_t n = 0; n < count; ++n) {
114 _plugins.push_back (plugin_factory (other.plugin (n)));
118 _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
122 RedirectCreated (this); /* EMIT SIGNAL */
126 PluginInsert::set_count (uint32_t num)
128 bool require_state = !_plugins.empty();
130 /* this is a bad idea.... we shouldn't do this while active.
131 only a route holding their redirect_lock should be calling this
136 } else if (num > _plugins.size()) {
137 uint32_t diff = num - _plugins.size();
139 for (uint32_t n = 0; n < diff; ++n) {
140 _plugins.push_back (plugin_factory (_plugins[0]));
143 /* XXX do something */
147 } else if (num < _plugins.size()) {
148 uint32_t diff = _plugins.size() - num;
149 for (uint32_t n= 0; n < diff; ++n) {
158 PluginInsert::init ()
162 set<uint32_t>::iterator s;
165 PluginInsert::~PluginInsert ()
167 GoingAway (); /* EMIT SIGNAL */
171 PluginInsert::automation_list_creation_callback (uint32_t which, AutomationList& alist)
173 alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
177 PluginInsert::auto_state_changed (uint32_t which)
179 AutomationList& alist (automation_list (which));
181 if (alist.automation_state() != Off) {
182 _plugins[0]->set_parameter (which, alist.eval (_session.transport_frame()));
187 PluginInsert::output_streams() const
189 int32_t out = _plugins[0]->get_info()->n_outputs;
192 return _plugins[0]->output_streams ();
194 return out * _plugins.size();
199 PluginInsert::input_streams() const
201 int32_t in = _plugins[0]->get_info()->n_inputs;
203 return _plugins[0]->input_streams ();
205 return in * _plugins.size();
210 PluginInsert::natural_output_streams() const
212 return _plugins[0]->get_info()->n_outputs;
216 PluginInsert::natural_input_streams() const
218 return _plugins[0]->get_info()->n_inputs;
222 PluginInsert::is_generator() const
224 /* XXX more finesse is possible here. VST plugins have a
225 a specific "instrument" flag, for example.
228 return _plugins[0]->get_info()->n_inputs == 0;
232 PluginInsert::set_automatable ()
236 a = _plugins.front()->automatable ();
238 for (set<uint32_t>::iterator i = a.begin(); i != a.end(); ++i) {
244 PluginInsert::parameter_changed (uint32_t which, float val)
246 vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
248 /* don't set the first plugin, just all the slaves */
250 if (i != _plugins.end()) {
252 for (; i != _plugins.end(); ++i) {
253 (*i)->set_parameter (which, val);
259 PluginInsert::set_block_size (nframes_t nframes)
261 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
262 (*i)->set_block_size (nframes);
267 PluginInsert::activate ()
269 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
275 PluginInsert::deactivate ()
277 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
283 PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now)
285 int32_t in_index = 0;
286 int32_t out_index = 0;
288 /* Note that we've already required that plugins
289 be able to handle in-place processing.
294 map<uint32_t,AutomationList*>::iterator li;
297 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
299 AutomationList& alist (*((*li).second));
301 if (alist.automation_playback()) {
304 float val = alist.rt_safe_eval (now, valid);
307 /* set the first plugin, the others will be set via signals */
308 _plugins[0]->set_parameter ((*li).first, val);
315 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
316 (*i)->connect_and_run (bufs, nbufs, in_index, out_index, nframes, offset);
319 /* leave remaining channel buffers alone */
323 PluginInsert::automation_snapshot (nframes_t now, bool force)
325 map<uint32_t,AutomationList*>::iterator li;
327 for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
329 AutomationList *alist = ((*li).second);
330 if (alist != 0 && alist->automation_write ()) {
332 float val = _plugins[0]->get_parameter ((*li).first);
333 alist->rt_add (now, val);
334 last_automation_snapshot = now;
340 PluginInsert::transport_stopped (nframes_t now)
342 map<uint32_t,AutomationList*>::iterator li;
344 for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
345 AutomationList& alist (*(li->second));
346 alist.reposition_for_rt_add (now);
348 if (alist.automation_state() != Off) {
349 _plugins[0]->set_parameter (li->first, alist.eval (now));
355 PluginInsert::silence (nframes_t nframes, nframes_t offset)
357 int32_t in_index = 0;
358 int32_t out_index = 0;
363 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
364 n = (*i) -> get_info()->n_inputs;
365 (*i)->connect_and_run (_session.get_silent_buffers (n), n, in_index, out_index, nframes, offset);
371 PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
375 if (_session.transport_rolling()) {
376 automation_run (bufs, nbufs, nframes, offset);
378 connect_and_run (bufs, nbufs, nframes, offset, false);
383 uint32_t in = _plugins[0]->get_info()->n_inputs;
384 uint32_t out = _plugins[0]->get_info()->n_outputs;
386 if (in < 0 || out < 0) {
392 /* not active, but something has make up for any channel count increase */
394 for (uint32_t n = out - in; n < out; ++n) {
395 memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
403 PluginInsert::set_parameter (uint32_t port, float val)
405 /* the others will be set from the event triggered by this */
407 _plugins[0]->set_parameter (port, val);
409 if (automation_list (port).automation_write()) {
410 automation_list (port).add (_session.audible_frame(), val);
413 _session.set_dirty();
417 PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
419 ControlEvent next_event (0, 0.0f);
420 nframes_t now = _session.transport_frame ();
421 nframes_t end = now + nframes;
423 Glib::Mutex::Lock lm (_automation_lock, Glib::TRY_LOCK);
426 connect_and_run (bufs, nbufs, nframes, offset, false);
430 if (!find_next_event (now, end, next_event)) {
432 /* no events have a time within the relevant range */
434 connect_and_run (bufs, nbufs, nframes, offset, true, now);
440 nframes_t cnt = min (((nframes_t) ceil (next_event.when) - now), nframes);
442 connect_and_run (bufs, nbufs, cnt, offset, true, now);
448 if (!find_next_event (now, end, next_event)) {
453 /* cleanup anything that is left to do */
456 connect_and_run (bufs, nbufs, nframes, offset, true, now);
461 PluginInsert::default_parameter_value (uint32_t port)
463 if (_plugins.empty()) {
464 fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
469 return _plugins[0]->default_value (port);
473 PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
475 if (port < _plugins[0]->parameter_count()) {
477 AutomationList& al = automation_list (port);
479 if (s != al.automation_state()) {
480 al.set_automation_state (s);
481 _session.set_dirty ();
487 PluginInsert::get_port_automation_state (uint32_t port)
489 if (port < _plugins[0]->parameter_count()) {
490 return automation_list (port).automation_state();
497 PluginInsert::protect_automation ()
499 set<uint32_t> automated_params;
501 what_has_automation (automated_params);
503 for (set<uint32_t>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
505 AutomationList& al = automation_list (*i);
507 switch (al.automation_state()) {
509 al.set_automation_state (Off);
512 al.set_automation_state (Play);
520 boost::shared_ptr<Plugin>
521 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
523 boost::shared_ptr<LadspaPlugin> lp;
525 boost::shared_ptr<LV2Plugin> lv2p;
528 boost::shared_ptr<VSTPlugin> vp;
530 #ifdef HAVE_AUDIOUNITS
531 boost::shared_ptr<AUPlugin> ap;
534 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
535 return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
537 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
538 return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
541 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
542 return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
544 #ifdef HAVE_AUDIOUNITS
545 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
546 return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
550 fatal << string_compose (_("programming error: %1"),
551 X_("unknown plugin type in PluginInsert::plugin_factory"))
554 return boost::shared_ptr<Plugin> ((Plugin*) 0);
558 PluginInsert::compute_output_streams (int32_t cnt) const
562 if ((outputs = _plugins[0]->get_info()->n_outputs) < 0) {
563 // have to ask the plugin itself, because it has flexible I/O
564 return _plugins[0]->compute_output_streams (cnt);
567 return outputs * cnt;
571 PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out)
573 return set_count (magic);
577 PluginInsert::can_support_input_configuration (int32_t in) const
579 int32_t outputs = _plugins[0]->get_info()->n_outputs;
580 int32_t inputs = _plugins[0]->get_info()->n_inputs;
582 if (outputs < 0 || inputs < 0) {
583 /* have to ask the plugin because its got reconfigurable I/O
585 return _plugins[0]->can_support_input_configuration (in);
590 /* instrument plugin, always legal, but it throws
591 away any existing active streams.
597 if (outputs == 1 && inputs == 1) {
598 /* mono plugin, replicate as needed */
607 if ((inputs < in) && (inputs % in == 0)) {
609 /* number of inputs is a factor of the requested input
610 configuration, so we can replicate.
622 PluginInsert::get_state(void)
628 PluginInsert::state (bool full)
631 XMLNode *node = new XMLNode("Insert");
633 node->add_child_nocopy (Redirect::state (full));
635 node->add_property ("type", _plugins[0]->state_node_name());
636 node->add_property("unique-id", _plugins[0]->unique_id());
637 node->add_property("count", string_compose("%1", _plugins.size()));
638 node->add_child_nocopy (_plugins[0]->get_state());
640 /* add controllables */
642 XMLNode* control_node = new XMLNode (X_("controls"));
644 for (uint32_t x = 0; x < _plugins[0]->parameter_count(); ++x) {
645 Controllable* c = _plugins[0]->get_nth_control (x, true);
647 XMLNode& controllable_state (c->get_state());
648 controllable_state.add_property ("parameter", to_string (x, std::dec));
649 control_node->add_child_nocopy (controllable_state);
652 node->add_child_nocopy (*control_node);
654 /* add port automation state */
655 XMLNode *autonode = new XMLNode(port_automation_node_name);
656 set<uint32_t> automatable = _plugins[0]->automatable();
658 for (set<uint32_t>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
660 XMLNode* child = new XMLNode("port");
661 snprintf(buf, sizeof(buf), "%" PRIu32, *x);
662 child->add_property("number", string(buf));
664 child->add_child_nocopy (automation_list (*x).state (full));
665 autonode->add_child_nocopy (*child);
668 node->add_child_nocopy (*autonode);
674 PluginInsert::set_state(const XMLNode& node)
676 XMLNodeList nlist = node.children();
677 XMLNodeIterator niter;
678 XMLPropertyList plist;
679 const XMLProperty *prop;
680 ARDOUR::PluginType type;
682 if ((prop = node.property ("type")) == 0) {
683 error << _("XML node describing insert is missing the `type' field") << endmsg;
687 if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
688 type = ARDOUR::LADSPA;
689 } else if (prop->value() == X_("lv2")) {
691 } else if (prop->value() == X_("vst")) {
693 } else if (prop->value() == X_("audiounit")) {
694 type = ARDOUR::AudioUnit;
696 error << string_compose (_("unknown plugin type %1 in plugin insert state"),
702 prop = node.property ("unique-id");
705 /* older sessions contain VST plugins with only an "id" field.
708 if (type == ARDOUR::VST) {
709 if (prop = node.property ("id")) {
716 error << _("Plugin has no unique ID field") << endmsg;
721 boost::shared_ptr<Plugin> plugin;
723 plugin = find_plugin (_session, prop->value(), type);
726 error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
727 "Perhaps it was removed or moved since it was last used."), prop->value())
734 if ((prop = node.property ("count")) != 0) {
735 sscanf (prop->value().c_str(), "%u", &count);
738 if (_plugins.size() != count) {
740 _plugins.push_back (plugin);
742 for (uint32_t n=1; n < count; ++n) {
743 _plugins.push_back (plugin_factory (plugin));
747 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
748 if ((*niter)->name() == plugin->state_node_name()) {
749 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
750 (*i)->set_state (**niter);
756 if (niter == nlist.end()) {
757 error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
761 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
762 if ((*niter)->name() == Redirect::state_node_name) {
763 Redirect::set_state (**niter);
768 if (niter == nlist.end()) {
769 error << _("XML node describing insert is missing a Redirect node") << endmsg;
773 /* look for controllables node */
775 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
777 if ((*niter)->name() != X_("controls")) {
781 XMLNodeList grandchildren ((*niter)->children());
783 XMLNodeIterator gciter;
786 for (gciter = grandchildren.begin(); gciter != grandchildren.end(); ++gciter) {
787 if ((prop = (*gciter)->property (X_("parameter"))) != 0) {
788 param = atoi (prop->value());
789 /* force creation of controllable for this parameter */
790 _plugins[0]->make_nth_control (param, **gciter);
797 /* look for port automation node */
799 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
801 if ((*niter)->name() != port_automation_node_name) {
807 XMLNodeConstIterator iter;
812 cnodes = (*niter)->children ("port");
814 for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
818 if ((cprop = child->property("number")) != 0) {
819 port = cprop->value().c_str();
821 warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
825 sscanf (port, "%" PRIu32, &port_id);
827 if (port_id >= _plugins[0]->parameter_count()) {
828 warning << _("PluginInsert: Auto: port id out of range") << endmsg;
832 if (!child->children().empty()) {
833 automation_list (port_id).set_state (*child->children().front());
835 if ((cprop = child->property("auto")) != 0) {
840 sscanf (cprop->value().c_str(), "0x%x", &x);
841 automation_list (port_id).set_automation_state (AutoState (x));
847 automation_list (port_id).set_automation_state (Off);
858 if (niter == nlist.end()) {
859 warning << string_compose(_("XML node describing a port automation is missing the `%1' information"), port_automation_node_name) << endmsg;
862 // The name of the PluginInsert comes from the plugin, nothing else
863 set_name(plugin->get_info()->name,this);
869 PluginInsert::describe_parameter (uint32_t what)
871 return _plugins[0]->describe_parameter (what);
875 PluginInsert::latency()
877 return _plugins[0]->latency ();
881 PluginInsert::type ()
883 boost::shared_ptr<LadspaPlugin> lp;
885 boost::shared_ptr<VSTPlugin> vp;
887 #ifdef HAVE_AUDIOUNITS
888 boost::shared_ptr<AUPlugin> ap;
891 PluginPtr other = plugin ();
893 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
894 return ARDOUR::LADSPA;
896 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
899 #ifdef HAVE_AUDIOUNITS
900 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
901 return ARDOUR::AudioUnit;
905 return (ARDOUR::PluginType) 0;
909 /***************************************************************
910 Port inserts: send output to a port, pick up input at a port
911 ***************************************************************/
913 PortInsert::PortInsert (Session& s, Placement p)
914 : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
917 RedirectCreated (this); /* EMIT SIGNAL */
921 PortInsert::PortInsert (const PortInsert& other)
922 : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
925 RedirectCreated (this); /* EMIT SIGNAL */
931 if (add_input_port ("", this)) {
932 error << _("PortInsert: cannot add input port") << endmsg;
933 throw failed_constructor();
936 if (add_output_port ("", this)) {
937 error << _("PortInsert: cannot add output port") << endmsg;
938 throw failed_constructor();
942 PortInsert::PortInsert (Session& s, const XMLNode& node)
943 : Insert (s, "will change", PreFader)
945 bitslot = 0xffffffff;
946 if (set_state (node)) {
947 throw failed_constructor();
950 RedirectCreated (this); /* EMIT SIGNAL */
953 PortInsert::~PortInsert ()
959 PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
961 if (n_outputs() == 0) {
966 /* deliver silence */
967 silence (nframes, offset);
972 vector<Port*>::iterator o;
973 vector<Port*>::iterator i;
977 for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
978 memcpy ((*o)->get_buffer (nframes) + offset, bufs[min(nbufs,n)], sizeof (Sample) * nframes);
979 (*o)->mark_silence (false);
984 for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) {
985 memcpy (bufs[min(nbufs,n)], (*i)->get_buffer (nframes) + offset, sizeof (Sample) * nframes);
990 PortInsert::get_state(void)
996 PortInsert::state (bool full)
998 XMLNode *node = new XMLNode("Insert");
1000 node->add_child_nocopy (Redirect::state(full));
1001 node->add_property ("type", "port");
1002 snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
1003 node->add_property ("bitslot", buf);
1009 PortInsert::set_state(const XMLNode& node)
1011 XMLNodeList nlist = node.children();
1012 XMLNodeIterator niter;
1013 XMLPropertyList plist;
1014 const XMLProperty *prop;
1016 if ((prop = node.property ("type")) == 0) {
1017 error << _("XML node describing insert is missing the `type' field") << endmsg;
1021 if (prop->value() != "port") {
1022 error << _("non-port insert XML used for port plugin insert") << endmsg;
1026 if ((prop = node.property ("bitslot")) == 0) {
1027 bitslot = _session.next_insert_id();
1029 uint32_t old_bitslot = bitslot;
1030 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
1032 if (old_bitslot != bitslot) {
1033 _session.mark_insert_id (bitslot);
1037 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1038 if ((*niter)->name() == Redirect::state_node_name) {
1039 Redirect::set_state (**niter);
1044 if (niter == nlist.end()) {
1045 error << _("XML node describing insert is missing a Redirect node") << endmsg;
1053 PortInsert::latency()
1055 /* because we deliver and collect within the same cycle,
1056 all I/O is necessarily delayed by at least frames_per_cycle().
1058 if the return port for insert has its own latency, we
1059 need to take that into account too.
1062 return _session.engine().frames_per_cycle() + input_latency();
1066 PortInsert::can_support_input_configuration (int32_t in) const
1068 if (input_maximum() == -1 && output_maximum() == -1) {
1070 /* not configured yet */
1072 return 1; /* we can support anything the first time we're asked */
1076 /* the "input" config for a port insert corresponds to how
1077 many output ports it will have.
1080 if (output_maximum() == in) {
1089 PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
1091 /* do not allow configuration to be changed outside the range of
1092 the last request config. or something like that.
1096 /* this is a bit odd:
1098 the number of inputs we are required to handle corresponds
1099 to the number of output ports we need.
1101 the number of outputs we are required to have corresponds
1102 to the number of input ports we need.
1105 set_output_maximum (in);
1106 set_output_minimum (in);
1107 set_input_maximum (out);
1108 set_input_minimum (out);
1118 return ensure_io (out, in, false, this);
1122 PortInsert::compute_output_streams (int32_t cnt) const
1124 /* puzzling, eh? think about it ... */
1129 PortInsert::output_streams() const
1135 PortInsert::input_streams() const
1137 return n_outputs ();