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