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