Merged changes from trunk 1699:1751 into 2.1-staging
[ardour.git] / libs / ardour / insert.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
3
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.
8
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.
13
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.
17
18 */
19
20 #include <string>
21
22 #include <sigc++/bind.h>
23
24 #include <pbd/failed_constructor.h>
25 #include <pbd/xml++.h>
26
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>
32
33 #ifdef VST_SUPPORT
34 #include <ardour/vst_plugin.h>
35 #endif
36
37 #ifdef HAVE_AUDIOUNITS
38 #include <ardour/audio_unit.h>
39 #endif
40
41 #include <ardour/audioengine.h>
42 #include <ardour/session.h>
43 #include <ardour/types.h>
44
45 #include "i18n.h"
46
47 using namespace std;
48 using namespace ARDOUR;
49 using namespace PBD;
50
51 Insert::Insert(Session& s, string name, Placement p)
52         : Redirect (s, name, p)
53 {
54 }
55
56 Insert::Insert(Session& s, string name, Placement p, int imin, int imax, int omin, int omax)
57         : Redirect (s, name, p, imin, imax, omin, omax)
58 {
59 }
60
61 /***************************************************************
62  Plugin inserts: send data through a plugin
63  ***************************************************************/
64
65 const string PluginInsert::port_automation_node_name = "PortAutomation";
66
67 PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placement placement)
68         : Insert (s, plug->name(), placement)
69 {
70         /* the first is the master */
71
72         _plugins.push_back (plug);
73
74         _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
75         
76         init ();
77
78         {
79                 Glib::Mutex::Lock em (_session.engine().process_lock());
80                 IO::MoreOutputs (output_streams ());
81         }
82
83         RedirectCreated (this); /* EMIT SIGNAL */
84 }
85
86 PluginInsert::PluginInsert (Session& s, const XMLNode& node)
87         : Insert (s, "will change", PreFader)
88 {
89         if (set_state (node)) {
90                 throw failed_constructor();
91         }
92
93         set_automatable ();
94
95         _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
96
97         {
98                 Glib::Mutex::Lock em (_session.engine().process_lock());
99                 IO::MoreOutputs (output_streams());
100         }
101 }
102
103 PluginInsert::PluginInsert (const PluginInsert& other)
104         : Insert (other._session, other.plugin()->name(), other.placement())
105 {
106         uint32_t count = other._plugins.size();
107
108         /* make as many copies as requested */
109         for (uint32_t n = 0; n < count; ++n) {
110                 _plugins.push_back (plugin_factory (other.plugin (n)));
111         }
112
113
114         _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
115
116         init ();
117
118         RedirectCreated (this); /* EMIT SIGNAL */
119 }
120
121 int
122 PluginInsert::set_count (uint32_t num)
123 {
124         bool require_state = !_plugins.empty();
125
126         /* this is a bad idea.... we shouldn't do this while active.
127            only a route holding their redirect_lock should be calling this 
128         */
129
130         if (num == 0) { 
131                 return -1;
132         } else if (num > _plugins.size()) {
133                 uint32_t diff = num - _plugins.size();
134
135                 for (uint32_t n = 0; n < diff; ++n) {
136                         _plugins.push_back (plugin_factory (_plugins[0]));
137
138                         if (require_state) {
139                                 /* XXX do something */
140                         }
141                 }
142
143         } else if (num < _plugins.size()) {
144                 uint32_t diff = _plugins.size() - num;
145                 for (uint32_t n= 0; n < diff; ++n) {
146                         _plugins.pop_back();
147                 }
148         }
149
150         return 0;
151 }
152
153 void
154 PluginInsert::init ()
155 {
156         set_automatable ();
157
158         set<uint32_t>::iterator s;
159 }
160
161 PluginInsert::~PluginInsert ()
162 {
163         GoingAway (); /* EMIT SIGNAL */
164 }
165
166 void
167 PluginInsert::automation_list_creation_callback (uint32_t which, AutomationList& alist)
168 {
169   alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
170 }
171
172 void
173 PluginInsert::auto_state_changed (uint32_t which)
174 {
175         AutomationList& alist (automation_list (which));
176
177         if (alist.automation_state() != Off) {
178                 _plugins[0]->set_parameter (which, alist.eval (_session.transport_frame()));
179         }
180 }
181
182 uint32_t
183 PluginInsert::output_streams() const
184 {
185         return _plugins[0]->get_info()->n_outputs * _plugins.size();
186 }
187
188 uint32_t
189 PluginInsert::input_streams() const
190 {
191         return _plugins[0]->get_info()->n_inputs * _plugins.size();
192 }
193
194 uint32_t
195 PluginInsert::natural_output_streams() const
196 {
197         return _plugins[0]->get_info()->n_outputs;
198 }
199
200 uint32_t
201 PluginInsert::natural_input_streams() const
202 {
203         return _plugins[0]->get_info()->n_inputs;
204 }
205
206 bool
207 PluginInsert::is_generator() const
208 {
209         /* XXX more finesse is possible here. VST plugins have a
210            a specific "instrument" flag, for example.
211          */
212
213         return _plugins[0]->get_info()->n_inputs == 0;
214 }
215
216 void
217 PluginInsert::set_automatable ()
218 {
219         set<uint32_t> a;
220         
221         a = _plugins.front()->automatable ();
222
223         for (set<uint32_t>::iterator i = a.begin(); i != a.end(); ++i) {
224                 can_automate (*i);
225         }
226 }
227
228 void
229 PluginInsert::parameter_changed (uint32_t which, float val)
230 {
231         vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
232
233         /* don't set the first plugin, just all the slaves */
234
235         if (i != _plugins.end()) {
236                 ++i;
237                 for (; i != _plugins.end(); ++i) {
238                         (*i)->set_parameter (which, val);
239                 }
240         }
241 }
242
243 void
244 PluginInsert::set_block_size (nframes_t nframes)
245 {
246         for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
247                 (*i)->set_block_size (nframes);
248         }
249 }
250
251 void
252 PluginInsert::activate ()
253 {
254         for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
255                 (*i)->activate ();
256         }
257 }
258
259 void
260 PluginInsert::deactivate ()
261 {
262         for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
263                 (*i)->deactivate ();
264         }
265 }
266
267 void
268 PluginInsert::connect_and_run (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now)
269 {
270         int32_t in_index = 0;
271         int32_t out_index = 0;
272
273         /* Note that we've already required that plugins
274            be able to handle in-place processing.
275         */
276
277         if (with_auto) {
278
279                 map<uint32_t,AutomationList*>::iterator li;
280                 uint32_t n;
281                 
282                 for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
283                         
284                         AutomationList& alist (*((*li).second));
285
286                         if (alist.automation_playback()) {
287                                 bool valid;
288
289                                 float val = alist.rt_safe_eval (now, valid);                            
290
291                                 if (valid) {
292                                         /* set the first plugin, the others will be set via signals */
293                                         _plugins[0]->set_parameter ((*li).first, val);
294                                 }
295
296                         } 
297                 }
298         }
299
300         for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
301                 (*i)->connect_and_run (bufs, nbufs, in_index, out_index, nframes, offset);
302         }
303
304         /* leave remaining channel buffers alone */
305 }
306
307 void
308 PluginInsert::automation_snapshot (nframes_t now)
309 {
310         map<uint32_t,AutomationList*>::iterator li;
311         
312         for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
313                 
314                 AutomationList *alist = ((*li).second);
315                 if (alist != 0 && alist->automation_write ()) {
316                         
317                         float val = _plugins[0]->get_parameter ((*li).first);
318                         alist->rt_add (now, val);
319                         last_automation_snapshot = now;
320                 }
321         }
322 }
323
324 void
325 PluginInsert::transport_stopped (nframes_t now)
326 {
327         map<uint32_t,AutomationList*>::iterator li;
328
329         for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
330                 AutomationList& alist (*(li->second));
331                 alist.reposition_for_rt_add (now);
332
333                 if (alist.automation_state() != Off) {
334                         _plugins[0]->set_parameter (li->first, alist.eval (now));
335                 }
336         }
337 }
338
339 void
340 PluginInsert::silence (nframes_t nframes, nframes_t offset)
341 {
342         int32_t in_index = 0;
343         int32_t out_index = 0;
344
345         uint32_t n;
346
347         if (active()) {
348                 for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
349                         n = (*i) -> get_info()->n_inputs;
350                         (*i)->connect_and_run (_session.get_silent_buffers (n), n, in_index, out_index, nframes, offset);
351                 }
352         }
353 }
354         
355 void
356 PluginInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
357 {
358         if (active()) {
359
360                 if (_session.transport_rolling()) {
361                         automation_run (bufs, nbufs, nframes, offset);
362                 } else {
363                         connect_and_run (bufs, nbufs, nframes, offset, false);
364                 }
365         } else {
366                 uint32_t in = _plugins[0]->get_info()->n_inputs;
367                 uint32_t out = _plugins[0]->get_info()->n_outputs;
368
369                 if (out > in) {
370
371                         /* not active, but something has make up for any channel count increase */
372                         
373                         for (uint32_t n = out - in; n < out; ++n) {
374                                 memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
375                         }
376                 }
377         }
378 }
379
380 void
381 PluginInsert::set_parameter (uint32_t port, float val)
382 {
383         /* the others will be set from the event triggered by this */
384
385         _plugins[0]->set_parameter (port, val);
386         
387         if (automation_list (port).automation_write()) {
388                 automation_list (port).add (_session.audible_frame(), val);
389         }
390
391         _session.set_dirty();
392 }
393
394 void
395 PluginInsert::automation_run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
396 {
397         ControlEvent next_event (0, 0.0f);
398         nframes_t now = _session.transport_frame ();
399         nframes_t end = now + nframes;
400
401         Glib::Mutex::Lock lm (_automation_lock, Glib::TRY_LOCK);
402
403         if (!lm.locked()) {
404                 connect_and_run (bufs, nbufs, nframes, offset, false);
405                 return;
406         }
407         
408         if (!find_next_event (now, end, next_event)) {
409                 
410                 /* no events have a time within the relevant range */
411                 
412                 connect_and_run (bufs, nbufs, nframes, offset, true, now);
413                 return;
414         }
415         
416         while (nframes) {
417
418                 nframes_t cnt = min (((nframes_t) floor (next_event.when) - now), nframes);
419   
420                 connect_and_run (bufs, nbufs, cnt, offset, true, now);
421                 
422                 nframes -= cnt;
423                 offset += cnt;
424                 now += cnt;
425
426                 if (!find_next_event (now, end, next_event)) {
427                         break;
428                 }
429         }
430   
431         /* cleanup anything that is left to do */
432   
433         if (nframes) {
434                 connect_and_run (bufs, nbufs, nframes, offset, true, now);
435         }
436 }       
437
438 float
439 PluginInsert::default_parameter_value (uint32_t port)
440 {
441         if (_plugins.empty()) {
442                 fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
443                       << endmsg;
444                 /*NOTREACHED*/
445         }
446
447         return _plugins[0]->default_value (port);
448 }
449         
450 void
451 PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
452 {
453         if (port < _plugins[0]->parameter_count()) {
454                 
455                 AutomationList& al = automation_list (port);
456
457                 if (s != al.automation_state()) {
458                         al.set_automation_state (s);
459                         _session.set_dirty ();
460                 }
461         }
462 }
463
464 AutoState
465 PluginInsert::get_port_automation_state (uint32_t port)
466 {
467         if (port < _plugins[0]->parameter_count()) {
468                 return automation_list (port).automation_state();
469         } else {
470                 return Off;
471         }
472 }
473
474 void
475 PluginInsert::protect_automation ()
476 {
477         set<uint32_t> automated_params;
478
479         what_has_automation (automated_params);
480
481         for (set<uint32_t>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
482
483                 AutomationList& al = automation_list (*i);
484
485                 switch (al.automation_state()) {
486                 case Write:
487                         al.set_automation_state (Off);
488                         break;
489                 case Touch:
490                         al.set_automation_state (Play);
491                         break;
492                 default:
493                         break;
494                 }
495         }
496 }
497
498 boost::shared_ptr<Plugin>
499 PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
500 {
501         boost::shared_ptr<LadspaPlugin> lp;
502 #ifdef VST_SUPPORT
503         boost::shared_ptr<VSTPlugin> vp;
504 #endif
505 #ifdef HAVE_AUDIOUNITS
506         boost::shared_ptr<AUPlugin> ap;
507 #endif
508
509         if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
510                 return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
511 #ifdef VST_SUPPORT
512         } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
513                 return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
514 #endif
515 #ifdef HAVE_AUDIOUNITS
516         } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
517                 return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
518 #endif
519         }
520
521         fatal << string_compose (_("programming error: %1"),
522                           X_("unknown plugin type in PluginInsert::plugin_factory"))
523               << endmsg;
524         /*NOTREACHED*/
525         return boost::shared_ptr<Plugin> ((Plugin*) 0);
526 }
527
528 int32_t
529 PluginInsert::compute_output_streams (int32_t cnt) const
530 {
531         return _plugins[0]->get_info()->n_outputs * cnt;
532 }
533
534 int32_t
535 PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out)
536 {
537         return set_count (magic);
538 }
539
540 int32_t 
541 PluginInsert::can_support_input_configuration (int32_t in) const
542 {
543         int32_t outputs = _plugins[0]->get_info()->n_outputs;
544         int32_t inputs = _plugins[0]->get_info()->n_inputs;
545
546         if (inputs == 0) {
547
548                 /* instrument plugin, always legal, but it throws
549                    away any existing active streams.
550                 */
551
552                 return 1;
553         }
554
555         if (outputs == 1 && inputs == 1) {
556                 /* mono plugin, replicate as needed */
557                 return in;
558         }
559
560         if (inputs == in) {
561                 /* exact match */
562                 return 1;
563         }
564
565         if ((inputs < in) && (inputs % in == 0)) {
566
567                 /* number of inputs is a factor of the requested input
568                    configuration, so we can replicate.
569                 */
570
571                 return in/inputs;
572         }
573
574         /* sorry */
575
576         return -1;
577 }
578
579 XMLNode&
580 PluginInsert::get_state(void)
581 {
582         return state (true);
583 }
584
585 XMLNode&
586 PluginInsert::state (bool full)
587 {
588         char buf[256];
589         XMLNode *node = new XMLNode("Insert");
590
591         node->add_child_nocopy (Redirect::state (full));
592
593         node->add_property ("type", _plugins[0]->state_node_name());
594         snprintf(buf, sizeof(buf), "%s", _plugins[0]->name());
595         node->add_property("id", string(buf));
596         if (_plugins[0]->state_node_name() == "ladspa") {
597                 char buf[32];
598                 snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info()->unique_id); 
599                 node->add_property("unique-id", string(buf));
600         }
601         node->add_property("count", string_compose("%1", _plugins.size()));
602         node->add_child_nocopy (_plugins[0]->get_state());
603
604         /* add port automation state */
605         XMLNode *autonode = new XMLNode(port_automation_node_name);
606         set<uint32_t> automatable = _plugins[0]->automatable();
607
608         for (set<uint32_t>::iterator x =  automatable.begin(); x != automatable.end(); ++x) {
609
610                 XMLNode* child = new XMLNode("port");
611                 snprintf(buf, sizeof(buf), "%" PRIu32, *x);
612                 child->add_property("number", string(buf));
613
614                 child->add_child_nocopy (automation_list (*x).state (full));
615                 autonode->add_child_nocopy (*child);
616         }
617
618         node->add_child_nocopy (*autonode);
619         
620         return *node;
621 }
622
623 int
624 PluginInsert::set_state(const XMLNode& node)
625 {
626         XMLNodeList nlist = node.children();
627         XMLNodeIterator niter;
628         XMLPropertyList plist;
629         const XMLProperty *prop;
630         long unique = 0;
631         ARDOUR::PluginType type;
632
633         if ((prop = node.property ("type")) == 0) {
634                 error << _("XML node describing insert is missing the `type' field") << endmsg;
635                 return -1;
636         }
637
638         if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
639                 type = ARDOUR::LADSPA;
640         } else if (prop->value() == X_("vst")) {
641                 type = ARDOUR::VST;
642         } else {
643                 error << string_compose (_("unknown plugin type %1 in plugin insert state"),
644                                   prop->value())
645                       << endmsg;
646                 return -1;
647         }
648
649         prop = node.property ("unique-id");
650         if (prop != 0) {
651                 unique = atol(prop->value().c_str());
652         }
653
654         if ((prop = node.property ("id")) == 0) {
655                 error << _("XML node describing insert is missing the `id' field") << endmsg;
656                 return -1;
657         }
658
659         boost::shared_ptr<Plugin> plugin;
660         
661         if (unique != 0) {
662                 plugin = find_plugin (_session, "", unique, type);      
663         } else {
664                 plugin = find_plugin (_session, prop->value(), 0, type);        
665         }
666
667         if (plugin == 0) {
668                 error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
669                                    "Perhaps it was removed or moved since it was last used."), prop->value()) 
670                       << endmsg;
671                 return -1;
672         }
673
674         uint32_t count = 1;
675
676         if ((prop = node.property ("count")) != 0) {
677                 sscanf (prop->value().c_str(), "%u", &count);
678         }
679
680         if (_plugins.size() != count) {
681                 
682                 _plugins.push_back (plugin);
683                 
684                 for (uint32_t n=1; n < count; ++n) {
685                         _plugins.push_back (plugin_factory (plugin));
686                 }
687         }
688         
689         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
690                 if ((*niter)->name() == plugin->state_node_name()) {
691                         for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
692                                 (*i)->set_state (**niter);
693                         }
694                         break;
695                 }
696         } 
697
698         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
699                 if ((*niter)->name() == Redirect::state_node_name) {
700                         Redirect::set_state (**niter);
701                         break;
702                 }
703         }
704
705         if (niter == nlist.end()) {
706                 error << _("XML node describing insert is missing a Redirect node") << endmsg;
707                 return -1;
708         }
709
710         if (niter == nlist.end()) {
711                 error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
712                 return -1;
713         }
714         
715         /* look for port automation node */
716         
717         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
718
719                 if ((*niter)->name() != port_automation_node_name) {
720                         continue;
721                 }
722
723                 XMLNodeList cnodes;
724                 XMLProperty *cprop;
725                 XMLNodeConstIterator iter;
726                 XMLNode *child;
727                 const char *port;
728                 uint32_t port_id;
729                 
730                 cnodes = (*niter)->children ("port");
731                 
732                 for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
733                         
734                         child = *iter;
735                         
736                         if ((cprop = child->property("number")) != 0) {
737                                 port = cprop->value().c_str();
738                         } else {
739                                 warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
740                                 continue;
741                         }
742                         
743                         sscanf (port, "%" PRIu32, &port_id);
744                         
745                         if (port_id >= _plugins[0]->parameter_count()) {
746                                 warning << _("PluginInsert: Auto: port id out of range") << endmsg;
747                                 continue;
748                         }
749
750                         if (!child->children().empty()) {
751                                 automation_list (port_id).set_state (*child->children().front());
752                         } else {
753                                 if ((cprop = child->property("auto")) != 0) {
754                                         
755                                         /* old school */
756
757                                         int x;
758                                         sscanf (cprop->value().c_str(), "0x%x", &x);
759                                         automation_list (port_id).set_automation_state (AutoState (x));
760
761                                 } else {
762                                         
763                                         /* missing */
764                                         
765                                         automation_list (port_id).set_automation_state (Off);
766                                 }
767                         }
768
769                 }
770
771                 /* done */
772
773                 break;
774         } 
775
776         if (niter == nlist.end()) {
777                 warning << string_compose(_("XML node describing a port automation is missing the `%1' information"), port_automation_node_name) << endmsg;
778         }
779         
780         // The name of the PluginInsert comes from the plugin, nothing else
781         set_name(plugin->get_info()->name,this);
782         
783         return 0;
784 }
785
786 string
787 PluginInsert::describe_parameter (uint32_t what)
788 {
789         return _plugins[0]->describe_parameter (what);
790 }
791
792 nframes_t 
793 PluginInsert::latency() 
794 {
795         return _plugins[0]->latency ();
796 }
797         
798 ARDOUR::PluginType
799 PluginInsert::type ()
800 {
801         boost::shared_ptr<LadspaPlugin> lp;
802 #ifdef VST_SUPPORT
803         boost::shared_ptr<VSTPlugin> vp;
804 #endif
805 #ifdef HAVE_AUDIOUNITS
806         boost::shared_ptr<AUPlugin> ap;
807 #endif
808         
809         PluginPtr other = plugin ();
810
811         if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
812                 return ARDOUR::LADSPA;
813 #ifdef VST_SUPPORT
814         } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
815                 return ARDOUR::VST;
816 #endif
817 #ifdef HAVE_AUDIOUNITS
818         } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
819                 return ARDOUR::AudioUnit;
820 #endif
821         } else {
822                 /* NOT REACHED */
823                 return (ARDOUR::PluginType) 0;
824         }
825 }
826
827 /***************************************************************
828  Port inserts: send output to a port, pick up input at a port
829  ***************************************************************/
830
831 PortInsert::PortInsert (Session& s, Placement p)
832         : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
833 {
834         init ();
835         RedirectCreated (this); /* EMIT SIGNAL */
836
837 }
838
839 PortInsert::PortInsert (const PortInsert& other)
840         : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
841 {
842         init ();
843         RedirectCreated (this); /* EMIT SIGNAL */
844 }
845
846 void
847 PortInsert::init ()
848 {
849         if (add_input_port ("", this)) {
850                 error << _("PortInsert: cannot add input port") << endmsg;
851                 throw failed_constructor();
852         }
853         
854         if (add_output_port ("", this)) {
855                 error << _("PortInsert: cannot add output port") << endmsg;
856                 throw failed_constructor();
857         }
858 }
859
860 PortInsert::PortInsert (Session& s, const XMLNode& node)
861         : Insert (s, "will change", PreFader)
862 {
863         if (set_state (node)) {
864                 throw failed_constructor();
865         }
866
867         RedirectCreated (this); /* EMIT SIGNAL */
868 }
869
870 PortInsert::~PortInsert ()
871 {
872         GoingAway ();
873 }
874
875 void
876 PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
877 {
878         if (n_outputs() == 0) {
879                 return;
880         }
881
882         if (!active()) {
883                 /* deliver silence */
884                 silence (nframes, offset);
885                 return;
886         }
887
888         uint32_t n;
889         vector<Port*>::iterator o;
890         vector<Port*>::iterator i;
891
892         /* deliver output */
893
894         for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
895                 memcpy ((*o)->get_buffer (nframes) + offset, bufs[min(nbufs,n)], sizeof (Sample) * nframes);
896                 (*o)->mark_silence (false);
897         }
898         
899         /* collect input */
900         
901         for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) {
902                 memcpy (bufs[min(nbufs,n)], (*i)->get_buffer (nframes) + offset, sizeof (Sample) * nframes);
903         }
904 }
905
906 XMLNode&
907 PortInsert::get_state(void)
908 {
909         return state (true);
910 }
911
912 XMLNode&
913 PortInsert::state (bool full)
914 {
915         XMLNode *node = new XMLNode("Insert");
916         char buf[32];
917         node->add_child_nocopy (Redirect::state(full)); 
918         node->add_property ("type", "port");
919         snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
920         node->add_property ("bitslot", buf);
921
922         return *node;
923 }
924
925 int
926 PortInsert::set_state(const XMLNode& node)
927 {
928         XMLNodeList nlist = node.children();
929         XMLNodeIterator niter;
930         XMLPropertyList plist;
931         const XMLProperty *prop;
932
933         if ((prop = node.property ("type")) == 0) {
934                 error << _("XML node describing insert is missing the `type' field") << endmsg;
935                 return -1;
936         }
937         
938         if (prop->value() != "port") {
939                 error << _("non-port insert XML used for port plugin insert") << endmsg;
940                 return -1;
941         }
942
943         if ((prop = node.property ("bitslot")) == 0) {
944                 bitslot = _session.next_insert_id();
945         } else {
946                 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
947                 _session.mark_insert_id (bitslot);
948         }
949
950         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
951                 if ((*niter)->name() == Redirect::state_node_name) {
952                         Redirect::set_state (**niter);
953                         break;
954                 }
955         }
956
957         if (niter == nlist.end()) {
958                 error << _("XML node describing insert is missing a Redirect node") << endmsg;
959                 return -1;
960         }
961
962         return 0;
963 }
964
965 nframes_t 
966 PortInsert::latency() 
967 {
968         /* because we deliver and collect within the same cycle,
969            all I/O is necessarily delayed by at least frames_per_cycle().
970
971            if the return port for insert has its own latency, we
972            need to take that into account too.
973         */
974
975         return _session.engine().frames_per_cycle() + input_latency();
976 }
977
978 int32_t
979 PortInsert::can_support_input_configuration (int32_t in) const
980 {
981         if (input_maximum() == -1 && output_maximum() == -1) {
982
983                 /* not configured yet */
984
985                 return 1; /* we can support anything the first time we're asked */
986
987         } else {
988
989                 /* the "input" config for a port insert corresponds to how
990                    many output ports it will have.
991                 */
992
993                 if (output_maximum() == in) {
994                         return 1;
995                 } 
996         }
997
998         return -1;
999 }
1000
1001 int32_t
1002 PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out)
1003 {
1004         /* do not allow configuration to be changed outside the range of
1005            the last request config. or something like that.
1006         */
1007
1008
1009         /* this is a bit odd: 
1010
1011            the number of inputs we are required to handle corresponds 
1012            to the number of output ports we need.
1013
1014            the number of outputs we are required to have corresponds
1015            to the number of input ports we need.
1016         */
1017
1018         set_output_maximum (in);
1019         set_output_minimum (in);
1020         set_input_maximum (out);
1021         set_input_minimum (out);
1022
1023         if (in < 0) {
1024                 in = n_outputs ();
1025         } 
1026
1027         if (out < 0) {
1028                 out = n_inputs ();
1029         }
1030
1031         return ensure_io (out, in, false, this);
1032 }
1033
1034 int32_t
1035 PortInsert::compute_output_streams (int32_t cnt) const
1036 {
1037         /* puzzling, eh? think about it ... */
1038         return n_inputs ();
1039 }
1040
1041 uint32_t
1042 PortInsert::output_streams() const
1043 {
1044         return n_inputs ();
1045 }
1046
1047 uint32_t
1048 PortInsert::input_streams() const
1049 {
1050         return n_outputs ();
1051 }
1052