2 Copyright (C) 2000-2006 Paul Davis
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.
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.
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.
25 #include <sigc++/bind.h>
27 #include <glibmm/thread.h>
29 #include <pbd/xml++.h>
31 #include <ardour/audioengine.h>
32 #include <ardour/io.h>
33 #include <ardour/port.h>
34 #include <ardour/audio_port.h>
35 #include <ardour/midi_port.h>
36 #include <ardour/connection.h>
37 #include <ardour/session.h>
38 #include <ardour/cycle_timer.h>
39 #include <ardour/panner.h>
40 #include <ardour/buffer_set.h>
41 #include <ardour/meter.h>
42 #include <ardour/amp.h>
49 A bug in OS X's cmath that causes isnan() and isinf() to be
50 "undeclared". the following works around that
53 #if defined(__APPLE__) && defined(__MACH__)
54 extern "C" int isnan (double);
55 extern "C" int isinf (double);
58 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
61 using namespace ARDOUR;
64 nframes_t IO::_automation_interval = 0;
66 const string IO::state_node_name = "IO";
67 bool IO::connecting_legal = false;
68 bool IO::ports_legal = false;
69 bool IO::panners_legal = false;
70 sigc::signal<void> IO::Meter;
71 sigc::signal<int> IO::ConnectingLegal;
72 sigc::signal<int> IO::PortsLegal;
73 sigc::signal<int> IO::PannersLegal;
74 sigc::signal<void,ChanCount> IO::MoreChannels;
75 sigc::signal<int> IO::PortsCreated;
77 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
79 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
80 others can be imagined.
83 static gain_t direct_control_to_gain (double fract) {
84 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
85 /* this maxes at +6dB */
86 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
89 static double direct_gain_to_control (gain_t gain) {
90 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
91 if (gain == 0) return 0.0;
93 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
97 /** @param default_type The type of port that will be created by ensure_io
98 * and friends if no type is explicitly requested (to avoid breakage).
100 IO::IO (Session& s, string name,
101 int input_min, int input_max, int output_min, int output_max,
102 DataType default_type)
104 _output_buffers(new BufferSet()),
106 _default_type(default_type),
107 _gain_control (X_("gaincontrol"), *this),
108 _gain_automation_curve (0.0, 2.0, 1.0),
109 _input_minimum (ChanCount::ZERO),
110 _input_maximum (ChanCount::INFINITE),
111 _output_minimum (ChanCount::ZERO),
112 _output_maximum (ChanCount::INFINITE)
114 _panner = new Panner (name, _session);
115 _meter = new PeakMeter (_session);
118 _input_minimum = ChanCount(_default_type, input_min);
120 if (input_max >= 0) {
121 _input_maximum = ChanCount(_default_type, input_max);
123 if (output_min > 0) {
124 _output_minimum = ChanCount(_default_type, output_min);
126 if (output_max >= 0) {
127 _output_maximum = ChanCount(_default_type, output_max);
132 _input_connection = 0;
133 _output_connection = 0;
134 pending_state_node = 0;
135 no_panner_reset = false;
136 _phase_invert = false;
139 apply_gain_automation = false;
141 last_automation_snapshot = 0;
143 _gain_automation_state = Off;
144 _gain_automation_style = Absolute;
147 // IO::Meter is emitted from another thread so the
148 // Meter signal must be protected.
149 Glib::Mutex::Lock guard (m_meter_signal_lock);
150 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
153 // Connect to our own MoreChannels signal to connect output buffers
154 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
156 _session.add_controllable (&_gain_control);
159 IO::IO (Session& s, const XMLNode& node, DataType dt)
161 _output_buffers(new BufferSet()),
163 _gain_control (X_("gaincontrol"), *this),
164 _gain_automation_curve (0, 0, 0) // all reset in set_state()
167 _meter = new PeakMeter (_session);
171 no_panner_reset = false;
174 _input_connection = 0;
175 _output_connection = 0;
177 apply_gain_automation = false;
182 // IO::Meter is emitted from another thread so the
183 // Meter signal must be protected.
184 Glib::Mutex::Lock guard (m_meter_signal_lock);
185 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
188 // Connect to our own MoreChannels signal to connect output buffers
189 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
191 _session.add_controllable (&_gain_control);
196 Glib::Mutex::Lock guard (m_meter_signal_lock);
198 Glib::Mutex::Lock lm (io_lock);
200 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
201 _session.engine().unregister_port (*i);
204 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
205 _session.engine().unregister_port (*i);
208 m_meter_connection.disconnect();
212 delete _output_buffers;
216 IO::silence (nframes_t nframes, nframes_t offset)
218 /* io_lock, not taken: function must be called from Session::process() calltree */
220 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
221 i->get_buffer().silence (nframes, offset);
225 /** Deliver bufs to the IO's Jack outputs.
227 * This function should automatically do whatever it necessary to correctly deliver bufs
228 * to the outputs, eg applying gain or pan or whatever else needs to be done.
231 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
233 // FIXME: type specific code doesn't actually need to be here, it will go away in time
235 /* ********** AUDIO ********** */
237 // Apply gain if gain automation isn't playing
238 if ( ! apply_gain_automation) {
240 gain_t dg = _gain; // desired gain
243 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
251 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
254 // Use the panner to distribute audio to output port buffers
255 if (_panner && !_panner->empty() && !_panner->bypassed()) {
256 _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
258 const DataType type = DataType::AUDIO;
260 // Copy any audio 1:1 to outputs
261 assert(bufs.count().get(DataType::AUDIO) == output_buffers().count().get(DataType::AUDIO));
262 BufferSet::iterator o = output_buffers().begin(type);
263 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
264 o->read_from(*i, nframes, offset);
269 /* ********** MIDI ********** */
271 // No MIDI, we're done here
272 if (bufs.count().get(DataType::MIDI) == 0) {
276 const DataType type = DataType::MIDI;
278 // Copy any MIDI 1:1 to outputs
279 assert(bufs.count().get(DataType::MIDI) == output_buffers().count().get(DataType::MIDI));
280 BufferSet::iterator o = output_buffers().begin(type);
281 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
282 o->read_from(*i, nframes, offset);
287 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
289 assert(outs.available() >= n_inputs());
291 outs.set_count(n_inputs());
293 if (outs.count() == ChanCount::ZERO)
296 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
298 BufferSet::iterator o = outs.begin(*t);
299 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
300 o->read_from(i->get_buffer(), nframes, offset);
307 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
308 nframes_t nframes, nframes_t offset)
310 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
312 collect_input (bufs, nframes, offset);
314 _meter->run(bufs, nframes);
318 IO::drop_input_connection ()
320 _input_connection = 0;
321 input_connection_configuration_connection.disconnect();
322 input_connection_connection_connection.disconnect();
323 _session.set_dirty ();
327 IO::drop_output_connection ()
329 _output_connection = 0;
330 output_connection_configuration_connection.disconnect();
331 output_connection_connection_connection.disconnect();
332 _session.set_dirty ();
336 IO::disconnect_input (Port* our_port, string other_port, void* src)
338 if (other_port.length() == 0 || our_port == 0) {
343 BLOCK_PROCESS_CALLBACK ();
346 Glib::Mutex::Lock lm (io_lock);
348 /* check that our_port is really one of ours */
350 if ( ! _inputs.contains(our_port)) {
354 /* disconnect it from the source */
356 if (_session.engine().disconnect (other_port, our_port->name())) {
357 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
361 drop_input_connection();
365 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
366 _session.set_dirty ();
372 IO::connect_input (Port* our_port, string other_port, void* src)
374 if (other_port.length() == 0 || our_port == 0) {
379 BLOCK_PROCESS_CALLBACK ();
382 Glib::Mutex::Lock lm (io_lock);
384 /* check that our_port is really one of ours */
386 if ( ! _inputs.contains(our_port) ) {
390 /* connect it to the source */
392 if (_session.engine().connect (other_port, our_port->name())) {
396 drop_input_connection ();
400 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
401 _session.set_dirty ();
406 IO::disconnect_output (Port* our_port, string other_port, void* src)
408 if (other_port.length() == 0 || our_port == 0) {
413 BLOCK_PROCESS_CALLBACK ();
416 Glib::Mutex::Lock lm (io_lock);
418 /* check that our_port is really one of ours */
420 if ( ! _outputs.contains(our_port) ) {
424 /* disconnect it from the destination */
426 if (_session.engine().disconnect (our_port->name(), other_port)) {
427 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
431 drop_output_connection ();
435 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
436 _session.set_dirty ();
441 IO::connect_output (Port* our_port, string other_port, void* src)
443 if (other_port.length() == 0 || our_port == 0) {
448 BLOCK_PROCESS_CALLBACK ();
452 Glib::Mutex::Lock lm (io_lock);
454 /* check that our_port is really one of ours */
456 if ( ! _outputs.contains(our_port) ) {
460 /* connect it to the destination */
462 if (_session.engine().connect (our_port->name(), other_port)) {
466 drop_output_connection ();
470 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
471 _session.set_dirty ();
476 IO::set_input (Port* other_port, void* src)
478 /* this removes all but one ports, and connects that one port
479 to the specified source.
482 if (_input_minimum.get_total() > 1) {
483 /* sorry, you can't do this */
487 if (other_port == 0) {
488 if (_input_minimum == ChanCount::ZERO) {
489 return ensure_inputs (ChanCount::ZERO, false, true, src);
495 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
499 return connect_input (_inputs.port(0), other_port->name(), src);
503 IO::remove_output_port (Port* port, void* src)
505 IOChange change (NoChange);
508 BLOCK_PROCESS_CALLBACK ();
512 Glib::Mutex::Lock lm (io_lock);
514 if (n_outputs() <= _output_minimum) {
515 /* sorry, you can't do this */
519 if (_outputs.remove(port)) {
520 change = IOChange (change|ConfigurationChanged);
522 if (port->connected()) {
523 change = IOChange (change|ConnectionsChanged);
526 _session.engine().unregister_port (*port);
527 drop_output_connection ();
529 setup_peak_meters ();
535 if (change != NoChange) {
536 output_changed (change, src);
537 _session.set_dirty ();
544 /** Add an output port.
546 * @param destination Name of input port to connect new port to.
547 * @param src Source for emitted ConfigurationChanged signal.
548 * @param type Data type of port. Default value (NIL) will use this IO's default type.
551 IO::add_output_port (string destination, void* src, DataType type)
556 if (type == DataType::NIL)
557 type = _default_type;
560 BLOCK_PROCESS_CALLBACK ();
564 Glib::Mutex::Lock lm (io_lock);
566 if (n_outputs() >= _output_maximum) {
570 /* Create a new output port */
572 // FIXME: naming scheme for differently typed ports?
573 if (_output_maximum.get(type) == 1) {
574 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
576 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
579 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
580 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
584 _outputs.add (our_port);
585 drop_output_connection ();
586 setup_peak_meters ();
590 MoreChannels (n_outputs()); /* EMIT SIGNAL */
593 if (destination.length()) {
594 if (_session.engine().connect (our_port->name(), destination)) {
599 // pan_changed (src); /* EMIT SIGNAL */
600 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
601 _session.set_dirty ();
607 IO::remove_input_port (Port* port, void* src)
609 IOChange change (NoChange);
612 BLOCK_PROCESS_CALLBACK ();
616 Glib::Mutex::Lock lm (io_lock);
618 if (n_inputs() <= _input_minimum) {
619 /* sorry, you can't do this */
623 if (_inputs.remove(port)) {
624 change = IOChange (change|ConfigurationChanged);
626 if (port->connected()) {
627 change = IOChange (change|ConnectionsChanged);
630 _session.engine().unregister_port (*port);
631 drop_input_connection ();
633 setup_peak_meters ();
639 if (change != NoChange) {
640 input_changed (change, src);
641 _session.set_dirty ();
649 /** Add an input port.
651 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
652 * @param destination Name of input port to connect new port to.
653 * @param src Source for emitted ConfigurationChanged signal.
656 IO::add_input_port (string source, void* src, DataType type)
661 if (type == DataType::NIL)
662 type = _default_type;
665 BLOCK_PROCESS_CALLBACK ();
668 Glib::Mutex::Lock lm (io_lock);
670 if (n_inputs() >= _input_maximum) {
674 /* Create a new input port */
676 // FIXME: naming scheme for differently typed ports?
677 if (_input_maximum.get(type) == 1) {
678 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
680 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
683 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
684 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
688 _inputs.add (our_port);
689 drop_input_connection ();
690 setup_peak_meters ();
694 MoreChannels (n_inputs()); /* EMIT SIGNAL */
697 if (source.length()) {
699 if (_session.engine().connect (source, our_port->name())) {
704 // pan_changed (src); /* EMIT SIGNAL */
705 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
706 _session.set_dirty ();
712 IO::disconnect_inputs (void* src)
715 BLOCK_PROCESS_CALLBACK ();
718 Glib::Mutex::Lock lm (io_lock);
720 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
721 _session.engine().disconnect (*i);
724 drop_input_connection ();
728 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
734 IO::disconnect_outputs (void* src)
737 BLOCK_PROCESS_CALLBACK ();
740 Glib::Mutex::Lock lm (io_lock);
742 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
743 _session.engine().disconnect (*i);
746 drop_output_connection ();
750 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
751 _session.set_dirty ();
757 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
759 Port* input_port = 0;
760 bool changed = false;
763 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
765 const size_t n = count.get(*t);
767 /* remove unused ports */
768 for (size_t i = n_inputs().get(*t); i > n; --i) {
769 input_port = _inputs.port(*t, i-1);
772 _inputs.remove(input_port);
773 _session.engine().unregister_port (*input_port);
778 /* create any necessary new ports */
779 while (n_inputs().get(*t) < n) {
783 if (_input_maximum.get(*t) == 1) {
784 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
786 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
791 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
792 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
797 catch (AudioEngine::PortRegistrationFailure& err) {
798 setup_peak_meters ();
801 throw AudioEngine::PortRegistrationFailure();
804 _inputs.add (input_port);
810 drop_input_connection ();
811 setup_peak_meters ();
813 MoreChannels (n_inputs()); /* EMIT SIGNAL */
814 _session.set_dirty ();
818 /* disconnect all existing ports so that we get a fresh start */
819 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
820 _session.engine().disconnect (*i);
827 /** Attach output_buffers to port buffers.
829 * Connected to IO's own MoreChannels signal.
832 IO::attach_buffers(ChanCount ignored)
834 _output_buffers->attach_buffers(_outputs);
838 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
840 bool in_changed = false;
841 bool out_changed = false;
842 bool need_pan_reset = false;
844 in = min (_input_maximum, in);
846 out = min (_output_maximum, out);
848 if (in == n_inputs() && out == n_outputs() && !clear) {
853 BLOCK_PROCESS_CALLBACK ();
854 Glib::Mutex::Lock lm (io_lock);
858 if (n_outputs() != out) {
859 need_pan_reset = true;
862 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
864 const size_t nin = in.get(*t);
865 const size_t nout = out.get(*t);
867 Port* output_port = 0;
868 Port* input_port = 0;
870 /* remove unused output ports */
871 for (size_t i = n_outputs().get(*t); i > nout; --i) {
872 output_port = _outputs.port(*t, i-1);
875 _outputs.remove(output_port);
876 _session.engine().unregister_port (*output_port);
881 /* remove unused input ports */
882 for (size_t i = n_inputs().get(*t); i > nin; --i) {
883 input_port = _inputs.port(*t, i-1);
886 _inputs.remove(input_port);
887 _session.engine().unregister_port (*input_port);
892 /* create any necessary new input ports */
894 while (n_inputs().get(*t) < nin) {
898 /* Create a new input port */
900 if (_input_maximum.get(*t) == 1) {
901 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
903 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
907 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
908 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
913 catch (AudioEngine::PortRegistrationFailure& err) {
914 setup_peak_meters ();
917 throw AudioEngine::PortRegistrationFailure();
924 /* create any necessary new output ports */
926 while (n_outputs().get(*t) < nout) {
930 /* Create a new output port */
932 if (_output_maximum.get(*t) == 1) {
933 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
935 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
939 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
940 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
945 catch (AudioEngine::PortRegistrationFailure& err) {
946 setup_peak_meters ();
949 throw AudioEngine::PortRegistrationFailure ();
959 /* disconnect all existing ports so that we get a fresh start */
961 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
962 _session.engine().disconnect (*i);
965 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
966 _session.engine().disconnect (*i);
970 if (in_changed || out_changed) {
971 setup_peak_meters ();
977 drop_output_connection ();
978 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
982 drop_input_connection ();
983 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
986 if (in_changed || out_changed) {
987 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
988 _session.set_dirty ();
995 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
997 bool changed = false;
999 count = min (_input_maximum, count);
1001 if (count == n_inputs() && !clear) {
1006 BLOCK_PROCESS_CALLBACK ();
1007 Glib::Mutex::Lock im (io_lock);
1008 changed = ensure_inputs_locked (count, clear, src);
1010 changed = ensure_inputs_locked (count, clear, src);
1014 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1015 _session.set_dirty ();
1021 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1023 Port* output_port = 0;
1024 bool changed = false;
1025 bool need_pan_reset = false;
1027 if (n_outputs() != count) {
1028 need_pan_reset = true;
1031 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1033 const size_t n = count.get(*t);
1035 /* remove unused ports */
1036 for (size_t i = n_outputs().get(*t); i > n; --i) {
1037 output_port = _outputs.port(*t, i-1);
1039 assert(output_port);
1040 _outputs.remove(output_port);
1041 _session.engine().unregister_port (*output_port);
1046 /* create any necessary new ports */
1047 while (n_outputs().get(*t) < n) {
1051 if (_output_maximum.get(*t) == 1) {
1052 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1054 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1057 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1058 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1062 _outputs.add (output_port);
1064 setup_peak_meters ();
1066 if (need_pan_reset) {
1073 drop_output_connection ();
1074 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1075 _session.set_dirty ();
1079 /* disconnect all existing ports so that we get a fresh start */
1080 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1081 _session.engine().disconnect (*i);
1089 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1091 bool changed = false;
1093 if (_output_maximum < ChanCount::INFINITE) {
1094 count = min (_output_maximum, count);
1095 if (count == n_outputs() && !clear) {
1100 /* XXX caller should hold io_lock, but generally doesn't */
1103 BLOCK_PROCESS_CALLBACK ();
1104 Glib::Mutex::Lock im (io_lock);
1105 changed = ensure_outputs_locked (count, clear, src);
1107 changed = ensure_outputs_locked (count, clear, src);
1111 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1118 IO::effective_gain () const
1120 if (gain_automation_playback()) {
1121 return _effective_gain;
1123 return _desired_gain;
1130 if (panners_legal) {
1131 if (!no_panner_reset) {
1132 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1135 panner_legal_c.disconnect ();
1136 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1141 IO::panners_became_legal ()
1143 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1144 _panner->load (); // automation
1145 panner_legal_c.disconnect ();
1150 IO::defer_pan_reset ()
1152 no_panner_reset = true;
1156 IO::allow_pan_reset ()
1158 no_panner_reset = false;
1164 IO::get_state (void)
1166 return state (true);
1170 IO::state (bool full_state)
1172 XMLNode* node = new XMLNode (state_node_name);
1175 bool need_ins = true;
1176 bool need_outs = true;
1177 LocaleGuard lg (X_("POSIX"));
1178 Glib::Mutex::Lock lm (io_lock);
1180 node->add_property("name", _name);
1181 id().print (buf, sizeof (buf));
1182 node->add_property("id", buf);
1186 if (_input_connection) {
1187 node->add_property ("input-connection", _input_connection->name());
1191 if (_output_connection) {
1192 node->add_property ("output-connection", _output_connection->name());
1197 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1199 const char **connections = i->get_connections();
1201 if (connections && connections[0]) {
1204 for (int n = 0; connections && connections[n]; ++n) {
1209 /* if its a connection to our own port,
1210 return only the port name, not the
1211 whole thing. this allows connections
1212 to be re-established even when our
1213 client name is different.
1216 str += _session.engine().make_port_name_relative (connections[n]);
1228 node->add_property ("inputs", str);
1234 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1236 const char **connections = i->get_connections();
1238 if (connections && connections[0]) {
1242 for (int n = 0; connections[n]; ++n) {
1247 str += _session.engine().make_port_name_relative (connections[n]);
1259 node->add_property ("outputs", str);
1262 node->add_child_nocopy (_panner->state (full_state));
1263 node->add_child_nocopy (_gain_control.get_state ());
1265 snprintf (buf, sizeof(buf), "%2.12f", gain());
1266 node->add_property ("gain", buf);
1268 // FIXME: this is NOT sufficient!
1269 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1270 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1271 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1272 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1274 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1276 node->add_property ("iolimits", buf);
1282 XMLNode* autonode = new XMLNode (X_("Automation"));
1283 autonode->add_child_nocopy (get_automation_state());
1284 node->add_child_nocopy (*autonode);
1286 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1288 /* never store anything except Off for automation state in a template */
1289 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1296 IO::set_state (const XMLNode& node)
1298 const XMLProperty* prop;
1299 XMLNodeConstIterator iter;
1300 LocaleGuard lg (X_("POSIX"));
1302 /* force use of non-localized representation of decimal point,
1303 since we use it a lot in XML files and so forth.
1306 if (node.name() != state_node_name) {
1307 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1311 if ((prop = node.property ("name")) != 0) {
1312 _name = prop->value();
1313 /* used to set panner name with this, but no more */
1316 if ((prop = node.property ("id")) != 0) {
1317 _id = prop->value ();
1322 size_t out_min = -1;
1323 size_t out_max = -1;
1325 if ((prop = node.property ("iolimits")) != 0) {
1326 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1327 &in_min, &in_max, &out_min, &out_max);
1328 _input_minimum = ChanCount(_default_type, in_min);
1329 _input_maximum = ChanCount(_default_type, in_max);
1330 _output_minimum = ChanCount(_default_type, out_min);
1331 _output_maximum = ChanCount(_default_type, out_max);
1334 if ((prop = node.property ("gain")) != 0) {
1335 set_gain (atof (prop->value().c_str()), this);
1336 _gain = _desired_gain;
1339 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1340 /* old school automation handling */
1343 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1345 if ((*iter)->name() == "Panner") {
1347 _panner = new Panner (_name, _session);
1349 _panner->set_state (**iter);
1352 if ((*iter)->name() == X_("Automation")) {
1354 set_automation_state (*(*iter)->children().front());
1357 if ((*iter)->name() == X_("controllable")) {
1358 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1359 _gain_control.set_state (**iter);
1366 if (create_ports (node)) {
1372 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1375 if (panners_legal) {
1378 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1381 if (connecting_legal) {
1383 if (make_connections (node)) {
1389 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1392 if (!ports_legal || !connecting_legal) {
1393 pending_state_node = new XMLNode (node);
1396 last_automation_snapshot = 0;
1402 IO::set_automation_state (const XMLNode& node)
1404 return _gain_automation_curve.set_state (node);
1408 IO::get_automation_state ()
1410 return (_gain_automation_curve.get_state ());
1414 IO::load_automation (string path)
1419 uint32_t linecnt = 0;
1421 LocaleGuard lg (X_("POSIX"));
1423 fullpath = _session.automation_dir();
1426 in.open (fullpath.c_str());
1429 fullpath = _session.automation_dir();
1430 fullpath += _session.snap_name();
1434 in.open (fullpath.c_str());
1437 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1442 clear_automation ();
1444 while (in.getline (line, sizeof(line), '\n')) {
1446 jack_nframes_t when;
1449 if (++linecnt == 1) {
1450 if (memcmp (line, "version", 7) == 0) {
1451 if (sscanf (line, "version %f", &version) != 1) {
1452 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1456 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1463 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1464 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1470 _gain_automation_curve.fast_simple_add (when, value);
1480 /* older (pre-1.0) versions of ardour used this */
1484 warning << _("dubious automation event found (and ignored)") << endmsg;
1492 IO::connecting_became_legal ()
1496 if (pending_state_node == 0) {
1497 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1502 connection_legal_c.disconnect ();
1504 ret = make_connections (*pending_state_node);
1507 delete pending_state_node;
1508 pending_state_node = 0;
1514 IO::ports_became_legal ()
1518 if (pending_state_node == 0) {
1519 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1524 port_legal_c.disconnect ();
1526 ret = create_ports (*pending_state_node);
1528 if (connecting_legal) {
1529 delete pending_state_node;
1530 pending_state_node = 0;
1537 IO::create_ports (const XMLNode& node)
1539 const XMLProperty* prop;
1541 int num_outputs = 0;
1543 if ((prop = node.property ("input-connection")) != 0) {
1545 Connection* c = _session.connection_by_name (prop->value());
1548 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1550 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1551 error << _("No input connections available as a replacement")
1555 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1560 num_inputs = c->nports();
1562 } else if ((prop = node.property ("inputs")) != 0) {
1564 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1567 if ((prop = node.property ("output-connection")) != 0) {
1568 Connection* c = _session.connection_by_name (prop->value());
1571 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1573 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1574 error << _("No output connections available as a replacement")
1578 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1583 num_outputs = c->nports ();
1585 } else if ((prop = node.property ("outputs")) != 0) {
1586 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1589 no_panner_reset = true;
1591 // FIXME: audio-only
1592 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1593 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1597 no_panner_reset = false;
1599 set_deferred_state ();
1607 IO::make_connections (const XMLNode& node)
1609 const XMLProperty* prop;
1611 if ((prop = node.property ("input-connection")) != 0) {
1612 Connection* c = _session.connection_by_name (prop->value());
1615 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1617 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1618 error << _("No input connections available as a replacement")
1622 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1627 use_input_connection (*c, this);
1629 } else if ((prop = node.property ("inputs")) != 0) {
1630 if (set_inputs (prop->value())) {
1631 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1636 if ((prop = node.property ("output-connection")) != 0) {
1637 Connection* c = _session.connection_by_name (prop->value());
1640 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1642 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1643 error << _("No output connections available as a replacement")
1647 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1652 use_output_connection (*c, this);
1654 } else if ((prop = node.property ("outputs")) != 0) {
1655 if (set_outputs (prop->value())) {
1656 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1665 IO::set_inputs (const string& str)
1667 vector<string> ports;
1672 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1676 // FIXME: audio-only
1677 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1681 string::size_type start, end, ostart;
1688 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1691 if ((end = str.find_first_of ('}', start)) == string::npos) {
1692 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1696 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1697 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1703 for (int x = 0; x < n; ++x) {
1704 connect_input (input (i), ports[x], this);
1716 IO::set_outputs (const string& str)
1718 vector<string> ports;
1723 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1727 // FIXME: audio-only
1728 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1732 string::size_type start, end, ostart;
1739 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1742 if ((end = str.find_first_of ('}', start)) == string::npos) {
1743 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1747 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1748 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1754 for (int x = 0; x < n; ++x) {
1755 connect_output (output (i), ports[x], this);
1767 IO::parse_io_string (const string& str, vector<string>& ports)
1769 string::size_type pos, opos;
1771 if (str.length() == 0) {
1780 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1781 ports.push_back (str.substr (opos, pos - opos));
1785 if (opos < str.length()) {
1786 ports.push_back (str.substr(opos));
1789 return ports.size();
1793 IO::parse_gain_string (const string& str, vector<string>& ports)
1795 string::size_type pos, opos;
1801 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1802 ports.push_back (str.substr (opos, pos - opos));
1806 if (opos < str.length()) {
1807 ports.push_back (str.substr(opos));
1810 return ports.size();
1814 IO::set_name (string name, void* src)
1816 if (name == _name) {
1820 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1821 string current_name = i->short_name();
1822 current_name.replace (current_name.find (_name), _name.length(), name);
1823 i->set_name (current_name);
1826 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1827 string current_name = i->short_name();
1828 current_name.replace (current_name.find (_name), _name.length(), name);
1829 i->set_name (current_name);
1833 name_changed (src); /* EMIT SIGNAL */
1839 IO::set_input_minimum (ChanCount n)
1845 IO::set_input_maximum (ChanCount n)
1851 IO::set_output_minimum (ChanCount n)
1853 _output_minimum = n;
1857 IO::set_output_maximum (ChanCount n)
1859 _output_maximum = n;
1863 IO::set_port_latency (nframes_t nframes)
1865 Glib::Mutex::Lock lm (io_lock);
1867 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1868 i->set_latency (nframes);
1873 IO::output_latency () const
1875 nframes_t max_latency;
1880 /* io lock not taken - must be protected by other means */
1882 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1883 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1884 max_latency = latency;
1892 IO::input_latency () const
1894 nframes_t max_latency;
1899 /* io lock not taken - must be protected by other means */
1901 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1902 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1903 max_latency = latency;
1911 IO::use_input_connection (Connection& c, void* src)
1916 BLOCK_PROCESS_CALLBACK ();
1917 Glib::Mutex::Lock lm2 (io_lock);
1921 drop_input_connection ();
1923 // FIXME connections only work for audio-only
1924 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1928 /* first pass: check the current state to see what's correctly
1929 connected, and drop anything that we don't want.
1932 for (uint32_t n = 0; n < limit; ++n) {
1933 const Connection::PortList& pl = c.port_connections (n);
1935 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1937 if (!_inputs.port(n)->connected_to ((*i))) {
1939 /* clear any existing connections */
1941 _session.engine().disconnect (*_inputs.port(n));
1943 } else if (_inputs.port(n)->connected() > 1) {
1945 /* OK, it is connected to the port we want,
1946 but its also connected to other ports.
1947 Change that situation.
1950 /* XXX could be optimized to not drop
1954 _session.engine().disconnect (*_inputs.port(n));
1960 /* second pass: connect all requested ports where necessary */
1962 for (uint32_t n = 0; n < limit; ++n) {
1963 const Connection::PortList& pl = c.port_connections (n);
1965 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1967 if (!_inputs.port(n)->connected_to ((*i))) {
1969 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1977 _input_connection = &c;
1979 input_connection_configuration_connection = c.ConfigurationChanged.connect
1980 (mem_fun (*this, &IO::input_connection_configuration_changed));
1981 input_connection_connection_connection = c.ConnectionsChanged.connect
1982 (mem_fun (*this, &IO::input_connection_connection_changed));
1985 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1990 IO::use_output_connection (Connection& c, void* src)
1995 BLOCK_PROCESS_CALLBACK ();
1996 Glib::Mutex::Lock lm2 (io_lock);
2000 drop_output_connection ();
2002 // FIXME: audio-only
2003 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2007 /* first pass: check the current state to see what's correctly
2008 connected, and drop anything that we don't want.
2011 for (uint32_t n = 0; n < limit; ++n) {
2013 const Connection::PortList& pl = c.port_connections (n);
2015 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2017 if (!_outputs.port(n)->connected_to ((*i))) {
2019 /* clear any existing connections */
2021 _session.engine().disconnect (*_outputs.port(n));
2023 } else if (_outputs.port(n)->connected() > 1) {
2025 /* OK, it is connected to the port we want,
2026 but its also connected to other ports.
2027 Change that situation.
2030 /* XXX could be optimized to not drop
2034 _session.engine().disconnect (*_outputs.port(n));
2039 /* second pass: connect all requested ports where necessary */
2041 for (uint32_t n = 0; n < limit; ++n) {
2043 const Connection::PortList& pl = c.port_connections (n);
2045 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2047 if (!_outputs.port(n)->connected_to ((*i))) {
2049 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2056 _output_connection = &c;
2058 output_connection_configuration_connection = c.ConfigurationChanged.connect
2059 (mem_fun (*this, &IO::output_connection_configuration_changed));
2060 output_connection_connection_connection = c.ConnectionsChanged.connect
2061 (mem_fun (*this, &IO::output_connection_connection_changed));
2064 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2070 IO::disable_connecting ()
2072 connecting_legal = false;
2077 IO::enable_connecting ()
2079 connecting_legal = true;
2080 return ConnectingLegal ();
2084 IO::disable_ports ()
2086 ports_legal = false;
2094 return PortsLegal ();
2098 IO::disable_panners (void)
2100 panners_legal = false;
2105 IO::reset_panners ()
2107 panners_legal = true;
2108 return PannersLegal ();
2112 IO::input_connection_connection_changed (int ignored)
2114 use_input_connection (*_input_connection, this);
2118 IO::input_connection_configuration_changed ()
2120 use_input_connection (*_input_connection, this);
2124 IO::output_connection_connection_changed (int ignored)
2126 use_output_connection (*_output_connection, this);
2130 IO::output_connection_configuration_changed ()
2132 use_output_connection (*_output_connection, this);
2136 IO::GainControllable::set_value (float val)
2138 io.set_gain (direct_control_to_gain (val), this);
2142 IO::GainControllable::get_value (void) const
2144 return direct_gain_to_control (io.effective_gain());
2148 IO::setup_peak_meters()
2150 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2154 Update the peak meters.
2156 The meter signal lock is taken to prevent modification of the
2157 Meter signal while updating the meters, taking the meter signal
2158 lock prior to taking the io_lock ensures that all IO will remain
2159 valid while metering.
2164 Glib::Mutex::Lock guard (m_meter_signal_lock);
2166 Meter(); /* EMIT SIGNAL */
2172 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2174 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2179 IO::clear_automation ()
2181 Glib::Mutex::Lock lm (automation_lock);
2182 _gain_automation_curve.clear ();
2183 _panner->clear_automation ();
2187 IO::set_gain_automation_state (AutoState state)
2189 bool changed = false;
2192 Glib::Mutex::Lock lm (automation_lock);
2194 if (state != _gain_automation_curve.automation_state()) {
2196 last_automation_snapshot = 0;
2197 _gain_automation_curve.set_automation_state (state);
2200 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2206 _session.set_dirty ();
2207 gain_automation_state_changed (); /* EMIT SIGNAL */
2212 IO::set_gain_automation_style (AutoStyle style)
2214 bool changed = false;
2217 Glib::Mutex::Lock lm (automation_lock);
2219 if (style != _gain_automation_curve.automation_style()) {
2221 _gain_automation_curve.set_automation_style (style);
2226 gain_automation_style_changed (); /* EMIT SIGNAL */
2230 IO::inc_gain (gain_t factor, void *src)
2232 if (_desired_gain == 0.0f)
2233 set_gain (0.000001f + (0.000001f * factor), src);
2235 set_gain (_desired_gain + (_desired_gain * factor), src);
2239 IO::set_gain (gain_t val, void *src)
2241 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2242 if (val>1.99526231f) val=1.99526231f;
2245 Glib::Mutex::Lock dm (declick_lock);
2246 _desired_gain = val;
2249 if (_session.transport_stopped()) {
2250 _effective_gain = val;
2255 _gain_control.Changed (); /* EMIT SIGNAL */
2257 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2258 _gain_automation_curve.add (_session.transport_frame(), val);
2262 _session.set_dirty();
2266 IO::start_gain_touch ()
2268 _gain_automation_curve.start_touch ();
2272 IO::end_gain_touch ()
2274 _gain_automation_curve.stop_touch ();
2278 IO::start_pan_touch (uint32_t which)
2280 if (which < _panner->size()) {
2281 (*_panner)[which]->automation().start_touch();
2286 IO::end_pan_touch (uint32_t which)
2288 if (which < _panner->size()) {
2289 (*_panner)[which]->automation().stop_touch();
2295 IO::automation_snapshot (nframes_t now)
2297 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2299 if (gain_automation_recording()) {
2300 _gain_automation_curve.rt_add (now, gain());
2303 _panner->snapshot (now);
2305 last_automation_snapshot = now;
2310 IO::transport_stopped (nframes_t frame)
2312 _gain_automation_curve.reposition_for_rt_add (frame);
2314 if (_gain_automation_curve.automation_state() != Off) {
2316 /* the src=0 condition is a special signal to not propagate
2317 automation gain changes into the mix group when locating.
2320 set_gain (_gain_automation_curve.eval (frame), 0);
2323 _panner->transport_stopped (frame);
2327 IO::find_input_port_hole ()
2329 /* CALLER MUST HOLD IO LOCK */
2333 if (_inputs.empty()) {
2337 for (n = 1; n < UINT_MAX; ++n) {
2338 char buf[jack_port_name_size()];
2339 PortSet::iterator i = _inputs.begin();
2341 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2343 for ( ; i != _inputs.end(); ++i) {
2344 if (i->short_name() == buf) {
2349 if (i == _inputs.end()) {
2357 IO::find_output_port_hole ()
2359 /* CALLER MUST HOLD IO LOCK */
2363 if (_outputs.empty()) {
2367 for (n = 1; n < UINT_MAX; ++n) {
2368 char buf[jack_port_name_size()];
2369 PortSet::iterator i = _outputs.begin();
2371 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2373 for ( ; i != _outputs.end(); ++i) {
2374 if (i->short_name() == buf) {
2379 if (i == _outputs.end()) {
2388 IO::audio_input(uint32_t n) const
2390 return dynamic_cast<AudioPort*>(input(n));
2394 IO::audio_output(uint32_t n) const
2396 return dynamic_cast<AudioPort*>(output(n));
2400 IO::midi_input(uint32_t n) const
2402 return dynamic_cast<MidiPort*>(input(n));
2406 IO::midi_output(uint32_t n) const
2408 return dynamic_cast<MidiPort*>(output(n));
2412 IO::set_phase_invert (bool yn, void *src)
2414 if (_phase_invert != yn) {
2417 // phase_invert_changed (src); /* EMIT SIGNAL */