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