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