Make sure we notice when an IO's port count is reduced as well as when it's increased...
[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::PortCountChanged;
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 PortCountChanged signal to connect output buffers
152         IO::PortCountChanged.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 PortCountChanged signal to connect output buffers
192         IO::PortCountChanged.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                 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
553         }
554
555         if (change == ConnectionsChanged) {
556                 setup_bundles ();
557         }
558
559         if (change != NoChange) {
560                 output_changed (change, src);
561                 _session.set_dirty ();
562                 return 0;
563         }
564
565         return -1;
566 }
567
568 /** Add an output port.
569  *
570  * @param destination Name of input port to connect new port to.
571  * @param src Source for emitted ConfigurationChanged signal.
572  * @param type Data type of port.  Default value (NIL) will use this IO's default type.
573  */
574 int
575 IO::add_output_port (string destination, void* src, DataType type)
576 {
577         Port* our_port;
578         char name[64];
579
580         if (type == DataType::NIL)
581                 type = _default_type;
582
583         {
584                 BLOCK_PROCESS_CALLBACK ();
585
586                 
587                 { 
588                         Glib::Mutex::Lock lm (io_lock);
589                         
590                         if (n_outputs() >= _output_maximum) {
591                                 return -1;
592                         }
593                 
594                         /* Create a new output port */
595                         
596                         // FIXME: naming scheme for differently typed ports?
597                         if (_output_maximum.get(type) == 1) {
598                                 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
599                         } else {
600                                 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
601                         }
602                         
603                         if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
604                                 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
605                                 return -1;
606                         }
607                         
608                         _outputs.add (our_port);
609                         drop_output_bundle ();
610                         setup_peak_meters ();
611                         reset_panner ();
612                 }
613
614                 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
615         }
616
617         if (destination.length()) {
618                 if (_session.engine().connect (our_port->name(), destination)) {
619                         return -1;
620                 }
621         }
622         
623         // pan_changed (src); /* EMIT SIGNAL */
624         output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
625         setup_bundles ();
626         _session.set_dirty ();
627
628         return 0;
629 }
630
631 int
632 IO::remove_input_port (Port* port, void* src)
633 {
634         IOChange change (NoChange);
635
636         {
637                 BLOCK_PROCESS_CALLBACK ();
638
639                 
640                 {
641                         Glib::Mutex::Lock lm (io_lock);
642
643                         if (n_inputs() <= _input_minimum) {
644                                 /* sorry, you can't do this */
645                                 return -1;
646                         }
647
648                         if (_inputs.remove(port)) {
649                                 change = IOChange (change|ConfigurationChanged);
650
651                                 if (port->connected()) {
652                                         change = IOChange (change|ConnectionsChanged);
653                                 } 
654
655                                 _session.engine().unregister_port (*port);
656                                 drop_input_bundle ();
657                                 
658                                 setup_peak_meters ();
659                                 reset_panner ();
660                         }
661                 }
662                 
663                 PortCountChanged (n_inputs ()); /* EMIT SIGNAL */
664         }
665
666         if (change == ConfigurationChanged) {
667                 setup_bundles ();
668         }
669
670         if (change != NoChange) {
671                 input_changed (change, src);
672                 _session.set_dirty ();
673                 return 0;
674         } 
675         
676         return -1;
677 }
678
679
680 /** Add an input port.
681  *
682  * @param type Data type of port.  The appropriate Jack port type, and @ref Port will be created.
683  * @param destination Name of input port to connect new port to.
684  * @param src Source for emitted ConfigurationChanged signal.
685  */
686 int
687 IO::add_input_port (string source, void* src, DataType type)
688 {
689         Port* our_port;
690         char name[64];
691         
692         if (type == DataType::NIL)
693                 type = _default_type;
694
695         {
696                 BLOCK_PROCESS_CALLBACK ();
697                 
698                 { 
699                         Glib::Mutex::Lock lm (io_lock);
700                         
701                         if (n_inputs() >= _input_maximum) {
702                                 return -1;
703                         }
704
705                         /* Create a new input port */
706                         
707                         // FIXME: naming scheme for differently typed ports?
708                         if (_input_maximum.get(type) == 1) {
709                                 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
710                         } else {
711                                 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
712                         }
713
714                         if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
715                                 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
716                                 return -1;
717                         }
718
719                         _inputs.add (our_port);
720                         drop_input_bundle ();
721                         setup_peak_meters ();
722                         reset_panner ();
723                 }
724
725                 PortCountChanged (n_inputs()); /* EMIT SIGNAL */
726         }
727
728         if (source.length()) {
729
730                 if (_session.engine().connect (source, our_port->name())) {
731                         return -1;
732                 }
733         } 
734
735         // pan_changed (src); /* EMIT SIGNAL */
736         input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
737         setup_bundles ();
738         _session.set_dirty ();
739         
740         return 0;
741 }
742
743 int
744 IO::disconnect_inputs (void* src)
745 {
746         { 
747                 BLOCK_PROCESS_CALLBACK ();
748                 
749                 {
750                         Glib::Mutex::Lock lm (io_lock);
751                         
752                         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
753                                 _session.engine().disconnect (*i);
754                         }
755
756                         drop_input_bundle ();
757                 }
758         }
759         
760         input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
761         
762         return 0;
763 }
764
765 int
766 IO::disconnect_outputs (void* src)
767 {
768         {
769                 BLOCK_PROCESS_CALLBACK ();
770                 
771                 {
772                         Glib::Mutex::Lock lm (io_lock);
773                         
774                         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
775                                 _session.engine().disconnect (*i);
776                         }
777
778                         drop_output_bundle ();
779                 }
780         }
781
782         output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
783         _session.set_dirty ();
784         
785         return 0;
786 }
787
788 bool
789 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
790 {
791         Port* input_port = 0;
792         bool  changed    = false;
793
794
795         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
796                 
797                 const size_t n = count.get(*t);
798         
799                 /* remove unused ports */
800                 for (size_t i = n_inputs().get(*t); i > n; --i) {
801                         input_port = _inputs.port(*t, i-1);
802
803                         assert(input_port);
804                         _inputs.remove(input_port);
805                         _session.engine().unregister_port (*input_port);
806
807                         changed = true;
808                 }
809
810                 /* create any necessary new ports */
811                 while (n_inputs().get(*t) < n) {
812
813                         char buf[64];
814
815                         if (_input_maximum.get(*t) == 1) {
816                                 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
817                         } else {
818                                 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
819                         }
820
821                         try {
822
823                                 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
824                                         error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
825                                         return -1;
826                                 }
827                         }
828
829                         catch (AudioEngine::PortRegistrationFailure& err) {
830                                 setup_peak_meters ();
831                                 reset_panner ();
832                                 /* pass it on */
833                                 throw AudioEngine::PortRegistrationFailure();
834                         }
835
836                         _inputs.add (input_port);
837                         changed = true;
838                 }
839         }
840         
841         if (changed) {
842                 drop_input_bundle ();
843                 setup_peak_meters ();
844                 reset_panner ();
845                 PortCountChanged (n_inputs()); /* EMIT SIGNAL */
846                 _session.set_dirty ();
847         }
848         
849         if (clear) {
850                 /* disconnect all existing ports so that we get a fresh start */
851                 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
852                         _session.engine().disconnect (*i);
853                 }
854         }
855
856         return changed;
857 }
858
859 /** Attach output_buffers to port buffers.
860  * 
861  * Connected to IO's own PortCountChanged signal.
862  */
863 void
864 IO::attach_buffers(ChanCount ignored)
865 {
866         _output_buffers->attach_buffers(_outputs);
867 }
868
869 int
870 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
871 {
872         bool in_changed     = false;
873         bool out_changed    = false;
874         bool need_pan_reset = false;
875
876         in = min (_input_maximum, in);
877
878         out = min (_output_maximum, out);
879
880         if (in == n_inputs() && out == n_outputs() && !clear) {
881                 return 0;
882         }
883
884         {
885                 BLOCK_PROCESS_CALLBACK ();
886                 Glib::Mutex::Lock lm (io_lock);
887
888                 Port* port;
889                 
890                 if (n_outputs() != out) {
891                         need_pan_reset = true;
892                 }
893                 
894                 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
895
896                         const size_t nin = in.get(*t);
897                         const size_t nout = out.get(*t);
898
899                         Port* output_port = 0;
900                         Port* input_port = 0;
901
902                         /* remove unused output ports */
903                         for (size_t i = n_outputs().get(*t); i > nout; --i) {
904                                 output_port = _outputs.port(*t, i-1);
905
906                                 assert(output_port);
907                                 _outputs.remove(output_port);
908                                 _session.engine().unregister_port (*output_port);
909
910                                 out_changed = true;
911                         }
912
913                         /* remove unused input ports */
914                         for (size_t i = n_inputs().get(*t); i > nin; --i) {
915                                 input_port = _inputs.port(*t, i-1);
916
917                                 assert(input_port);
918                                 _inputs.remove(input_port);
919                                 _session.engine().unregister_port (*input_port);
920
921                                 in_changed = true;
922                         }
923
924                         /* create any necessary new input ports */
925
926                         while (n_inputs().get(*t) < nin) {
927
928                                 char buf[64];
929
930                                 /* Create a new input port */
931
932                                 if (_input_maximum.get(*t) == 1) {
933                                         snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
934                                 } else {
935                                         snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
936                                 }
937
938                                 try {
939                                         if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
940                                                 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
941                                                 return -1;
942                                         }
943                                 }
944                                 
945                                 catch (AudioEngine::PortRegistrationFailure& err) {
946                                         setup_peak_meters ();
947                                         reset_panner ();
948                                         /* pass it on */
949                                         throw AudioEngine::PortRegistrationFailure();
950                                 }
951
952                                 _inputs.add (port);
953                                 in_changed = true;
954                         }
955
956                         /* create any necessary new output ports */
957
958                         while (n_outputs().get(*t) < nout) {
959
960                                 char buf[64];
961
962                                 /* Create a new output port */
963
964                                 if (_output_maximum.get(*t) == 1) {
965                                         snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
966                                 } else {
967                                         snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
968                                 }
969
970                                 try { 
971                                         if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
972                                                 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
973                                                 return -1;
974                                         }
975                                 }
976
977                                 catch (AudioEngine::PortRegistrationFailure& err) {
978                                         setup_peak_meters ();
979                                         reset_panner ();
980                                         /* pass it on */
981                                         throw AudioEngine::PortRegistrationFailure ();
982                                 }
983
984                                 _outputs.add (port);
985                                 out_changed = true;
986                         }
987                 }
988                 
989                 if (clear) {
990                         
991                         /* disconnect all existing ports so that we get a fresh start */
992                         
993                         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
994                                 _session.engine().disconnect (*i);
995                         }
996                         
997                         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
998                                 _session.engine().disconnect (*i);
999                         }
1000                 }
1001                 
1002                 if (in_changed || out_changed) {
1003                         setup_peak_meters ();
1004                         reset_panner ();
1005                 }
1006         }
1007
1008         if (out_changed) {
1009                 drop_output_bundle ();
1010                 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1011         }
1012         
1013         if (in_changed) {
1014                 drop_input_bundle ();
1015                 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1016         }
1017
1018         if (in_changed || out_changed) {
1019                 PortCountChanged (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1020                 setup_bundles ();
1021                 _session.set_dirty ();
1022         }
1023
1024         return 0;
1025 }
1026
1027 int
1028 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1029 {
1030         bool changed = false;
1031
1032         count = min (_input_maximum, count);
1033
1034         if (count == n_inputs() && !clear) {
1035                 return 0;
1036         }
1037
1038         if (lockit) {
1039                 BLOCK_PROCESS_CALLBACK ();
1040                 Glib::Mutex::Lock im (io_lock);
1041                 changed = ensure_inputs_locked (count, clear, src);
1042         } else {
1043                 changed = ensure_inputs_locked (count, clear, src);
1044         }
1045
1046         if (changed) {
1047                 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1048                 setup_bundles ();
1049                 _session.set_dirty ();
1050         }
1051         return 0;
1052 }
1053
1054 bool
1055 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1056 {
1057         Port* output_port    = 0;
1058         bool  changed        = false;
1059         bool  need_pan_reset = false;
1060
1061         if (n_outputs() != count) {
1062                 need_pan_reset = true;
1063         }
1064         
1065         for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1066
1067                 const size_t n = count.get(*t);
1068
1069                 /* remove unused ports */
1070                 for (size_t i = n_outputs().get(*t); i > n; --i) {
1071                         output_port = _outputs.port(*t, i-1);
1072
1073                         assert(output_port);
1074                         _outputs.remove(output_port);
1075                         _session.engine().unregister_port (*output_port);
1076
1077                         changed = true;
1078                 }
1079
1080                 /* create any necessary new ports */
1081                 while (n_outputs().get(*t) < n) {
1082
1083                         char buf[64];
1084
1085                         if (_output_maximum.get(*t) == 1) {
1086                                 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1087                         } else {
1088                                 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1089                         }
1090
1091                         if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1092                                 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1093                                 return -1;
1094                         }
1095
1096                         _outputs.add (output_port);
1097                         changed = true;
1098                         setup_peak_meters ();
1099
1100                         if (need_pan_reset) {
1101                                 reset_panner ();
1102                         }
1103                 }
1104         }
1105         
1106         if (changed) {
1107                 drop_output_bundle ();
1108                 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
1109                 _session.set_dirty ();
1110         }
1111         
1112         if (clear) {
1113                 /* disconnect all existing ports so that we get a fresh start */
1114                 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1115                         _session.engine().disconnect (*i);
1116                 }
1117         }
1118
1119         return changed;
1120 }
1121
1122 int
1123 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1124 {
1125         bool changed = false;
1126
1127         if (_output_maximum < ChanCount::INFINITE) {
1128                 count = min (_output_maximum, count);
1129                 if (count == n_outputs() && !clear) {
1130                         return 0;
1131                 }
1132         }
1133
1134         /* XXX caller should hold io_lock, but generally doesn't */
1135
1136         if (lockit) {
1137                 BLOCK_PROCESS_CALLBACK ();
1138                 Glib::Mutex::Lock im (io_lock);
1139                 changed = ensure_outputs_locked (count, clear, src);
1140         } else {
1141                 changed = ensure_outputs_locked (count, clear, src);
1142         }
1143
1144         if (changed) {
1145                  output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1146                  setup_bundles ();
1147         }
1148
1149         return 0;
1150 }
1151
1152 gain_t
1153 IO::effective_gain () const
1154 {
1155         if (_gain_control->list()->automation_playback()) {
1156                 return _gain_control->get_value();
1157         } else {
1158                 return _desired_gain;
1159         }
1160 }
1161
1162 void
1163 IO::reset_panner ()
1164 {
1165         if (panners_legal) {
1166                 if (!no_panner_reset) {
1167                         _panner->reset (n_outputs().n_audio(), pans_required());
1168                 }
1169         } else {
1170                 panner_legal_c.disconnect ();
1171                 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1172         }
1173 }
1174
1175 int
1176 IO::panners_became_legal ()
1177 {
1178         _panner->reset (n_outputs().n_audio(), pans_required());
1179         _panner->load (); // automation
1180         panner_legal_c.disconnect ();
1181         return 0;
1182 }
1183
1184 void
1185 IO::defer_pan_reset ()
1186 {
1187         no_panner_reset = true;
1188 }
1189
1190 void
1191 IO::allow_pan_reset ()
1192 {
1193         no_panner_reset = false;
1194         reset_panner ();
1195 }
1196
1197
1198 XMLNode&
1199 IO::get_state (void)
1200 {
1201         return state (true);
1202 }
1203
1204 XMLNode&
1205 IO::state (bool full_state)
1206 {
1207         XMLNode* node = new XMLNode (state_node_name);
1208         char buf[64];
1209         string str;
1210         bool need_ins = true;
1211         bool need_outs = true;
1212         LocaleGuard lg (X_("POSIX"));
1213         Glib::Mutex::Lock lm (io_lock);
1214
1215         node->add_property("name", _name);
1216         id().print (buf, sizeof (buf));
1217         node->add_property("id", buf);
1218
1219         str = "";
1220
1221         if (_input_bundle && !_input_bundle->dynamic()) {
1222                 node->add_property ("input-connection", _input_bundle->name());
1223                 need_ins = false;
1224         }
1225
1226         if (_output_bundle && !_output_bundle->dynamic()) {
1227                 node->add_property ("output-connection", _output_bundle->name());
1228                 need_outs = false;
1229         }
1230
1231         if (need_ins) {
1232                 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1233                         
1234                         const char **connections = i->get_connections();
1235                         
1236                         if (connections && connections[0]) {
1237                                 str += '{';
1238                                 
1239                                 for (int n = 0; connections && connections[n]; ++n) {
1240                                         if (n) {
1241                                                 str += ',';
1242                                         }
1243                                         
1244                                         /* if its a connection to our own port,
1245                                            return only the port name, not the
1246                                            whole thing. this allows connections
1247                                            to be re-established even when our
1248                                            client name is different.
1249                                         */
1250                                         
1251                                         str += _session.engine().make_port_name_relative (connections[n]);
1252                                 }       
1253
1254                                 str += '}';
1255                                 
1256                                 free (connections);
1257                         }
1258                         else {
1259                                 str += "{}";
1260                         }
1261                 }
1262                 
1263                 node->add_property ("inputs", str);
1264         }
1265
1266         if (need_outs) {
1267                 str = "";
1268                 
1269                 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1270                         
1271                         const char **connections = i->get_connections();
1272                         
1273                         if (connections && connections[0]) {
1274                                 
1275                                 str += '{';
1276                                 
1277                                 for (int n = 0; connections[n]; ++n) {
1278                                         if (n) {
1279                                                 str += ',';
1280                                         }
1281
1282                                         str += _session.engine().make_port_name_relative (connections[n]);
1283                                 }
1284
1285                                 str += '}';
1286                                 
1287                                 free (connections);
1288                         }
1289                         else {
1290                                 str += "{}";
1291                         }
1292                 }
1293                 
1294                 node->add_property ("outputs", str);
1295         }
1296
1297         node->add_child_nocopy (_panner->state (full_state));
1298         node->add_child_nocopy (_gain_control->get_state ());
1299
1300         snprintf (buf, sizeof(buf), "%2.12f", gain());
1301         node->add_property ("gain", buf);
1302
1303         /* To make backwards compatibility a bit easier, write ChanCount::INFINITE to the session file
1304            as -1.
1305         */
1306
1307         int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
1308         int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
1309
1310         snprintf (buf, sizeof(buf)-1, "%zd,%d,%zd,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
1311
1312         node->add_property ("iolimits", buf);
1313
1314         /* automation */
1315         
1316         if (full_state)
1317                 node->add_child_nocopy (get_automation_state());
1318
1319         return *node;
1320 }
1321
1322 int
1323 IO::set_state (const XMLNode& node)
1324 {
1325         const XMLProperty* prop;
1326         XMLNodeConstIterator iter;
1327         LocaleGuard lg (X_("POSIX"));
1328
1329         /* force use of non-localized representation of decimal point,
1330            since we use it a lot in XML files and so forth.
1331         */
1332
1333         if (node.name() != state_node_name) {
1334                 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1335                 return -1;
1336         }
1337
1338         if ((prop = node.property ("name")) != 0) {
1339                 _name = prop->value();
1340                 /* used to set panner name with this, but no more */
1341         } 
1342
1343         if ((prop = node.property ("id")) != 0) {
1344                 _id = prop->value ();
1345         }
1346
1347         int in_min = -1;
1348         int in_max = -1;
1349         int out_min = -1;
1350         int out_max = -1;
1351
1352         if ((prop = node.property ("iolimits")) != 0) {
1353                 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1354                         &in_min, &in_max, &out_min, &out_max);
1355
1356                 /* Correct for the difference between the way we write things to session files and the
1357                    way things are described by ChanCount; see comments in io.h about what the different
1358                    ChanCount values mean. */
1359
1360                 if (in_min < 0) {
1361                         _input_minimum = ChanCount::ZERO;
1362                 } else {
1363                         _input_minimum = ChanCount (_default_type, in_min);
1364                 }
1365
1366                 if (in_max < 0) {
1367                         _input_maximum = ChanCount::INFINITE;
1368                 } else {
1369                         _input_maximum = ChanCount (_default_type, in_max);
1370                 }
1371
1372                 if (out_min < 0) {
1373                         _output_minimum = ChanCount::ZERO;
1374                 } else {
1375                         _output_minimum = ChanCount (_default_type, out_min);
1376                 }
1377                 
1378                 if (out_max < 0) {
1379                         _output_maximum = ChanCount::INFINITE;
1380                 } else {
1381                         _output_maximum = ChanCount (_default_type, out_max);
1382                 }
1383         }
1384         
1385         if ((prop = node.property ("gain")) != 0) {
1386                 set_gain (atof (prop->value().c_str()), this);
1387                 _gain = _desired_gain;
1388         }
1389
1390         if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1391                 /* old school automation handling */
1392         }
1393
1394         for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1395
1396                 if ((*iter)->name() == "Panner") {
1397                         if (_panner == 0) {
1398                                 _panner = new Panner (_name, _session);
1399                         }
1400                         _panner->set_state (**iter);
1401                 }
1402
1403                 if ((*iter)->name() == X_("Automation")) {
1404
1405                         set_automation_state (*(*iter), Parameter(GainAutomation));
1406                 }
1407
1408                 if ((*iter)->name() == X_("controllable")) {
1409                         if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1410                                 _gain_control->set_state (**iter);
1411                         }
1412                 }
1413         }
1414
1415         if (ports_legal) {
1416
1417                 if (create_ports (node)) {
1418                         return -1;
1419                 }
1420
1421         } else {
1422
1423                 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1424         }
1425
1426         if (panners_legal) {
1427                 reset_panner ();
1428         } else {
1429                 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1430         }
1431
1432         if (connecting_legal) {
1433
1434                 if (make_connections (node)) {
1435                         return -1;
1436                 }
1437
1438         } else {
1439                 
1440                 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1441         }
1442
1443         if (!ports_legal || !connecting_legal) {
1444                 pending_state_node = new XMLNode (node);
1445         }
1446
1447         return 0;
1448 }
1449
1450 int
1451 IO::load_automation (string path)
1452 {
1453         string fullpath;
1454         ifstream in;
1455         char line[128];
1456         uint32_t linecnt = 0;
1457         float version;
1458         LocaleGuard lg (X_("POSIX"));
1459
1460         fullpath = _session.automation_dir();
1461         fullpath += path;
1462
1463         in.open (fullpath.c_str());
1464
1465         if (!in) {
1466                 fullpath = _session.automation_dir();
1467                 fullpath += _session.snap_name();
1468                 fullpath += '-';
1469                 fullpath += path;
1470
1471                 in.open (fullpath.c_str());
1472
1473                 if (!in) {
1474                         error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1475                         return -1;
1476                 }
1477         }
1478
1479         clear_automation ();
1480
1481         while (in.getline (line, sizeof(line), '\n')) {
1482                 char type;
1483                 nframes_t when;
1484                 double value;
1485
1486                 if (++linecnt == 1) {
1487                         if (memcmp (line, "version", 7) == 0) {
1488                                 if (sscanf (line, "version %f", &version) != 1) {
1489                                         error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1490                                         return -1;
1491                                 }
1492                         } else {
1493                                 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1494                                 return -1;
1495                         }
1496
1497                         continue;
1498                 }
1499
1500                 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1501                         warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1502                         continue;
1503                 }
1504
1505                 switch (type) {
1506                 case 'g':
1507                         _gain_control->list()->fast_simple_add (when, value);
1508                         break;
1509
1510                 case 's':
1511                         break;
1512
1513                 case 'm':
1514                         break;
1515
1516                 case 'p':
1517                         /* older (pre-1.0) versions of ardour used this */
1518                         break;
1519
1520                 default:
1521                         warning << _("dubious automation event found (and ignored)") << endmsg;
1522                 }
1523         }
1524
1525         return 0;
1526 }
1527
1528 int
1529 IO::connecting_became_legal ()
1530 {
1531         int ret;
1532
1533         if (pending_state_node == 0) {
1534                 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1535                 /*NOTREACHED*/
1536                 return -1;
1537         }
1538
1539         connection_legal_c.disconnect ();
1540
1541         ret = make_connections (*pending_state_node);
1542
1543         if (ports_legal) {
1544                 delete pending_state_node;
1545                 pending_state_node = 0;
1546         }
1547
1548         return ret;
1549 }
1550 int
1551 IO::ports_became_legal ()
1552 {
1553         int ret;
1554
1555         if (pending_state_node == 0) {
1556                 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1557                 /*NOTREACHED*/
1558                 return -1;
1559         }
1560
1561         port_legal_c.disconnect ();
1562
1563         ret = create_ports (*pending_state_node);
1564
1565         if (connecting_legal) {
1566                 delete pending_state_node;
1567                 pending_state_node = 0;
1568         }
1569
1570         return ret;
1571 }
1572
1573 int
1574 IO::create_ports (const XMLNode& node)
1575 {
1576         const XMLProperty* prop;
1577         int num_inputs = 0;
1578         int num_outputs = 0;
1579
1580         /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1581          * break the session file format.
1582          */
1583         if ((prop = node.property ("input-connection")) != 0) {
1584
1585                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1586                 
1587                 if (c == 0) {
1588                         error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1589
1590                         if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1591                                 error << _("No input bundles available as a replacement")
1592                                       << endmsg;
1593                                 return -1;
1594                         }  else {
1595                                 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1596                                      << endmsg;
1597                         }
1598                 } 
1599
1600                 num_inputs = c->nchannels();
1601
1602         } else if ((prop = node.property ("inputs")) != 0) {
1603
1604                 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1605         }
1606         
1607         if ((prop = node.property ("output-connection")) != 0) {
1608                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1609
1610                 if (c == 0) {
1611                         error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1612
1613                         if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1614                                 error << _("No output bundles available as a replacement")
1615                                       << endmsg;
1616                                 return -1;
1617                         }  else {
1618                                 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1619                                      << endmsg;
1620                         }
1621                 } 
1622
1623                 num_outputs = c->nchannels ();
1624                 
1625         } else if ((prop = node.property ("outputs")) != 0) {
1626                 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1627         }
1628
1629         no_panner_reset = true;
1630
1631         // FIXME: audio-only
1632         if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1633                 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1634                 return -1;
1635         }
1636
1637         no_panner_reset = false;
1638
1639         set_deferred_state ();
1640
1641         PortsCreated();
1642         return 0;
1643 }
1644
1645
1646 int
1647 IO::make_connections (const XMLNode& node)
1648 {
1649         const XMLProperty* prop;
1650
1651         if ((prop = node.property ("input-connection")) != 0) {
1652                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1653                 
1654                 if (c == 0) {
1655                         error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1656
1657                         if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1658                                 error << _("No input connections available as a replacement")
1659                                       << endmsg;
1660                                 return -1;
1661                         } else {
1662                                 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1663                                      << endmsg;
1664                         }
1665                 } 
1666
1667                 connect_input_ports_to_bundle (c, this);
1668
1669         } else if ((prop = node.property ("inputs")) != 0) {
1670                 if (set_inputs (prop->value())) {
1671                         error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1672                         return -1;
1673                 }
1674         }
1675         
1676         if ((prop = node.property ("output-bundle")) != 0) {
1677                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1678                 
1679                 if (c == 0) {
1680                         error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1681
1682                         if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1683                                 error << _("No output bundles available as a replacement")
1684                                       << endmsg;
1685                                 return -1;
1686                         }  else {
1687                                 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1688                                      << endmsg;
1689                         }
1690                 } 
1691
1692                 connect_output_ports_to_bundle (c, this);
1693                 
1694         } else if ((prop = node.property ("outputs")) != 0) {
1695                 if (set_outputs (prop->value())) {
1696                         error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1697                         return -1;
1698                 }
1699         }
1700         
1701         return 0;
1702 }
1703
1704 int
1705 IO::set_inputs (const string& str)
1706 {
1707         vector<string> ports;
1708         int i;
1709         int n;
1710         uint32_t nports;
1711         
1712         if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1713                 return 0;
1714         }
1715
1716         // FIXME: audio-only
1717         if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1718                 return -1;
1719         }
1720
1721         string::size_type start, end, ostart;
1722
1723         ostart = 0;
1724         start = 0;
1725         end = 0;
1726         i = 0;
1727
1728         while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1729                 start += 1;
1730
1731                 if ((end = str.find_first_of ('}', start)) == string::npos) {
1732                         error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1733                         return -1;
1734                 }
1735
1736                 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1737                         error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1738
1739                         return -1;
1740                         
1741                 } else if (n > 0) {
1742
1743                         for (int x = 0; x < n; ++x) {
1744                                 connect_input (input (i), ports[x], this);
1745                         }
1746                 }
1747
1748                 ostart = end+1;
1749                 i++;
1750         }
1751
1752         return 0;
1753 }
1754
1755 int
1756 IO::set_outputs (const string& str)
1757 {
1758         vector<string> ports;
1759         int i;
1760         int n;
1761         uint32_t nports;
1762         
1763         if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1764                 return 0;
1765         }
1766
1767         // FIXME: audio-only
1768         if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1769                 return -1;
1770         }
1771
1772         string::size_type start, end, ostart;
1773
1774         ostart = 0;
1775         start = 0;
1776         end = 0;
1777         i = 0;
1778
1779         while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1780                 start += 1;
1781
1782                 if ((end = str.find_first_of ('}', start)) == string::npos) {
1783                         error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1784                         return -1;
1785                 }
1786
1787                 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1788                         error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1789
1790                         return -1;
1791                         
1792                 } else if (n > 0) {
1793
1794                         for (int x = 0; x < n; ++x) {
1795                                 connect_output (output (i), ports[x], this);
1796                         }
1797                 }
1798
1799                 ostart = end+1;
1800                 i++;
1801         }
1802
1803         return 0;
1804 }
1805
1806 int
1807 IO::parse_io_string (const string& str, vector<string>& ports)
1808 {
1809         string::size_type pos, opos;
1810
1811         if (str.length() == 0) {
1812                 return 0;
1813         }
1814
1815         pos = 0;
1816         opos = 0;
1817
1818         ports.clear ();
1819
1820         while ((pos = str.find_first_of (',', opos)) != string::npos) {
1821                 ports.push_back (str.substr (opos, pos - opos));
1822                 opos = pos + 1;
1823         }
1824         
1825         if (opos < str.length()) {
1826                 ports.push_back (str.substr(opos));
1827         }
1828
1829         return ports.size();
1830 }
1831
1832 int
1833 IO::parse_gain_string (const string& str, vector<string>& ports)
1834 {
1835         string::size_type pos, opos;
1836
1837         pos = 0;
1838         opos = 0;
1839         ports.clear ();
1840
1841         while ((pos = str.find_first_of (',', opos)) != string::npos) {
1842                 ports.push_back (str.substr (opos, pos - opos));
1843                 opos = pos + 1;
1844         }
1845         
1846         if (opos < str.length()) {
1847                 ports.push_back (str.substr(opos));
1848         }
1849
1850         return ports.size();
1851 }
1852
1853 bool
1854 IO::set_name (const string& str)
1855 {
1856         if (str == _name) {
1857                 return true;
1858         }
1859         
1860         /* replace all colons in the name. i wish we didn't have to do this */
1861         string name = str;
1862
1863         if (replace_all (name, ":", "-")) {
1864                 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1865         }
1866
1867         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1868                 string current_name = i->short_name();
1869                 current_name.replace (current_name.find (_name), _name.length(), name);
1870                 i->set_name (current_name);
1871         }
1872
1873         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1874                 string current_name = i->short_name();
1875                 current_name.replace (current_name.find (_name), _name.length(), name);
1876                 i->set_name (current_name);
1877         }
1878
1879         bool const r = SessionObject::set_name(name);
1880
1881         setup_bundles ();
1882
1883         return r;
1884 }
1885
1886 void
1887 IO::set_input_minimum (ChanCount n)
1888 {
1889         _input_minimum = n;
1890 }
1891
1892 void
1893 IO::set_input_maximum (ChanCount n)
1894 {
1895         _input_maximum = n;
1896 }
1897
1898 void
1899 IO::set_output_minimum (ChanCount n)
1900 {
1901         _output_minimum = n;
1902 }
1903
1904 void
1905 IO::set_output_maximum (ChanCount n)
1906 {
1907         _output_maximum = n;
1908 }
1909
1910 void
1911 IO::set_port_latency (nframes_t nframes)
1912 {
1913         Glib::Mutex::Lock lm (io_lock);
1914
1915         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1916                 i->set_latency (nframes);
1917         }
1918 }
1919
1920 nframes_t
1921 IO::output_latency () const
1922 {
1923         nframes_t max_latency;
1924         nframes_t latency;
1925
1926         max_latency = 0;
1927
1928         /* io lock not taken - must be protected by other means */
1929
1930         for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1931                 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1932                         max_latency = latency;
1933                 }
1934         }
1935
1936         return max_latency;
1937 }
1938
1939 nframes_t
1940 IO::input_latency () const
1941 {
1942         nframes_t max_latency;
1943         nframes_t latency;
1944
1945         max_latency = 0;
1946
1947         /* io lock not taken - must be protected by other means */
1948
1949         for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1950                 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1951                         max_latency = latency;
1952                 } 
1953         }
1954
1955         return max_latency;
1956 }
1957
1958 int
1959 IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
1960 {
1961         uint32_t limit;
1962
1963         {
1964                 BLOCK_PROCESS_CALLBACK ();
1965                 Glib::Mutex::Lock lm2 (io_lock);
1966                 
1967                 limit = c->nchannels();
1968                 
1969                 drop_input_bundle ();
1970                 
1971                 // FIXME bundles only work for audio-only
1972                 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1973                         return -1;
1974                 }
1975
1976                 /* first pass: check the current state to see what's correctly
1977                    connected, and drop anything that we don't want.
1978                 */
1979                 
1980                 for (uint32_t n = 0; n < limit; ++n) {
1981                         const Bundle::PortList& pl = c->channel_ports (n);
1982                         
1983                         for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1984                                 
1985                                 if (!_inputs.port(n)->connected_to ((*i))) {
1986                                         
1987                                         /* clear any existing connections */
1988                                         
1989                                         _session.engine().disconnect (*_inputs.port(n));
1990                                         
1991                                 } else if (_inputs.port(n)->connected() > 1) {
1992                                         
1993                                         /* OK, it is connected to the port we want,
1994                                            but its also connected to other ports.
1995                                            Change that situation.
1996                                         */
1997                                         
1998                                         /* XXX could be optimized to not drop
1999                                            the one we want.
2000                                         */
2001                                         
2002                                         _session.engine().disconnect (*_inputs.port(n));
2003                                         
2004                                 }
2005                         }
2006                 }
2007                 
2008                 /* second pass: connect all requested ports where necessary */
2009                 
2010                 for (uint32_t n = 0; n < limit; ++n) {
2011                         const Bundle::PortList& pl = c->channel_ports (n);
2012                         
2013                         for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2014                                 
2015                                 if (!_inputs.port(n)->connected_to ((*i))) {
2016                                         
2017                                         if (_session.engine().connect (*i, _inputs.port(n)->name())) {
2018                                                 return -1;
2019                                         }
2020                                 }
2021                                 
2022                         }
2023                 }
2024                 
2025                 _input_bundle = c;
2026                 
2027                 input_bundle_configuration_connection = c->ConfigurationChanged.connect
2028                         (mem_fun (*this, &IO::input_bundle_configuration_changed));
2029                 input_bundle_connection_connection = c->PortsChanged.connect
2030                         (mem_fun (*this, &IO::input_bundle_connection_changed));
2031         }
2032
2033         input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2034         return 0;
2035 }
2036
2037 int
2038 IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
2039 {
2040         uint32_t limit; 
2041
2042         {
2043                 BLOCK_PROCESS_CALLBACK ();
2044                 Glib::Mutex::Lock lm2 (io_lock);
2045
2046                 limit = c->nchannels();
2047                         
2048                 drop_output_bundle ();
2049
2050                 // FIXME: audio-only
2051                 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2052                         return -1;
2053                 }
2054
2055                 /* first pass: check the current state to see what's correctly
2056                    connected, and drop anything that we don't want.
2057                 */
2058                         
2059                 for (uint32_t n = 0; n < limit; ++n) {
2060
2061                         const Bundle::PortList& pl = c->channel_ports (n);
2062                                 
2063                         for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2064                                         
2065                                 if (!_outputs.port(n)->connected_to ((*i))) {
2066
2067                                         /* clear any existing connections */
2068
2069                                         _session.engine().disconnect (*_outputs.port(n));
2070
2071                                 } else if (_outputs.port(n)->connected() > 1) {
2072
2073                                         /* OK, it is connected to the port we want,
2074                                            but its also connected to other ports.
2075                                            Change that situation.
2076                                         */
2077
2078                                         /* XXX could be optimized to not drop
2079                                            the one we want.
2080                                         */
2081                                                 
2082                                         _session.engine().disconnect (*_outputs.port(n));
2083                                 }
2084                         }
2085                 }
2086
2087                 /* second pass: connect all requested ports where necessary */
2088
2089                 for (uint32_t n = 0; n < limit; ++n) {
2090
2091                         const Bundle::PortList& pl = c->channel_ports (n);
2092                                 
2093                         for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2094                                         
2095                                 if (!_outputs.port(n)->connected_to ((*i))) {
2096                                                 
2097                                         if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2098                                                 return -1;
2099                                         }
2100                                 }
2101                         }
2102                 }
2103
2104                 _output_bundle = c;
2105
2106                 output_bundle_configuration_connection = c->ConfigurationChanged.connect
2107                         (mem_fun (*this, &IO::output_bundle_configuration_changed));
2108                 output_bundle_connection_connection = c->PortsChanged.connect
2109                         (mem_fun (*this, &IO::output_bundle_connection_changed));
2110         }
2111
2112         output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2113
2114         return 0;
2115 }
2116
2117 int
2118 IO::disable_connecting ()
2119 {
2120         connecting_legal = false;
2121         return 0;
2122 }
2123
2124 int
2125 IO::enable_connecting ()
2126 {
2127         connecting_legal = true;
2128         return ConnectingLegal ();
2129 }
2130
2131 int
2132 IO::disable_ports ()
2133 {
2134         ports_legal = false;
2135         return 0;
2136 }
2137
2138 int
2139 IO::enable_ports ()
2140 {
2141         ports_legal = true;
2142         return PortsLegal ();
2143 }
2144
2145 int
2146 IO::disable_panners (void)
2147 {
2148         panners_legal = false;
2149         return 0;
2150 }
2151
2152 int
2153 IO::reset_panners ()
2154 {
2155         panners_legal = true;
2156         return PannersLegal ();
2157 }
2158
2159 void
2160 IO::input_bundle_connection_changed (int ignored)
2161 {
2162         connect_input_ports_to_bundle (_input_bundle, this);
2163 }
2164
2165 void
2166 IO::input_bundle_configuration_changed ()
2167 {
2168         connect_input_ports_to_bundle (_input_bundle, this);
2169 }
2170
2171 void
2172 IO::output_bundle_connection_changed (int ignored)
2173 {
2174         connect_output_ports_to_bundle (_output_bundle, this);
2175 }
2176
2177 void
2178 IO::output_bundle_configuration_changed ()
2179 {
2180         connect_output_ports_to_bundle (_output_bundle, this);
2181 }
2182
2183 void
2184 IO::GainControl::set_value (float val)
2185 {
2186         // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2187         if (val > 1.99526231f)
2188                 val = 1.99526231f;
2189
2190         _user_value = val;
2191         _io.set_gain (val, this);
2192         
2193         Changed(); /* EMIT SIGNAL */
2194 }
2195
2196 float
2197 IO::GainControl::get_value (void) const
2198 {
2199         return AutomationControl::get_value();
2200 }
2201
2202 void
2203 IO::setup_peak_meters()
2204 {
2205         ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2206         _meter->configure_io(max_streams, max_streams);
2207 }
2208
2209 /**
2210     Update the peak meters.
2211
2212     The meter signal lock is taken to prevent modification of the 
2213     Meter signal while updating the meters, taking the meter signal
2214     lock prior to taking the io_lock ensures that all IO will remain 
2215     valid while metering.
2216 */   
2217 void
2218 IO::update_meters()
2219 {
2220     Glib::Mutex::Lock guard (m_meter_signal_lock);
2221     
2222     Meter(); /* EMIT SIGNAL */
2223 }
2224
2225 void
2226 IO::meter ()
2227 {
2228         // FIXME: Ugly.  Meter should manage the lock, if it's necessary
2229         
2230         Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2231         _meter->meter();
2232 }
2233
2234 void
2235 IO::clear_automation ()
2236 {
2237         Automatable::clear_automation (); // clears gain automation
2238         _panner->clear_automation ();
2239 }
2240
2241 void
2242 IO::set_parameter_automation_state (Parameter param, AutoState state)
2243 {
2244         // XXX: would be nice to get rid of this special hack
2245
2246         if (param.type() == GainAutomation) {
2247
2248                 bool changed = false;
2249
2250                 { 
2251                         Glib::Mutex::Lock lm (_automation_lock);
2252
2253                         boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
2254
2255                         if (state != gain_auto->automation_state()) {
2256                                 changed = true;
2257                                 _last_automation_snapshot = 0;
2258                                 gain_auto->set_automation_state (state);
2259
2260                                 if (state != Off) {
2261                                         // FIXME: shouldn't this use Curve?
2262                                         set_gain (gain_auto->eval (_session.transport_frame()), this);
2263                                 }
2264                         }
2265                 }
2266
2267                 if (changed) {
2268                         _session.set_dirty ();
2269                 }
2270
2271         } else {
2272                 Automatable::set_parameter_automation_state(param, state);
2273         }
2274 }
2275
2276 void
2277 IO::inc_gain (gain_t factor, void *src)
2278 {
2279         if (_desired_gain == 0.0f)
2280                 set_gain (0.000001f + (0.000001f * factor), src);
2281         else
2282                 set_gain (_desired_gain + (_desired_gain * factor), src);
2283 }
2284
2285 void
2286 IO::set_gain (gain_t val, void *src)
2287 {
2288         // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2289         if (val > 1.99526231f)
2290                 val = 1.99526231f;
2291
2292         if (src != _gain_control.get()) {
2293                 _gain_control->set_value(val);
2294                 // bit twisty, this will come back and call us again
2295                 // (this keeps control in sync with reality)
2296                 return;
2297         }
2298
2299         {
2300                 Glib::Mutex::Lock dm (declick_lock);
2301                 _desired_gain = val;
2302         }
2303
2304         if (_session.transport_stopped()) {
2305                 _gain = val;
2306         }
2307         
2308         if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
2309                 _gain_control->list()->add (_session.transport_frame(), val);
2310                 
2311         }
2312
2313         _session.set_dirty();
2314 }
2315
2316 void
2317 IO::start_pan_touch (uint32_t which)
2318 {
2319         if (which < _panner->size()) {
2320                 (*_panner)[which]->pan_control()->list()->start_touch();
2321         }
2322 }
2323
2324 void
2325 IO::end_pan_touch (uint32_t which)
2326 {
2327         if (which < _panner->size()) {
2328                 (*_panner)[which]->pan_control()->list()->stop_touch();
2329         }
2330
2331 }
2332
2333 void
2334 IO::automation_snapshot (nframes_t now)
2335 {
2336         Automatable::automation_snapshot (now);
2337
2338         if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
2339                 _panner->snapshot (now);
2340         }
2341 }
2342
2343 void
2344 IO::transport_stopped (nframes_t frame)
2345 {
2346         _gain_control->list()->reposition_for_rt_add (frame);
2347
2348         if (_gain_control->list()->automation_state() != Off) {
2349                 
2350                 /* the src=0 condition is a special signal to not propagate 
2351                    automation gain changes into the mix group when locating.
2352                 */
2353
2354                 // FIXME: shouldn't this use Curve?
2355                 set_gain (_gain_control->list()->eval (frame), 0);
2356         }
2357
2358         _panner->transport_stopped (frame);
2359 }
2360
2361 int32_t
2362 IO::find_input_port_hole ()
2363 {
2364         /* CALLER MUST HOLD IO LOCK */
2365
2366         uint32_t n;
2367
2368         if (_inputs.empty()) {
2369                 return 1;
2370         }
2371
2372         for (n = 1; n < UINT_MAX; ++n) {
2373                 char buf[jack_port_name_size()];
2374                 PortSet::iterator i = _inputs.begin();
2375
2376                 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2377
2378                 for ( ; i != _inputs.end(); ++i) {
2379                         if (i->short_name() == buf) {
2380                                 break;
2381                         }
2382                 }
2383
2384                 if (i == _inputs.end()) {
2385                         break;
2386                 }
2387         }
2388         return n;
2389 }
2390
2391 int32_t
2392 IO::find_output_port_hole ()
2393 {
2394         /* CALLER MUST HOLD IO LOCK */
2395
2396         uint32_t n;
2397
2398         if (_outputs.empty()) {
2399                 return 1;
2400         }
2401
2402         for (n = 1; n < UINT_MAX; ++n) {
2403                 char buf[jack_port_name_size()];
2404                 PortSet::iterator i = _outputs.begin();
2405
2406                 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2407
2408                 for ( ; i != _outputs.end(); ++i) {
2409                         if (i->short_name() == buf) {
2410                                 break;
2411                         }
2412                 }
2413
2414                 if (i == _outputs.end()) {
2415                         break;
2416                 }
2417         }
2418         
2419         return n;
2420 }
2421
2422 AudioPort*
2423 IO::audio_input(uint32_t n) const
2424 {
2425         return dynamic_cast<AudioPort*>(input(n));
2426 }
2427
2428 AudioPort*
2429 IO::audio_output(uint32_t n) const
2430 {
2431         return dynamic_cast<AudioPort*>(output(n));
2432 }
2433
2434 MidiPort*
2435 IO::midi_input(uint32_t n) const
2436 {
2437         return dynamic_cast<MidiPort*>(input(n));
2438 }
2439
2440 MidiPort*
2441 IO::midi_output(uint32_t n) const
2442 {
2443         return dynamic_cast<MidiPort*>(output(n));
2444 }
2445
2446 void
2447 IO::set_phase_invert (bool yn, void *src)
2448 {
2449         if (_phase_invert != yn) {
2450                 _phase_invert = yn;
2451                 //  phase_invert_changed (src); /* EMIT SIGNAL */
2452         }
2453 }
2454
2455 void
2456 IO::set_denormal_protection (bool yn, void *src)
2457 {
2458         if (_denormal_protection != yn) {
2459                 _denormal_protection = yn;
2460                 //  denormal_protection_changed (src); /* EMIT SIGNAL */
2461         }
2462 }
2463
2464 void
2465 IO::update_port_total_latencies ()
2466 {
2467         /* io_lock, not taken: function must be called from Session::process() calltree */
2468
2469         for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2470                 _session.engine().update_total_latency (*i);
2471         }
2472
2473         for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2474                 _session.engine().update_total_latency (*i);
2475         }
2476 }
2477
2478
2479 /**
2480  *  Setup bundles that describe our inputs and outputs.
2481  */
2482
2483 void
2484 IO::setup_bundles ()
2485 {
2486         char buf[32];
2487
2488         snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
2489         _bundle_for_inputs->set_name (buf, 0);
2490         int const ins = n_inputs().n_total();
2491         _bundle_for_inputs->set_nchannels (ins);
2492         
2493         for (int i = 0; i < ins; ++i) {
2494                 _bundle_for_inputs->add_port_to_channel (i, _inputs.port(i)->name ());
2495         }
2496
2497         snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
2498         _bundle_for_outputs->set_name (buf, 0);
2499         int const outs = n_outputs().n_total();
2500         _bundle_for_outputs->set_nchannels (outs);
2501         
2502         for (int i = 0; i < outs; ++i) {
2503                 _bundle_for_outputs->add_port_to_channel (i, _outputs.port(i)->name ());
2504         }
2505 }
2506
2507
2508 /**
2509  *  Create and setup bundles that describe our inputs and outputs.
2510  */
2511
2512 void
2513 IO::create_bundles ()
2514 {
2515         _bundle_for_inputs = boost::shared_ptr<Bundle> (
2516                 new InputBundle ("", true)
2517                 );
2518         
2519         _bundle_for_outputs = boost::shared_ptr<Bundle> (
2520                 new OutputBundle ("", true)
2521                 );
2522
2523         setup_bundles ();
2524 }
2525
2526 boost::shared_ptr<Bundle>
2527 IO::input_bundle()
2528 {
2529         if (_input_bundle) {
2530                 return _input_bundle;
2531         }
2532
2533         /* XXX: will only report the first bundle found; should really return a list, I think */
2534            
2535         /* check that _input_bundle is right wrt the connections that are currently made */
2536
2537         /* make a vector of the first output connected to each of our inputs */
2538         std::vector<std::string> connected;
2539         for (uint32_t i = 0; i < _inputs.num_ports(); ++i) {
2540                 const char** c = _inputs.port(i)->get_connections ();
2541                 if (c) {
2542                         connected.push_back (c[0]);
2543                 }
2544         }
2545
2546         _input_bundle = _session.bundle_by_ports (connected);
2547         return _input_bundle;
2548 }
2549
2550
2551 boost::shared_ptr<Bundle>
2552 IO::output_bundle()
2553 {
2554         if (_output_bundle) {
2555                 return _output_bundle;
2556         }
2557         
2558         /* XXX: will only report the first bundle found; should really return a list, I think */
2559            
2560         /* check that _output_bundle is right wrt the connections that are currently made */
2561
2562         /* make a vector of the first input connected to each of our outputs */
2563         std::vector<std::string> connected;
2564         for (uint32_t i = 0; i < _outputs.num_ports(); ++i) {
2565                 const char** c = _outputs.port(i)->get_connections ();
2566                 if (c) {
2567                         connected.push_back (c[0]);
2568                 }
2569         }
2570
2571         _output_bundle = _session.bundle_by_ports (connected);
2572         return _output_bundle;
2573 }