Few cleanups related to signed-ness of minimum/maximum port counts.
[ardour.git] / libs / ardour / io.cc
1 /*
2     Copyright (C) 2000-2006 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 #include <fstream>
20 #include <algorithm>
21 #include <unistd.h>
22 #include <locale.h>
23 #include <errno.h>
24
25 #include <sigc++/bind.h>
26
27 #include <glibmm/thread.h>
28
29 #include <pbd/xml++.h>
30 #include <pbd/replace_all.h>
31
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/audio_port.h>
36 #include <ardour/midi_port.h>
37 #include <ardour/bundle.h>
38 #include <ardour/session.h>
39 #include <ardour/cycle_timer.h>
40 #include <ardour/panner.h>
41 #include <ardour/buffer_set.h>
42 #include <ardour/meter.h>
43 #include <ardour/amp.h>
44
45 #include "i18n.h"
46
47 #include <cmath>
48
49 /*
50   A bug in OS X's cmath that causes isnan() and isinf() to be 
51   "undeclared". the following works around that
52 */
53
54 #if defined(__APPLE__) && defined(__MACH__)
55 extern "C" int isnan (double);
56 extern "C" int isinf (double);
57 #endif
58
59 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
60
61 using namespace std;
62 using namespace ARDOUR;
63 using namespace PBD;
64
65 const string                 IO::state_node_name = "IO";
66 bool                         IO::connecting_legal = false;
67 bool                         IO::ports_legal = false;
68 bool                         IO::panners_legal = false;
69 sigc::signal<void>           IO::Meter;
70 sigc::signal<int>            IO::ConnectingLegal;
71 sigc::signal<int>            IO::PortsLegal;
72 sigc::signal<int>            IO::PannersLegal;
73 sigc::signal<void,ChanCount> IO::MoreChannels;
74 sigc::signal<int>            IO::PortsCreated;
75
76 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
77
78 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
79    others can be imagined. 
80 */
81
82 #if 0
83 static gain_t direct_control_to_gain (double fract) { 
84         /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
85         /* this maxes at +6dB */
86         return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
87 }
88
89 static double direct_gain_to_control (gain_t gain) { 
90         /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
91         if (gain == 0) return 0.0;
92         
93         return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
94 }
95 #endif
96
97 /** @param default_type The type of port that will be created by ensure_io
98  * and friends if no type is explicitly requested (to avoid breakage).
99  */
100 IO::IO (Session& s, const string& name,
101         int input_min, int input_max, int output_min, int output_max,
102         DataType default_type)
103         : Automatable (s, name),
104       _output_buffers (new BufferSet()),
105           _default_type (default_type),
106           _input_minimum (ChanCount::ZERO),
107           _input_maximum (ChanCount::INFINITE),
108           _output_minimum (ChanCount::ZERO),
109           _output_maximum (ChanCount::INFINITE)
110 {
111         _panner = new Panner (name, _session);
112         _meter = new PeakMeter (_session);
113
114         if (input_min > 0) {
115                 _input_minimum = ChanCount(_default_type, input_min);
116         }
117         if (input_max >= 0) {
118                 _input_maximum = ChanCount(_default_type, input_max);
119         }
120         if (output_min > 0) {
121                 _output_minimum = ChanCount(_default_type, output_min);
122         }
123         if (output_max >= 0) {
124                 _output_maximum = ChanCount(_default_type, output_max);
125         }
126
127         _gain = 1.0;
128         _desired_gain = 1.0;
129         pending_state_node = 0;
130         no_panner_reset = false;
131         _phase_invert = false;
132         deferred_state = 0;
133
134         boost::shared_ptr<AutomationList> gl(
135                         new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
136
137         _gain_control = boost::shared_ptr<GainControl>(
138                         new GainControl(X_("gaincontrol"), *this, gl));
139
140         add_control(_gain_control);
141
142         apply_gain_automation = false;
143         
144         {
145                 // IO::Meter is emitted from another thread so the
146                 // Meter signal must be protected.
147                 Glib::Mutex::Lock guard (m_meter_signal_lock);
148                 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
149         }
150         
151         // Connect to our own MoreChannels signal to connect output buffers
152         IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
153
154         _session.add_controllable (_gain_control);
155
156         create_bundles ();
157 }
158
159 IO::IO (Session& s, const XMLNode& node, DataType dt)
160         : Automatable (s, "unnamed io"),
161       _output_buffers (new BufferSet()),
162           _default_type (dt)
163 {
164         _meter = new PeakMeter (_session);
165
166         _panner = 0;
167         deferred_state = 0;
168         no_panner_reset = false;
169         _desired_gain = 1.0;
170         _gain = 1.0;
171
172         apply_gain_automation = false;
173         
174         boost::shared_ptr<AutomationList> gl(
175                         new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
176
177         _gain_control = boost::shared_ptr<GainControl>(
178                         new GainControl(X_("gaincontrol"), *this, gl));
179
180         add_control(_gain_control);
181
182         set_state (node);
183
184         {
185                 // IO::Meter is emitted from another thread so the
186                 // Meter signal must be protected.
187                 Glib::Mutex::Lock guard (m_meter_signal_lock);
188                 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
189         }
190         
191         // Connect to our own MoreChannels signal to connect output buffers
192         IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
193
194         _session.add_controllable (_gain_control);
195
196         create_bundles ();
197 }
198
199 IO::~IO ()
200 {
201         Glib::Mutex::Lock guard (m_meter_signal_lock);
202         
203         Glib::Mutex::Lock lm (io_lock);
204
205         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
206                 _session.engine().unregister_port (*i);
207         }
208
209         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
210                 _session.engine().unregister_port (*i);
211         }
212
213         m_meter_connection.disconnect();
214
215         delete _meter;
216         delete _panner;
217         delete _output_buffers;
218 }
219
220 void
221 IO::silence (nframes_t nframes, nframes_t offset)
222 {
223         /* io_lock, not taken: function must be called from Session::process() calltree */
224
225         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
226                 i->get_buffer().silence (nframes, offset);
227         }
228 }
229
230 /** Deliver bufs to the IO's Jack outputs.
231  *
232  * This function should automatically do whatever it necessary to correctly deliver bufs
233  * to the outputs, eg applying gain or pan or whatever else needs to be done.
234  */
235 void
236 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
237 {
238         // FIXME: type specific code doesn't actually need to be here, it will go away in time
239
240         /* ********** AUDIO ********** */
241
242         // Apply gain if gain automation isn't playing
243         if ( ! apply_gain_automation) {
244                 
245                 gain_t dg = _gain; // desired gain
246
247                 {
248                         Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
249
250                         if (dm.locked()) {
251                                 dg = _desired_gain;
252                         }
253
254                 }
255
256                 if (dg != _gain || dg != 1.0)
257                         Amp::run_in_place(bufs, nframes, _gain, dg, _phase_invert);
258         }
259         
260         // Use the panner to distribute audio to output port buffers
261         if (_panner && !_panner->empty() && !_panner->bypassed()) {
262                 _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
263         } else {
264                 const DataType type = DataType::AUDIO;
265                 
266                 // Copy any audio 1:1 to outputs
267                 
268                 BufferSet::iterator o = output_buffers().begin(type);
269                 BufferSet::iterator i = bufs.begin(type);
270                 BufferSet::iterator prev = i;
271                 
272                 while (i != bufs.end(type) && o != output_buffers().end (type)) {
273                         o->read_from(*i, nframes, offset);
274                         prev = i;
275                         ++i;
276                         ++o;
277                 }
278
279                 /* extra outputs get a copy of the last buffer */
280
281                 while (o != output_buffers().end(type)) {
282                         o->read_from(*prev, nframes, offset);
283                         ++o;
284                 }
285         }
286
287         /* ********** MIDI ********** */
288
289         // No MIDI, we're done here
290         if (bufs.count().n_midi() == 0) {
291                 return;
292         }
293
294         const DataType type = DataType::MIDI;
295
296         // Copy any MIDI 1:1 to outputs
297         assert(bufs.count().n_midi() == output_buffers().count().n_midi());
298         BufferSet::iterator o = output_buffers().begin(type);
299         for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
300                 o->read_from(*i, nframes, offset);
301         }
302 }
303
304 void
305 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
306 {
307         assert(outs.available() >= n_inputs());
308
309         outs.set_count(n_inputs());
310         
311         if (outs.count() == ChanCount::ZERO)
312                 return;
313
314         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
315                 
316                 BufferSet::iterator o = outs.begin(*t);
317                 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
318                         o->read_from(i->get_buffer(), nframes, offset);
319                 }
320
321         }
322 }
323
324 void
325 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame, 
326                       nframes_t nframes, nframes_t offset)
327 {
328         BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
329
330         collect_input (bufs, nframes, offset);
331
332         _meter->run(bufs, start_frame, end_frame, nframes, offset);
333 }
334
335 void
336 IO::drop_input_bundle ()
337 {
338         _input_bundle.reset ();
339         input_bundle_configuration_connection.disconnect();
340         input_bundle_connection_connection.disconnect();
341         _session.set_dirty ();
342 }
343
344 void
345 IO::drop_output_bundle ()
346 {
347         _output_bundle.reset ();
348         output_bundle_configuration_connection.disconnect();
349         output_bundle_connection_connection.disconnect();
350         _session.set_dirty ();
351 }
352
353 int
354 IO::disconnect_input (Port* our_port, string other_port, void* src)
355 {
356         if (other_port.length() == 0 || our_port == 0) {
357                 return 0;
358         }
359
360         { 
361                 BLOCK_PROCESS_CALLBACK ();
362                 
363                 {
364                         Glib::Mutex::Lock lm (io_lock);
365                         
366                         /* check that our_port is really one of ours */
367                         
368                         if ( ! _inputs.contains(our_port)) {
369                                 return -1;
370                         }
371                         
372                         /* disconnect it from the source */
373                         
374                         if (_session.engine().disconnect (other_port, our_port->name())) {
375                                 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
376                                 return -1;
377                         }
378
379                         drop_input_bundle ();
380                 }
381         }
382
383         input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
384         _session.set_dirty ();
385
386         return 0;
387 }
388
389 int
390 IO::connect_input (Port* our_port, string other_port, void* src)
391 {
392         if (other_port.length() == 0 || our_port == 0) {
393                 return 0;
394         }
395
396         {
397                 BLOCK_PROCESS_CALLBACK ();
398                 
399                 {
400                         Glib::Mutex::Lock lm (io_lock);
401                         
402                         /* check that our_port is really one of ours */
403                         
404                         if ( ! _inputs.contains(our_port) ) {
405                                 return -1;
406                         }
407                         
408                         /* connect it to the source */
409
410                         if (_session.engine().connect (other_port, our_port->name())) {
411                                 return -1;
412                         }
413                         
414                         drop_input_bundle ();
415                 }
416         }
417
418         input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
419         _session.set_dirty ();
420         return 0;
421 }
422
423 int
424 IO::disconnect_output (Port* our_port, string other_port, void* src)
425 {
426         if (other_port.length() == 0 || our_port == 0) {
427                 return 0;
428         }
429
430         {
431                 BLOCK_PROCESS_CALLBACK ();
432                 
433                 {
434                         Glib::Mutex::Lock lm (io_lock);
435                         
436                         /* check that our_port is really one of ours */
437                         
438                         if ( ! _outputs.contains(our_port) ) {
439                                 return -1;
440                         }
441                         
442                         /* disconnect it from the destination */
443                         
444                         if (_session.engine().disconnect (our_port->name(), other_port)) {
445                                 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
446                                 return -1;
447                         }
448
449                         drop_output_bundle ();
450                 }
451         }
452
453         output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
454         _session.set_dirty ();
455         return 0;
456 }
457
458 int
459 IO::connect_output (Port* our_port, string other_port, void* src)
460 {
461         if (other_port.length() == 0 || our_port == 0) {
462                 return 0;
463         }
464
465         {
466                 BLOCK_PROCESS_CALLBACK ();
467
468                 
469                 {
470                         Glib::Mutex::Lock lm (io_lock);
471                         
472                         /* check that our_port is really one of ours */
473                         
474                         if ( ! _outputs.contains(our_port) ) {
475                                 return -1;
476                         }
477                         
478                         /* connect it to the destination */
479                         
480                         if (_session.engine().connect (our_port->name(), other_port)) {
481                                 return -1;
482                         }
483
484                         drop_output_bundle ();
485                 }
486         }
487
488         output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
489         _session.set_dirty ();
490         return 0;
491 }
492
493 int
494 IO::set_input (Port* other_port, void* src)
495 {
496         /* this removes all but one ports, and connects that one port
497            to the specified source.
498         */
499
500         if (_input_minimum.n_total() > 1) {
501                 /* sorry, you can't do this */
502                 return -1;
503         }
504
505         if (other_port == 0) {
506                 if (_input_minimum == ChanCount::ZERO) {
507                         return ensure_inputs (ChanCount::ZERO, false, true, src);
508                 } else {
509                         return -1;
510                 }
511         }
512
513         if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
514                 return -1;
515         }
516
517         return connect_input (_inputs.port(0), other_port->name(), src);
518 }
519
520 int
521 IO::remove_output_port (Port* port, void* src)
522 {
523         IOChange change (NoChange);
524
525         {
526                 BLOCK_PROCESS_CALLBACK ();
527
528                 
529                 {
530                         Glib::Mutex::Lock lm (io_lock);
531
532                         if (n_outputs() <= _output_minimum) {
533                                 /* sorry, you can't do this */
534                                 return -1;
535                         }
536
537                         if (_outputs.remove(port)) {
538                                 change = IOChange (change|ConfigurationChanged);
539
540                                 if (port->connected()) {
541                                         change = IOChange (change|ConnectionsChanged);
542                                 } 
543
544                                 _session.engine().unregister_port (*port);
545                                 drop_output_bundle ();
546                                 
547                                 setup_peak_meters ();
548                                 reset_panner ();
549                         }
550                 }
551         }
552
553         if (change == ConnectionsChanged) {
554                 setup_bundles ();
555         }
556
557         if (change != NoChange) {
558                 output_changed (change, src);
559                 _session.set_dirty ();
560                 return 0;
561         } 
562         
563         return -1;
564 }
565
566 /** Add an output port.
567  *
568  * @param destination Name of input port to connect new port to.
569  * @param src Source for emitted ConfigurationChanged signal.
570  * @param type Data type of port.  Default value (NIL) will use this IO's default type.
571  */
572 int
573 IO::add_output_port (string destination, void* src, DataType type)
574 {
575         Port* our_port;
576         char name[64];
577
578         if (type == DataType::NIL)
579                 type = _default_type;
580
581         {
582                 BLOCK_PROCESS_CALLBACK ();
583
584                 
585                 { 
586                         Glib::Mutex::Lock lm (io_lock);
587                         
588                         if (n_outputs() >= _output_maximum) {
589                                 return -1;
590                         }
591                 
592                         /* Create a new output port */
593                         
594                         // FIXME: naming scheme for differently typed ports?
595                         if (_output_maximum.get(type) == 1) {
596                                 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
597                         } else {
598                                 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
599                         }
600                         
601                         if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
602                                 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
603                                 return -1;
604                         }
605                         
606                         _outputs.add (our_port);
607                         drop_output_bundle ();
608                         setup_peak_meters ();
609                         reset_panner ();
610                 }
611
612                 MoreChannels (n_outputs()); /* EMIT SIGNAL */
613         }
614
615         if (destination.length()) {
616                 if (_session.engine().connect (our_port->name(), destination)) {
617                         return -1;
618                 }
619         }
620         
621         // pan_changed (src); /* EMIT SIGNAL */
622         output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
623         setup_bundles ();
624         _session.set_dirty ();
625         
626         return 0;
627 }
628
629 int
630 IO::remove_input_port (Port* port, void* src)
631 {
632         IOChange change (NoChange);
633
634         {
635                 BLOCK_PROCESS_CALLBACK ();
636
637                 
638                 {
639                         Glib::Mutex::Lock lm (io_lock);
640
641                         if (n_inputs() <= _input_minimum) {
642                                 /* sorry, you can't do this */
643                                 return -1;
644                         }
645
646                         if (_inputs.remove(port)) {
647                                 change = IOChange (change|ConfigurationChanged);
648
649                                 if (port->connected()) {
650                                         change = IOChange (change|ConnectionsChanged);
651                                 } 
652
653                                 _session.engine().unregister_port (*port);
654                                 drop_input_bundle ();
655                                 
656                                 setup_peak_meters ();
657                                 reset_panner ();
658                         }
659                 }
660         }
661
662         if (change == ConfigurationChanged) {
663                 setup_bundles ();
664         }
665
666         if (change != NoChange) {
667                 input_changed (change, src);
668                 _session.set_dirty ();
669                 return 0;
670         } 
671         
672         return -1;
673 }
674
675
676 /** Add an input port.
677  *
678  * @param type Data type of port.  The appropriate Jack port type, and @ref Port will be created.
679  * @param destination Name of input port to connect new port to.
680  * @param src Source for emitted ConfigurationChanged signal.
681  */
682 int
683 IO::add_input_port (string source, void* src, DataType type)
684 {
685         Port* our_port;
686         char name[64];
687         
688         if (type == DataType::NIL)
689                 type = _default_type;
690
691         {
692                 BLOCK_PROCESS_CALLBACK ();
693                 
694                 { 
695                         Glib::Mutex::Lock lm (io_lock);
696                         
697                         if (n_inputs() >= _input_maximum) {
698                                 return -1;
699                         }
700
701                         /* Create a new input port */
702                         
703                         // FIXME: naming scheme for differently typed ports?
704                         if (_input_maximum.get(type) == 1) {
705                                 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
706                         } else {
707                                 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
708                         }
709
710                         if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
711                                 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
712                                 return -1;
713                         }
714
715                         _inputs.add (our_port);
716                         drop_input_bundle ();
717                         setup_peak_meters ();
718                         reset_panner ();
719                 }
720
721                 MoreChannels (n_inputs()); /* EMIT SIGNAL */
722         }
723
724         if (source.length()) {
725
726                 if (_session.engine().connect (source, our_port->name())) {
727                         return -1;
728                 }
729         } 
730
731         // pan_changed (src); /* EMIT SIGNAL */
732         input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
733         setup_bundles ();
734         _session.set_dirty ();
735         
736         return 0;
737 }
738
739 int
740 IO::disconnect_inputs (void* src)
741 {
742         { 
743                 BLOCK_PROCESS_CALLBACK ();
744                 
745                 {
746                         Glib::Mutex::Lock lm (io_lock);
747                         
748                         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
749                                 _session.engine().disconnect (*i);
750                         }
751
752                         drop_input_bundle ();
753                 }
754         }
755         
756         input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
757         
758         return 0;
759 }
760
761 int
762 IO::disconnect_outputs (void* src)
763 {
764         {
765                 BLOCK_PROCESS_CALLBACK ();
766                 
767                 {
768                         Glib::Mutex::Lock lm (io_lock);
769                         
770                         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
771                                 _session.engine().disconnect (*i);
772                         }
773
774                         drop_output_bundle ();
775                 }
776         }
777
778         output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
779         _session.set_dirty ();
780         
781         return 0;
782 }
783
784 bool
785 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
786 {
787         Port* input_port = 0;
788         bool  changed    = false;
789
790
791         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
792                 
793                 const size_t n = count.get(*t);
794         
795                 /* remove unused ports */
796                 for (size_t i = n_inputs().get(*t); i > n; --i) {
797                         input_port = _inputs.port(*t, i-1);
798
799                         assert(input_port);
800                         _inputs.remove(input_port);
801                         _session.engine().unregister_port (*input_port);
802
803                         changed = true;
804                 }
805
806                 /* create any necessary new ports */
807                 while (n_inputs().get(*t) < n) {
808
809                         char buf[64];
810
811                         if (_input_maximum.get(*t) == 1) {
812                                 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
813                         } else {
814                                 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
815                         }
816
817                         try {
818
819                                 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
820                                         error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
821                                         return -1;
822                                 }
823                         }
824
825                         catch (AudioEngine::PortRegistrationFailure& err) {
826                                 setup_peak_meters ();
827                                 reset_panner ();
828                                 /* pass it on */
829                                 throw AudioEngine::PortRegistrationFailure();
830                         }
831
832                         _inputs.add (input_port);
833                         changed = true;
834                 }
835         }
836         
837         if (changed) {
838                 drop_input_bundle ();
839                 setup_peak_meters ();
840                 reset_panner ();
841                 MoreChannels (n_inputs()); /* EMIT SIGNAL */
842                 _session.set_dirty ();
843         }
844         
845         if (clear) {
846                 /* disconnect all existing ports so that we get a fresh start */
847                 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
848                         _session.engine().disconnect (*i);
849                 }
850         }
851
852         return changed;
853 }
854
855 /** Attach output_buffers to port buffers.
856  * 
857  * Connected to IO's own MoreChannels signal.
858  */
859 void
860 IO::attach_buffers(ChanCount ignored)
861 {
862         _output_buffers->attach_buffers(_outputs);
863 }
864
865 int
866 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
867 {
868         bool in_changed     = false;
869         bool out_changed    = false;
870         bool need_pan_reset = false;
871
872         in = min (_input_maximum, in);
873
874         out = min (_output_maximum, out);
875
876         if (in == n_inputs() && out == n_outputs() && !clear) {
877                 return 0;
878         }
879
880         {
881                 BLOCK_PROCESS_CALLBACK ();
882                 Glib::Mutex::Lock lm (io_lock);
883
884                 Port* port;
885                 
886                 if (n_outputs() != out) {
887                         need_pan_reset = true;
888                 }
889                 
890                 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
891
892                         const size_t nin = in.get(*t);
893                         const size_t nout = out.get(*t);
894
895                         Port* output_port = 0;
896                         Port* input_port = 0;
897
898                         /* remove unused output ports */
899                         for (size_t i = n_outputs().get(*t); i > nout; --i) {
900                                 output_port = _outputs.port(*t, i-1);
901
902                                 assert(output_port);
903                                 _outputs.remove(output_port);
904                                 _session.engine().unregister_port (*output_port);
905
906                                 out_changed = true;
907                         }
908
909                         /* remove unused input ports */
910                         for (size_t i = n_inputs().get(*t); i > nin; --i) {
911                                 input_port = _inputs.port(*t, i-1);
912
913                                 assert(input_port);
914                                 _inputs.remove(input_port);
915                                 _session.engine().unregister_port (*input_port);
916
917                                 in_changed = true;
918                         }
919
920                         /* create any necessary new input ports */
921
922                         while (n_inputs().get(*t) < nin) {
923
924                                 char buf[64];
925
926                                 /* Create a new input port */
927
928                                 if (_input_maximum.get(*t) == 1) {
929                                         snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
930                                 } else {
931                                         snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
932                                 }
933
934                                 try {
935                                         if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
936                                                 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
937                                                 return -1;
938                                         }
939                                 }
940                                 
941                                 catch (AudioEngine::PortRegistrationFailure& err) {
942                                         setup_peak_meters ();
943                                         reset_panner ();
944                                         /* pass it on */
945                                         throw AudioEngine::PortRegistrationFailure();
946                                 }
947
948                                 _inputs.add (port);
949                                 in_changed = true;
950                         }
951
952                         /* create any necessary new output ports */
953
954                         while (n_outputs().get(*t) < nout) {
955
956                                 char buf[64];
957
958                                 /* Create a new output port */
959
960                                 if (_output_maximum.get(*t) == 1) {
961                                         snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
962                                 } else {
963                                         snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
964                                 }
965
966                                 try { 
967                                         if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
968                                                 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
969                                                 return -1;
970                                         }
971                                 }
972
973                                 catch (AudioEngine::PortRegistrationFailure& err) {
974                                         setup_peak_meters ();
975                                         reset_panner ();
976                                         /* pass it on */
977                                         throw AudioEngine::PortRegistrationFailure ();
978                                 }
979
980                                 _outputs.add (port);
981                                 out_changed = true;
982                         }
983                 }
984                 
985                 if (clear) {
986                         
987                         /* disconnect all existing ports so that we get a fresh start */
988                         
989                         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
990                                 _session.engine().disconnect (*i);
991                         }
992                         
993                         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
994                                 _session.engine().disconnect (*i);
995                         }
996                 }
997                 
998                 if (in_changed || out_changed) {
999                         setup_peak_meters ();
1000                         reset_panner ();
1001                 }
1002         }
1003
1004         if (out_changed) {
1005                 drop_output_bundle ();
1006                 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1007         }
1008         
1009         if (in_changed) {
1010                 drop_input_bundle ();
1011                 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1012         }
1013
1014         if (in_changed || out_changed) {
1015                 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1016                 setup_bundles ();
1017                 _session.set_dirty ();
1018         }
1019
1020         return 0;
1021 }
1022
1023 int
1024 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1025 {
1026         bool changed = false;
1027
1028         count = min (_input_maximum, count);
1029
1030         if (count == n_inputs() && !clear) {
1031                 return 0;
1032         }
1033
1034         if (lockit) {
1035                 BLOCK_PROCESS_CALLBACK ();
1036                 Glib::Mutex::Lock im (io_lock);
1037                 changed = ensure_inputs_locked (count, clear, src);
1038         } else {
1039                 changed = ensure_inputs_locked (count, clear, src);
1040         }
1041
1042         if (changed) {
1043                 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1044                 setup_bundles ();
1045                 _session.set_dirty ();
1046         }
1047         return 0;
1048 }
1049
1050 bool
1051 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1052 {
1053         Port* output_port    = 0;
1054         bool  changed        = false;
1055         bool  need_pan_reset = false;
1056
1057         if (n_outputs() != count) {
1058                 need_pan_reset = true;
1059         }
1060         
1061         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1062
1063                 const size_t n = count.get(*t);
1064
1065                 /* remove unused ports */
1066                 for (size_t i = n_outputs().get(*t); i > n; --i) {
1067                         output_port = _outputs.port(*t, i-1);
1068
1069                         assert(output_port);
1070                         _outputs.remove(output_port);
1071                         _session.engine().unregister_port (*output_port);
1072
1073                         changed = true;
1074                 }
1075
1076                 /* create any necessary new ports */
1077                 while (n_outputs().get(*t) < n) {
1078
1079                         char buf[64];
1080
1081                         if (_output_maximum.get(*t) == 1) {
1082                                 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1083                         } else {
1084                                 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1085                         }
1086
1087                         if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1088                                 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1089                                 return -1;
1090                         }
1091
1092                         _outputs.add (output_port);
1093                         changed = true;
1094                         setup_peak_meters ();
1095
1096                         if (need_pan_reset) {
1097                                 reset_panner ();
1098                         }
1099                 }
1100         }
1101         
1102         if (changed) {
1103                 drop_output_bundle ();
1104                 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1105                 _session.set_dirty ();
1106         }
1107         
1108         if (clear) {
1109                 /* disconnect all existing ports so that we get a fresh start */
1110                 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1111                         _session.engine().disconnect (*i);
1112                 }
1113         }
1114
1115         return changed;
1116 }
1117
1118 int
1119 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1120 {
1121         bool changed = false;
1122
1123         if (_output_maximum < ChanCount::INFINITE) {
1124                 count = min (_output_maximum, count);
1125                 if (count == n_outputs() && !clear) {
1126                         return 0;
1127                 }
1128         }
1129
1130         /* XXX caller should hold io_lock, but generally doesn't */
1131
1132         if (lockit) {
1133                 BLOCK_PROCESS_CALLBACK ();
1134                 Glib::Mutex::Lock im (io_lock);
1135                 changed = ensure_outputs_locked (count, clear, src);
1136         } else {
1137                 changed = ensure_outputs_locked (count, clear, src);
1138         }
1139
1140         if (changed) {
1141                  output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1142                  setup_bundles ();
1143         }
1144
1145         return 0;
1146 }
1147
1148 gain_t
1149 IO::effective_gain () const
1150 {
1151         if (_gain_control->list()->automation_playback()) {
1152                 return _gain_control->get_value();
1153         } else {
1154                 return _desired_gain;
1155         }
1156 }
1157
1158 void
1159 IO::reset_panner ()
1160 {
1161         if (panners_legal) {
1162                 if (!no_panner_reset) {
1163                         _panner->reset (n_outputs().n_audio(), pans_required());
1164                 }
1165         } else {
1166                 panner_legal_c.disconnect ();
1167                 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1168         }
1169 }
1170
1171 int
1172 IO::panners_became_legal ()
1173 {
1174         _panner->reset (n_outputs().n_audio(), pans_required());
1175         _panner->load (); // automation
1176         panner_legal_c.disconnect ();
1177         return 0;
1178 }
1179
1180 void
1181 IO::defer_pan_reset ()
1182 {
1183         no_panner_reset = true;
1184 }
1185
1186 void
1187 IO::allow_pan_reset ()
1188 {
1189         no_panner_reset = false;
1190         reset_panner ();
1191 }
1192
1193
1194 XMLNode&
1195 IO::get_state (void)
1196 {
1197         return state (true);
1198 }
1199
1200 XMLNode&
1201 IO::state (bool full_state)
1202 {
1203         XMLNode* node = new XMLNode (state_node_name);
1204         char buf[64];
1205         string str;
1206         bool need_ins = true;
1207         bool need_outs = true;
1208         LocaleGuard lg (X_("POSIX"));
1209         Glib::Mutex::Lock lm (io_lock);
1210
1211         node->add_property("name", _name);
1212         id().print (buf, sizeof (buf));
1213         node->add_property("id", buf);
1214
1215         str = "";
1216
1217         if (_input_bundle && !_input_bundle->dynamic()) {
1218                 node->add_property ("input-connection", _input_bundle->name());
1219                 need_ins = false;
1220         }
1221
1222         if (_output_bundle && !_output_bundle->dynamic()) {
1223                 node->add_property ("output-connection", _output_bundle->name());
1224                 need_outs = false;
1225         }
1226
1227         if (need_ins) {
1228                 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1229                         
1230                         const char **connections = i->get_connections();
1231                         
1232                         if (connections && connections[0]) {
1233                                 str += '{';
1234                                 
1235                                 for (int n = 0; connections && connections[n]; ++n) {
1236                                         if (n) {
1237                                                 str += ',';
1238                                         }
1239                                         
1240                                         /* if its a connection to our own port,
1241                                            return only the port name, not the
1242                                            whole thing. this allows connections
1243                                            to be re-established even when our
1244                                            client name is different.
1245                                         */
1246                                         
1247                                         str += _session.engine().make_port_name_relative (connections[n]);
1248                                 }       
1249
1250                                 str += '}';
1251                                 
1252                                 free (connections);
1253                         }
1254                         else {
1255                                 str += "{}";
1256                         }
1257                 }
1258                 
1259                 node->add_property ("inputs", str);
1260         }
1261
1262         if (need_outs) {
1263                 str = "";
1264                 
1265                 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1266                         
1267                         const char **connections = i->get_connections();
1268                         
1269                         if (connections && connections[0]) {
1270                                 
1271                                 str += '{';
1272                                 
1273                                 for (int n = 0; connections[n]; ++n) {
1274                                         if (n) {
1275                                                 str += ',';
1276                                         }
1277
1278                                         str += _session.engine().make_port_name_relative (connections[n]);
1279                                 }
1280
1281                                 str += '}';
1282                                 
1283                                 free (connections);
1284                         }
1285                         else {
1286                                 str += "{}";
1287                         }
1288                 }
1289                 
1290                 node->add_property ("outputs", str);
1291         }
1292
1293         node->add_child_nocopy (_panner->state (full_state));
1294         node->add_child_nocopy (_gain_control->get_state ());
1295
1296         snprintf (buf, sizeof(buf), "%2.12f", gain());
1297         node->add_property ("gain", buf);
1298
1299         /* To make backwards compatibility a bit easier, write ChanCount::INFINITE to the session file
1300            as -1.
1301         */
1302
1303         int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
1304         int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
1305
1306         snprintf (buf, sizeof(buf)-1, "%zd,%d,%zd,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
1307
1308         node->add_property ("iolimits", buf);
1309
1310         /* automation */
1311         
1312         if (full_state)
1313                 node->add_child_nocopy (get_automation_state());
1314
1315         return *node;
1316 }
1317
1318 int
1319 IO::set_state (const XMLNode& node)
1320 {
1321         const XMLProperty* prop;
1322         XMLNodeConstIterator iter;
1323         LocaleGuard lg (X_("POSIX"));
1324
1325         /* force use of non-localized representation of decimal point,
1326            since we use it a lot in XML files and so forth.
1327         */
1328
1329         if (node.name() != state_node_name) {
1330                 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1331                 return -1;
1332         }
1333
1334         if ((prop = node.property ("name")) != 0) {
1335                 _name = prop->value();
1336                 /* used to set panner name with this, but no more */
1337         } 
1338
1339         if ((prop = node.property ("id")) != 0) {
1340                 _id = prop->value ();
1341         }
1342
1343         int in_min = -1;
1344         int in_max = -1;
1345         int out_min = -1;
1346         int out_max = -1;
1347
1348         if ((prop = node.property ("iolimits")) != 0) {
1349                 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1350                         &in_min, &in_max, &out_min, &out_max);
1351
1352                 /* Correct for the difference between the way we write things to session files and the
1353                    way things are described by ChanCount; see comments in io.h about what the different
1354                    ChanCount values mean. */
1355
1356                 if (in_min < 0) {
1357                         _input_minimum = ChanCount::ZERO;
1358                 } else {
1359                         _input_minimum = ChanCount (_default_type, in_min);
1360                 }
1361
1362                 if (in_max < 0) {
1363                         _input_maximum = ChanCount::INFINITE;
1364                 } else {
1365                         _input_maximum = ChanCount (_default_type, in_max);
1366                 }
1367
1368                 if (out_min < 0) {
1369                         _output_minimum = ChanCount::ZERO;
1370                 } else {
1371                         _output_minimum = ChanCount (_default_type, out_min);
1372                 }
1373                 
1374                 if (out_max < 0) {
1375                         _output_maximum = ChanCount::INFINITE;
1376                 } else {
1377                         _output_maximum = ChanCount (_default_type, out_max);
1378                 }
1379         }
1380         
1381         if ((prop = node.property ("gain")) != 0) {
1382                 set_gain (atof (prop->value().c_str()), this);
1383                 _gain = _desired_gain;
1384         }
1385
1386         if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1387                 /* old school automation handling */
1388         }
1389
1390         for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1391
1392                 if ((*iter)->name() == "Panner") {
1393                         if (_panner == 0) {
1394                                 _panner = new Panner (_name, _session);
1395                         }
1396                         _panner->set_state (**iter);
1397                 }
1398
1399                 if ((*iter)->name() == X_("Automation")) {
1400
1401                         set_automation_state (*(*iter), Parameter(GainAutomation));
1402                 }
1403
1404                 if ((*iter)->name() == X_("controllable")) {
1405                         if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1406                                 _gain_control->set_state (**iter);
1407                         }
1408                 }
1409         }
1410
1411         if (ports_legal) {
1412
1413                 if (create_ports (node)) {
1414                         return -1;
1415                 }
1416
1417         } else {
1418
1419                 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1420         }
1421
1422         if (panners_legal) {
1423                 reset_panner ();
1424         } else {
1425                 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1426         }
1427
1428         if (connecting_legal) {
1429
1430                 if (make_connections (node)) {
1431                         return -1;
1432                 }
1433
1434         } else {
1435                 
1436                 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1437         }
1438
1439         if (!ports_legal || !connecting_legal) {
1440                 pending_state_node = new XMLNode (node);
1441         }
1442
1443         return 0;
1444 }
1445
1446 int
1447 IO::load_automation (string path)
1448 {
1449         string fullpath;
1450         ifstream in;
1451         char line[128];
1452         uint32_t linecnt = 0;
1453         float version;
1454         LocaleGuard lg (X_("POSIX"));
1455
1456         fullpath = _session.automation_dir();
1457         fullpath += path;
1458
1459         in.open (fullpath.c_str());
1460
1461         if (!in) {
1462                 fullpath = _session.automation_dir();
1463                 fullpath += _session.snap_name();
1464                 fullpath += '-';
1465                 fullpath += path;
1466
1467                 in.open (fullpath.c_str());
1468
1469                 if (!in) {
1470                         error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1471                         return -1;
1472                 }
1473         }
1474
1475         clear_automation ();
1476
1477         while (in.getline (line, sizeof(line), '\n')) {
1478                 char type;
1479                 nframes_t when;
1480                 double value;
1481
1482                 if (++linecnt == 1) {
1483                         if (memcmp (line, "version", 7) == 0) {
1484                                 if (sscanf (line, "version %f", &version) != 1) {
1485                                         error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1486                                         return -1;
1487                                 }
1488                         } else {
1489                                 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1490                                 return -1;
1491                         }
1492
1493                         continue;
1494                 }
1495
1496                 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1497                         warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1498                         continue;
1499                 }
1500
1501                 switch (type) {
1502                 case 'g':
1503                         _gain_control->list()->fast_simple_add (when, value);
1504                         break;
1505
1506                 case 's':
1507                         break;
1508
1509                 case 'm':
1510                         break;
1511
1512                 case 'p':
1513                         /* older (pre-1.0) versions of ardour used this */
1514                         break;
1515
1516                 default:
1517                         warning << _("dubious automation event found (and ignored)") << endmsg;
1518                 }
1519         }
1520
1521         return 0;
1522 }
1523
1524 int
1525 IO::connecting_became_legal ()
1526 {
1527         int ret;
1528
1529         if (pending_state_node == 0) {
1530                 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1531                 /*NOTREACHED*/
1532                 return -1;
1533         }
1534
1535         connection_legal_c.disconnect ();
1536
1537         ret = make_connections (*pending_state_node);
1538
1539         if (ports_legal) {
1540                 delete pending_state_node;
1541                 pending_state_node = 0;
1542         }
1543
1544         return ret;
1545 }
1546 int
1547 IO::ports_became_legal ()
1548 {
1549         int ret;
1550
1551         if (pending_state_node == 0) {
1552                 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1553                 /*NOTREACHED*/
1554                 return -1;
1555         }
1556
1557         port_legal_c.disconnect ();
1558
1559         ret = create_ports (*pending_state_node);
1560
1561         if (connecting_legal) {
1562                 delete pending_state_node;
1563                 pending_state_node = 0;
1564         }
1565
1566         return ret;
1567 }
1568
1569 int
1570 IO::create_ports (const XMLNode& node)
1571 {
1572         const XMLProperty* prop;
1573         int num_inputs = 0;
1574         int num_outputs = 0;
1575
1576         /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1577          * break the session file format.
1578          */
1579         if ((prop = node.property ("input-connection")) != 0) {
1580
1581                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1582                 
1583                 if (c == 0) {
1584                         error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1585
1586                         if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1587                                 error << _("No input bundles available as a replacement")
1588                                       << endmsg;
1589                                 return -1;
1590                         }  else {
1591                                 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1592                                      << endmsg;
1593                         }
1594                 } 
1595
1596                 num_inputs = c->nchannels();
1597
1598         } else if ((prop = node.property ("inputs")) != 0) {
1599
1600                 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1601         }
1602         
1603         if ((prop = node.property ("output-connection")) != 0) {
1604                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1605
1606                 if (c == 0) {
1607                         error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1608
1609                         if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1610                                 error << _("No output bundles available as a replacement")
1611                                       << endmsg;
1612                                 return -1;
1613                         }  else {
1614                                 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1615                                      << endmsg;
1616                         }
1617                 } 
1618
1619                 num_outputs = c->nchannels ();
1620                 
1621         } else if ((prop = node.property ("outputs")) != 0) {
1622                 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1623         }
1624
1625         no_panner_reset = true;
1626
1627         // FIXME: audio-only
1628         if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1629                 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1630                 return -1;
1631         }
1632
1633         no_panner_reset = false;
1634
1635         set_deferred_state ();
1636
1637         PortsCreated();
1638         return 0;
1639 }
1640
1641
1642 int
1643 IO::make_connections (const XMLNode& node)
1644 {
1645         const XMLProperty* prop;
1646
1647         if ((prop = node.property ("input-connection")) != 0) {
1648                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1649                 
1650                 if (c == 0) {
1651                         error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1652
1653                         if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1654                                 error << _("No input connections available as a replacement")
1655                                       << endmsg;
1656                                 return -1;
1657                         } else {
1658                                 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1659                                      << endmsg;
1660                         }
1661                 } 
1662
1663                 connect_input_ports_to_bundle (c, this);
1664
1665         } else if ((prop = node.property ("inputs")) != 0) {
1666                 if (set_inputs (prop->value())) {
1667                         error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1668                         return -1;
1669                 }
1670         }
1671         
1672         if ((prop = node.property ("output-bundle")) != 0) {
1673                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1674                 
1675                 if (c == 0) {
1676                         error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1677
1678                         if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1679                                 error << _("No output bundles available as a replacement")
1680                                       << endmsg;
1681                                 return -1;
1682                         }  else {
1683                                 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1684                                      << endmsg;
1685                         }
1686                 } 
1687
1688                 connect_output_ports_to_bundle (c, this);
1689                 
1690         } else if ((prop = node.property ("outputs")) != 0) {
1691                 if (set_outputs (prop->value())) {
1692                         error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1693                         return -1;
1694                 }
1695         }
1696         
1697         return 0;
1698 }
1699
1700 int
1701 IO::set_inputs (const string& str)
1702 {
1703         vector<string> ports;
1704         int i;
1705         int n;
1706         uint32_t nports;
1707         
1708         if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1709                 return 0;
1710         }
1711
1712         // FIXME: audio-only
1713         if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1714                 return -1;
1715         }
1716
1717         string::size_type start, end, ostart;
1718
1719         ostart = 0;
1720         start = 0;
1721         end = 0;
1722         i = 0;
1723
1724         while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1725                 start += 1;
1726
1727                 if ((end = str.find_first_of ('}', start)) == string::npos) {
1728                         error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1729                         return -1;
1730                 }
1731
1732                 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1733                         error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1734
1735                         return -1;
1736                         
1737                 } else if (n > 0) {
1738
1739                         for (int x = 0; x < n; ++x) {
1740                                 connect_input (input (i), ports[x], this);
1741                         }
1742                 }
1743
1744                 ostart = end+1;
1745                 i++;
1746         }
1747
1748         return 0;
1749 }
1750
1751 int
1752 IO::set_outputs (const string& str)
1753 {
1754         vector<string> ports;
1755         int i;
1756         int n;
1757         uint32_t nports;
1758         
1759         if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1760                 return 0;
1761         }
1762
1763         // FIXME: audio-only
1764         if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1765                 return -1;
1766         }
1767
1768         string::size_type start, end, ostart;
1769
1770         ostart = 0;
1771         start = 0;
1772         end = 0;
1773         i = 0;
1774
1775         while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1776                 start += 1;
1777
1778                 if ((end = str.find_first_of ('}', start)) == string::npos) {
1779                         error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1780                         return -1;
1781                 }
1782
1783                 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1784                         error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1785
1786                         return -1;
1787                         
1788                 } else if (n > 0) {
1789
1790                         for (int x = 0; x < n; ++x) {
1791                                 connect_output (output (i), ports[x], this);
1792                         }
1793                 }
1794
1795                 ostart = end+1;
1796                 i++;
1797         }
1798
1799         return 0;
1800 }
1801
1802 int
1803 IO::parse_io_string (const string& str, vector<string>& ports)
1804 {
1805         string::size_type pos, opos;
1806
1807         if (str.length() == 0) {
1808                 return 0;
1809         }
1810
1811         pos = 0;
1812         opos = 0;
1813
1814         ports.clear ();
1815
1816         while ((pos = str.find_first_of (',', opos)) != string::npos) {
1817                 ports.push_back (str.substr (opos, pos - opos));
1818                 opos = pos + 1;
1819         }
1820         
1821         if (opos < str.length()) {
1822                 ports.push_back (str.substr(opos));
1823         }
1824
1825         return ports.size();
1826 }
1827
1828 int
1829 IO::parse_gain_string (const string& str, vector<string>& ports)
1830 {
1831         string::size_type pos, opos;
1832
1833         pos = 0;
1834         opos = 0;
1835         ports.clear ();
1836
1837         while ((pos = str.find_first_of (',', opos)) != string::npos) {
1838                 ports.push_back (str.substr (opos, pos - opos));
1839                 opos = pos + 1;
1840         }
1841         
1842         if (opos < str.length()) {
1843                 ports.push_back (str.substr(opos));
1844         }
1845
1846         return ports.size();
1847 }
1848
1849 bool
1850 IO::set_name (const string& str)
1851 {
1852         if (str == _name) {
1853                 return true;
1854         }
1855         
1856         /* replace all colons in the name. i wish we didn't have to do this */
1857         string name = str;
1858
1859         if (replace_all (name, ":", "-")) {
1860                 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1861         }
1862
1863         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1864                 string current_name = i->short_name();
1865                 current_name.replace (current_name.find (_name), _name.length(), name);
1866                 i->set_name (current_name);
1867         }
1868
1869         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1870                 string current_name = i->short_name();
1871                 current_name.replace (current_name.find (_name), _name.length(), name);
1872                 i->set_name (current_name);
1873         }
1874
1875         bool const r = SessionObject::set_name(name);
1876
1877         setup_bundles ();
1878
1879         return r;
1880 }
1881
1882 void
1883 IO::set_input_minimum (ChanCount n)
1884 {
1885         _input_minimum = n;
1886 }
1887
1888 void
1889 IO::set_input_maximum (ChanCount n)
1890 {
1891         _input_maximum = n;
1892 }
1893
1894 void
1895 IO::set_output_minimum (ChanCount n)
1896 {
1897         _output_minimum = n;
1898 }
1899
1900 void
1901 IO::set_output_maximum (ChanCount n)
1902 {
1903         _output_maximum = n;
1904 }
1905
1906 void
1907 IO::set_port_latency (nframes_t nframes)
1908 {
1909         Glib::Mutex::Lock lm (io_lock);
1910
1911         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1912                 i->set_latency (nframes);
1913         }
1914 }
1915
1916 nframes_t
1917 IO::output_latency () const
1918 {
1919         nframes_t max_latency;
1920         nframes_t latency;
1921
1922         max_latency = 0;
1923
1924         /* io lock not taken - must be protected by other means */
1925
1926         for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1927                 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1928                         max_latency = latency;
1929                 }
1930         }
1931
1932         return max_latency;
1933 }
1934
1935 nframes_t
1936 IO::input_latency () const
1937 {
1938         nframes_t max_latency;
1939         nframes_t latency;
1940
1941         max_latency = 0;
1942
1943         /* io lock not taken - must be protected by other means */
1944
1945         for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1946                 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1947                         max_latency = latency;
1948                 } 
1949         }
1950
1951         return max_latency;
1952 }
1953
1954 int
1955 IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
1956 {
1957         uint32_t limit;
1958
1959         {
1960                 BLOCK_PROCESS_CALLBACK ();
1961                 Glib::Mutex::Lock lm2 (io_lock);
1962                 
1963                 limit = c->nchannels();
1964                 
1965                 drop_input_bundle ();
1966                 
1967                 // FIXME bundles only work for audio-only
1968                 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1969                         return -1;
1970                 }
1971
1972                 /* first pass: check the current state to see what's correctly
1973                    connected, and drop anything that we don't want.
1974                 */
1975                 
1976                 for (uint32_t n = 0; n < limit; ++n) {
1977                         const Bundle::PortList& pl = c->channel_ports (n);
1978                         
1979                         for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1980                                 
1981                                 if (!_inputs.port(n)->connected_to ((*i))) {
1982                                         
1983                                         /* clear any existing connections */
1984                                         
1985                                         _session.engine().disconnect (*_inputs.port(n));
1986                                         
1987                                 } else if (_inputs.port(n)->connected() > 1) {
1988                                         
1989                                         /* OK, it is connected to the port we want,
1990                                            but its also connected to other ports.
1991                                            Change that situation.
1992                                         */
1993                                         
1994                                         /* XXX could be optimized to not drop
1995                                            the one we want.
1996                                         */
1997                                         
1998                                         _session.engine().disconnect (*_inputs.port(n));
1999                                         
2000                                 }
2001                         }
2002                 }
2003                 
2004                 /* second pass: connect all requested ports where necessary */
2005                 
2006                 for (uint32_t n = 0; n < limit; ++n) {
2007                         const Bundle::PortList& pl = c->channel_ports (n);
2008                         
2009                         for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2010                                 
2011                                 if (!_inputs.port(n)->connected_to ((*i))) {
2012                                         
2013                                         if (_session.engine().connect (*i, _inputs.port(n)->name())) {
2014                                                 return -1;
2015                                         }
2016                                 }
2017                                 
2018                         }
2019                 }
2020                 
2021                 _input_bundle = c;
2022                 
2023                 input_bundle_configuration_connection = c->ConfigurationChanged.connect
2024                         (mem_fun (*this, &IO::input_bundle_configuration_changed));
2025                 input_bundle_connection_connection = c->PortsChanged.connect
2026                         (mem_fun (*this, &IO::input_bundle_connection_changed));
2027         }
2028
2029         input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2030         return 0;
2031 }
2032
2033 int
2034 IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
2035 {
2036         uint32_t limit; 
2037
2038         {
2039                 BLOCK_PROCESS_CALLBACK ();
2040                 Glib::Mutex::Lock lm2 (io_lock);
2041
2042                 limit = c->nchannels();
2043                         
2044                 drop_output_bundle ();
2045
2046                 // FIXME: audio-only
2047                 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2048                         return -1;
2049                 }
2050
2051                 /* first pass: check the current state to see what's correctly
2052                    connected, and drop anything that we don't want.
2053                 */
2054                         
2055                 for (uint32_t n = 0; n < limit; ++n) {
2056
2057                         const Bundle::PortList& pl = c->channel_ports (n);
2058                                 
2059                         for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2060                                         
2061                                 if (!_outputs.port(n)->connected_to ((*i))) {
2062
2063                                         /* clear any existing connections */
2064
2065                                         _session.engine().disconnect (*_outputs.port(n));
2066
2067                                 } else if (_outputs.port(n)->connected() > 1) {
2068
2069                                         /* OK, it is connected to the port we want,
2070                                            but its also connected to other ports.
2071                                            Change that situation.
2072                                         */
2073
2074                                         /* XXX could be optimized to not drop
2075                                            the one we want.
2076                                         */
2077                                                 
2078                                         _session.engine().disconnect (*_outputs.port(n));
2079                                 }
2080                         }
2081                 }
2082
2083                 /* second pass: connect all requested ports where necessary */
2084
2085                 for (uint32_t n = 0; n < limit; ++n) {
2086
2087                         const Bundle::PortList& pl = c->channel_ports (n);
2088                                 
2089                         for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2090                                         
2091                                 if (!_outputs.port(n)->connected_to ((*i))) {
2092                                                 
2093                                         if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2094                                                 return -1;
2095                                         }
2096                                 }
2097                         }
2098                 }
2099
2100                 _output_bundle = c;
2101
2102                 output_bundle_configuration_connection = c->ConfigurationChanged.connect
2103                         (mem_fun (*this, &IO::output_bundle_configuration_changed));
2104                 output_bundle_connection_connection = c->PortsChanged.connect
2105                         (mem_fun (*this, &IO::output_bundle_connection_changed));
2106         }
2107
2108         output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2109
2110         return 0;
2111 }
2112
2113 int
2114 IO::disable_connecting ()
2115 {
2116         connecting_legal = false;
2117         return 0;
2118 }
2119
2120 int
2121 IO::enable_connecting ()
2122 {
2123         connecting_legal = true;
2124         return ConnectingLegal ();
2125 }
2126
2127 int
2128 IO::disable_ports ()
2129 {
2130         ports_legal = false;
2131         return 0;
2132 }
2133
2134 int
2135 IO::enable_ports ()
2136 {
2137         ports_legal = true;
2138         return PortsLegal ();
2139 }
2140
2141 int
2142 IO::disable_panners (void)
2143 {
2144         panners_legal = false;
2145         return 0;
2146 }
2147
2148 int
2149 IO::reset_panners ()
2150 {
2151         panners_legal = true;
2152         return PannersLegal ();
2153 }
2154
2155 void
2156 IO::input_bundle_connection_changed (int ignored)
2157 {
2158         connect_input_ports_to_bundle (_input_bundle, this);
2159 }
2160
2161 void
2162 IO::input_bundle_configuration_changed ()
2163 {
2164         connect_input_ports_to_bundle (_input_bundle, this);
2165 }
2166
2167 void
2168 IO::output_bundle_connection_changed (int ignored)
2169 {
2170         connect_output_ports_to_bundle (_output_bundle, this);
2171 }
2172
2173 void
2174 IO::output_bundle_configuration_changed ()
2175 {
2176         connect_output_ports_to_bundle (_output_bundle, this);
2177 }
2178
2179 void
2180 IO::GainControl::set_value (float val)
2181 {
2182         // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2183         if (val > 1.99526231f)
2184                 val = 1.99526231f;
2185
2186         _user_value = val;
2187         _io.set_gain (val, this);
2188         
2189         Changed(); /* EMIT SIGNAL */
2190 }
2191
2192 float
2193 IO::GainControl::get_value (void) const
2194 {
2195         return AutomationControl::get_value();
2196 }
2197
2198 void
2199 IO::setup_peak_meters()
2200 {
2201         ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2202         _meter->configure_io(max_streams, max_streams);
2203 }
2204
2205 /**
2206     Update the peak meters.
2207
2208     The meter signal lock is taken to prevent modification of the 
2209     Meter signal while updating the meters, taking the meter signal
2210     lock prior to taking the io_lock ensures that all IO will remain 
2211     valid while metering.
2212 */   
2213 void
2214 IO::update_meters()
2215 {
2216     Glib::Mutex::Lock guard (m_meter_signal_lock);
2217     
2218     Meter(); /* EMIT SIGNAL */
2219 }
2220
2221 void
2222 IO::meter ()
2223 {
2224         // FIXME: Ugly.  Meter should manage the lock, if it's necessary
2225         
2226         Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2227         _meter->meter();
2228 }
2229
2230 void
2231 IO::clear_automation ()
2232 {
2233         Automatable::clear_automation (); // clears gain automation
2234         _panner->clear_automation ();
2235 }
2236
2237 void
2238 IO::set_parameter_automation_state (Parameter param, AutoState state)
2239 {
2240         // XXX: would be nice to get rid of this special hack
2241
2242         if (param.type() == GainAutomation) {
2243
2244                 bool changed = false;
2245
2246                 { 
2247                         Glib::Mutex::Lock lm (_automation_lock);
2248
2249                         boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
2250
2251                         if (state != gain_auto->automation_state()) {
2252                                 changed = true;
2253                                 _last_automation_snapshot = 0;
2254                                 gain_auto->set_automation_state (state);
2255
2256                                 if (state != Off) {
2257                                         // FIXME: shouldn't this use Curve?
2258                                         set_gain (gain_auto->eval (_session.transport_frame()), this);
2259                                 }
2260                         }
2261                 }
2262
2263                 if (changed) {
2264                         _session.set_dirty ();
2265                 }
2266
2267         } else {
2268                 Automatable::set_parameter_automation_state(param, state);
2269         }
2270 }
2271
2272 void
2273 IO::inc_gain (gain_t factor, void *src)
2274 {
2275         if (_desired_gain == 0.0f)
2276                 set_gain (0.000001f + (0.000001f * factor), src);
2277         else
2278                 set_gain (_desired_gain + (_desired_gain * factor), src);
2279 }
2280
2281 void
2282 IO::set_gain (gain_t val, void *src)
2283 {
2284         // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2285         if (val > 1.99526231f)
2286                 val = 1.99526231f;
2287
2288         if (src != _gain_control.get()) {
2289                 _gain_control->set_value(val);
2290                 // bit twisty, this will come back and call us again
2291                 // (this keeps control in sync with reality)
2292                 return;
2293         }
2294
2295         {
2296                 Glib::Mutex::Lock dm (declick_lock);
2297                 _desired_gain = val;
2298         }
2299
2300         if (_session.transport_stopped()) {
2301                 _gain = val;
2302         }
2303         
2304         if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
2305                 _gain_control->list()->add (_session.transport_frame(), val);
2306                 
2307         }
2308
2309         _session.set_dirty();
2310 }
2311
2312 void
2313 IO::start_pan_touch (uint32_t which)
2314 {
2315         if (which < _panner->size()) {
2316                 (*_panner)[which]->pan_control()->list()->start_touch();
2317         }
2318 }
2319
2320 void
2321 IO::end_pan_touch (uint32_t which)
2322 {
2323         if (which < _panner->size()) {
2324                 (*_panner)[which]->pan_control()->list()->stop_touch();
2325         }
2326
2327 }
2328
2329 void
2330 IO::automation_snapshot (nframes_t now)
2331 {
2332         Automatable::automation_snapshot (now);
2333
2334         if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
2335                 _panner->snapshot (now);
2336         }
2337 }
2338
2339 void
2340 IO::transport_stopped (nframes_t frame)
2341 {
2342         _gain_control->list()->reposition_for_rt_add (frame);
2343
2344         if (_gain_control->list()->automation_state() != Off) {
2345                 
2346                 /* the src=0 condition is a special signal to not propagate 
2347                    automation gain changes into the mix group when locating.
2348                 */
2349
2350                 // FIXME: shouldn't this use Curve?
2351                 set_gain (_gain_control->list()->eval (frame), 0);
2352         }
2353
2354         _panner->transport_stopped (frame);
2355 }
2356
2357 int32_t
2358 IO::find_input_port_hole ()
2359 {
2360         /* CALLER MUST HOLD IO LOCK */
2361
2362         uint32_t n;
2363
2364         if (_inputs.empty()) {
2365                 return 1;
2366         }
2367
2368         for (n = 1; n < UINT_MAX; ++n) {
2369                 char buf[jack_port_name_size()];
2370                 PortSet::iterator i = _inputs.begin();
2371
2372                 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2373
2374                 for ( ; i != _inputs.end(); ++i) {
2375                         if (i->short_name() == buf) {
2376                                 break;
2377                         }
2378                 }
2379
2380                 if (i == _inputs.end()) {
2381                         break;
2382                 }
2383         }
2384         return n;
2385 }
2386
2387 int32_t
2388 IO::find_output_port_hole ()
2389 {
2390         /* CALLER MUST HOLD IO LOCK */
2391
2392         uint32_t n;
2393
2394         if (_outputs.empty()) {
2395                 return 1;
2396         }
2397
2398         for (n = 1; n < UINT_MAX; ++n) {
2399                 char buf[jack_port_name_size()];
2400                 PortSet::iterator i = _outputs.begin();
2401
2402                 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2403
2404                 for ( ; i != _outputs.end(); ++i) {
2405                         if (i->short_name() == buf) {
2406                                 break;
2407                         }
2408                 }
2409
2410                 if (i == _outputs.end()) {
2411                         break;
2412                 }
2413         }
2414         
2415         return n;
2416 }
2417
2418 AudioPort*
2419 IO::audio_input(uint32_t n) const
2420 {
2421         return dynamic_cast<AudioPort*>(input(n));
2422 }
2423
2424 AudioPort*
2425 IO::audio_output(uint32_t n) const
2426 {
2427         return dynamic_cast<AudioPort*>(output(n));
2428 }
2429
2430 MidiPort*
2431 IO::midi_input(uint32_t n) const
2432 {
2433         return dynamic_cast<MidiPort*>(input(n));
2434 }
2435
2436 MidiPort*
2437 IO::midi_output(uint32_t n) const
2438 {
2439         return dynamic_cast<MidiPort*>(output(n));
2440 }
2441
2442 void
2443 IO::set_phase_invert (bool yn, void *src)
2444 {
2445         if (_phase_invert != yn) {
2446                 _phase_invert = yn;
2447                 //  phase_invert_changed (src); /* EMIT SIGNAL */
2448         }
2449 }
2450
2451 void
2452 IO::set_denormal_protection (bool yn, void *src)
2453 {
2454         if (_denormal_protection != yn) {
2455                 _denormal_protection = yn;
2456                 //  denormal_protection_changed (src); /* EMIT SIGNAL */
2457         }
2458 }
2459
2460 void
2461 IO::update_port_total_latencies ()
2462 {
2463         /* io_lock, not taken: function must be called from Session::process() calltree */
2464
2465         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2466                 _session.engine().update_total_latency (*i);
2467         }
2468
2469         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2470                 _session.engine().update_total_latency (*i);
2471         }
2472 }
2473
2474
2475 /**
2476  *  Setup bundles that describe our inputs and outputs.
2477  */
2478
2479 void
2480 IO::setup_bundles ()
2481 {
2482         char buf[32];
2483
2484         snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
2485         _bundle_for_inputs->set_name (buf, 0);
2486         int const ins = n_inputs().n_total();
2487         _bundle_for_inputs->set_nchannels (ins);
2488         
2489         for (int i = 0; i < ins; ++i) {
2490                 _bundle_for_inputs->add_port_to_channel (i, _inputs.port(i)->name ());
2491         }
2492
2493         snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
2494         _bundle_for_outputs->set_name (buf, 0);
2495         int const outs = n_outputs().n_total();
2496         _bundle_for_outputs->set_nchannels (outs);
2497         
2498         for (int i = 0; i < outs; ++i) {
2499                 _bundle_for_outputs->add_port_to_channel (i, _outputs.port(i)->name ());
2500         }
2501 }
2502
2503
2504 /**
2505  *  Create and setup bundles that describe our inputs and outputs.
2506  */
2507
2508 void
2509 IO::create_bundles ()
2510 {
2511         _bundle_for_inputs = boost::shared_ptr<Bundle> (
2512                 new InputBundle ("", true)
2513                 );
2514         
2515         _bundle_for_outputs = boost::shared_ptr<Bundle> (
2516                 new OutputBundle ("", true)
2517                 );
2518
2519         setup_bundles ();
2520 }
2521
2522 boost::shared_ptr<Bundle>
2523 IO::input_bundle()
2524 {
2525         if (_input_bundle) {
2526                 return _input_bundle;
2527         }
2528
2529         /* XXX: will only report the first bundle found; should really return a list, I think */
2530            
2531         /* check that _input_bundle is right wrt the connections that are currently made */
2532
2533         /* make a vector of the first output connected to each of our inputs */
2534         std::vector<std::string> connected;
2535         for (uint32_t i = 0; i < _inputs.num_ports(); ++i) {
2536                 const char** c = _inputs.port(i)->get_connections ();
2537                 if (c) {
2538                         connected.push_back (c[0]);
2539                 }
2540         }
2541
2542         _input_bundle = _session.bundle_by_ports (connected);
2543         return _input_bundle;
2544 }
2545
2546
2547 boost::shared_ptr<Bundle>
2548 IO::output_bundle()
2549 {
2550         if (_output_bundle) {
2551                 return _output_bundle;
2552         }
2553         
2554         /* XXX: will only report the first bundle found; should really return a list, I think */
2555            
2556         /* check that _output_bundle is right wrt the connections that are currently made */
2557
2558         /* make a vector of the first input connected to each of our outputs */
2559         std::vector<std::string> connected;
2560         for (uint32_t i = 0; i < _outputs.num_ports(); ++i) {
2561                 const char** c = _outputs.port(i)->get_connections ();
2562                 if (c) {
2563                         connected.push_back (c[0]);
2564                 }
2565         }
2566
2567         _output_bundle = _session.bundle_by_ports (connected);
2568         return _output_bundle;
2569 }