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