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>
26 #include <pbd/stacktrace.h>
28 #include <ardour/insert.h>
29 #include <ardour/plugin.h>
30 #include <ardour/port.h>
31 #include <ardour/route.h>
32 #include <ardour/ladspa_plugin.h>
35 #include <ardour/lv2_plugin.h>
39 #include <ardour/vst_plugin.h>
42 #ifdef HAVE_AUDIOUNITS
43 #include <ardour/audio_unit.h>
46 #include <ardour/audioengine.h>
47 #include <ardour/session.h>
48 #include <ardour/types.h>
53 using namespace ARDOUR;
56 Insert::Insert(Session& s, string name, Placement p)
57 : Redirect (s, name, p)
61 Insert::Insert(Session& s, string name, Placement p, int imin, int imax, int omin, int omax)
62 : Redirect (s, name, p, imin, imax, omin, omax)
66 /***************************************************************
67 Plugin inserts: send data through a plugin
68 ***************************************************************/
70 const string PluginInsert::port_automation_node_name = "PortAutomation";
72 PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placement placement)
73 : Insert (s, plug->name(), placement)
75 /* the first is the master */
77 _plugins.push_back (plug);
79 _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
83 if (_plugins[0]->fixed_io()) {
84 Glib::Mutex::Lock em (_session.engine().process_lock());
85 IO::MoreOutputs (output_streams ());
88 RedirectCreated (this); /* EMIT SIGNAL */
91 PluginInsert::PluginInsert (Session& s, const XMLNode& node)
92 : Insert (s, "will change", PreFader)
94 if (set_state (node)) {
95 throw failed_constructor();
100 _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
102 if (_plugins[0]->fixed_io()) {
103 Glib::Mutex::Lock em (_session.engine().process_lock());
104 IO::MoreOutputs (output_streams());
108 PluginInsert::PluginInsert (const PluginInsert& other)
109 : Insert (other._session, other.plugin()->name(), other.placement())
111 uint32_t count = other._plugins.size();
113 /* make as many copies as requested */
114 for (uint32_t n = 0; n < count; ++n) {
115 _plugins.push_back (plugin_factory (other.plugin (n)));
119 _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
123 RedirectCreated (this); /* EMIT SIGNAL */
127 PluginInsert::set_count (uint32_t num)
129 bool require_state = !_plugins.empty();
131 /* this is a bad idea.... we shouldn't do this while active.
132 only a route holding their redirect_lock should be calling this
137 } else if (num > _plugins.size()) {
138 uint32_t diff = num - _plugins.size();
140 for (uint32_t n = 0; n < diff; ++n) {
141 _plugins.push_back (plugin_factory (_plugins[0]));
144 /* XXX do something */
148 } else if (num < _plugins.size()) {
149 uint32_t diff = _plugins.size() - num;
150 for (uint32_t n= 0; n < diff; ++n) {
159 PluginInsert::init ()
163 set<uint32_t>::iterator s;
166 PluginInsert::~PluginInsert ()
168 GoingAway (); /* EMIT SIGNAL */
172 PluginInsert::automation_list_creation_callback (uint32_t which, AutomationList& alist)
174 alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
178 PluginInsert::auto_state_changed (uint32_t which)
180 AutomationList& alist (automation_list (which));
182 if (alist.automation_state() != Off) {
183 _plugins[0]->set_parameter (which, alist.eval (_session.transport_frame()));
188 PluginInsert::output_streams() const
190 int32_t out = _plugins[0]->get_info()->n_outputs;
193 return _plugins[0]->output_streams ();
195 return out * _plugins.size();
200 PluginInsert::input_streams() const
202 int32_t in = _plugins[0]->get_info()->n_inputs;
204 return _plugins[0]->input_streams ();
206 return in * _plugins.size();
211 PluginInsert::natural_output_streams() const
213 return _plugins[0]->get_info()->n_outputs;
217 PluginInsert::natural_input_streams() const
219 return _plugins[0]->get_info()->n_inputs;
223 PluginInsert::is_generator() const
225 /* XXX more finesse is possible here. VST plugins have a
226 a specific "instrument" flag, for example.
229 return _plugins[0]->get_info()->n_inputs == 0;
233 PluginInsert::set_automatable ()
237 a = _plugins.front()->automatable ();
239 for (set<uint32_t>::iterator i = a.begin(); i != a.end(); ++i) {
245 PluginInsert::parameter_changed (uint32_t which, float val)
247 vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
249 /* don't set the first plugin, just all the slaves */
251 if (i != _plugins.end()) {
253 for (; i != _plugins.end(); ++i) {
254 (*i)->set_parameter (which, val);
260 PluginInsert::set_block_size (nframes_t nframes)
262 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
263 (*i)->set_block_size (nframes);
268 PluginInsert::activate ()
270 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
276 PluginInsert::deactivate ()
278 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
284 PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now)
286 int32_t in_index = 0;
287 int32_t out_index = 0;
289 /* Note that we've already required that plugins
290 be able to handle in-place processing.
295 map<uint32_t,AutomationList*>::iterator li;
298 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
300 AutomationList& alist (*((*li).second));
302 if (alist.automation_playback()) {
305 float val = alist.rt_safe_eval (now, valid);
308 /* set the first plugin, the others will be set via signals */
309 _plugins[0]->set_parameter ((*li).first, val);
316 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
317 (*i)->connect_and_run (bufs, nbufs, in_index, out_index, nframes, offset);
320 /* leave remaining channel buffers alone */
324 PluginInsert::automation_snapshot (nframes_t now, bool force)
326 map<uint32_t,AutomationList*>::iterator li;
328 for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
330 AutomationList *alist = ((*li).second);
331 if (alist != 0 && alist->automation_write ()) {
333 float val = _plugins[0]->get_parameter ((*li).first);
334 alist->rt_add (now, val);
335 last_automation_snapshot = now;
341 PluginInsert::transport_stopped (nframes_t now)
343 map<uint32_t,AutomationList*>::iterator li;
345 for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
346 AutomationList& alist (*(li->second));
347 alist.reposition_for_rt_add (now);
349 if (alist.automation_state() != Off) {
350 _plugins[0]->set_parameter (li->first, alist.eval (now));
356 PluginInsert::silence (nframes_t nframes, nframes_t offset)
358 int32_t in_index = 0;
359 int32_t out_index = 0;
363 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
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 = input_streams ();
384 uint32_t out = output_streams ();
388 /* not active, but something has make up for any channel count increase,
389 so copy the last buffer to the extras.
392 for (uint32_t n = out - in; n < out && n < nbufs; ++n) {
393 memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
400 PluginInsert::set_parameter (uint32_t port, float val)
402 /* the others will be set from the event triggered by this */
404 _plugins[0]->set_parameter (port, val);
406 if (automation_list (port).automation_write()) {
407 automation_list (port).add (_session.audible_frame(), val);
410 _session.set_dirty();
414 PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
416 ControlEvent next_event (0, 0.0f);
417 nframes_t now = _session.transport_frame ();
418 nframes_t end = now + nframes;
420 Glib::Mutex::Lock lm (_automation_lock, Glib::TRY_LOCK);
423 connect_and_run (bufs, nbufs, nframes, offset, false);
427 if (!find_next_event (now, end, next_event)) {
429 /* no events have a time within the relevant range */
431 connect_and_run (bufs, nbufs, nframes, offset, true, now);
437 nframes_t cnt = min (((nframes_t) ceil (next_event.when) - now), nframes);
439 connect_and_run (bufs, nbufs, cnt, offset, true, now);
445 if (!find_next_event (now, end, next_event)) {
450 /* cleanup anything that is left to do */
453 connect_and_run (bufs, nbufs, nframes, offset, true, now);
458 PluginInsert::default_parameter_value (uint32_t port)
460 if (_plugins.empty()) {
461 fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
466 return _plugins[0]->default_value (port);
470 PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
472 if (port < _plugins[0]->parameter_count()) {
474 AutomationList& al = automation_list (port);
476 if (s != al.automation_state()) {
477 al.set_automation_state (s);
478 _session.set_dirty ();
484 PluginInsert::get_port_automation_state (uint32_t port)
486 if (port < _plugins[0]->parameter_count()) {
487 return automation_list (port).automation_state();
494 PluginInsert::protect_automation ()
496 set<uint32_t> automated_params;
498 what_has_automation (automated_params);
500 for (set<uint32_t>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
502 AutomationList& al = automation_list (*i);
504 switch (al.automation_state()) {
506 al.set_automation_state (Off);
509 al.set_automation_state (Play);
517 boost::shared_ptr<Plugin>
518 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
520 boost::shared_ptr<LadspaPlugin> lp;
522 boost::shared_ptr<LV2Plugin> lv2p;
525 boost::shared_ptr<VSTPlugin> vp;
527 #ifdef HAVE_AUDIOUNITS
528 boost::shared_ptr<AUPlugin> ap;
531 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
532 return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
534 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
535 return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
538 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
539 return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
541 #ifdef HAVE_AUDIOUNITS
542 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
543 return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
547 fatal << string_compose (_("programming error: %1"),
548 X_("unknown plugin type in PluginInsert::plugin_factory"))
551 return boost::shared_ptr<Plugin> ((Plugin*) 0);
555 PluginInsert::compute_output_streams (int32_t cnt) const
559 if ((outputs = _plugins[0]->get_info()->n_outputs) < 0) {
560 // have to ask the plugin itself, because it has flexible I/O
561 return _plugins[0]->compute_output_streams (cnt);
564 return outputs * cnt;
568 PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out)
570 return set_count (magic);
574 PluginInsert::can_support_input_configuration (int32_t in) const
576 int32_t outputs = _plugins[0]->get_info()->n_outputs;
577 int32_t inputs = _plugins[0]->get_info()->n_inputs;
579 if (outputs < 0 || inputs < 0) {
580 /* have to ask the plugin because its got reconfigurable I/O
582 return _plugins[0]->can_support_input_configuration (in);
587 /* instrument plugin, always legal, but it throws
588 away any existing active streams.
594 if (outputs == 1 && inputs == 1) {
595 /* mono plugin, replicate as needed */
604 if ((inputs < in) && (inputs % in == 0)) {
606 /* number of inputs is a factor of the requested input
607 configuration, so we can replicate.
619 PluginInsert::get_state(void)
625 PluginInsert::state (bool full)
628 XMLNode *node = new XMLNode("Insert");
630 node->add_child_nocopy (Redirect::state (full));
632 node->add_property ("type", _plugins[0]->state_node_name());
633 node->add_property("unique-id", _plugins[0]->unique_id());
634 node->add_property("count", string_compose("%1", _plugins.size()));
635 node->add_child_nocopy (_plugins[0]->get_state());
637 /* add controllables */
639 XMLNode* control_node = new XMLNode (X_("controls"));
641 for (uint32_t x = 0; x < _plugins[0]->parameter_count(); ++x) {
642 Controllable* c = _plugins[0]->get_nth_control (x, true);
644 XMLNode& controllable_state (c->get_state());
645 controllable_state.add_property ("parameter", to_string (x, std::dec));
646 control_node->add_child_nocopy (controllable_state);
649 node->add_child_nocopy (*control_node);
651 /* add port automation state */
652 XMLNode *autonode = new XMLNode(port_automation_node_name);
653 set<uint32_t> automatable = _plugins[0]->automatable();
655 for (set<uint32_t>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
657 XMLNode* child = new XMLNode("port");
658 snprintf(buf, sizeof(buf), "%" PRIu32, *x);
659 child->add_property("number", string(buf));
661 child->add_child_nocopy (automation_list (*x).state (full));
662 autonode->add_child_nocopy (*child);
665 node->add_child_nocopy (*autonode);
671 PluginInsert::set_state(const XMLNode& node)
673 XMLNodeList nlist = node.children();
674 XMLNodeIterator niter;
675 XMLPropertyList plist;
676 const XMLProperty *prop;
677 ARDOUR::PluginType type;
679 if ((prop = node.property ("type")) == 0) {
680 error << _("XML node describing insert is missing the `type' field") << endmsg;
684 if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
685 type = ARDOUR::LADSPA;
686 } else if (prop->value() == X_("lv2")) {
688 } else if (prop->value() == X_("vst")) {
690 } else if (prop->value() == X_("audiounit")) {
691 type = ARDOUR::AudioUnit;
693 error << string_compose (_("unknown plugin type %1 in plugin insert state"),
699 prop = node.property ("unique-id");
702 /* older sessions contain VST plugins with only an "id" field.
705 if (type == ARDOUR::VST) {
706 if (prop = node.property ("id")) {
713 error << _("Plugin has no unique ID field") << endmsg;
718 boost::shared_ptr<Plugin> plugin;
720 plugin = find_plugin (_session, prop->value(), type);
723 error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
724 "Perhaps it was removed or moved since it was last used."), prop->value())
731 if ((prop = node.property ("count")) != 0) {
732 sscanf (prop->value().c_str(), "%u", &count);
735 if (_plugins.size() != count) {
737 _plugins.push_back (plugin);
739 for (uint32_t n=1; n < count; ++n) {
740 _plugins.push_back (plugin_factory (plugin));
744 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
745 if ((*niter)->name() == plugin->state_node_name()) {
746 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
747 (*i)->set_state (**niter);
753 if (niter == nlist.end()) {
754 error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
758 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
759 if ((*niter)->name() == Redirect::state_node_name) {
760 Redirect::set_state (**niter);
765 if (niter == nlist.end()) {
766 error << _("XML node describing insert is missing a Redirect node") << endmsg;
770 /* look for controllables node */
772 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
774 if ((*niter)->name() != X_("controls")) {
778 XMLNodeList grandchildren ((*niter)->children());
780 XMLNodeIterator gciter;
783 for (gciter = grandchildren.begin(); gciter != grandchildren.end(); ++gciter) {
784 if ((prop = (*gciter)->property (X_("parameter"))) != 0) {
785 param = atoi (prop->value());
786 /* force creation of controllable for this parameter */
787 _plugins[0]->make_nth_control (param, **gciter);
794 /* look for port automation node */
796 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
798 if ((*niter)->name() != port_automation_node_name) {
804 XMLNodeConstIterator iter;
809 cnodes = (*niter)->children ("port");
811 for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
815 if ((cprop = child->property("number")) != 0) {
816 port = cprop->value().c_str();
818 warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
822 sscanf (port, "%" PRIu32, &port_id);
824 if (port_id >= _plugins[0]->parameter_count()) {
825 warning << _("PluginInsert: Auto: port id out of range") << endmsg;
829 if (!child->children().empty()) {
830 automation_list (port_id).set_state (*child->children().front());
832 if ((cprop = child->property("auto")) != 0) {
837 sscanf (cprop->value().c_str(), "0x%x", &x);
838 automation_list (port_id).set_automation_state (AutoState (x));
844 automation_list (port_id).set_automation_state (Off);
855 if (niter == nlist.end()) {
856 warning << string_compose(_("XML node describing a port automation is missing the `%1' information"), port_automation_node_name) << endmsg;
859 // The name of the PluginInsert comes from the plugin, nothing else
860 set_name(plugin->get_info()->name,this);
866 PluginInsert::describe_parameter (uint32_t what)
868 return _plugins[0]->describe_parameter (what);
872 PluginInsert::latency()
874 return _plugins[0]->latency ();
878 PluginInsert::type ()
880 boost::shared_ptr<LadspaPlugin> lp;
882 boost::shared_ptr<VSTPlugin> vp;
884 #ifdef HAVE_AUDIOUNITS
885 boost::shared_ptr<AUPlugin> ap;
888 PluginPtr other = plugin ();
890 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
891 return ARDOUR::LADSPA;
893 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
896 #ifdef HAVE_AUDIOUNITS
897 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
898 return ARDOUR::AudioUnit;
902 return (ARDOUR::PluginType) 0;
906 /***************************************************************
907 Port inserts: send output to a port, pick up input at a port
908 ***************************************************************/
910 PortInsert::PortInsert (Session& s, Placement p)
911 : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
914 RedirectCreated (this); /* EMIT SIGNAL */
918 PortInsert::PortInsert (const PortInsert& other)
919 : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
922 RedirectCreated (this); /* EMIT SIGNAL */
930 PortInsert::PortInsert (Session& s, const XMLNode& node)
931 : Insert (s, "will change", PreFader)
933 bitslot = 0xffffffff;
934 if (set_state (node)) {
935 throw failed_constructor();
938 RedirectCreated (this); /* EMIT SIGNAL */
941 PortInsert::~PortInsert ()
947 PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
949 if (n_outputs() == 0) {
954 /* deliver silence */
955 silence (nframes, offset);
960 vector<Port*>::iterator o;
961 vector<Port*>::iterator i;
965 for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
966 memcpy ((*o)->get_buffer (nframes) + offset, bufs[min(nbufs,n)], sizeof (Sample) * nframes);
967 (*o)->mark_silence (false);
972 for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) {
973 memcpy (bufs[min(nbufs,n)], (*i)->get_buffer (nframes) + offset, sizeof (Sample) * nframes);
978 PortInsert::get_state(void)
984 PortInsert::state (bool full)
986 XMLNode *node = new XMLNode("Insert");
988 node->add_child_nocopy (Redirect::state(full));
989 node->add_property ("type", "port");
990 snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
991 node->add_property ("bitslot", buf);
997 PortInsert::set_state(const XMLNode& node)
999 XMLNodeList nlist = node.children();
1000 XMLNodeIterator niter;
1001 XMLPropertyList plist;
1002 const XMLProperty *prop;
1004 if ((prop = node.property ("type")) == 0) {
1005 error << _("XML node describing insert is missing the `type' field") << endmsg;
1009 if (prop->value() != "port") {
1010 error << _("non-port insert XML used for port plugin insert") << endmsg;
1014 if ((prop = node.property ("bitslot")) == 0) {
1015 bitslot = _session.next_insert_id();
1017 uint32_t old_bitslot = bitslot;
1018 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
1020 if (old_bitslot != bitslot) {
1021 _session.mark_insert_id (bitslot);
1025 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1026 if ((*niter)->name() == Redirect::state_node_name) {
1027 Redirect::set_state (**niter);
1032 if (niter == nlist.end()) {
1033 error << _("XML node describing insert is missing a Redirect node") << endmsg;
1041 PortInsert::latency()
1043 /* because we deliver and collect within the same cycle,
1044 all I/O is necessarily delayed by at least frames_per_cycle().
1046 if the return port for insert has its own latency, we
1047 need to take that into account too.
1050 return _session.engine().frames_per_cycle() + input_latency();
1054 PortInsert::can_support_input_configuration (int32_t in) const
1056 if (input_maximum() == -1 && output_maximum() == -1) {
1058 /* not configured yet */
1060 return in; /* we can support anything the first time we're asked */
1064 /* the "input" config for a port insert corresponds to how
1065 many output ports it will have.
1068 if (output_maximum() == in) {
1077 PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
1079 /* do not allow configuration to be changed outside the range of
1080 the last request config. or something like that.
1083 set_output_maximum (in);
1084 set_output_minimum (in);
1085 set_input_maximum (out);
1086 set_input_minimum (out);
1088 /* this can be momentarily confusing:
1090 the number of inputs we are required to handle corresponds
1091 to the number of output ports we need.
1093 the number of outputs we are required to have corresponds
1094 to the number of input ports we need.
1105 return ensure_io (out, in, false, this);
1109 PortInsert::compute_output_streams (int32_t cnt) const
1111 if (n_inputs() == 0) {
1112 /* not configured yet */
1116 /* puzzling, eh? think about it ... */
1121 PortInsert::output_streams() const
1127 PortInsert::input_streams() const
1129 return n_outputs ();