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