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