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