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>
30 #include <pbd/replace_all.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/audio_port.h>
36 #include <ardour/midi_port.h>
37 #include <ardour/bundle.h>
38 #include <ardour/session.h>
39 #include <ardour/cycle_timer.h>
40 #include <ardour/panner.h>
41 #include <ardour/buffer_set.h>
42 #include <ardour/meter.h>
43 #include <ardour/amp.h>
50 A bug in OS X's cmath that causes isnan() and isinf() to be
51 "undeclared". the following works around that
54 #if defined(__APPLE__) && defined(__MACH__)
55 extern "C" int isnan (double);
56 extern "C" int isinf (double);
59 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
62 using namespace ARDOUR;
65 const string IO::state_node_name = "IO";
66 bool IO::connecting_legal = false;
67 bool IO::ports_legal = false;
68 bool IO::panners_legal = false;
69 sigc::signal<void> IO::Meter;
70 sigc::signal<int> IO::ConnectingLegal;
71 sigc::signal<int> IO::PortsLegal;
72 sigc::signal<int> IO::PannersLegal;
73 sigc::signal<void,ChanCount> IO::PortCountChanged;
74 sigc::signal<int> IO::PortsCreated;
76 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
78 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
79 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, const string& name,
101 int input_min, int input_max, int output_min, int output_max,
102 DataType default_type)
103 : Automatable (s, name),
104 _output_buffers (new BufferSet()),
105 _default_type (default_type),
106 _input_minimum (ChanCount::ZERO),
107 _input_maximum (ChanCount::INFINITE),
108 _output_minimum (ChanCount::ZERO),
109 _output_maximum (ChanCount::INFINITE)
111 _panner = new Panner (name, _session);
112 _meter = new PeakMeter (_session);
115 _input_minimum = ChanCount(_default_type, input_min);
117 if (input_max >= 0) {
118 _input_maximum = ChanCount(_default_type, input_max);
120 if (output_min > 0) {
121 _output_minimum = ChanCount(_default_type, output_min);
123 if (output_max >= 0) {
124 _output_maximum = ChanCount(_default_type, output_max);
129 pending_state_node = 0;
130 no_panner_reset = false;
131 _phase_invert = false;
134 boost::shared_ptr<AutomationList> gl(
135 new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
137 _gain_control = boost::shared_ptr<GainControl>(
138 new GainControl(X_("gaincontrol"), *this, gl));
140 add_control(_gain_control);
142 apply_gain_automation = false;
145 // IO::Meter is emitted from another thread so the
146 // Meter signal must be protected.
147 Glib::Mutex::Lock guard (m_meter_signal_lock);
148 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
151 // Connect to our own PortCountChanged signal to connect output buffers
152 IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
154 _session.add_controllable (_gain_control);
159 IO::IO (Session& s, const XMLNode& node, DataType dt)
160 : Automatable (s, "unnamed io"),
161 _output_buffers (new BufferSet()),
164 _meter = new PeakMeter (_session);
168 no_panner_reset = false;
172 apply_gain_automation = false;
174 boost::shared_ptr<AutomationList> gl(
175 new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
177 _gain_control = boost::shared_ptr<GainControl>(
178 new GainControl(X_("gaincontrol"), *this, gl));
180 add_control(_gain_control);
185 // IO::Meter is emitted from another thread so the
186 // Meter signal must be protected.
187 Glib::Mutex::Lock guard (m_meter_signal_lock);
188 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
191 // Connect to our own PortCountChanged signal to connect output buffers
192 IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
194 _session.add_controllable (_gain_control);
201 cerr << "Deleting IO called " << _name << endl;
203 Glib::Mutex::Lock guard (m_meter_signal_lock);
205 Glib::Mutex::Lock lm (io_lock);
207 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
208 _session.engine().unregister_port (*i);
211 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
212 _session.engine().unregister_port (*i);
215 m_meter_connection.disconnect();
219 delete _output_buffers;
223 IO::silence (nframes_t nframes, nframes_t offset)
225 /* io_lock, not taken: function must be called from Session::process() calltree */
227 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
228 i->get_buffer().silence (nframes, offset);
232 /** Deliver bufs to the IO's Jack outputs.
234 * This function should automatically do whatever it necessary to correctly deliver bufs
235 * to the outputs, eg applying gain or pan or whatever else needs to be done.
238 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
240 // FIXME: type specific code doesn't actually need to be here, it will go away in time
242 /* ********** AUDIO ********** */
244 // Apply gain if gain automation isn't playing
245 if ( ! apply_gain_automation) {
247 gain_t dg = _gain; // desired gain
250 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
258 if (dg != _gain || dg != 1.0)
259 Amp::run_in_place(bufs, nframes, _gain, dg, _phase_invert);
262 // Use the panner to distribute audio to output port buffers
263 if (_panner && !_panner->empty() && !_panner->bypassed()) {
264 _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
266 const DataType type = DataType::AUDIO;
268 // Copy any audio 1:1 to outputs
270 BufferSet::iterator o = output_buffers().begin(type);
271 BufferSet::iterator i = bufs.begin(type);
272 BufferSet::iterator prev = i;
274 while (i != bufs.end(type) && o != output_buffers().end (type)) {
275 o->read_from(*i, nframes, offset);
281 /* extra outputs get a copy of the last buffer */
283 while (o != output_buffers().end(type)) {
284 o->read_from(*prev, nframes, offset);
289 /* ********** MIDI ********** */
291 // No MIDI, we're done here
292 if (bufs.count().n_midi() == 0) {
296 const DataType type = DataType::MIDI;
298 // Copy any MIDI 1:1 to outputs
299 assert(bufs.count().n_midi() == output_buffers().count().n_midi());
300 BufferSet::iterator o = output_buffers().begin(type);
301 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
302 o->read_from(*i, nframes, offset);
307 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
309 assert(outs.available() >= n_inputs());
311 outs.set_count(n_inputs());
313 if (outs.count() == ChanCount::ZERO)
316 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
318 BufferSet::iterator o = outs.begin(*t);
319 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
320 o->read_from(i->get_buffer(), nframes, offset);
327 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
328 nframes_t nframes, nframes_t offset)
330 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
332 collect_input (bufs, nframes, offset);
334 _meter->run(bufs, start_frame, end_frame, nframes, offset);
338 IO::drop_input_bundle ()
340 _input_bundle.reset ();
341 input_bundle_configuration_connection.disconnect();
342 input_bundle_connection_connection.disconnect();
343 _session.set_dirty ();
347 IO::drop_output_bundle ()
349 _output_bundle.reset ();
350 output_bundle_configuration_connection.disconnect();
351 output_bundle_connection_connection.disconnect();
352 _session.set_dirty ();
356 IO::disconnect_input (Port* our_port, string other_port, void* src)
358 if (other_port.length() == 0 || our_port == 0) {
363 BLOCK_PROCESS_CALLBACK ();
366 Glib::Mutex::Lock lm (io_lock);
368 /* check that our_port is really one of ours */
370 if ( ! _inputs.contains(our_port)) {
374 /* disconnect it from the source */
376 if (_session.engine().disconnect (other_port, our_port->name())) {
377 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
381 drop_input_bundle ();
385 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
386 _session.set_dirty ();
392 IO::connect_input (Port* our_port, string other_port, void* src)
394 if (other_port.length() == 0 || our_port == 0) {
399 BLOCK_PROCESS_CALLBACK ();
402 Glib::Mutex::Lock lm (io_lock);
404 /* check that our_port is really one of ours */
406 if ( ! _inputs.contains(our_port) ) {
410 /* connect it to the source */
412 if (_session.engine().connect (other_port, our_port->name())) {
416 drop_input_bundle ();
420 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
421 _session.set_dirty ();
426 IO::disconnect_output (Port* our_port, string other_port, void* src)
428 if (other_port.length() == 0 || our_port == 0) {
433 BLOCK_PROCESS_CALLBACK ();
436 Glib::Mutex::Lock lm (io_lock);
438 /* check that our_port is really one of ours */
440 if ( ! _outputs.contains(our_port) ) {
444 /* disconnect it from the destination */
446 if (_session.engine().disconnect (our_port->name(), other_port)) {
447 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
451 drop_output_bundle ();
455 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
456 _session.set_dirty ();
461 IO::connect_output (Port* our_port, string other_port, void* src)
463 if (other_port.length() == 0 || our_port == 0) {
468 BLOCK_PROCESS_CALLBACK ();
472 Glib::Mutex::Lock lm (io_lock);
474 /* check that our_port is really one of ours */
476 if ( ! _outputs.contains(our_port) ) {
480 /* connect it to the destination */
482 if (_session.engine().connect (our_port->name(), other_port)) {
486 drop_output_bundle ();
490 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
491 _session.set_dirty ();
496 IO::set_input (Port* other_port, void* src)
498 /* this removes all but one ports, and connects that one port
499 to the specified source.
502 if (_input_minimum.n_total() > 1) {
503 /* sorry, you can't do this */
507 if (other_port == 0) {
508 if (_input_minimum == ChanCount::ZERO) {
509 return ensure_inputs (ChanCount::ZERO, false, true, src);
515 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
519 return connect_input (_inputs.port(0), other_port->name(), src);
523 IO::remove_output_port (Port* port, void* src)
525 IOChange change (NoChange);
528 BLOCK_PROCESS_CALLBACK ();
532 Glib::Mutex::Lock lm (io_lock);
534 if (n_outputs() <= _output_minimum) {
535 /* sorry, you can't do this */
539 if (_outputs.remove(port)) {
540 change = IOChange (change|ConfigurationChanged);
542 if (port->connected()) {
543 change = IOChange (change|ConnectionsChanged);
546 _session.engine().unregister_port (*port);
547 drop_output_bundle ();
549 setup_peak_meters ();
554 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
557 if (change == ConnectionsChanged) {
561 if (change != NoChange) {
562 output_changed (change, src);
563 _session.set_dirty ();
570 /** Add an output port.
572 * @param destination Name of input port to connect new port to.
573 * @param src Source for emitted ConfigurationChanged signal.
574 * @param type Data type of port. Default value (NIL) will use this IO's default type.
577 IO::add_output_port (string destination, void* src, DataType type)
582 if (type == DataType::NIL)
583 type = _default_type;
586 BLOCK_PROCESS_CALLBACK ();
590 Glib::Mutex::Lock lm (io_lock);
592 if (n_outputs() >= _output_maximum) {
596 /* Create a new output port */
598 // FIXME: naming scheme for differently typed ports?
599 if (_output_maximum.get(type) == 1) {
600 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
602 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
605 if ((our_port = _session.engine().register_output_port (Jack, type, name)) == 0) {
606 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
610 _outputs.add (our_port);
611 drop_output_bundle ();
612 setup_peak_meters ();
616 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
619 if (destination.length()) {
620 if (_session.engine().connect (our_port->name(), destination)) {
625 // pan_changed (src); /* EMIT SIGNAL */
626 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
628 _session.set_dirty ();
634 IO::remove_input_port (Port* port, void* src)
636 IOChange change (NoChange);
639 BLOCK_PROCESS_CALLBACK ();
643 Glib::Mutex::Lock lm (io_lock);
645 if (n_inputs() <= _input_minimum) {
646 /* sorry, you can't do this */
650 if (_inputs.remove(port)) {
651 change = IOChange (change|ConfigurationChanged);
653 if (port->connected()) {
654 change = IOChange (change|ConnectionsChanged);
657 _session.engine().unregister_port (*port);
658 drop_input_bundle ();
660 setup_peak_meters ();
665 PortCountChanged (n_inputs ()); /* EMIT SIGNAL */
668 if (change == ConfigurationChanged) {
672 if (change != NoChange) {
673 input_changed (change, src);
674 _session.set_dirty ();
682 /** Add an input port.
684 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
685 * @param destination Name of input port to connect new port to.
686 * @param src Source for emitted ConfigurationChanged signal.
689 IO::add_input_port (string source, void* src, DataType type)
694 if (type == DataType::NIL)
695 type = _default_type;
698 BLOCK_PROCESS_CALLBACK ();
701 Glib::Mutex::Lock lm (io_lock);
703 if (n_inputs() >= _input_maximum) {
707 /* Create a new input port */
709 // FIXME: naming scheme for differently typed ports?
710 if (_input_maximum.get(type) == 1) {
711 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
713 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
716 if ((our_port = _session.engine().register_input_port (Jack, type, name)) == 0) {
717 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
721 _inputs.add (our_port);
722 drop_input_bundle ();
723 setup_peak_meters ();
727 PortCountChanged (n_inputs()); /* EMIT SIGNAL */
730 if (source.length()) {
732 if (_session.engine().connect (source, our_port->name())) {
737 // pan_changed (src); /* EMIT SIGNAL */
738 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
740 _session.set_dirty ();
746 IO::disconnect_inputs (void* src)
749 BLOCK_PROCESS_CALLBACK ();
752 Glib::Mutex::Lock lm (io_lock);
754 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
755 _session.engine().disconnect (*i);
758 drop_input_bundle ();
762 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
768 IO::disconnect_outputs (void* src)
771 BLOCK_PROCESS_CALLBACK ();
774 Glib::Mutex::Lock lm (io_lock);
776 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
777 _session.engine().disconnect (*i);
780 drop_output_bundle ();
784 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
785 _session.set_dirty ();
791 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
793 Port* input_port = 0;
794 bool changed = false;
797 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
799 const size_t n = count.get(*t);
801 /* remove unused ports */
802 for (size_t i = n_inputs().get(*t); i > n; --i) {
803 input_port = _inputs.port(*t, i-1);
806 _inputs.remove(input_port);
807 _session.engine().unregister_port (*input_port);
812 /* create any necessary new ports */
813 while (n_inputs().get(*t) < n) {
817 if (_input_maximum.get(*t) == 1) {
818 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
820 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
825 if ((input_port = _session.engine().register_input_port (Jack, *t, buf)) == 0) {
826 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
831 catch (AudioEngine::PortRegistrationFailure& err) {
832 setup_peak_meters ();
835 throw AudioEngine::PortRegistrationFailure();
838 _inputs.add (input_port);
844 drop_input_bundle ();
845 setup_peak_meters ();
847 PortCountChanged (n_inputs()); /* EMIT SIGNAL */
848 _session.set_dirty ();
852 /* disconnect all existing ports so that we get a fresh start */
853 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
854 _session.engine().disconnect (*i);
861 /** Attach output_buffers to port buffers.
863 * Connected to IO's own PortCountChanged signal.
866 IO::attach_buffers(ChanCount ignored)
868 _output_buffers->attach_buffers(_outputs);
872 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
874 bool in_changed = false;
875 bool out_changed = false;
876 bool need_pan_reset = false;
878 in = min (_input_maximum, in);
880 out = min (_output_maximum, out);
882 if (in == n_inputs() && out == n_outputs() && !clear) {
887 BLOCK_PROCESS_CALLBACK ();
888 Glib::Mutex::Lock lm (io_lock);
892 if (n_outputs() != out) {
893 need_pan_reset = true;
896 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
898 const size_t nin = in.get(*t);
899 const size_t nout = out.get(*t);
901 Port* output_port = 0;
902 Port* input_port = 0;
904 /* remove unused output ports */
905 for (size_t i = n_outputs().get(*t); i > nout; --i) {
906 output_port = _outputs.port(*t, i-1);
909 _outputs.remove(output_port);
910 _session.engine().unregister_port (*output_port);
915 /* remove unused input ports */
916 for (size_t i = n_inputs().get(*t); i > nin; --i) {
917 input_port = _inputs.port(*t, i-1);
920 _inputs.remove(input_port);
921 _session.engine().unregister_port (*input_port);
926 /* create any necessary new input ports */
928 while (n_inputs().get(*t) < nin) {
932 /* Create a new input port */
934 if (_input_maximum.get(*t) == 1) {
935 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
937 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
941 if ((port = _session.engine().register_input_port (Jack, *t, buf)) == 0) {
942 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
947 catch (AudioEngine::PortRegistrationFailure& err) {
948 setup_peak_meters ();
951 throw AudioEngine::PortRegistrationFailure();
958 /* create any necessary new output ports */
960 while (n_outputs().get(*t) < nout) {
964 /* Create a new output port */
966 if (_output_maximum.get(*t) == 1) {
967 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
969 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
973 if ((port = _session.engine().register_output_port (Jack, *t, buf)) == 0) {
974 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
979 catch (AudioEngine::PortRegistrationFailure& err) {
980 setup_peak_meters ();
983 throw AudioEngine::PortRegistrationFailure ();
993 /* disconnect all existing ports so that we get a fresh start */
995 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
996 _session.engine().disconnect (*i);
999 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1000 _session.engine().disconnect (*i);
1004 if (in_changed || out_changed) {
1005 setup_peak_meters ();
1011 drop_output_bundle ();
1012 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1016 drop_input_bundle ();
1017 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1020 if (in_changed || out_changed) {
1021 PortCountChanged (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1023 _session.set_dirty ();
1030 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1032 bool changed = false;
1034 count = min (_input_maximum, count);
1036 if (count == n_inputs() && !clear) {
1041 BLOCK_PROCESS_CALLBACK ();
1042 Glib::Mutex::Lock im (io_lock);
1043 changed = ensure_inputs_locked (count, clear, src);
1045 changed = ensure_inputs_locked (count, clear, src);
1049 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1051 _session.set_dirty ();
1057 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1059 Port* output_port = 0;
1060 bool changed = false;
1061 bool need_pan_reset = false;
1063 if (n_outputs() != count) {
1064 need_pan_reset = true;
1067 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1069 const size_t n = count.get(*t);
1071 /* remove unused ports */
1072 for (size_t i = n_outputs().get(*t); i > n; --i) {
1073 output_port = _outputs.port(*t, i-1);
1075 assert(output_port);
1076 _outputs.remove(output_port);
1077 _session.engine().unregister_port (*output_port);
1082 /* create any necessary new ports */
1083 while (n_outputs().get(*t) < n) {
1087 if (_output_maximum.get(*t) == 1) {
1088 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1090 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1093 if ((output_port = _session.engine().register_output_port (Jack, *t, buf)) == 0) {
1094 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1098 _outputs.add (output_port);
1100 setup_peak_meters ();
1102 if (need_pan_reset) {
1109 drop_output_bundle ();
1110 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
1111 _session.set_dirty ();
1115 /* disconnect all existing ports so that we get a fresh start */
1116 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1117 _session.engine().disconnect (*i);
1125 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1127 bool changed = false;
1129 if (_output_maximum < ChanCount::INFINITE) {
1130 count = min (_output_maximum, count);
1131 if (count == n_outputs() && !clear) {
1136 /* XXX caller should hold io_lock, but generally doesn't */
1139 BLOCK_PROCESS_CALLBACK ();
1140 Glib::Mutex::Lock im (io_lock);
1141 changed = ensure_outputs_locked (count, clear, src);
1143 changed = ensure_outputs_locked (count, clear, src);
1147 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1155 IO::effective_gain () const
1157 if (_gain_control->list()->automation_playback()) {
1158 return _gain_control->get_value();
1160 return _desired_gain;
1167 if (panners_legal) {
1168 if (!no_panner_reset) {
1169 _panner->reset (n_outputs().n_audio(), pans_required());
1172 panner_legal_c.disconnect ();
1173 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1178 IO::panners_became_legal ()
1180 _panner->reset (n_outputs().n_audio(), pans_required());
1181 _panner->load (); // automation
1182 panner_legal_c.disconnect ();
1187 IO::defer_pan_reset ()
1189 no_panner_reset = true;
1193 IO::allow_pan_reset ()
1195 no_panner_reset = false;
1201 IO::get_state (void)
1203 return state (true);
1207 IO::state (bool full_state)
1209 XMLNode* node = new XMLNode (state_node_name);
1212 bool need_ins = true;
1213 bool need_outs = true;
1214 LocaleGuard lg (X_("POSIX"));
1215 Glib::Mutex::Lock lm (io_lock);
1217 node->add_property("name", _name);
1218 id().print (buf, sizeof (buf));
1219 node->add_property("id", buf);
1223 if (_input_bundle && !_input_bundle->dynamic()) {
1224 node->add_property ("input-connection", _input_bundle->name());
1228 if (_output_bundle && !_output_bundle->dynamic()) {
1229 node->add_property ("output-connection", _output_bundle->name());
1234 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1236 const char **connections = i->get_connections();
1238 if (connections && connections[0]) {
1241 for (int n = 0; connections && connections[n]; ++n) {
1246 /* if its a connection to our own port,
1247 return only the port name, not the
1248 whole thing. this allows connections
1249 to be re-established even when our
1250 client name is different.
1253 str += _session.engine().make_port_name_relative (connections[n]);
1265 node->add_property ("inputs", str);
1271 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1273 const char **connections = i->get_connections();
1275 if (connections && connections[0]) {
1279 for (int n = 0; connections[n]; ++n) {
1284 str += _session.engine().make_port_name_relative (connections[n]);
1296 node->add_property ("outputs", str);
1299 node->add_child_nocopy (_panner->state (full_state));
1300 node->add_child_nocopy (_gain_control->get_state ());
1302 snprintf (buf, sizeof(buf), "%2.12f", gain());
1303 node->add_property ("gain", buf);
1305 /* To make backwards compatibility a bit easier, write ChanCount::INFINITE to the session file
1309 int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
1310 int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
1312 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
1314 node->add_property ("iolimits", buf);
1319 node->add_child_nocopy (get_automation_state());
1325 IO::set_state (const XMLNode& node)
1327 const XMLProperty* prop;
1328 XMLNodeConstIterator iter;
1329 LocaleGuard lg (X_("POSIX"));
1331 /* force use of non-localized representation of decimal point,
1332 since we use it a lot in XML files and so forth.
1335 if (node.name() != state_node_name) {
1336 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1340 if ((prop = node.property ("name")) != 0) {
1341 _name = prop->value();
1342 /* used to set panner name with this, but no more */
1345 if ((prop = node.property ("id")) != 0) {
1346 _id = prop->value ();
1354 if ((prop = node.property ("iolimits")) != 0) {
1355 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1356 &in_min, &in_max, &out_min, &out_max);
1358 /* Correct for the difference between the way we write things to session files and the
1359 way things are described by ChanCount; see comments in io.h about what the different
1360 ChanCount values mean. */
1363 _input_minimum = ChanCount::ZERO;
1365 _input_minimum = ChanCount (_default_type, in_min);
1369 _input_maximum = ChanCount::INFINITE;
1371 _input_maximum = ChanCount (_default_type, in_max);
1375 _output_minimum = ChanCount::ZERO;
1377 _output_minimum = ChanCount (_default_type, out_min);
1381 _output_maximum = ChanCount::INFINITE;
1383 _output_maximum = ChanCount (_default_type, out_max);
1387 if ((prop = node.property ("gain")) != 0) {
1388 set_gain (atof (prop->value().c_str()), this);
1389 _gain = _desired_gain;
1392 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1393 /* old school automation handling */
1396 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1398 if ((*iter)->name() == "Panner") {
1400 _panner = new Panner (_name, _session);
1402 _panner->set_state (**iter);
1405 if ((*iter)->name() == X_("Automation")) {
1407 set_automation_state (*(*iter), Parameter(GainAutomation));
1410 if ((*iter)->name() == X_("controllable")) {
1411 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1412 _gain_control->set_state (**iter);
1419 if (create_ports (node)) {
1425 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1428 if (panners_legal) {
1431 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1434 if (connecting_legal) {
1436 if (make_connections (node)) {
1442 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1445 if (!ports_legal || !connecting_legal) {
1446 pending_state_node = new XMLNode (node);
1453 IO::load_automation (string path)
1458 uint32_t linecnt = 0;
1460 LocaleGuard lg (X_("POSIX"));
1462 fullpath = _session.automation_dir();
1465 in.open (fullpath.c_str());
1468 fullpath = _session.automation_dir();
1469 fullpath += _session.snap_name();
1473 in.open (fullpath.c_str());
1476 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1481 clear_automation ();
1483 while (in.getline (line, sizeof(line), '\n')) {
1488 if (++linecnt == 1) {
1489 if (memcmp (line, "version", 7) == 0) {
1490 if (sscanf (line, "version %f", &version) != 1) {
1491 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1495 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1502 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1503 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1509 _gain_control->list()->fast_simple_add (when, value);
1519 /* older (pre-1.0) versions of ardour used this */
1523 warning << _("dubious automation event found (and ignored)") << endmsg;
1531 IO::connecting_became_legal ()
1535 if (pending_state_node == 0) {
1536 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1541 connection_legal_c.disconnect ();
1543 ret = make_connections (*pending_state_node);
1546 delete pending_state_node;
1547 pending_state_node = 0;
1553 IO::ports_became_legal ()
1557 if (pending_state_node == 0) {
1558 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1563 port_legal_c.disconnect ();
1565 ret = create_ports (*pending_state_node);
1567 if (connecting_legal) {
1568 delete pending_state_node;
1569 pending_state_node = 0;
1576 IO::create_ports (const XMLNode& node)
1578 const XMLProperty* prop;
1580 int num_outputs = 0;
1582 /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1583 * break the session file format.
1585 if ((prop = node.property ("input-connection")) != 0) {
1587 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1590 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1592 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1593 error << _("No input bundles available as a replacement")
1597 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1602 num_inputs = c->nchannels();
1604 } else if ((prop = node.property ("inputs")) != 0) {
1606 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1609 if ((prop = node.property ("output-connection")) != 0) {
1610 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1613 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1615 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1616 error << _("No output bundles available as a replacement")
1620 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1625 num_outputs = c->nchannels ();
1627 } else if ((prop = node.property ("outputs")) != 0) {
1628 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1631 no_panner_reset = true;
1633 // FIXME: audio-only
1634 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1635 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1639 no_panner_reset = false;
1641 set_deferred_state ();
1649 IO::make_connections (const XMLNode& node)
1651 const XMLProperty* prop;
1653 if ((prop = node.property ("input-connection")) != 0) {
1654 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1657 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1659 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1660 error << _("No input connections available as a replacement")
1664 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1669 connect_input_ports_to_bundle (c, this);
1671 } else if ((prop = node.property ("inputs")) != 0) {
1672 if (set_inputs (prop->value())) {
1673 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1678 if ((prop = node.property ("output-bundle")) != 0) {
1679 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1682 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1684 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1685 error << _("No output bundles available as a replacement")
1689 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1694 connect_output_ports_to_bundle (c, this);
1696 } else if ((prop = node.property ("outputs")) != 0) {
1697 if (set_outputs (prop->value())) {
1698 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1707 IO::set_inputs (const string& str)
1709 vector<string> ports;
1714 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1718 // FIXME: audio-only
1719 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1723 string::size_type start, end, ostart;
1730 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1733 if ((end = str.find_first_of ('}', start)) == string::npos) {
1734 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1738 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1739 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1745 for (int x = 0; x < n; ++x) {
1746 connect_input (input (i), ports[x], this);
1758 IO::set_outputs (const string& str)
1760 vector<string> ports;
1765 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1769 // FIXME: audio-only
1770 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1774 string::size_type start, end, ostart;
1781 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1784 if ((end = str.find_first_of ('}', start)) == string::npos) {
1785 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1789 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1790 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1796 for (int x = 0; x < n; ++x) {
1797 connect_output (output (i), ports[x], this);
1809 IO::parse_io_string (const string& str, vector<string>& ports)
1811 string::size_type pos, opos;
1813 if (str.length() == 0) {
1822 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1823 ports.push_back (str.substr (opos, pos - opos));
1827 if (opos < str.length()) {
1828 ports.push_back (str.substr(opos));
1831 return ports.size();
1835 IO::parse_gain_string (const string& str, vector<string>& ports)
1837 string::size_type pos, opos;
1843 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1844 ports.push_back (str.substr (opos, pos - opos));
1848 if (opos < str.length()) {
1849 ports.push_back (str.substr(opos));
1852 return ports.size();
1856 IO::set_name (const string& str)
1862 /* replace all colons in the name. i wish we didn't have to do this */
1865 if (replace_all (name, ":", "-")) {
1866 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1869 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1870 string current_name = i->short_name();
1871 current_name.replace (current_name.find (_name), _name.length(), name);
1872 i->set_name (current_name);
1875 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1876 string current_name = i->short_name();
1877 current_name.replace (current_name.find (_name), _name.length(), name);
1878 i->set_name (current_name);
1881 bool const r = SessionObject::set_name(name);
1889 IO::set_input_minimum (ChanCount n)
1895 IO::set_input_maximum (ChanCount n)
1901 IO::set_output_minimum (ChanCount n)
1903 _output_minimum = n;
1907 IO::set_output_maximum (ChanCount n)
1909 _output_maximum = n;
1913 IO::set_port_latency (nframes_t nframes)
1915 Glib::Mutex::Lock lm (io_lock);
1917 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1918 i->set_latency (nframes);
1923 IO::output_latency () const
1925 nframes_t max_latency;
1930 /* io lock not taken - must be protected by other means */
1932 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1933 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1934 max_latency = latency;
1942 IO::input_latency () const
1944 nframes_t max_latency;
1949 /* io lock not taken - must be protected by other means */
1951 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1952 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1953 max_latency = latency;
1961 IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
1966 BLOCK_PROCESS_CALLBACK ();
1967 Glib::Mutex::Lock lm2 (io_lock);
1969 limit = c->nchannels();
1971 drop_input_bundle ();
1973 // FIXME bundles only work for audio-only
1974 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1978 /* first pass: check the current state to see what's correctly
1979 connected, and drop anything that we don't want.
1982 for (uint32_t n = 0; n < limit; ++n) {
1983 const Bundle::PortList& pl = c->channel_ports (n);
1985 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1987 if (!_inputs.port(n)->connected_to ((*i))) {
1989 /* clear any existing connections */
1991 _session.engine().disconnect (*_inputs.port(n));
1993 } else if (_inputs.port(n)->connected() > 1) {
1995 /* OK, it is connected to the port we want,
1996 but its also connected to other ports.
1997 Change that situation.
2000 /* XXX could be optimized to not drop
2004 _session.engine().disconnect (*_inputs.port(n));
2010 /* second pass: connect all requested ports where necessary */
2012 for (uint32_t n = 0; n < limit; ++n) {
2013 const Bundle::PortList& pl = c->channel_ports (n);
2015 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2017 if (!_inputs.port(n)->connected_to ((*i))) {
2019 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
2029 input_bundle_configuration_connection = c->ConfigurationChanged.connect
2030 (mem_fun (*this, &IO::input_bundle_configuration_changed));
2031 input_bundle_connection_connection = c->PortsChanged.connect
2032 (mem_fun (*this, &IO::input_bundle_connection_changed));
2035 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2040 IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
2045 BLOCK_PROCESS_CALLBACK ();
2046 Glib::Mutex::Lock lm2 (io_lock);
2048 limit = c->nchannels();
2050 drop_output_bundle ();
2052 // FIXME: audio-only
2053 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2057 /* first pass: check the current state to see what's correctly
2058 connected, and drop anything that we don't want.
2061 for (uint32_t n = 0; n < limit; ++n) {
2063 const Bundle::PortList& pl = c->channel_ports (n);
2065 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2067 if (!_outputs.port(n)->connected_to ((*i))) {
2069 /* clear any existing connections */
2071 _session.engine().disconnect (*_outputs.port(n));
2073 } else if (_outputs.port(n)->connected() > 1) {
2075 /* OK, it is connected to the port we want,
2076 but its also connected to other ports.
2077 Change that situation.
2080 /* XXX could be optimized to not drop
2084 _session.engine().disconnect (*_outputs.port(n));
2089 /* second pass: connect all requested ports where necessary */
2091 for (uint32_t n = 0; n < limit; ++n) {
2093 const Bundle::PortList& pl = c->channel_ports (n);
2095 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2097 if (!_outputs.port(n)->connected_to ((*i))) {
2099 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2108 output_bundle_configuration_connection = c->ConfigurationChanged.connect
2109 (mem_fun (*this, &IO::output_bundle_configuration_changed));
2110 output_bundle_connection_connection = c->PortsChanged.connect
2111 (mem_fun (*this, &IO::output_bundle_connection_changed));
2114 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2120 IO::disable_connecting ()
2122 connecting_legal = false;
2127 IO::enable_connecting ()
2129 connecting_legal = true;
2130 return ConnectingLegal ();
2134 IO::disable_ports ()
2136 ports_legal = false;
2144 return PortsLegal ();
2148 IO::disable_panners (void)
2150 panners_legal = false;
2155 IO::reset_panners ()
2157 panners_legal = true;
2158 return PannersLegal ();
2162 IO::input_bundle_connection_changed (int ignored)
2164 connect_input_ports_to_bundle (_input_bundle, this);
2168 IO::input_bundle_configuration_changed ()
2170 connect_input_ports_to_bundle (_input_bundle, this);
2174 IO::output_bundle_connection_changed (int ignored)
2176 connect_output_ports_to_bundle (_output_bundle, this);
2180 IO::output_bundle_configuration_changed ()
2182 connect_output_ports_to_bundle (_output_bundle, this);
2186 IO::GainControl::set_value (float val)
2188 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2189 if (val > 1.99526231f)
2193 _io.set_gain (val, this);
2195 Changed(); /* EMIT SIGNAL */
2199 IO::GainControl::get_value (void) const
2201 return AutomationControl::get_value();
2205 IO::setup_peak_meters()
2207 ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2208 _meter->configure_io(max_streams, max_streams);
2212 Update the peak meters.
2214 The meter signal lock is taken to prevent modification of the
2215 Meter signal while updating the meters, taking the meter signal
2216 lock prior to taking the io_lock ensures that all IO will remain
2217 valid while metering.
2222 Glib::Mutex::Lock guard (m_meter_signal_lock);
2224 Meter(); /* EMIT SIGNAL */
2230 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2232 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2237 IO::clear_automation ()
2239 Automatable::clear_automation (); // clears gain automation
2240 _panner->clear_automation ();
2244 IO::set_parameter_automation_state (Parameter param, AutoState state)
2246 // XXX: would be nice to get rid of this special hack
2248 if (param.type() == GainAutomation) {
2250 bool changed = false;
2253 Glib::Mutex::Lock lm (_automation_lock);
2255 boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
2257 if (state != gain_auto->automation_state()) {
2259 _last_automation_snapshot = 0;
2260 gain_auto->set_automation_state (state);
2263 // FIXME: shouldn't this use Curve?
2264 set_gain (gain_auto->eval (_session.transport_frame()), this);
2270 _session.set_dirty ();
2274 Automatable::set_parameter_automation_state(param, state);
2279 IO::inc_gain (gain_t factor, void *src)
2281 if (_desired_gain == 0.0f)
2282 set_gain (0.000001f + (0.000001f * factor), src);
2284 set_gain (_desired_gain + (_desired_gain * factor), src);
2288 IO::set_gain (gain_t val, void *src)
2290 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2291 if (val > 1.99526231f)
2294 if (src != _gain_control.get()) {
2295 _gain_control->set_value(val);
2296 // bit twisty, this will come back and call us again
2297 // (this keeps control in sync with reality)
2302 Glib::Mutex::Lock dm (declick_lock);
2303 _desired_gain = val;
2306 if (_session.transport_stopped()) {
2310 if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
2311 _gain_control->list()->add (_session.transport_frame(), val);
2315 _session.set_dirty();
2319 IO::start_pan_touch (uint32_t which)
2321 if (which < _panner->size()) {
2322 (*_panner)[which]->pan_control()->list()->start_touch();
2327 IO::end_pan_touch (uint32_t which)
2329 if (which < _panner->size()) {
2330 (*_panner)[which]->pan_control()->list()->stop_touch();
2336 IO::automation_snapshot (nframes_t now)
2338 Automatable::automation_snapshot (now);
2340 if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
2341 _panner->snapshot (now);
2346 IO::transport_stopped (nframes_t frame)
2348 _gain_control->list()->reposition_for_rt_add (frame);
2350 if (_gain_control->list()->automation_state() != Off) {
2352 /* the src=0 condition is a special signal to not propagate
2353 automation gain changes into the mix group when locating.
2356 // FIXME: shouldn't this use Curve?
2357 set_gain (_gain_control->list()->eval (frame), 0);
2360 _panner->transport_stopped (frame);
2364 IO::find_input_port_hole ()
2366 /* CALLER MUST HOLD IO LOCK */
2370 if (_inputs.empty()) {
2374 for (n = 1; n < UINT_MAX; ++n) {
2375 char buf[jack_port_name_size()];
2376 PortSet::iterator i = _inputs.begin();
2378 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2380 for ( ; i != _inputs.end(); ++i) {
2381 if (i->short_name() == buf) {
2386 if (i == _inputs.end()) {
2394 IO::find_output_port_hole ()
2396 /* CALLER MUST HOLD IO LOCK */
2400 if (_outputs.empty()) {
2404 for (n = 1; n < UINT_MAX; ++n) {
2405 char buf[jack_port_name_size()];
2406 PortSet::iterator i = _outputs.begin();
2408 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2410 for ( ; i != _outputs.end(); ++i) {
2411 if (i->short_name() == buf) {
2416 if (i == _outputs.end()) {
2425 IO::audio_input(uint32_t n) const
2427 return dynamic_cast<AudioPort*>(input(n));
2431 IO::audio_output(uint32_t n) const
2433 return dynamic_cast<AudioPort*>(output(n));
2437 IO::midi_input(uint32_t n) const
2439 return dynamic_cast<MidiPort*>(input(n));
2443 IO::midi_output(uint32_t n) const
2445 return dynamic_cast<MidiPort*>(output(n));
2449 IO::set_phase_invert (bool yn, void *src)
2451 if (_phase_invert != yn) {
2453 // phase_invert_changed (src); /* EMIT SIGNAL */
2458 IO::set_denormal_protection (bool yn, void *src)
2460 if (_denormal_protection != yn) {
2461 _denormal_protection = yn;
2462 // denormal_protection_changed (src); /* EMIT SIGNAL */
2467 IO::update_port_total_latencies ()
2469 /* io_lock, not taken: function must be called from Session::process() calltree */
2471 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2472 _session.engine().update_total_latency (*i);
2475 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2476 _session.engine().update_total_latency (*i);
2482 * Setup bundles that describe our inputs and outputs.
2486 IO::setup_bundles ()
2490 snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
2491 _bundle_for_inputs->set_name (buf, 0);
2492 int const ins = n_inputs().n_total();
2493 _bundle_for_inputs->set_nchannels (ins);
2495 for (int i = 0; i < ins; ++i) {
2496 _bundle_for_inputs->add_port_to_channel (i, _inputs.port(i)->name ());
2499 snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
2500 _bundle_for_outputs->set_name (buf, 0);
2501 int const outs = n_outputs().n_total();
2502 _bundle_for_outputs->set_nchannels (outs);
2504 for (int i = 0; i < outs; ++i) {
2505 _bundle_for_outputs->add_port_to_channel (i, _outputs.port(i)->name ());
2511 * Create and setup bundles that describe our inputs and outputs.
2515 IO::create_bundles ()
2517 _bundle_for_inputs = boost::shared_ptr<Bundle> (
2518 new InputBundle ("", true)
2521 _bundle_for_outputs = boost::shared_ptr<Bundle> (
2522 new OutputBundle ("", true)
2528 boost::shared_ptr<Bundle>
2531 if (_input_bundle) {
2532 return _input_bundle;
2535 /* XXX: will only report the first bundle found; should really return a list, I think */
2537 /* check that _input_bundle is right wrt the connections that are currently made */
2539 /* make a vector of the first output connected to each of our inputs */
2540 std::vector<std::string> connected;
2541 for (uint32_t i = 0; i < _inputs.num_ports(); ++i) {
2542 const char** c = _inputs.port(i)->get_connections ();
2544 connected.push_back (c[0]);
2548 _input_bundle = _session.bundle_by_ports (connected);
2549 return _input_bundle;
2553 boost::shared_ptr<Bundle>
2556 if (_output_bundle) {
2557 return _output_bundle;
2560 /* XXX: will only report the first bundle found; should really return a list, I think */
2562 /* check that _output_bundle is right wrt the connections that are currently made */
2564 /* make a vector of the first input connected to each of our outputs */
2565 std::vector<std::string> connected;
2566 for (uint32_t i = 0; i < _outputs.num_ports(); ++i) {
2567 const char** c = _outputs.port(i)->get_connections ();
2569 connected.push_back (c[0]);
2573 _output_bundle = _session.bundle_by_ports (connected);
2574 return _output_bundle;