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