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