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)
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);
381 uint32_t in = _plugins[0]->get_info()->n_inputs;
382 uint32_t out = _plugins[0]->get_info()->n_outputs;
384 if (in < 0 || out < 0) {
390 /* not active, but something has make up for any channel count increase */
392 for (uint32_t n = out - in; n < out; ++n) {
393 memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
401 PluginInsert::set_parameter (uint32_t port, float val)
403 /* the others will be set from the event triggered by this */
405 _plugins[0]->set_parameter (port, val);
407 if (automation_list (port).automation_write()) {
408 automation_list (port).add (_session.audible_frame(), val);
411 _session.set_dirty();
415 PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
417 ControlEvent next_event (0, 0.0f);
418 nframes_t now = _session.transport_frame ();
419 nframes_t end = now + nframes;
421 Glib::Mutex::Lock lm (_automation_lock, Glib::TRY_LOCK);
424 connect_and_run (bufs, nbufs, nframes, offset, false);
428 if (!find_next_event (now, end, next_event)) {
430 /* no events have a time within the relevant range */
432 connect_and_run (bufs, nbufs, nframes, offset, true, now);
438 nframes_t cnt = min (((nframes_t) ceil (next_event.when) - now), nframes);
440 connect_and_run (bufs, nbufs, cnt, offset, true, now);
446 if (!find_next_event (now, end, next_event)) {
451 /* cleanup anything that is left to do */
454 connect_and_run (bufs, nbufs, nframes, offset, true, now);
459 PluginInsert::default_parameter_value (uint32_t port)
461 if (_plugins.empty()) {
462 fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
467 return _plugins[0]->default_value (port);
471 PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
473 if (port < _plugins[0]->parameter_count()) {
475 AutomationList& al = automation_list (port);
477 if (s != al.automation_state()) {
478 al.set_automation_state (s);
479 _session.set_dirty ();
485 PluginInsert::get_port_automation_state (uint32_t port)
487 if (port < _plugins[0]->parameter_count()) {
488 return automation_list (port).automation_state();
495 PluginInsert::protect_automation ()
497 set<uint32_t> automated_params;
499 what_has_automation (automated_params);
501 for (set<uint32_t>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
503 AutomationList& al = automation_list (*i);
505 switch (al.automation_state()) {
507 al.set_automation_state (Off);
510 al.set_automation_state (Play);
518 boost::shared_ptr<Plugin>
519 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
521 boost::shared_ptr<LadspaPlugin> lp;
523 boost::shared_ptr<LV2Plugin> lv2p;
526 boost::shared_ptr<VSTPlugin> vp;
528 #ifdef HAVE_AUDIOUNITS
529 boost::shared_ptr<AUPlugin> ap;
532 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
533 return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
535 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
536 return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
539 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
540 return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
542 #ifdef HAVE_AUDIOUNITS
543 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
544 return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
548 fatal << string_compose (_("programming error: %1"),
549 X_("unknown plugin type in PluginInsert::plugin_factory"))
552 return boost::shared_ptr<Plugin> ((Plugin*) 0);
556 PluginInsert::compute_output_streams (int32_t cnt) const
560 if ((outputs = _plugins[0]->get_info()->n_outputs) < 0) {
561 // have to ask the plugin itself, because it has flexible I/O
562 return _plugins[0]->compute_output_streams (cnt);
565 return outputs * cnt;
569 PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out)
571 return set_count (magic);
575 PluginInsert::can_support_input_configuration (int32_t in) const
577 int32_t outputs = _plugins[0]->get_info()->n_outputs;
578 int32_t inputs = _plugins[0]->get_info()->n_inputs;
580 if (outputs < 0 || inputs < 0) {
581 /* have to ask the plugin because its got reconfigurable I/O
583 return _plugins[0]->can_support_input_configuration (in);
588 /* instrument plugin, always legal, but it throws
589 away any existing active streams.
595 if (outputs == 1 && inputs == 1) {
596 /* mono plugin, replicate as needed */
605 if ((inputs < in) && (inputs % in == 0)) {
607 /* number of inputs is a factor of the requested input
608 configuration, so we can replicate.
620 PluginInsert::get_state(void)
626 PluginInsert::state (bool full)
629 XMLNode *node = new XMLNode("Insert");
631 node->add_child_nocopy (Redirect::state (full));
633 node->add_property ("type", _plugins[0]->state_node_name());
634 node->add_property("unique-id", _plugins[0]->unique_id());
635 node->add_property("count", string_compose("%1", _plugins.size()));
636 node->add_child_nocopy (_plugins[0]->get_state());
638 /* add controllables */
640 XMLNode* control_node = new XMLNode (X_("controls"));
642 for (uint32_t x = 0; x < _plugins[0]->parameter_count(); ++x) {
643 Controllable* c = _plugins[0]->get_nth_control (x, true);
645 XMLNode& controllable_state (c->get_state());
646 controllable_state.add_property ("parameter", to_string (x, std::dec));
647 control_node->add_child_nocopy (controllable_state);
650 node->add_child_nocopy (*control_node);
652 /* add port automation state */
653 XMLNode *autonode = new XMLNode(port_automation_node_name);
654 set<uint32_t> automatable = _plugins[0]->automatable();
656 for (set<uint32_t>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
658 XMLNode* child = new XMLNode("port");
659 snprintf(buf, sizeof(buf), "%" PRIu32, *x);
660 child->add_property("number", string(buf));
662 child->add_child_nocopy (automation_list (*x).state (full));
663 autonode->add_child_nocopy (*child);
666 node->add_child_nocopy (*autonode);
672 PluginInsert::set_state(const XMLNode& node)
674 XMLNodeList nlist = node.children();
675 XMLNodeIterator niter;
676 XMLPropertyList plist;
677 const XMLProperty *prop;
678 ARDOUR::PluginType type;
680 if ((prop = node.property ("type")) == 0) {
681 error << _("XML node describing insert is missing the `type' field") << endmsg;
685 if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
686 type = ARDOUR::LADSPA;
687 } else if (prop->value() == X_("lv2")) {
689 } else if (prop->value() == X_("vst")) {
691 } else if (prop->value() == X_("audiounit")) {
692 type = ARDOUR::AudioUnit;
694 error << string_compose (_("unknown plugin type %1 in plugin insert state"),
700 prop = node.property ("unique-id");
703 /* older sessions contain VST plugins with only an "id" field.
706 if (type == ARDOUR::VST) {
707 if (prop = node.property ("id")) {
714 error << _("Plugin has no unique ID field") << endmsg;
719 boost::shared_ptr<Plugin> plugin;
721 plugin = find_plugin (_session, prop->value(), type);
724 error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
725 "Perhaps it was removed or moved since it was last used."), prop->value())
732 if ((prop = node.property ("count")) != 0) {
733 sscanf (prop->value().c_str(), "%u", &count);
736 if (_plugins.size() != count) {
738 _plugins.push_back (plugin);
740 for (uint32_t n=1; n < count; ++n) {
741 _plugins.push_back (plugin_factory (plugin));
745 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
746 if ((*niter)->name() == plugin->state_node_name()) {
747 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
748 (*i)->set_state (**niter);
754 if (niter == nlist.end()) {
755 error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
759 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
760 if ((*niter)->name() == Redirect::state_node_name) {
761 Redirect::set_state (**niter);
766 if (niter == nlist.end()) {
767 error << _("XML node describing insert is missing a Redirect node") << endmsg;
771 /* look for controllables node */
773 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
775 if ((*niter)->name() != X_("controls")) {
779 XMLNodeList grandchildren ((*niter)->children());
781 XMLNodeIterator gciter;
784 for (gciter = grandchildren.begin(); gciter != grandchildren.end(); ++gciter) {
785 if ((prop = (*gciter)->property (X_("parameter"))) != 0) {
786 param = atoi (prop->value());
787 /* force creation of controllable for this parameter */
788 _plugins[0]->make_nth_control (param, **gciter);
795 /* look for port automation node */
797 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
799 if ((*niter)->name() != port_automation_node_name) {
805 XMLNodeConstIterator iter;
810 cnodes = (*niter)->children ("port");
812 for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
816 if ((cprop = child->property("number")) != 0) {
817 port = cprop->value().c_str();
819 warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
823 sscanf (port, "%" PRIu32, &port_id);
825 if (port_id >= _plugins[0]->parameter_count()) {
826 warning << _("PluginInsert: Auto: port id out of range") << endmsg;
830 if (!child->children().empty()) {
831 automation_list (port_id).set_state (*child->children().front());
833 if ((cprop = child->property("auto")) != 0) {
838 sscanf (cprop->value().c_str(), "0x%x", &x);
839 automation_list (port_id).set_automation_state (AutoState (x));
845 automation_list (port_id).set_automation_state (Off);
856 if (niter == nlist.end()) {
857 warning << string_compose(_("XML node describing a port automation is missing the `%1' information"), port_automation_node_name) << endmsg;
860 // The name of the PluginInsert comes from the plugin, nothing else
861 set_name(plugin->get_info()->name,this);
867 PluginInsert::describe_parameter (uint32_t what)
869 return _plugins[0]->describe_parameter (what);
873 PluginInsert::latency()
875 return _plugins[0]->latency ();
879 PluginInsert::type ()
881 boost::shared_ptr<LadspaPlugin> lp;
883 boost::shared_ptr<VSTPlugin> vp;
885 #ifdef HAVE_AUDIOUNITS
886 boost::shared_ptr<AUPlugin> ap;
889 PluginPtr other = plugin ();
891 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
892 return ARDOUR::LADSPA;
894 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
897 #ifdef HAVE_AUDIOUNITS
898 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
899 return ARDOUR::AudioUnit;
903 return (ARDOUR::PluginType) 0;
907 /***************************************************************
908 Port inserts: send output to a port, pick up input at a port
909 ***************************************************************/
911 PortInsert::PortInsert (Session& s, Placement p)
912 : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
915 RedirectCreated (this); /* EMIT SIGNAL */
919 PortInsert::PortInsert (const PortInsert& other)
920 : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
923 RedirectCreated (this); /* EMIT SIGNAL */
929 if (add_input_port ("", this)) {
930 error << _("PortInsert: cannot add input port") << endmsg;
931 throw failed_constructor();
934 if (add_output_port ("", this)) {
935 error << _("PortInsert: cannot add output port") << endmsg;
936 throw failed_constructor();
940 PortInsert::PortInsert (Session& s, const XMLNode& node)
941 : Insert (s, "will change", PreFader)
943 bitslot = 0xffffffff;
944 if (set_state (node)) {
945 throw failed_constructor();
948 RedirectCreated (this); /* EMIT SIGNAL */
951 PortInsert::~PortInsert ()
957 PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
959 if (n_outputs() == 0) {
964 /* deliver silence */
965 silence (nframes, offset);
970 vector<Port*>::iterator o;
971 vector<Port*>::iterator i;
975 for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
976 memcpy ((*o)->get_buffer (nframes) + offset, bufs[min(nbufs,n)], sizeof (Sample) * nframes);
977 (*o)->mark_silence (false);
982 for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) {
983 memcpy (bufs[min(nbufs,n)], (*i)->get_buffer (nframes) + offset, sizeof (Sample) * nframes);
988 PortInsert::get_state(void)
994 PortInsert::state (bool full)
996 XMLNode *node = new XMLNode("Insert");
998 node->add_child_nocopy (Redirect::state(full));
999 node->add_property ("type", "port");
1000 snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
1001 node->add_property ("bitslot", buf);
1007 PortInsert::set_state(const XMLNode& node)
1009 XMLNodeList nlist = node.children();
1010 XMLNodeIterator niter;
1011 XMLPropertyList plist;
1012 const XMLProperty *prop;
1014 if ((prop = node.property ("type")) == 0) {
1015 error << _("XML node describing insert is missing the `type' field") << endmsg;
1019 if (prop->value() != "port") {
1020 error << _("non-port insert XML used for port plugin insert") << endmsg;
1024 if ((prop = node.property ("bitslot")) == 0) {
1025 bitslot = _session.next_insert_id();
1027 uint32_t old_bitslot = bitslot;
1028 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
1030 if (old_bitslot != bitslot) {
1031 _session.mark_insert_id (bitslot);
1035 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1036 if ((*niter)->name() == Redirect::state_node_name) {
1037 Redirect::set_state (**niter);
1042 if (niter == nlist.end()) {
1043 error << _("XML node describing insert is missing a Redirect node") << endmsg;
1051 PortInsert::latency()
1053 /* because we deliver and collect within the same cycle,
1054 all I/O is necessarily delayed by at least frames_per_cycle().
1056 if the return port for insert has its own latency, we
1057 need to take that into account too.
1060 return _session.engine().frames_per_cycle() + input_latency();
1064 PortInsert::can_support_input_configuration (int32_t in) const
1066 if (input_maximum() == -1 && output_maximum() == -1) {
1068 /* not configured yet */
1070 return 1; /* we can support anything the first time we're asked */
1074 /* the "input" config for a port insert corresponds to how
1075 many output ports it will have.
1078 if (output_maximum() == in) {
1087 PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
1089 /* do not allow configuration to be changed outside the range of
1090 the last request config. or something like that.
1094 /* this is a bit odd:
1096 the number of inputs we are required to handle corresponds
1097 to the number of output ports we need.
1099 the number of outputs we are required to have corresponds
1100 to the number of input ports we need.
1103 set_output_maximum (in);
1104 set_output_minimum (in);
1105 set_input_maximum (out);
1106 set_input_minimum (out);
1116 return ensure_io (out, in, false, this);
1120 PortInsert::compute_output_streams (int32_t cnt) const
1122 /* puzzling, eh? think about it ... */
1127 PortInsert::output_streams() const
1133 PortInsert::input_streams() const
1135 return n_outputs ();