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