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