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