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