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 Glib::Mutex::Lock guard (m_meter_signal_lock);
203 Glib::Mutex::Lock lm (io_lock);
205 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
206 _session.engine().unregister_port (*i);
209 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
210 _session.engine().unregister_port (*i);
213 m_meter_connection.disconnect();
217 delete _output_buffers;
221 IO::silence (nframes_t nframes, nframes_t offset)
223 /* io_lock, not taken: function must be called from Session::process() calltree */
225 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
226 i->get_buffer().silence (nframes, offset);
230 /** Deliver bufs to the IO's Jack outputs.
232 * This function should automatically do whatever it necessary to correctly deliver bufs
233 * to the outputs, eg applying gain or pan or whatever else needs to be done.
236 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
238 // FIXME: type specific code doesn't actually need to be here, it will go away in time
240 /* ********** AUDIO ********** */
242 // Apply gain if gain automation isn't playing
243 if ( ! apply_gain_automation) {
245 gain_t dg = _gain; // desired gain
248 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
256 if (dg != _gain || dg != 1.0)
257 Amp::run_in_place(bufs, nframes, _gain, dg, _phase_invert);
260 // Use the panner to distribute audio to output port buffers
261 if (_panner && !_panner->empty() && !_panner->bypassed()) {
262 _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
264 const DataType type = DataType::AUDIO;
266 // Copy any audio 1:1 to outputs
268 BufferSet::iterator o = output_buffers().begin(type);
269 BufferSet::iterator i = bufs.begin(type);
270 BufferSet::iterator prev = i;
272 while (i != bufs.end(type) && o != output_buffers().end (type)) {
273 o->read_from(*i, nframes, offset);
279 /* extra outputs get a copy of the last buffer */
281 while (o != output_buffers().end(type)) {
282 o->read_from(*prev, nframes, offset);
287 /* ********** MIDI ********** */
289 // No MIDI, we're done here
290 if (bufs.count().n_midi() == 0) {
294 const DataType type = DataType::MIDI;
296 // Copy any MIDI 1:1 to outputs
297 assert(bufs.count().n_midi() == output_buffers().count().n_midi());
298 BufferSet::iterator o = output_buffers().begin(type);
299 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
300 o->read_from(*i, nframes, offset);
305 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
307 assert(outs.available() >= n_inputs());
309 outs.set_count(n_inputs());
311 if (outs.count() == ChanCount::ZERO)
314 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
316 BufferSet::iterator o = outs.begin(*t);
317 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
318 o->read_from(i->get_buffer(), nframes, offset);
325 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
326 nframes_t nframes, nframes_t offset)
328 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
330 collect_input (bufs, nframes, offset);
332 _meter->run(bufs, start_frame, end_frame, nframes, offset);
336 IO::drop_input_bundle ()
338 _input_bundle.reset ();
339 input_bundle_configuration_connection.disconnect();
340 input_bundle_connection_connection.disconnect();
341 _session.set_dirty ();
345 IO::drop_output_bundle ()
347 _output_bundle.reset ();
348 output_bundle_configuration_connection.disconnect();
349 output_bundle_connection_connection.disconnect();
350 _session.set_dirty ();
354 IO::disconnect_input (Port* our_port, string other_port, void* src)
356 if (other_port.length() == 0 || our_port == 0) {
361 BLOCK_PROCESS_CALLBACK ();
364 Glib::Mutex::Lock lm (io_lock);
366 /* check that our_port is really one of ours */
368 if ( ! _inputs.contains(our_port)) {
372 /* disconnect it from the source */
374 if (_session.engine().disconnect (other_port, our_port->name())) {
375 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
379 drop_input_bundle ();
383 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
384 _session.set_dirty ();
390 IO::connect_input (Port* our_port, string other_port, void* src)
392 if (other_port.length() == 0 || our_port == 0) {
397 BLOCK_PROCESS_CALLBACK ();
400 Glib::Mutex::Lock lm (io_lock);
402 /* check that our_port is really one of ours */
404 if ( ! _inputs.contains(our_port) ) {
408 /* connect it to the source */
410 if (_session.engine().connect (other_port, our_port->name())) {
414 drop_input_bundle ();
418 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
419 _session.set_dirty ();
424 IO::disconnect_output (Port* our_port, string other_port, void* src)
426 if (other_port.length() == 0 || our_port == 0) {
431 BLOCK_PROCESS_CALLBACK ();
434 Glib::Mutex::Lock lm (io_lock);
436 /* check that our_port is really one of ours */
438 if ( ! _outputs.contains(our_port) ) {
442 /* disconnect it from the destination */
444 if (_session.engine().disconnect (our_port->name(), other_port)) {
445 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
449 drop_output_bundle ();
453 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
454 _session.set_dirty ();
459 IO::connect_output (Port* our_port, string other_port, void* src)
461 if (other_port.length() == 0 || our_port == 0) {
466 BLOCK_PROCESS_CALLBACK ();
470 Glib::Mutex::Lock lm (io_lock);
472 /* check that our_port is really one of ours */
474 if ( ! _outputs.contains(our_port) ) {
478 /* connect it to the destination */
480 if (_session.engine().connect (our_port->name(), other_port)) {
484 drop_output_bundle ();
488 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
489 _session.set_dirty ();
494 IO::set_input (Port* other_port, void* src)
496 /* this removes all but one ports, and connects that one port
497 to the specified source.
500 if (_input_minimum.n_total() > 1) {
501 /* sorry, you can't do this */
505 if (other_port == 0) {
506 if (_input_minimum == ChanCount::ZERO) {
507 return ensure_inputs (ChanCount::ZERO, false, true, src);
513 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
517 return connect_input (_inputs.port(0), other_port->name(), src);
521 IO::remove_output_port (Port* port, void* src)
523 IOChange change (NoChange);
526 BLOCK_PROCESS_CALLBACK ();
530 Glib::Mutex::Lock lm (io_lock);
532 if (n_outputs() <= _output_minimum) {
533 /* sorry, you can't do this */
537 if (_outputs.remove(port)) {
538 change = IOChange (change|ConfigurationChanged);
540 if (port->connected()) {
541 change = IOChange (change|ConnectionsChanged);
544 _session.engine().unregister_port (*port);
545 drop_output_bundle ();
547 setup_peak_meters ();
552 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
555 if (change == ConnectionsChanged) {
559 if (change != NoChange) {
560 output_changed (change, src);
561 _session.set_dirty ();
568 /** Add an output port.
570 * @param destination Name of input port to connect new port to.
571 * @param src Source for emitted ConfigurationChanged signal.
572 * @param type Data type of port. Default value (NIL) will use this IO's default type.
575 IO::add_output_port (string destination, void* src, DataType type)
580 if (type == DataType::NIL)
581 type = _default_type;
584 BLOCK_PROCESS_CALLBACK ();
588 Glib::Mutex::Lock lm (io_lock);
590 if (n_outputs() >= _output_maximum) {
594 /* Create a new output port */
596 // FIXME: naming scheme for differently typed ports?
597 if (_output_maximum.get(type) == 1) {
598 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
600 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
603 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
604 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
608 _outputs.add (our_port);
609 drop_output_bundle ();
610 setup_peak_meters ();
614 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
617 if (destination.length()) {
618 if (_session.engine().connect (our_port->name(), destination)) {
623 // pan_changed (src); /* EMIT SIGNAL */
624 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
626 _session.set_dirty ();
632 IO::remove_input_port (Port* port, void* src)
634 IOChange change (NoChange);
637 BLOCK_PROCESS_CALLBACK ();
641 Glib::Mutex::Lock lm (io_lock);
643 if (n_inputs() <= _input_minimum) {
644 /* sorry, you can't do this */
648 if (_inputs.remove(port)) {
649 change = IOChange (change|ConfigurationChanged);
651 if (port->connected()) {
652 change = IOChange (change|ConnectionsChanged);
655 _session.engine().unregister_port (*port);
656 drop_input_bundle ();
658 setup_peak_meters ();
663 PortCountChanged (n_inputs ()); /* EMIT SIGNAL */
666 if (change == ConfigurationChanged) {
670 if (change != NoChange) {
671 input_changed (change, src);
672 _session.set_dirty ();
680 /** Add an input port.
682 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
683 * @param destination Name of input port to connect new port to.
684 * @param src Source for emitted ConfigurationChanged signal.
687 IO::add_input_port (string source, void* src, DataType type)
692 if (type == DataType::NIL)
693 type = _default_type;
696 BLOCK_PROCESS_CALLBACK ();
699 Glib::Mutex::Lock lm (io_lock);
701 if (n_inputs() >= _input_maximum) {
705 /* Create a new input port */
707 // FIXME: naming scheme for differently typed ports?
708 if (_input_maximum.get(type) == 1) {
709 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
711 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
714 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
715 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
719 _inputs.add (our_port);
720 drop_input_bundle ();
721 setup_peak_meters ();
725 PortCountChanged (n_inputs()); /* EMIT SIGNAL */
728 if (source.length()) {
730 if (_session.engine().connect (source, our_port->name())) {
735 // pan_changed (src); /* EMIT SIGNAL */
736 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
738 _session.set_dirty ();
744 IO::disconnect_inputs (void* src)
747 BLOCK_PROCESS_CALLBACK ();
750 Glib::Mutex::Lock lm (io_lock);
752 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
753 _session.engine().disconnect (*i);
756 drop_input_bundle ();
760 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
766 IO::disconnect_outputs (void* src)
769 BLOCK_PROCESS_CALLBACK ();
772 Glib::Mutex::Lock lm (io_lock);
774 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
775 _session.engine().disconnect (*i);
778 drop_output_bundle ();
782 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
783 _session.set_dirty ();
789 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
791 Port* input_port = 0;
792 bool changed = false;
795 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
797 const size_t n = count.get(*t);
799 /* remove unused ports */
800 for (size_t i = n_inputs().get(*t); i > n; --i) {
801 input_port = _inputs.port(*t, i-1);
804 _inputs.remove(input_port);
805 _session.engine().unregister_port (*input_port);
810 /* create any necessary new ports */
811 while (n_inputs().get(*t) < n) {
815 if (_input_maximum.get(*t) == 1) {
816 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
818 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
823 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
824 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
829 catch (AudioEngine::PortRegistrationFailure& err) {
830 setup_peak_meters ();
833 throw AudioEngine::PortRegistrationFailure();
836 _inputs.add (input_port);
842 drop_input_bundle ();
843 setup_peak_meters ();
845 PortCountChanged (n_inputs()); /* EMIT SIGNAL */
846 _session.set_dirty ();
850 /* disconnect all existing ports so that we get a fresh start */
851 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
852 _session.engine().disconnect (*i);
859 /** Attach output_buffers to port buffers.
861 * Connected to IO's own PortCountChanged signal.
864 IO::attach_buffers(ChanCount ignored)
866 _output_buffers->attach_buffers(_outputs);
870 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
872 bool in_changed = false;
873 bool out_changed = false;
874 bool need_pan_reset = false;
876 in = min (_input_maximum, in);
878 out = min (_output_maximum, out);
880 if (in == n_inputs() && out == n_outputs() && !clear) {
885 BLOCK_PROCESS_CALLBACK ();
886 Glib::Mutex::Lock lm (io_lock);
890 if (n_outputs() != out) {
891 need_pan_reset = true;
894 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
896 const size_t nin = in.get(*t);
897 const size_t nout = out.get(*t);
899 Port* output_port = 0;
900 Port* input_port = 0;
902 /* remove unused output ports */
903 for (size_t i = n_outputs().get(*t); i > nout; --i) {
904 output_port = _outputs.port(*t, i-1);
907 _outputs.remove(output_port);
908 _session.engine().unregister_port (*output_port);
913 /* remove unused input ports */
914 for (size_t i = n_inputs().get(*t); i > nin; --i) {
915 input_port = _inputs.port(*t, i-1);
918 _inputs.remove(input_port);
919 _session.engine().unregister_port (*input_port);
924 /* create any necessary new input ports */
926 while (n_inputs().get(*t) < nin) {
930 /* Create a new input port */
932 if (_input_maximum.get(*t) == 1) {
933 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
935 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
939 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
940 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
945 catch (AudioEngine::PortRegistrationFailure& err) {
946 setup_peak_meters ();
949 throw AudioEngine::PortRegistrationFailure();
956 /* create any necessary new output ports */
958 while (n_outputs().get(*t) < nout) {
962 /* Create a new output port */
964 if (_output_maximum.get(*t) == 1) {
965 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
967 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
971 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
972 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
977 catch (AudioEngine::PortRegistrationFailure& err) {
978 setup_peak_meters ();
981 throw AudioEngine::PortRegistrationFailure ();
991 /* disconnect all existing ports so that we get a fresh start */
993 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
994 _session.engine().disconnect (*i);
997 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
998 _session.engine().disconnect (*i);
1002 if (in_changed || out_changed) {
1003 setup_peak_meters ();
1009 drop_output_bundle ();
1010 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1014 drop_input_bundle ();
1015 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1018 if (in_changed || out_changed) {
1019 PortCountChanged (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1021 _session.set_dirty ();
1028 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1030 bool changed = false;
1032 count = min (_input_maximum, count);
1034 if (count == n_inputs() && !clear) {
1039 BLOCK_PROCESS_CALLBACK ();
1040 Glib::Mutex::Lock im (io_lock);
1041 changed = ensure_inputs_locked (count, clear, src);
1043 changed = ensure_inputs_locked (count, clear, src);
1047 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1049 _session.set_dirty ();
1055 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1057 Port* output_port = 0;
1058 bool changed = false;
1059 bool need_pan_reset = false;
1061 if (n_outputs() != count) {
1062 need_pan_reset = true;
1065 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1067 const size_t n = count.get(*t);
1069 /* remove unused ports */
1070 for (size_t i = n_outputs().get(*t); i > n; --i) {
1071 output_port = _outputs.port(*t, i-1);
1073 assert(output_port);
1074 _outputs.remove(output_port);
1075 _session.engine().unregister_port (*output_port);
1080 /* create any necessary new ports */
1081 while (n_outputs().get(*t) < n) {
1085 if (_output_maximum.get(*t) == 1) {
1086 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1088 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1091 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1092 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1096 _outputs.add (output_port);
1098 setup_peak_meters ();
1100 if (need_pan_reset) {
1107 drop_output_bundle ();
1108 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
1109 _session.set_dirty ();
1113 /* disconnect all existing ports so that we get a fresh start */
1114 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1115 _session.engine().disconnect (*i);
1123 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1125 bool changed = false;
1127 if (_output_maximum < ChanCount::INFINITE) {
1128 count = min (_output_maximum, count);
1129 if (count == n_outputs() && !clear) {
1134 /* XXX caller should hold io_lock, but generally doesn't */
1137 BLOCK_PROCESS_CALLBACK ();
1138 Glib::Mutex::Lock im (io_lock);
1139 changed = ensure_outputs_locked (count, clear, src);
1141 changed = ensure_outputs_locked (count, clear, src);
1145 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1153 IO::effective_gain () const
1155 if (_gain_control->list()->automation_playback()) {
1156 return _gain_control->get_value();
1158 return _desired_gain;
1165 if (panners_legal) {
1166 if (!no_panner_reset) {
1167 _panner->reset (n_outputs().n_audio(), pans_required());
1170 panner_legal_c.disconnect ();
1171 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1176 IO::panners_became_legal ()
1178 _panner->reset (n_outputs().n_audio(), pans_required());
1179 _panner->load (); // automation
1180 panner_legal_c.disconnect ();
1185 IO::defer_pan_reset ()
1187 no_panner_reset = true;
1191 IO::allow_pan_reset ()
1193 no_panner_reset = false;
1199 IO::get_state (void)
1201 return state (true);
1205 IO::state (bool full_state)
1207 XMLNode* node = new XMLNode (state_node_name);
1210 bool need_ins = true;
1211 bool need_outs = true;
1212 LocaleGuard lg (X_("POSIX"));
1213 Glib::Mutex::Lock lm (io_lock);
1215 node->add_property("name", _name);
1216 id().print (buf, sizeof (buf));
1217 node->add_property("id", buf);
1221 if (_input_bundle && !_input_bundle->dynamic()) {
1222 node->add_property ("input-connection", _input_bundle->name());
1226 if (_output_bundle && !_output_bundle->dynamic()) {
1227 node->add_property ("output-connection", _output_bundle->name());
1232 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1234 const char **connections = i->get_connections();
1236 if (connections && connections[0]) {
1239 for (int n = 0; connections && connections[n]; ++n) {
1244 /* if its a connection to our own port,
1245 return only the port name, not the
1246 whole thing. this allows connections
1247 to be re-established even when our
1248 client name is different.
1251 str += _session.engine().make_port_name_relative (connections[n]);
1263 node->add_property ("inputs", str);
1269 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1271 const char **connections = i->get_connections();
1273 if (connections && connections[0]) {
1277 for (int n = 0; connections[n]; ++n) {
1282 str += _session.engine().make_port_name_relative (connections[n]);
1294 node->add_property ("outputs", str);
1297 node->add_child_nocopy (_panner->state (full_state));
1298 node->add_child_nocopy (_gain_control->get_state ());
1300 snprintf (buf, sizeof(buf), "%2.12f", gain());
1301 node->add_property ("gain", buf);
1303 /* To make backwards compatibility a bit easier, write ChanCount::INFINITE to the session file
1307 int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
1308 int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
1310 snprintf (buf, sizeof(buf)-1, "%zd,%d,%zd,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
1312 node->add_property ("iolimits", buf);
1317 node->add_child_nocopy (get_automation_state());
1323 IO::set_state (const XMLNode& node)
1325 const XMLProperty* prop;
1326 XMLNodeConstIterator iter;
1327 LocaleGuard lg (X_("POSIX"));
1329 /* force use of non-localized representation of decimal point,
1330 since we use it a lot in XML files and so forth.
1333 if (node.name() != state_node_name) {
1334 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1338 if ((prop = node.property ("name")) != 0) {
1339 _name = prop->value();
1340 /* used to set panner name with this, but no more */
1343 if ((prop = node.property ("id")) != 0) {
1344 _id = prop->value ();
1352 if ((prop = node.property ("iolimits")) != 0) {
1353 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1354 &in_min, &in_max, &out_min, &out_max);
1356 /* Correct for the difference between the way we write things to session files and the
1357 way things are described by ChanCount; see comments in io.h about what the different
1358 ChanCount values mean. */
1361 _input_minimum = ChanCount::ZERO;
1363 _input_minimum = ChanCount (_default_type, in_min);
1367 _input_maximum = ChanCount::INFINITE;
1369 _input_maximum = ChanCount (_default_type, in_max);
1373 _output_minimum = ChanCount::ZERO;
1375 _output_minimum = ChanCount (_default_type, out_min);
1379 _output_maximum = ChanCount::INFINITE;
1381 _output_maximum = ChanCount (_default_type, out_max);
1385 if ((prop = node.property ("gain")) != 0) {
1386 set_gain (atof (prop->value().c_str()), this);
1387 _gain = _desired_gain;
1390 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1391 /* old school automation handling */
1394 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1396 if ((*iter)->name() == "Panner") {
1398 _panner = new Panner (_name, _session);
1400 _panner->set_state (**iter);
1403 if ((*iter)->name() == X_("Automation")) {
1405 set_automation_state (*(*iter), Parameter(GainAutomation));
1408 if ((*iter)->name() == X_("controllable")) {
1409 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1410 _gain_control->set_state (**iter);
1417 if (create_ports (node)) {
1423 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1426 if (panners_legal) {
1429 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1432 if (connecting_legal) {
1434 if (make_connections (node)) {
1440 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1443 if (!ports_legal || !connecting_legal) {
1444 pending_state_node = new XMLNode (node);
1451 IO::load_automation (string path)
1456 uint32_t linecnt = 0;
1458 LocaleGuard lg (X_("POSIX"));
1460 fullpath = _session.automation_dir();
1463 in.open (fullpath.c_str());
1466 fullpath = _session.automation_dir();
1467 fullpath += _session.snap_name();
1471 in.open (fullpath.c_str());
1474 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1479 clear_automation ();
1481 while (in.getline (line, sizeof(line), '\n')) {
1486 if (++linecnt == 1) {
1487 if (memcmp (line, "version", 7) == 0) {
1488 if (sscanf (line, "version %f", &version) != 1) {
1489 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1493 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1500 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1501 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1507 _gain_control->list()->fast_simple_add (when, value);
1517 /* older (pre-1.0) versions of ardour used this */
1521 warning << _("dubious automation event found (and ignored)") << endmsg;
1529 IO::connecting_became_legal ()
1533 if (pending_state_node == 0) {
1534 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1539 connection_legal_c.disconnect ();
1541 ret = make_connections (*pending_state_node);
1544 delete pending_state_node;
1545 pending_state_node = 0;
1551 IO::ports_became_legal ()
1555 if (pending_state_node == 0) {
1556 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1561 port_legal_c.disconnect ();
1563 ret = create_ports (*pending_state_node);
1565 if (connecting_legal) {
1566 delete pending_state_node;
1567 pending_state_node = 0;
1574 IO::create_ports (const XMLNode& node)
1576 const XMLProperty* prop;
1578 int num_outputs = 0;
1580 /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1581 * break the session file format.
1583 if ((prop = node.property ("input-connection")) != 0) {
1585 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1588 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1590 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1591 error << _("No input bundles available as a replacement")
1595 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1600 num_inputs = c->nchannels();
1602 } else if ((prop = node.property ("inputs")) != 0) {
1604 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1607 if ((prop = node.property ("output-connection")) != 0) {
1608 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1611 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1613 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1614 error << _("No output bundles available as a replacement")
1618 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1623 num_outputs = c->nchannels ();
1625 } else if ((prop = node.property ("outputs")) != 0) {
1626 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1629 no_panner_reset = true;
1631 // FIXME: audio-only
1632 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1633 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1637 no_panner_reset = false;
1639 set_deferred_state ();
1647 IO::make_connections (const XMLNode& node)
1649 const XMLProperty* prop;
1651 if ((prop = node.property ("input-connection")) != 0) {
1652 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1655 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1657 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1658 error << _("No input connections available as a replacement")
1662 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1667 connect_input_ports_to_bundle (c, this);
1669 } else if ((prop = node.property ("inputs")) != 0) {
1670 if (set_inputs (prop->value())) {
1671 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1676 if ((prop = node.property ("output-bundle")) != 0) {
1677 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1680 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1682 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1683 error << _("No output bundles available as a replacement")
1687 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1692 connect_output_ports_to_bundle (c, this);
1694 } else if ((prop = node.property ("outputs")) != 0) {
1695 if (set_outputs (prop->value())) {
1696 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1705 IO::set_inputs (const string& str)
1707 vector<string> ports;
1712 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1716 // FIXME: audio-only
1717 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1721 string::size_type start, end, ostart;
1728 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1731 if ((end = str.find_first_of ('}', start)) == string::npos) {
1732 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1736 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1737 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1743 for (int x = 0; x < n; ++x) {
1744 connect_input (input (i), ports[x], this);
1756 IO::set_outputs (const string& str)
1758 vector<string> ports;
1763 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1767 // FIXME: audio-only
1768 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1772 string::size_type start, end, ostart;
1779 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1782 if ((end = str.find_first_of ('}', start)) == string::npos) {
1783 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1787 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1788 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1794 for (int x = 0; x < n; ++x) {
1795 connect_output (output (i), ports[x], this);
1807 IO::parse_io_string (const string& str, vector<string>& ports)
1809 string::size_type pos, opos;
1811 if (str.length() == 0) {
1820 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1821 ports.push_back (str.substr (opos, pos - opos));
1825 if (opos < str.length()) {
1826 ports.push_back (str.substr(opos));
1829 return ports.size();
1833 IO::parse_gain_string (const string& str, vector<string>& ports)
1835 string::size_type pos, opos;
1841 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1842 ports.push_back (str.substr (opos, pos - opos));
1846 if (opos < str.length()) {
1847 ports.push_back (str.substr(opos));
1850 return ports.size();
1854 IO::set_name (const string& str)
1860 /* replace all colons in the name. i wish we didn't have to do this */
1863 if (replace_all (name, ":", "-")) {
1864 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1867 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1868 string current_name = i->short_name();
1869 current_name.replace (current_name.find (_name), _name.length(), name);
1870 i->set_name (current_name);
1873 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1874 string current_name = i->short_name();
1875 current_name.replace (current_name.find (_name), _name.length(), name);
1876 i->set_name (current_name);
1879 bool const r = SessionObject::set_name(name);
1887 IO::set_input_minimum (ChanCount n)
1893 IO::set_input_maximum (ChanCount n)
1899 IO::set_output_minimum (ChanCount n)
1901 _output_minimum = n;
1905 IO::set_output_maximum (ChanCount n)
1907 _output_maximum = n;
1911 IO::set_port_latency (nframes_t nframes)
1913 Glib::Mutex::Lock lm (io_lock);
1915 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1916 i->set_latency (nframes);
1921 IO::output_latency () const
1923 nframes_t max_latency;
1928 /* io lock not taken - must be protected by other means */
1930 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1931 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1932 max_latency = latency;
1940 IO::input_latency () const
1942 nframes_t max_latency;
1947 /* io lock not taken - must be protected by other means */
1949 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1950 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1951 max_latency = latency;
1959 IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
1964 BLOCK_PROCESS_CALLBACK ();
1965 Glib::Mutex::Lock lm2 (io_lock);
1967 limit = c->nchannels();
1969 drop_input_bundle ();
1971 // FIXME bundles only work for audio-only
1972 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1976 /* first pass: check the current state to see what's correctly
1977 connected, and drop anything that we don't want.
1980 for (uint32_t n = 0; n < limit; ++n) {
1981 const Bundle::PortList& pl = c->channel_ports (n);
1983 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1985 if (!_inputs.port(n)->connected_to ((*i))) {
1987 /* clear any existing connections */
1989 _session.engine().disconnect (*_inputs.port(n));
1991 } else if (_inputs.port(n)->connected() > 1) {
1993 /* OK, it is connected to the port we want,
1994 but its also connected to other ports.
1995 Change that situation.
1998 /* XXX could be optimized to not drop
2002 _session.engine().disconnect (*_inputs.port(n));
2008 /* second pass: connect all requested ports where necessary */
2010 for (uint32_t n = 0; n < limit; ++n) {
2011 const Bundle::PortList& pl = c->channel_ports (n);
2013 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2015 if (!_inputs.port(n)->connected_to ((*i))) {
2017 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
2027 input_bundle_configuration_connection = c->ConfigurationChanged.connect
2028 (mem_fun (*this, &IO::input_bundle_configuration_changed));
2029 input_bundle_connection_connection = c->PortsChanged.connect
2030 (mem_fun (*this, &IO::input_bundle_connection_changed));
2033 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2038 IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
2043 BLOCK_PROCESS_CALLBACK ();
2044 Glib::Mutex::Lock lm2 (io_lock);
2046 limit = c->nchannels();
2048 drop_output_bundle ();
2050 // FIXME: audio-only
2051 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2055 /* first pass: check the current state to see what's correctly
2056 connected, and drop anything that we don't want.
2059 for (uint32_t n = 0; n < limit; ++n) {
2061 const Bundle::PortList& pl = c->channel_ports (n);
2063 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2065 if (!_outputs.port(n)->connected_to ((*i))) {
2067 /* clear any existing connections */
2069 _session.engine().disconnect (*_outputs.port(n));
2071 } else if (_outputs.port(n)->connected() > 1) {
2073 /* OK, it is connected to the port we want,
2074 but its also connected to other ports.
2075 Change that situation.
2078 /* XXX could be optimized to not drop
2082 _session.engine().disconnect (*_outputs.port(n));
2087 /* second pass: connect all requested ports where necessary */
2089 for (uint32_t n = 0; n < limit; ++n) {
2091 const Bundle::PortList& pl = c->channel_ports (n);
2093 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2095 if (!_outputs.port(n)->connected_to ((*i))) {
2097 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2106 output_bundle_configuration_connection = c->ConfigurationChanged.connect
2107 (mem_fun (*this, &IO::output_bundle_configuration_changed));
2108 output_bundle_connection_connection = c->PortsChanged.connect
2109 (mem_fun (*this, &IO::output_bundle_connection_changed));
2112 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2118 IO::disable_connecting ()
2120 connecting_legal = false;
2125 IO::enable_connecting ()
2127 connecting_legal = true;
2128 return ConnectingLegal ();
2132 IO::disable_ports ()
2134 ports_legal = false;
2142 return PortsLegal ();
2146 IO::disable_panners (void)
2148 panners_legal = false;
2153 IO::reset_panners ()
2155 panners_legal = true;
2156 return PannersLegal ();
2160 IO::input_bundle_connection_changed (int ignored)
2162 connect_input_ports_to_bundle (_input_bundle, this);
2166 IO::input_bundle_configuration_changed ()
2168 connect_input_ports_to_bundle (_input_bundle, this);
2172 IO::output_bundle_connection_changed (int ignored)
2174 connect_output_ports_to_bundle (_output_bundle, this);
2178 IO::output_bundle_configuration_changed ()
2180 connect_output_ports_to_bundle (_output_bundle, this);
2184 IO::GainControl::set_value (float val)
2186 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2187 if (val > 1.99526231f)
2191 _io.set_gain (val, this);
2193 Changed(); /* EMIT SIGNAL */
2197 IO::GainControl::get_value (void) const
2199 return AutomationControl::get_value();
2203 IO::setup_peak_meters()
2205 ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2206 _meter->configure_io(max_streams, max_streams);
2210 Update the peak meters.
2212 The meter signal lock is taken to prevent modification of the
2213 Meter signal while updating the meters, taking the meter signal
2214 lock prior to taking the io_lock ensures that all IO will remain
2215 valid while metering.
2220 Glib::Mutex::Lock guard (m_meter_signal_lock);
2222 Meter(); /* EMIT SIGNAL */
2228 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2230 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2235 IO::clear_automation ()
2237 Automatable::clear_automation (); // clears gain automation
2238 _panner->clear_automation ();
2242 IO::set_parameter_automation_state (Parameter param, AutoState state)
2244 // XXX: would be nice to get rid of this special hack
2246 if (param.type() == GainAutomation) {
2248 bool changed = false;
2251 Glib::Mutex::Lock lm (_automation_lock);
2253 boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
2255 if (state != gain_auto->automation_state()) {
2257 _last_automation_snapshot = 0;
2258 gain_auto->set_automation_state (state);
2261 // FIXME: shouldn't this use Curve?
2262 set_gain (gain_auto->eval (_session.transport_frame()), this);
2268 _session.set_dirty ();
2272 Automatable::set_parameter_automation_state(param, state);
2277 IO::inc_gain (gain_t factor, void *src)
2279 if (_desired_gain == 0.0f)
2280 set_gain (0.000001f + (0.000001f * factor), src);
2282 set_gain (_desired_gain + (_desired_gain * factor), src);
2286 IO::set_gain (gain_t val, void *src)
2288 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2289 if (val > 1.99526231f)
2292 if (src != _gain_control.get()) {
2293 _gain_control->set_value(val);
2294 // bit twisty, this will come back and call us again
2295 // (this keeps control in sync with reality)
2300 Glib::Mutex::Lock dm (declick_lock);
2301 _desired_gain = val;
2304 if (_session.transport_stopped()) {
2308 if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
2309 _gain_control->list()->add (_session.transport_frame(), val);
2313 _session.set_dirty();
2317 IO::start_pan_touch (uint32_t which)
2319 if (which < _panner->size()) {
2320 (*_panner)[which]->pan_control()->list()->start_touch();
2325 IO::end_pan_touch (uint32_t which)
2327 if (which < _panner->size()) {
2328 (*_panner)[which]->pan_control()->list()->stop_touch();
2334 IO::automation_snapshot (nframes_t now)
2336 Automatable::automation_snapshot (now);
2338 if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
2339 _panner->snapshot (now);
2344 IO::transport_stopped (nframes_t frame)
2346 _gain_control->list()->reposition_for_rt_add (frame);
2348 if (_gain_control->list()->automation_state() != Off) {
2350 /* the src=0 condition is a special signal to not propagate
2351 automation gain changes into the mix group when locating.
2354 // FIXME: shouldn't this use Curve?
2355 set_gain (_gain_control->list()->eval (frame), 0);
2358 _panner->transport_stopped (frame);
2362 IO::find_input_port_hole ()
2364 /* CALLER MUST HOLD IO LOCK */
2368 if (_inputs.empty()) {
2372 for (n = 1; n < UINT_MAX; ++n) {
2373 char buf[jack_port_name_size()];
2374 PortSet::iterator i = _inputs.begin();
2376 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2378 for ( ; i != _inputs.end(); ++i) {
2379 if (i->short_name() == buf) {
2384 if (i == _inputs.end()) {
2392 IO::find_output_port_hole ()
2394 /* CALLER MUST HOLD IO LOCK */
2398 if (_outputs.empty()) {
2402 for (n = 1; n < UINT_MAX; ++n) {
2403 char buf[jack_port_name_size()];
2404 PortSet::iterator i = _outputs.begin();
2406 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2408 for ( ; i != _outputs.end(); ++i) {
2409 if (i->short_name() == buf) {
2414 if (i == _outputs.end()) {
2423 IO::audio_input(uint32_t n) const
2425 return dynamic_cast<AudioPort*>(input(n));
2429 IO::audio_output(uint32_t n) const
2431 return dynamic_cast<AudioPort*>(output(n));
2435 IO::midi_input(uint32_t n) const
2437 return dynamic_cast<MidiPort*>(input(n));
2441 IO::midi_output(uint32_t n) const
2443 return dynamic_cast<MidiPort*>(output(n));
2447 IO::set_phase_invert (bool yn, void *src)
2449 if (_phase_invert != yn) {
2451 // phase_invert_changed (src); /* EMIT SIGNAL */
2456 IO::set_denormal_protection (bool yn, void *src)
2458 if (_denormal_protection != yn) {
2459 _denormal_protection = yn;
2460 // denormal_protection_changed (src); /* EMIT SIGNAL */
2465 IO::update_port_total_latencies ()
2467 /* io_lock, not taken: function must be called from Session::process() calltree */
2469 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2470 _session.engine().update_total_latency (*i);
2473 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2474 _session.engine().update_total_latency (*i);
2480 * Setup bundles that describe our inputs and outputs.
2484 IO::setup_bundles ()
2488 snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
2489 _bundle_for_inputs->set_name (buf, 0);
2490 int const ins = n_inputs().n_total();
2491 _bundle_for_inputs->set_nchannels (ins);
2493 for (int i = 0; i < ins; ++i) {
2494 _bundle_for_inputs->add_port_to_channel (i, _inputs.port(i)->name ());
2497 snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
2498 _bundle_for_outputs->set_name (buf, 0);
2499 int const outs = n_outputs().n_total();
2500 _bundle_for_outputs->set_nchannels (outs);
2502 for (int i = 0; i < outs; ++i) {
2503 _bundle_for_outputs->add_port_to_channel (i, _outputs.port(i)->name ());
2509 * Create and setup bundles that describe our inputs and outputs.
2513 IO::create_bundles ()
2515 _bundle_for_inputs = boost::shared_ptr<Bundle> (
2516 new InputBundle ("", true)
2519 _bundle_for_outputs = boost::shared_ptr<Bundle> (
2520 new OutputBundle ("", true)
2526 boost::shared_ptr<Bundle>
2529 if (_input_bundle) {
2530 return _input_bundle;
2533 /* XXX: will only report the first bundle found; should really return a list, I think */
2535 /* check that _input_bundle is right wrt the connections that are currently made */
2537 /* make a vector of the first output connected to each of our inputs */
2538 std::vector<std::string> connected;
2539 for (uint32_t i = 0; i < _inputs.num_ports(); ++i) {
2540 const char** c = _inputs.port(i)->get_connections ();
2542 connected.push_back (c[0]);
2546 _input_bundle = _session.bundle_by_ports (connected);
2547 return _input_bundle;
2551 boost::shared_ptr<Bundle>
2554 if (_output_bundle) {
2555 return _output_bundle;
2558 /* XXX: will only report the first bundle found; should really return a list, I think */
2560 /* check that _output_bundle is right wrt the connections that are currently made */
2562 /* make a vector of the first input connected to each of our outputs */
2563 std::vector<std::string> connected;
2564 for (uint32_t i = 0; i < _outputs.num_ports(); ++i) {
2565 const char** c = _outputs.port(i)->get_connections ();
2567 connected.push_back (c[0]);
2571 _output_bundle = _session.bundle_by_ports (connected);
2572 return _output_bundle;