merge from thirdparty rubberband 1.3 @ 4901
[ardour2.git] / libs / ardour / insert.cc
blobe748e4bb2970e597341562638cd1541885723d47
1 /*
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.
20 #include <string>
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>
34 #ifdef HAVE_SLV2
35 #include <ardour/lv2_plugin.h>
36 #endif
38 #ifdef VST_SUPPORT
39 #include <ardour/vst_plugin.h>
40 #endif
42 #ifdef HAVE_AUDIOUNITS
43 #include <ardour/audio_unit.h>
44 #endif
46 #include <ardour/audioengine.h>
47 #include <ardour/session.h>
48 #include <ardour/types.h>
50 #include "i18n.h"
52 using namespace std;
53 using namespace ARDOUR;
54 using namespace PBD;
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));
81 init ();
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));
109 init ();
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
123 if (num == 0) {
124 return -1;
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]));
131 if (require_state) {
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) {
139 _plugins.pop_back();
143 return 0;
146 void
147 PluginInsert::init ()
149 set_automatable ();
152 PluginInsert::~PluginInsert ()
154 GoingAway (); /* EMIT SIGNAL */
157 void
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)));
163 void
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()));
173 uint32_t
174 PluginInsert::output_streams() const
176 int32_t out = _plugins[0]->get_info()->n_outputs;
178 if (out < 0) {
179 return _plugins[0]->output_streams ();
180 } else {
181 return out * _plugins.size();
185 uint32_t
186 PluginInsert::input_streams() const
188 int32_t in = _plugins[0]->get_info()->n_inputs;
190 if (in < 0) {
191 return _plugins[0]->input_streams ();
192 } else {
193 return in * _plugins.size();
197 uint32_t
198 PluginInsert::natural_output_streams() const
200 return _plugins[0]->get_info()->n_outputs;
203 uint32_t
204 PluginInsert::natural_input_streams() const
206 return _plugins[0]->get_info()->n_inputs;
209 bool
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;
219 void
220 PluginInsert::set_automatable ()
222 /* fill the parameter automation list with null AutomationLists */
224 parameter_automation.assign (_plugins.front()->parameter_count(), (AutomationList*) 0);
226 set<uint32_t> a;
228 a = _plugins.front()->automatable ();
230 for (set<uint32_t>::iterator i = a.begin(); i != a.end(); ++i) {
231 can_automate (*i);
235 void
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()) {
243 ++i;
244 for (; i != _plugins.end(); ++i) {
245 (*i)->set_parameter (which, val);
250 void
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);
258 void
259 PluginInsert::activate ()
261 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
262 (*i)->activate ();
266 void
267 PluginInsert::deactivate ()
269 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
270 (*i)->deactivate ();
274 void
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.
284 // cerr << "Connect and run for " << _plugins[0]->name() << " auto ? " << with_auto << " nf = " << nframes << " off = " << offset << endl;
286 if (with_auto) {
288 vector<AutomationList*>::iterator li;
289 uint32_t n;
291 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
293 AutomationList* alist = *li;
295 if (alist && alist->automation_playback()) {
296 bool valid;
298 float val = alist->rt_safe_eval (now, valid);
300 if (valid) {
301 /* set the first plugin, the others will be set via signals */
302 // cerr << "\t@ " << now << " param[" << n << "] = " << val << endl;
303 _plugins[0]->set_parameter (n, val);
310 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
311 // cerr << "\trun C&R with in = " << in_index << " out = " << out_index << " nf = " << nframes << " off = " << offset << endl;
312 (*i)->connect_and_run (bufs, nbufs, in_index, out_index, nframes, offset);
315 /* leave remaining channel buffers alone */
316 // cerr << "--- and out\n";
319 void
320 PluginInsert::automation_snapshot (nframes_t now, bool force)
322 vector<AutomationList*>::iterator li;
323 uint32_t n;
325 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
327 AutomationList *alist = *li;
329 if (alist && alist->automation_write ()) {
331 float val = _plugins[0]->get_parameter (n);
332 alist->rt_add (now, val);
333 last_automation_snapshot = now;
338 void
339 PluginInsert::transport_stopped (nframes_t now)
341 vector<AutomationList*>::iterator li;
342 uint32_t n;
344 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
346 AutomationList* alist = *li;
348 if (alist) {
349 alist->reposition_for_rt_add (now);
350 if (alist->automation_state() != Off) {
351 _plugins[0]->set_parameter (n, alist->eval (now));
357 void
358 PluginInsert::silence (nframes_t nframes, nframes_t offset)
360 int32_t in_index = 0;
361 int32_t out_index = 0;
362 int32_t n;
364 if (active()) {
365 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
366 n = input_streams();
367 (*i)->connect_and_run (_session.get_silent_buffers (n), n, in_index, out_index, nframes, offset);
372 void
373 PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
375 if (active()) {
377 if (_session.transport_rolling()) {
378 automation_run (bufs, nbufs, nframes, offset);
379 } else {
380 connect_and_run (bufs, nbufs, nframes, offset, false);
383 } else {
385 uint32_t in = input_streams ();
386 uint32_t out = output_streams ();
388 if (out > in) {
390 /* not active, but something has make up for any channel count increase,
391 so copy the last buffer to the extras.
394 for (uint32_t n = out - in; n < out && n < nbufs; ++n) {
395 memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
401 void
402 PluginInsert::set_parameter (uint32_t port, float val)
404 /* the others will be set from the event triggered by this */
406 _plugins[0]->set_parameter (port, val);
408 if (automation_list (port).automation_write()) {
409 automation_list (port).add (_session.audible_frame(), val);
412 _session.set_dirty();
415 void
416 PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
418 ControlEvent next_event (0, 0.0f);
419 nframes_t now = _session.transport_frame ();
420 nframes_t end = now + nframes;
422 Glib::Mutex::Lock lm (_automation_lock, Glib::TRY_LOCK);
424 if (!lm.locked()) {
425 connect_and_run (bufs, nbufs, nframes, offset, false);
426 return;
429 if (!find_next_event (now, end, next_event)) {
431 /* no events have a time within the relevant range */
433 connect_and_run (bufs, nbufs, nframes, offset, true, now);
434 return;
437 nframes_t buffer_correct = 0;
439 while (nframes) {
440 nframes_t cnt = min (((nframes_t) ceil (next_event.when) - now), nframes);
442 // This is called first, but nframes = 256
443 connect_and_run (bufs, nbufs, cnt, offset, true, now);
445 nframes -= cnt;
446 now += cnt;
447 buffer_correct += cnt;
449 /* we are going to advance the buffer pointers by "cnt" so there
450 is no reason to specify a non-zero offset anymore.
453 offset = 0;
455 for (uint32_t i = 0; i < nbufs; i++) {
456 bufs[i] += cnt;
459 if (!find_next_event (now, end, next_event)) {
460 break;
464 /* cleanup anything that is left to do */
466 if (nframes) {
467 connect_and_run (bufs, nbufs, nframes, offset, true, now);
470 for (uint32_t i = 0; i < nbufs; i++) {
471 bufs[i] -= buffer_correct;
475 float
476 PluginInsert::default_parameter_value (uint32_t port)
478 if (_plugins.empty()) {
479 fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
480 << endmsg;
481 /*NOTREACHED*/
484 return _plugins[0]->default_value (port);
487 void
488 PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
490 if (port < _plugins[0]->parameter_count()) {
492 AutomationList& al = automation_list (port);
494 if (s != al.automation_state()) {
495 al.set_automation_state (s);
496 _session.set_dirty ();
501 AutoState
502 PluginInsert::get_port_automation_state (uint32_t port)
504 if (port < _plugins[0]->parameter_count()) {
505 return automation_list (port).automation_state();
506 } else {
507 return Off;
511 void
512 PluginInsert::protect_automation ()
514 set<uint32_t> automated_params;
516 what_has_automation (automated_params);
518 for (set<uint32_t>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
520 AutomationList& al = automation_list (*i);
522 switch (al.automation_state()) {
523 case Write:
524 al.set_automation_state (Off);
525 break;
526 case Touch:
527 al.set_automation_state (Play);
528 break;
529 default:
530 break;
535 boost::shared_ptr<Plugin>
536 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
538 boost::shared_ptr<LadspaPlugin> lp;
539 #ifdef HAVE_SLV2
540 boost::shared_ptr<LV2Plugin> lv2p;
541 #endif
542 #ifdef VST_SUPPORT
543 boost::shared_ptr<VSTPlugin> vp;
544 #endif
545 #ifdef HAVE_AUDIOUNITS
546 boost::shared_ptr<AUPlugin> ap;
547 #endif
549 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
550 return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
551 #ifdef HAVE_SLV2
552 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
553 return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
554 #endif
555 #ifdef VST_SUPPORT
556 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
557 return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
558 #endif
559 #ifdef HAVE_AUDIOUNITS
560 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
561 return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
562 #endif
565 fatal << string_compose (_("programming error: %1"),
566 X_("unknown plugin type in PluginInsert::plugin_factory"))
567 << endmsg;
568 /*NOTREACHED*/
569 return boost::shared_ptr<Plugin> ((Plugin*) 0);
572 int32_t
573 PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out)
575 int32_t ret;
577 if ((ret = set_count (magic)) < 0) {
578 return ret;
581 /* if we're running replicated plugins, each plugin has
582 the same i/o configuration and we may need to announce how many
583 output streams there are.
585 if we running a single plugin, we need to configure it.
588 return _plugins[0]->configure_io (in, out);
591 int32_t
592 PluginInsert::can_do (int32_t in, int32_t& out)
594 return _plugins[0]->can_do (in, out);
597 XMLNode&
598 PluginInsert::get_state(void)
600 return state (true);
603 XMLNode&
604 PluginInsert::state (bool full)
606 char buf[256];
607 XMLNode *node = new XMLNode("Insert");
609 node->add_child_nocopy (Redirect::state (full));
611 node->add_property ("type", _plugins[0]->state_node_name());
612 node->add_property("unique-id", _plugins[0]->unique_id());
613 node->add_property("count", string_compose("%1", _plugins.size()));
614 node->add_child_nocopy (_plugins[0]->get_state());
616 /* add controllables */
618 XMLNode* control_node = new XMLNode (X_("controls"));
620 for (uint32_t x = 0; x < _plugins[0]->parameter_count(); ++x) {
621 Controllable* c = _plugins[0]->get_nth_control (x, true);
622 if (c) {
623 XMLNode& controllable_state (c->get_state());
624 controllable_state.add_property ("parameter", to_string (x, std::dec));
625 control_node->add_child_nocopy (controllable_state);
628 node->add_child_nocopy (*control_node);
630 /* add port automation state */
631 XMLNode *autonode = new XMLNode(port_automation_node_name);
632 set<uint32_t> automatable = _plugins[0]->automatable();
634 for (set<uint32_t>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
636 XMLNode* child = new XMLNode("port");
637 snprintf(buf, sizeof(buf), "%" PRIu32, *x);
638 child->add_property("number", string(buf));
640 #ifdef HAVE_SLV2
641 LV2Plugin* lv2p = dynamic_cast<LV2Plugin*>(_plugins[0].get());
642 if (lv2p) {
643 child->add_property("symbol", string(lv2p->port_symbol(*x)));
645 #endif
647 child->add_child_nocopy (automation_list (*x).state (full));
648 autonode->add_child_nocopy (*child);
651 node->add_child_nocopy (*autonode);
653 return *node;
657 PluginInsert::set_state(const XMLNode& node)
659 XMLNodeList nlist = node.children();
660 XMLNodeIterator niter;
661 XMLPropertyList plist;
662 const XMLProperty *prop;
663 ARDOUR::PluginType type;
665 if ((prop = node.property ("type")) == 0) {
666 error << _("XML node describing insert is missing the `type' field") << endmsg;
667 return -1;
670 if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
671 type = ARDOUR::LADSPA;
672 } else if (prop->value() == X_("lv2")) {
673 type = ARDOUR::LV2;
674 } else if (prop->value() == X_("vst")) {
675 type = ARDOUR::VST;
676 } else if (prop->value() == X_("audiounit")) {
677 type = ARDOUR::AudioUnit;
678 } else {
679 error << string_compose (_("unknown plugin type %1 in plugin insert state"),
680 prop->value())
681 << endmsg;
682 return -1;
685 prop = node.property ("unique-id");
686 if (prop == 0) {
687 #ifdef VST_SUPPORT
688 /* older sessions contain VST plugins with only an "id" field.
691 if (type == ARDOUR::VST) {
692 prop = node.property ("id");
694 #endif
695 /* recheck */
697 if (prop == 0) {
698 error << _("Plugin has no unique ID field") << endmsg;
699 return -1;
703 boost::shared_ptr<Plugin> plugin;
705 plugin = find_plugin (_session, prop->value(), type);
707 if (plugin == 0) {
708 error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
709 "Perhaps it was removed or moved since it was last used."), prop->value())
710 << endmsg;
711 return -1;
714 uint32_t count = 1;
716 if ((prop = node.property ("count")) != 0) {
717 sscanf (prop->value().c_str(), "%u", &count);
720 if (_plugins.size() != count) {
722 _plugins.push_back (plugin);
724 for (uint32_t n=1; n < count; ++n) {
725 _plugins.push_back (plugin_factory (plugin));
729 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
730 if ((*niter)->name() == plugin->state_node_name()) {
731 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
732 (*i)->set_state (**niter);
734 break;
738 if (niter == nlist.end()) {
739 error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
740 return -1;
743 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
744 if ((*niter)->name() == Redirect::state_node_name) {
745 Redirect::set_state (**niter);
746 break;
750 if (niter == nlist.end()) {
751 error << _("XML node describing insert is missing a Redirect node") << endmsg;
752 return -1;
755 /* look for controllables node */
757 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
759 if ((*niter)->name() != X_("controls")) {
760 continue;
763 XMLNodeList grandchildren ((*niter)->children());
764 XMLProperty* prop;
765 XMLNodeIterator gciter;
766 uint32_t param;
768 for (gciter = grandchildren.begin(); gciter != grandchildren.end(); ++gciter) {
769 if ((prop = (*gciter)->property (X_("parameter"))) != 0) {
770 param = atoi (prop->value());
771 /* force creation of controllable for this parameter */
772 _plugins[0]->make_nth_control (param, **gciter);
776 break;
779 set_automatable ();
781 /* look for port automation node */
783 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
785 if ((*niter)->name() != port_automation_node_name) {
786 continue;
789 XMLNodeList cnodes;
790 XMLProperty *cprop;
791 XMLNodeConstIterator iter;
792 XMLNode *child;
793 const char *port;
794 uint32_t port_id;
796 cnodes = (*niter)->children ("port");
798 for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
800 child = *iter;
802 if ((cprop = child->property("number")) != 0) {
803 port = cprop->value().c_str();
804 } else {
805 warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
806 continue;
809 sscanf (port, "%" PRIu32, &port_id);
811 if (port_id >= _plugins[0]->parameter_count()) {
812 warning << _("PluginInsert: Auto: port id out of range") << endmsg;
813 continue;
816 if (!child->children().empty()) {
817 automation_list (port_id).set_state (*child->children().front());
818 } else {
819 if ((cprop = child->property("auto")) != 0) {
821 /* old school */
823 int x;
824 sscanf (cprop->value().c_str(), "0x%x", &x);
825 automation_list (port_id).set_automation_state (AutoState (x));
827 } else {
829 /* missing */
831 automation_list (port_id).set_automation_state (Off);
837 /* done */
839 break;
842 if (niter == nlist.end()) {
843 warning << string_compose(_("XML node describing a port automation is missing the `%1' information"), port_automation_node_name) << endmsg;
846 // The name of the PluginInsert comes from the plugin, nothing else
847 set_name(plugin->get_info()->name,this);
849 return 0;
852 string
853 PluginInsert::describe_parameter (uint32_t what)
855 return _plugins[0]->describe_parameter (what);
858 nframes_t
859 PluginInsert::latency()
861 return _plugins[0]->latency ();
864 ARDOUR::PluginType
865 PluginInsert::type ()
867 boost::shared_ptr<LadspaPlugin> lp;
868 #ifdef VST_SUPPORT
869 boost::shared_ptr<VSTPlugin> vp;
870 #endif
871 #ifdef HAVE_AUDIOUNITS
872 boost::shared_ptr<AUPlugin> ap;
873 #endif
874 #ifdef HAVE_LV2
875 boost::shared_ptr<LV2Plugin> lv2p;
876 #endif
878 PluginPtr other = plugin ();
880 if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
881 return ARDOUR::LADSPA;
882 #ifdef VST_SUPPORT
883 } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
884 return ARDOUR::VST;
885 #endif
886 #ifdef HAVE_AUDIOUNITS
887 } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
888 return ARDOUR::AudioUnit;
889 #endif
890 #ifdef HAVE_LV2
891 } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
892 return ARDOUR::LV2;
893 #endif
894 } else {
895 error << "Unknown plugin type" << endmsg;
896 /* NOT REACHED */
897 return (ARDOUR::PluginType) 0;
901 /***************************************************************
902 Port inserts: send output to a port, pick up input at a port
903 ***************************************************************/
905 PortInsert::PortInsert (Session& s, Placement p)
906 : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
908 init ();
909 RedirectCreated (this); /* EMIT SIGNAL */
913 PortInsert::PortInsert (const PortInsert& other)
914 : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
916 init ();
917 RedirectCreated (this); /* EMIT SIGNAL */
920 void
921 PortInsert::init ()
925 PortInsert::PortInsert (Session& s, const XMLNode& node)
926 : Insert (s, "will change", PreFader)
928 bitslot = 0xffffffff;
929 if (set_state (node)) {
930 throw failed_constructor();
933 RedirectCreated (this); /* EMIT SIGNAL */
936 PortInsert::~PortInsert ()
938 GoingAway ();
941 void
942 PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
944 if (n_outputs() == 0) {
945 return;
948 if (!active()) {
949 /* deliver silence */
950 silence (nframes, offset);
951 return;
954 uint32_t n;
955 vector<Port*>::iterator o;
956 vector<Port*>::iterator i;
958 /* deliver output */
960 for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
961 memcpy ((*o)->get_buffer (nframes) + offset, bufs[min(nbufs,n)], sizeof (Sample) * nframes);
962 (*o)->mark_silence (false);
965 /* collect input */
967 for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) {
968 memcpy (bufs[min(nbufs,n)], (*i)->get_buffer (nframes) + offset, sizeof (Sample) * nframes);
972 XMLNode&
973 PortInsert::get_state(void)
975 return state (true);
978 XMLNode&
979 PortInsert::state (bool full)
981 XMLNode *node = new XMLNode("Insert");
982 char buf[32];
983 node->add_child_nocopy (Redirect::state(full));
984 node->add_property ("type", "port");
985 snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
986 node->add_property ("bitslot", buf);
988 return *node;
992 PortInsert::set_state(const XMLNode& node)
994 XMLNodeList nlist = node.children();
995 XMLNodeIterator niter;
996 XMLPropertyList plist;
997 const XMLProperty *prop;
999 if ((prop = node.property ("type")) == 0) {
1000 error << _("XML node describing insert is missing the `type' field") << endmsg;
1001 return -1;
1004 if (prop->value() != "port") {
1005 error << _("non-port insert XML used for port plugin insert") << endmsg;
1006 return -1;
1009 if ((prop = node.property ("bitslot")) == 0) {
1010 bitslot = _session.next_insert_id();
1011 } else {
1012 uint32_t old_bitslot = bitslot;
1013 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
1015 if (old_bitslot != bitslot) {
1016 _session.mark_insert_id (bitslot);
1020 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1021 if ((*niter)->name() == Redirect::state_node_name) {
1022 Redirect::set_state (**niter);
1023 break;
1027 if (niter == nlist.end()) {
1028 error << _("XML node describing insert is missing a Redirect node") << endmsg;
1029 return -1;
1032 return 0;
1035 nframes_t
1036 PortInsert::latency()
1038 /* because we deliver and collect within the same cycle,
1039 all I/O is necessarily delayed by at least frames_per_cycle().
1041 if the return port for insert has its own latency, we
1042 need to take that into account too.
1045 return _session.engine().frames_per_cycle() + input_latency();
1048 int32_t
1049 PortInsert::can_do (int32_t in, int32_t& out)
1051 if (input_maximum() == -1 && output_maximum() == -1) {
1053 /* not configured yet */
1055 out = in;
1056 return 1;
1058 } else {
1060 /* the "input" config for a port insert corresponds to how
1061 many output ports it will have.
1064 if (output_maximum() == in) {
1065 out = in;
1066 return 1;
1070 return -1;
1073 int32_t
1074 PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
1076 /* do not allow configuration to be changed outside the range of
1077 the last request config. or something like that.
1080 set_output_maximum (in);
1081 set_output_minimum (in);
1082 set_input_maximum (out);
1083 set_input_minimum (out);
1085 /* this can be momentarily confusing:
1087 the number of inputs we are required to handle corresponds
1088 to the number of output ports we need.
1090 the number of outputs we are required to have corresponds
1091 to the number of input ports we need.
1094 if (in < 0) {
1095 in = n_outputs ();
1098 if (out < 0) {
1099 out = n_inputs ();
1102 return ensure_io (out, in, false, this);
1105 uint32_t
1106 PortInsert::output_streams() const
1108 return n_inputs ();
1111 uint32_t
1112 PortInsert::input_streams() const
1114 return n_outputs ();