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