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