#include <sigc++/bind.h>
-#include <pbd/lockmonitor.h>
+#include <glibmm/thread.h>
+
#include <pbd/xml++.h>
#include <ardour/audioengine.h>
using namespace std;
using namespace ARDOUR;
-//using namespace sigc;
+using namespace PBD;
+
static float current_automation_version_number = 1.0;
bool IO::connecting_legal = false;
bool IO::ports_legal = false;
bool IO::panners_legal = false;
-sigc::signal<void> IO::GrabPeakPower;
+sigc::signal<void> IO::Meter;
sigc::signal<int> IO::ConnectingLegal;
sigc::signal<int> IO::PortsLegal;
sigc::signal<int> IO::PannersLegal;
sigc::signal<void,uint32_t> IO::MoreOutputs;
sigc::signal<int> IO::PortsCreated;
+Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
+
/* this is a default mapper of MIDI control values to a gain coefficient.
others can be imagined. see IO::set_midi_to_gain_function().
*/
_gain_automation_state = Off;
_gain_automation_style = Absolute;
-
- GrabPeakPower.connect (mem_fun (*this, &IO::grab_peak_power));
+
+ {
+ // IO::Meter is emitted from another thread so the
+ // Meter signal must be protected.
+ Glib::Mutex::Lock guard (m_meter_signal_lock);
+ m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
+ }
}
IO::~IO ()
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+
+ Glib::Mutex::Lock guard (m_meter_signal_lock);
+ Glib::Mutex::Lock lm (io_lock);
vector<Port *>::iterator i;
for (i = _inputs.begin(); i != _inputs.end(); ++i) {
for (i = _outputs.begin(); i != _outputs.end(); ++i) {
_session.engine().unregister_port (*i);
}
+
+ m_meter_connection.disconnect();
}
void
Sample *buffer;
double fractional_shift;
double fractional_pos;
+ gain_t polscale = invert_polarity ? -1.0f : 1.0f;
+ if (nframes == 0) return;
+
fractional_shift = -1.0/declick;
if (target < initial) {
buffer = bufs[n];
fractional_pos = 1.0;
- if (invert_polarity) {
- for (jack_nframes_t nx = 0; nx < declick; ++nx) {
- buffer[nx] *= -(initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
- fractional_pos += fractional_shift;
- }
- } else {
- for (jack_nframes_t nx = 0; nx < declick; ++nx) {
- buffer[nx] *= (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
- fractional_pos += fractional_shift;
- }
+ for (jack_nframes_t nx = 0; nx < declick; ++nx) {
+ buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
+ fractional_pos += fractional_shift;
}
/* now ensure the rest of the buffer has the target value
return;
}
- if (_panner->bypassed()) {
+ if (_panner->bypassed() || _panner->empty()) {
deliver_output_no_pan (bufs, nbufs, nframes, offset);
return;
}
gain_t dg;
-
+ gain_t pangain = _gain;
+
{
- TentativeLockMonitor dm (declick_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
if (dm.locked()) {
dg = _desired_gain;
if (dg != _gain) {
apply_declick (bufs, nbufs, nframes, _gain, dg, false);
_gain = dg;
+ pangain = 1.0f;
}
/* simple, non-automation panning to outputs */
if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
- pan (bufs, nbufs, nframes, offset, _gain * speed_quietning);
+ pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
} else {
- pan (bufs, nbufs, nframes, offset, _gain);
+ pan (bufs, nbufs, nframes, offset, pangain);
}
}
}
gain_t dg;
- gain_t old_gain;
+ gain_t old_gain = _gain;
if (apply_gain_automation) {
speed quietning.
*/
- old_gain = _gain;
_gain = 1.0f;
dg = _gain;
} else {
- TentativeLockMonitor dm (declick_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
if (dm.locked()) {
dg = _desired_gain;
}
{
- LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em (_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
/* check that our_port is really one of ours */
/* disconnect it from the source */
if (_session.engine().disconnect (other_port, our_port->name())) {
- error << compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
+ error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
return -1;
}
}
{
- LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em(_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
/* check that our_port is really one of ours */
}
{
- LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em(_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
return -1;
/* disconnect it from the destination */
if (_session.engine().disconnect (our_port->name(), other_port)) {
- error << compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
+ error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
return -1;
}
}
{
- LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em(_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
/* check that our_port is really one of ours */
IOChange change (NoChange);
{
- LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em(_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
if (_noutputs - 1 == (uint32_t) _output_minimum) {
/* sorry, you can't do this */
char buf[64];
{
- LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em(_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
return -1;
}
if ((our_port = _session.engine().register_audio_output_port (buf)) == 0) {
- error << compose(_("IO: cannot register output port %1"), buf) << endmsg;
+ error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
return -1;
}
IOChange change (NoChange);
{
- LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em(_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
if (((int)_ninputs - 1) < _input_minimum) {
/* sorry, you can't do this */
char buf[64];
{
- LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em (_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
return -1;
}
if ((our_port = _session.engine().register_audio_input_port (buf)) == 0) {
- error << compose(_("IO: cannot register input port %1"), buf) << endmsg;
+ error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
return -1;
}
IO::disconnect_inputs (void* src)
{
{
- LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em (_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
_session.engine().disconnect (*i);
IO::disconnect_outputs (void* src)
{
{
- LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em (_session.engine().process_lock());
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
_session.engine().disconnect (*i);
try {
if ((input_port = _session.engine().register_audio_input_port (buf)) == 0) {
- error << compose(_("IO: cannot register input port %1"), buf) << endmsg;
+ error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
return -1;
}
}
}
{
- LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock em (_session.engine().process_lock());
+ Glib::Mutex::Lock lm (io_lock);
Port* port;
try {
if ((port = _session.engine().register_audio_input_port (buf)) == 0) {
- error << compose(_("IO: cannot register input port %1"), buf) << endmsg;
+ error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
return -1;
}
}
try {
if ((port = _session.engine().register_audio_output_port (buf)) == 0) {
- error << compose(_("IO: cannot register output port %1"), buf) << endmsg;
+ error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
return -1;
}
}
_session.engine().disconnect (*i);
}
}
- }
-
- if (in_changed || out_changed) {
- setup_peak_meters ();
- reset_panner ();
+
+ if (in_changed || out_changed) {
+ setup_peak_meters ();
+ reset_panner ();
+ }
}
if (out_changed) {
}
if (lockit) {
- LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em (_session.engine().process_lock());
+ Glib::Mutex::Lock im (io_lock);
changed = ensure_inputs_locked (n, clear, src);
} else {
changed = ensure_inputs_locked (n, clear, src);
}
if ((output_port = _session.engine().register_audio_output_port (buf)) == 0) {
- error << compose(_("IO: cannot register output port %1"), buf) << endmsg;
+ error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
return -1;
}
/* XXX caller should hold io_lock, but generally doesn't */
if (lockit) {
- LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
+ Glib::Mutex::Lock em (_session.engine().process_lock());
+ Glib::Mutex::Lock im (io_lock);
changed = ensure_outputs_locked (n, clear, src);
} else {
changed = ensure_outputs_locked (n, clear, src);
bool need_ins = true;
bool need_outs = true;
LocaleGuard lg (X_("POSIX"));
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
node->add_property("name", _name);
snprintf (buf, sizeof(buf), "%" PRIu64, id());
*/
if (node.name() != state_node_name) {
- error << compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
+ error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
return -1;
}
}
if ((prop = node.property ("id")) != 0) {
- sscanf (prop->value().c_str(), "%llu", &_id);
+ sscanf (prop->value().c_str(), "%" PRIu64, &_id);
}
if ((prop = node.property ("iolimits")) != 0) {
if (get_midi_node_info (child, ev, chn, additional)) {
_midi_gain_control.set_control_type (chn, ev, additional);
} else {
- error << compose(_("MIDI gain control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg;
+ error << string_compose(_("MIDI gain control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg;
}
}
}
Connection* c = _session.connection_by_name (prop->value());
if (c == 0) {
- error << compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
+ error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
if ((c = _session.connection_by_name (_("in 1"))) == 0) {
error << _("No input connections available as a replacement")
<< endmsg;
return -1;
} else {
- info << compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
+ info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
<< endmsg;
}
}
Connection* c = _session.connection_by_name (prop->value());
if (c == 0) {
- error << compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
+ error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
if ((c = _session.connection_by_name (_("out 1"))) == 0) {
error << _("No output connections available as a replacement")
<< endmsg;
return -1;
} else {
- info << compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
+ info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
<< endmsg;
}
}
no_panner_reset = true;
if (ensure_io (num_inputs, num_outputs, true, this)) {
- error << compose(_("%1: cannot create I/O ports"), _name) << endmsg;
+ error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
return -1;
}
Connection* c = _session.connection_by_name (prop->value());
if (c == 0) {
- error << compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
+ error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
if ((c = _session.connection_by_name (_("in 1"))) == 0) {
error << _("No input connections available as a replacement")
<< endmsg;
return -1;
} else {
- info << compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
+ info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
<< endmsg;
}
}
} else if ((prop = node.property ("inputs")) != 0) {
if (set_inputs (prop->value())) {
- error << compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
+ error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
return -1;
}
}
Connection* c = _session.connection_by_name (prop->value());
if (c == 0) {
- error << compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
+ error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
if ((c = _session.connection_by_name (_("out 1"))) == 0) {
error << _("No output connections available as a replacement")
<< endmsg;
return -1;
} else {
- info << compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
+ info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
<< endmsg;
}
}
} else if ((prop = node.property ("outputs")) != 0) {
if (set_outputs (prop->value())) {
- error << compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
+ error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
return -1;
}
}
start += 1;
if ((end = str.find_first_of ('}', start)) == string::npos) {
- error << compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
+ error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
return -1;
}
if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
- error << compose(_("bad input string in XML node \"%1\""), str) << endmsg;
+ error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
return -1;
start += 1;
if ((end = str.find_first_of ('}', start)) == string::npos) {
- error << compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
+ error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
return -1;
}
if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
- error << compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
+ error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
return -1;
void
IO::set_port_latency (jack_nframes_t nframes)
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (io_lock);
for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
(*i)->set_latency (nframes);
uint32_t limit;
{
- LockMonitor lm (_session.engine().process_lock(), __LINE__, __FILE__);
- LockMonitor lm2 (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (_session.engine().process_lock());
+ Glib::Mutex::Lock lm2 (io_lock);
limit = c.nports();
uint32_t limit;
{
- LockMonitor lm (_session.engine().process_lock(), __LINE__, __FILE__);
- LockMonitor lm2 (io_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (_session.engine().process_lock());
+ Glib::Mutex::Lock lm2 (io_lock);
limit = c.nports();
if (get_control_info (ch, ev, additional)) {
data.controller_number = additional;
data.value = val;
-
+ last_written = val;
+
io._session.send_midi_message (get_port(), ev, ch, data);
}
//send_midi_feedback (gain_to_midi (gain));
while (_peak_power.size() < limit) {
_peak_power.push_back (0);
- _stored_peak_power.push_back (0);
+ _visible_peak_power.push_back (0);
}
}
return state;
}
+/**
+ Update the peak meters.
+
+ The meter signal lock is taken to prevent modification of the
+ Meter signal while updating the meters, taking the meter signal
+ lock prior to taking the io_lock ensures that all IO will remain
+ valid while metering.
+*/
void
-IO::send_state_changed ()
+IO::update_meters()
{
- return;
+ Glib::Mutex::Lock guard (m_meter_signal_lock);
+
+ Meter();
}
void
-IO::grab_peak_power ()
+IO::meter ()
{
- LockMonitor lm (io_lock, __LINE__, __FILE__);
-
+ Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
uint32_t limit = max (_ninputs, _noutputs);
-
+
for (uint32_t n = 0; n < limit; ++n) {
- /* XXX should we use atomic exchange here ? */
- _stored_peak_power[n] = _peak_power[n];
+
+ /* XXX we should use atomic exchange here */
+
+ /* grab peak since last read */
+
+ float new_peak = _peak_power[n];
_peak_power[n] = 0;
+
+ /* compute new visible value using falloff */
+
+ if (new_peak > 0.0) {
+ new_peak = coefficient_to_dB (new_peak);
+ } else {
+ new_peak = minus_infinity();
+ }
+
+ if (_session.meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
+ _visible_peak_power[n] = new_peak;
+ } else {
+ // do falloff
+ new_peak = _visible_peak_power[n] - _session.meter_falloff();
+ _visible_peak_power[n] = max (new_peak, -INFINITY);
+ }
}
}
out.open (fullpath.c_str());
if (!out) {
- error << compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
+ error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
return -1;
}
fullpath += path;
in.open (fullpath.c_str());
if (!in) {
- error << compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
+ error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
return -1;
}
}
if (++linecnt == 1) {
if (memcmp (line, "version", 7) == 0) {
if (sscanf (line, "version %f", &version) != 1) {
- error << compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
+ error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
return -1;
}
} else {
- error << compose(_("no version information in automation event file \"%1\""), path) << endmsg;
+ error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
return -1;
}
if (version != current_automation_version_number) {
- error << compose(_("mismatched automation event file version (%1)"), version) << endmsg;
+ error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
return -1;
}
}
if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
- warning << compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
+ warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
continue;
}
void
IO::clear_automation ()
{
- LockMonitor lm (automation_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (automation_lock);
_gain_automation_curve.clear ();
_panner->clear_automation ();
}
bool changed = false;
{
- LockMonitor lm (automation_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (automation_lock);
if (state != _gain_automation_curve.automation_state()) {
changed = true;
bool changed = false;
{
- LockMonitor lm (automation_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock lm (automation_lock);
if (style != _gain_automation_curve.automation_style()) {
changed = true;
if (val>1.99526231f) val=1.99526231f;
{
- LockMonitor dm (declick_lock, __LINE__, __FILE__);
+ Glib::Mutex::Lock dm (declick_lock);
_desired_gain = val;
}