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