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 RedirectCreated (this); /* EMIT SIGNAL */
86 PluginInsert::PluginInsert (Session& s, const XMLNode& node)
87 : Insert (s, "will change", PreFader)
89 if (set_state (node)) {
90 throw failed_constructor();
93 _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
96 PluginInsert::PluginInsert (const PluginInsert& other)
97 : Insert (other._session, other.plugin()->name(), other.placement())
99 uint32_t count = other._plugins.size();
101 /* make as many copies as requested */
102 for (uint32_t n = 0; n < count; ++n) {
103 _plugins.push_back (plugin_factory (other.plugin (n)));
107 _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
111 RedirectCreated (this); /* EMIT SIGNAL */
115 PluginInsert::set_count (uint32_t num)
117 bool require_state = !_plugins.empty();
119 /* this is a bad idea.... we shouldn't do this while active.
120 only a route holding their redirect_lock should be calling this
125 } else if (num > _plugins.size()) {
126 uint32_t diff = num - _plugins.size();
128 for (uint32_t n = 0; n < diff; ++n) {
129 _plugins.push_back (plugin_factory (_plugins[0]));
132 /* XXX do something */
136 } else if (num < _plugins.size()) {
137 uint32_t diff = _plugins.size() - num;
138 for (uint32_t n= 0; n < diff; ++n) {
147 PluginInsert::init ()
152 PluginInsert::~PluginInsert ()
154 GoingAway (); /* EMIT SIGNAL */
158 PluginInsert::automation_list_creation_callback (uint32_t which, AutomationList& alist)
160 alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
164 PluginInsert::auto_state_changed (uint32_t which)
166 AutomationList& alist (automation_list (which));
168 if (alist.automation_state() != Off) {
169 _plugins[0]->set_parameter (which, alist.eval (_session.transport_frame()));
174 PluginInsert::output_streams() const
176 int32_t out = _plugins[0]->get_info()->n_outputs;
179 return _plugins[0]->output_streams ();
181 return out * _plugins.size();
186 PluginInsert::input_streams() const
188 int32_t in = _plugins[0]->get_info()->n_inputs;
191 return _plugins[0]->input_streams ();
193 return in * _plugins.size();
198 PluginInsert::natural_output_streams() const
200 return _plugins[0]->get_info()->n_outputs;
204 PluginInsert::natural_input_streams() const
206 return _plugins[0]->get_info()->n_inputs;
210 PluginInsert::is_generator() const
212 /* XXX more finesse is possible here. VST plugins have a
213 a specific "instrument" flag, for example.
216 return _plugins[0]->get_info()->n_inputs == 0;
220 PluginInsert::set_automatable ()
222 /* fill the parameter automation list with null AutomationLists */
224 parameter_automation.assign (_plugins.front()->parameter_count(), (AutomationList*) 0);
228 a = _plugins.front()->automatable ();
230 for (set<uint32_t>::iterator i = a.begin(); i != a.end(); ++i) {
236 PluginInsert::parameter_changed (uint32_t which, float val)
238 vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
240 /* don't set the first plugin, just all the slaves */
242 if (i != _plugins.end()) {
244 for (; i != _plugins.end(); ++i) {
245 (*i)->set_parameter (which, val);
251 PluginInsert::set_block_size (nframes_t nframes)
253 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
254 (*i)->set_block_size (nframes);
259 PluginInsert::activate ()
261 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
267 PluginInsert::deactivate ()
269 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
275 PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now)
277 int32_t in_index = 0;
278 int32_t out_index = 0;
280 /* Note that we've already required that plugins
281 be able to handle in-place processing.
286 vector<AutomationList*>::iterator li;
289 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
291 AutomationList* alist = *li;
293 if (alist && alist->automation_playback()) {
296 float val = alist->rt_safe_eval (now, valid);
299 /* set the first plugin, the others will be set via signals */
300 _plugins[0]->set_parameter (n, val);
307 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
308 (*i)->connect_and_run (bufs, nbufs, in_index, out_index, nframes, offset);
311 /* leave remaining channel buffers alone */
315 PluginInsert::automation_snapshot (nframes_t now, bool force)
317 vector<AutomationList*>::iterator li;
320 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
322 AutomationList *alist = *li;
324 if (alist && alist->automation_write ()) {
326 float val = _plugins[0]->get_parameter (n);
327 alist->rt_add (now, val);
328 last_automation_snapshot = now;
334 PluginInsert::transport_stopped (nframes_t now)
336 vector<AutomationList*>::iterator li;
339 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
341 AutomationList* alist = *li;
344 alist->reposition_for_rt_add (now);
345 if (alist->automation_state() != Off) {
346 _plugins[0]->set_parameter (n, alist->eval (now));
353 PluginInsert::silence (nframes_t nframes, nframes_t offset)
355 int32_t in_index = 0;
356 int32_t out_index = 0;
360 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
362 (*i)->connect_and_run (_session.get_silent_buffers (n), n, in_index, out_index, nframes, offset);
368 PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
372 if (_session.transport_rolling()) {
373 automation_run (bufs, nbufs, nframes, offset);
375 connect_and_run (bufs, nbufs, nframes, offset, false);
380 uint32_t in = input_streams ();
381 uint32_t out = output_streams ();
385 /* not active, but something has make up for any channel count increase,
386 so copy the last buffer to the extras.
389 for (uint32_t n = out - in; n < out && n < nbufs; ++n) {
390 memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
397 PluginInsert::set_parameter (uint32_t port, float val)
399 /* the others will be set from the event triggered by this */
401 _plugins[0]->set_parameter (port, val);
403 if (automation_list (port).automation_write()) {
404 automation_list (port).add (_session.audible_frame(), val);
407 _session.set_dirty();
411 PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
413 ControlEvent next_event (0, 0.0f);
414 nframes_t now = _session.transport_frame ();
415 nframes_t end = now + nframes;
417 Glib::Mutex::Lock lm (_automation_lock, Glib::TRY_LOCK);
420 connect_and_run (bufs, nbufs, nframes, offset, false);
424 if (!find_next_event (now, end, next_event)) {
426 /* no events have a time within the relevant range */
428 connect_and_run (bufs, nbufs, nframes, offset, true, now);
432 nframes_t buffer_correct = 0;
435 nframes_t cnt = min (((nframes_t) ceil (next_event.when) - now), nframes);
437 // This is called first, but nframes = 256
438 connect_and_run (bufs, nbufs, cnt, offset, true, now);
443 buffer_correct += cnt;
445 for (uint32_t i = 0; i < nbufs; i++) {
449 if (!find_next_event (now, end, next_event)) {
454 /* cleanup anything that is left to do */
457 connect_and_run (bufs, nbufs, nframes, offset, true, now);
460 for (uint32_t i = 0; i < nbufs; i++) {
461 bufs[i] -= buffer_correct;
466 PluginInsert::default_parameter_value (uint32_t port)
468 if (_plugins.empty()) {
469 fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
474 return _plugins[0]->default_value (port);
478 PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
480 if (port < _plugins[0]->parameter_count()) {
482 AutomationList& al = automation_list (port);
484 if (s != al.automation_state()) {
485 al.set_automation_state (s);
486 _session.set_dirty ();
492 PluginInsert::get_port_automation_state (uint32_t port)
494 if (port < _plugins[0]->parameter_count()) {
495 return automation_list (port).automation_state();
502 PluginInsert::protect_automation ()
504 set<uint32_t> automated_params;
506 what_has_automation (automated_params);
508 for (set<uint32_t>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
510 AutomationList& al = automation_list (*i);
512 switch (al.automation_state()) {
514 al.set_automation_state (Off);
517 al.set_automation_state (Play);
525 boost::shared_ptr<Plugin>
526 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
528 boost::shared_ptr<LadspaPlugin> lp;
530 boost::shared_ptr<LV2Plugin> lv2p;
533 boost::shared_ptr<VSTPlugin> vp;
535 #ifdef HAVE_AUDIOUNITS
536 boost::shared_ptr<AUPlugin> ap;
539 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
540 return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
542 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
543 return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
546 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
547 return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
549 #ifdef HAVE_AUDIOUNITS
550 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
551 return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
555 fatal << string_compose (_("programming error: %1"),
556 X_("unknown plugin type in PluginInsert::plugin_factory"))
559 return boost::shared_ptr<Plugin> ((Plugin*) 0);
563 PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out)
567 if ((ret = set_count (magic)) < 0) {
571 /* if we're running replicated plugins, each plugin has
572 the same i/o configuration and we may need to announce how many
573 output streams there are.
575 if we running a single plugin, we need to configure it.
578 return _plugins[0]->configure_io (in, out);
582 PluginInsert::can_do (int32_t in, int32_t& out)
584 return _plugins[0]->can_do (in, out);
588 PluginInsert::get_state(void)
594 PluginInsert::state (bool full)
597 XMLNode *node = new XMLNode("Insert");
599 node->add_child_nocopy (Redirect::state (full));
601 node->add_property ("type", _plugins[0]->state_node_name());
602 node->add_property("unique-id", _plugins[0]->unique_id());
603 node->add_property("count", string_compose("%1", _plugins.size()));
604 node->add_child_nocopy (_plugins[0]->get_state());
606 /* add controllables */
608 XMLNode* control_node = new XMLNode (X_("controls"));
610 for (uint32_t x = 0; x < _plugins[0]->parameter_count(); ++x) {
611 Controllable* c = _plugins[0]->get_nth_control (x, true);
613 XMLNode& controllable_state (c->get_state());
614 controllable_state.add_property ("parameter", to_string (x, std::dec));
615 control_node->add_child_nocopy (controllable_state);
618 node->add_child_nocopy (*control_node);
620 /* add port automation state */
621 XMLNode *autonode = new XMLNode(port_automation_node_name);
622 set<uint32_t> automatable = _plugins[0]->automatable();
624 for (set<uint32_t>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
626 XMLNode* child = new XMLNode("port");
627 snprintf(buf, sizeof(buf), "%" PRIu32, *x);
628 child->add_property("number", string(buf));
631 LV2Plugin* lv2p = dynamic_cast<LV2Plugin*>(_plugins[0].get());
633 child->add_property("symbol", string(lv2p->port_symbol(*x)));
637 child->add_child_nocopy (automation_list (*x).state (full));
638 autonode->add_child_nocopy (*child);
641 node->add_child_nocopy (*autonode);
647 PluginInsert::set_state(const XMLNode& node)
649 XMLNodeList nlist = node.children();
650 XMLNodeIterator niter;
651 XMLPropertyList plist;
652 const XMLProperty *prop;
653 ARDOUR::PluginType type;
655 if ((prop = node.property ("type")) == 0) {
656 error << _("XML node describing insert is missing the `type' field") << endmsg;
660 if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
661 type = ARDOUR::LADSPA;
662 } else if (prop->value() == X_("lv2")) {
664 } else if (prop->value() == X_("vst")) {
666 } else if (prop->value() == X_("audiounit")) {
667 type = ARDOUR::AudioUnit;
669 error << string_compose (_("unknown plugin type %1 in plugin insert state"),
675 prop = node.property ("unique-id");
678 /* older sessions contain VST plugins with only an "id" field.
681 if (type == ARDOUR::VST) {
682 if (prop = node.property ("id")) {
689 error << _("Plugin has no unique ID field") << endmsg;
694 boost::shared_ptr<Plugin> plugin;
696 plugin = find_plugin (_session, prop->value(), type);
699 error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
700 "Perhaps it was removed or moved since it was last used."), prop->value())
707 if ((prop = node.property ("count")) != 0) {
708 sscanf (prop->value().c_str(), "%u", &count);
711 if (_plugins.size() != count) {
713 _plugins.push_back (plugin);
715 for (uint32_t n=1; n < count; ++n) {
716 _plugins.push_back (plugin_factory (plugin));
720 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
721 if ((*niter)->name() == plugin->state_node_name()) {
722 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
723 (*i)->set_state (**niter);
729 if (niter == nlist.end()) {
730 error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
734 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
735 if ((*niter)->name() == Redirect::state_node_name) {
736 Redirect::set_state (**niter);
741 if (niter == nlist.end()) {
742 error << _("XML node describing insert is missing a Redirect node") << endmsg;
746 /* look for controllables node */
748 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
750 if ((*niter)->name() != X_("controls")) {
754 XMLNodeList grandchildren ((*niter)->children());
756 XMLNodeIterator gciter;
759 for (gciter = grandchildren.begin(); gciter != grandchildren.end(); ++gciter) {
760 if ((prop = (*gciter)->property (X_("parameter"))) != 0) {
761 param = atoi (prop->value());
762 /* force creation of controllable for this parameter */
763 _plugins[0]->make_nth_control (param, **gciter);
772 /* look for port automation node */
774 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
776 if ((*niter)->name() != port_automation_node_name) {
782 XMLNodeConstIterator iter;
787 cnodes = (*niter)->children ("port");
789 for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
793 if ((cprop = child->property("number")) != 0) {
794 port = cprop->value().c_str();
796 warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
800 sscanf (port, "%" PRIu32, &port_id);
802 if (port_id >= _plugins[0]->parameter_count()) {
803 warning << _("PluginInsert: Auto: port id out of range") << endmsg;
807 if (!child->children().empty()) {
808 automation_list (port_id).set_state (*child->children().front());
810 if ((cprop = child->property("auto")) != 0) {
815 sscanf (cprop->value().c_str(), "0x%x", &x);
816 automation_list (port_id).set_automation_state (AutoState (x));
822 automation_list (port_id).set_automation_state (Off);
833 if (niter == nlist.end()) {
834 warning << string_compose(_("XML node describing a port automation is missing the `%1' information"), port_automation_node_name) << endmsg;
837 // The name of the PluginInsert comes from the plugin, nothing else
838 set_name(plugin->get_info()->name,this);
844 PluginInsert::describe_parameter (uint32_t what)
846 return _plugins[0]->describe_parameter (what);
850 PluginInsert::latency()
852 return _plugins[0]->latency ();
856 PluginInsert::type ()
858 boost::shared_ptr<LadspaPlugin> lp;
860 boost::shared_ptr<VSTPlugin> vp;
862 #ifdef HAVE_AUDIOUNITS
863 boost::shared_ptr<AUPlugin> ap;
866 boost::shared_ptr<LV2Plugin> lv2p;
869 PluginPtr other = plugin ();
871 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
872 return ARDOUR::LADSPA;
874 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
877 #ifdef HAVE_AUDIOUNITS
878 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
879 return ARDOUR::AudioUnit;
882 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
886 error << "Unknown plugin type" << endmsg;
888 return (ARDOUR::PluginType) 0;
892 /***************************************************************
893 Port inserts: send output to a port, pick up input at a port
894 ***************************************************************/
896 PortInsert::PortInsert (Session& s, Placement p)
897 : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
900 RedirectCreated (this); /* EMIT SIGNAL */
904 PortInsert::PortInsert (const PortInsert& other)
905 : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
908 RedirectCreated (this); /* EMIT SIGNAL */
916 PortInsert::PortInsert (Session& s, const XMLNode& node)
917 : Insert (s, "will change", PreFader)
919 bitslot = 0xffffffff;
920 if (set_state (node)) {
921 throw failed_constructor();
924 RedirectCreated (this); /* EMIT SIGNAL */
927 PortInsert::~PortInsert ()
933 PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
935 if (n_outputs() == 0) {
940 /* deliver silence */
941 silence (nframes, offset);
946 vector<Port*>::iterator o;
947 vector<Port*>::iterator i;
951 for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
952 memcpy ((*o)->get_buffer (nframes) + offset, bufs[min(nbufs,n)], sizeof (Sample) * nframes);
953 (*o)->mark_silence (false);
958 for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) {
959 memcpy (bufs[min(nbufs,n)], (*i)->get_buffer (nframes) + offset, sizeof (Sample) * nframes);
964 PortInsert::get_state(void)
970 PortInsert::state (bool full)
972 XMLNode *node = new XMLNode("Insert");
974 node->add_child_nocopy (Redirect::state(full));
975 node->add_property ("type", "port");
976 snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
977 node->add_property ("bitslot", buf);
983 PortInsert::set_state(const XMLNode& node)
985 XMLNodeList nlist = node.children();
986 XMLNodeIterator niter;
987 XMLPropertyList plist;
988 const XMLProperty *prop;
990 if ((prop = node.property ("type")) == 0) {
991 error << _("XML node describing insert is missing the `type' field") << endmsg;
995 if (prop->value() != "port") {
996 error << _("non-port insert XML used for port plugin insert") << endmsg;
1000 if ((prop = node.property ("bitslot")) == 0) {
1001 bitslot = _session.next_insert_id();
1003 uint32_t old_bitslot = bitslot;
1004 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
1006 if (old_bitslot != bitslot) {
1007 _session.mark_insert_id (bitslot);
1011 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1012 if ((*niter)->name() == Redirect::state_node_name) {
1013 Redirect::set_state (**niter);
1018 if (niter == nlist.end()) {
1019 error << _("XML node describing insert is missing a Redirect node") << endmsg;
1027 PortInsert::latency()
1029 /* because we deliver and collect within the same cycle,
1030 all I/O is necessarily delayed by at least frames_per_cycle().
1032 if the return port for insert has its own latency, we
1033 need to take that into account too.
1036 return _session.engine().frames_per_cycle() + input_latency();
1040 PortInsert::can_do (int32_t in, int32_t& out)
1042 if (input_maximum() == -1 && output_maximum() == -1) {
1044 /* not configured yet */
1051 /* the "input" config for a port insert corresponds to how
1052 many output ports it will have.
1055 if (output_maximum() == in) {
1065 PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
1067 /* do not allow configuration to be changed outside the range of
1068 the last request config. or something like that.
1071 set_output_maximum (in);
1072 set_output_minimum (in);
1073 set_input_maximum (out);
1074 set_input_minimum (out);
1076 /* this can be momentarily confusing:
1078 the number of inputs we are required to handle corresponds
1079 to the number of output ports we need.
1081 the number of outputs we are required to have corresponds
1082 to the number of input ports we need.
1093 return ensure_io (out, in, false, this);
1097 PortInsert::output_streams() const
1103 PortInsert::input_streams() const
1105 return n_outputs ();