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