Fixed i18n system.
[ardour.git] / libs / ardour / io.cc
index efee6fc397e11fb8e69e8829f24da9ecaf62efbd..87c03c6b70fafe56440cc694af29a188dcc697ea 100644 (file)
@@ -25,7 +25,8 @@
 
 #include <sigc++/bind.h>
 
-#include <pbd/lockmonitor.h>
+#include <glibmm/thread.h>
+
 #include <pbd/xml++.h>
 
 #include <ardour/audioengine.h>
@@ -54,7 +55,8 @@ extern "C" int isinf (double);
 
 using namespace std;
 using namespace ARDOUR;
-//using namespace sigc;
+using namespace PBD;
+
 
 static float current_automation_version_number = 1.0;
 
@@ -63,13 +65,15 @@ const string IO::state_node_name = "IO";
 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().
 */
@@ -126,13 +130,20 @@ IO::IO (Session& s, string name,
 
        _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) {
@@ -142,6 +153,8 @@ IO::~IO ()
        for (i = _outputs.begin(); i != _outputs.end(); ++i) {
                _session.engine().unregister_port (*i);
        }
+
+    m_meter_connection.disconnect();
 }
 
 void
@@ -162,7 +175,10 @@ IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe
        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) {
@@ -178,16 +194,9 @@ IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe
                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
@@ -374,16 +383,17 @@ IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nfram
                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;
@@ -395,14 +405,15 @@ IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nfram
        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);
        }
 }
 
@@ -416,7 +427,7 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_
        }
 
        gain_t dg;
-       gain_t old_gain;
+       gain_t old_gain = _gain;
 
        if (apply_gain_automation) {
 
@@ -424,13 +435,12 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_
                   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;
@@ -571,10 +581,10 @@ IO::disconnect_input (Port* our_port, string other_port, 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);
                        
                        /* check that our_port is really one of ours */
                        
@@ -585,7 +595,7 @@ IO::disconnect_input (Port* our_port, string other_port, void* src)
                        /* 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;
                        }
 
@@ -607,10 +617,10 @@ IO::connect_input (Port* our_port, string other_port, 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);
                        
                        /* check that our_port is really one of ours */
                        
@@ -641,10 +651,10 @@ IO::disconnect_output (Port* our_port, string other_port, 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);
                        
                        if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
                                return -1;
@@ -653,7 +663,7 @@ IO::disconnect_output (Port* our_port, string other_port, void* src)
                        /* 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;
                        }
 
@@ -674,10 +684,10 @@ IO::connect_output (Port* our_port, string other_port, 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);
                        
                        /* check that our_port is really one of ours */
                        
@@ -733,10 +743,10 @@ IO::remove_output_port (Port* port, void* src)
        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 */
@@ -782,10 +792,10 @@ IO::add_output_port (string destination, void* src)
        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;
@@ -800,7 +810,7 @@ IO::add_output_port (string destination, void* src)
                        }
                        
                        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;
                        }
                        
@@ -833,10 +843,10 @@ IO::remove_input_port (Port* port, void* src)
        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 */
@@ -883,10 +893,10 @@ IO::add_input_port (string source, void* src)
        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;
@@ -901,7 +911,7 @@ IO::add_input_port (string source, void* src)
                        }
                        
                        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;
                        }
                        
@@ -934,10 +944,10 @@ int
 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);
@@ -954,10 +964,10 @@ int
 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);
@@ -1007,7 +1017,7 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
                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;
                        }
                }
@@ -1066,8 +1076,8 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
        }
 
        {
-               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;
                
@@ -1112,7 +1122,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
                        
                        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;
                                }
                        }
@@ -1145,7 +1155,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
                        
                        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;
                                }
                        }
@@ -1174,11 +1184,11 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
                                _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) {
@@ -1215,7 +1225,8 @@ IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
        }
        
        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);
@@ -1269,7 +1280,7 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* 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;
                }
                
@@ -1316,7 +1327,8 @@ IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
        /* 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);
@@ -1390,7 +1402,7 @@ IO::state (bool full_state)
        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());
@@ -1579,7 +1591,7 @@ IO::set_state (const XMLNode& node)
        */
 
        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;
        }
 
@@ -1589,7 +1601,7 @@ IO::set_state (const XMLNode& node)
        } 
 
        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) {
@@ -1634,7 +1646,7 @@ IO::set_state (const XMLNode& node)
                                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;
                                }
                        }
                }
@@ -1701,14 +1713,14 @@ IO::create_ports (const XMLNode& node)
                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;
                        }
                } 
@@ -1724,14 +1736,14 @@ IO::create_ports (const XMLNode& node)
                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;
                        }
                } 
@@ -1745,7 +1757,7 @@ IO::create_ports (const XMLNode& node)
        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;
        }
 
@@ -1811,14 +1823,14 @@ IO::make_connections (const XMLNode& node)
                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;
                        }
                } 
@@ -1827,7 +1839,7 @@ IO::make_connections (const XMLNode& node)
 
        } 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;
                }
        }
@@ -1836,14 +1848,14 @@ IO::make_connections (const XMLNode& node)
                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;
                        }
                } 
@@ -1852,7 +1864,7 @@ IO::make_connections (const XMLNode& node)
                
        } 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;
                }
        }
@@ -1887,12 +1899,12 @@ IO::set_inputs (const string& str)
                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;
                        
@@ -1937,12 +1949,12 @@ IO::set_outputs (const string& str)
                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;
                        
@@ -2059,7 +2071,7 @@ IO::set_output_maximum (int n)
 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);
@@ -2110,8 +2122,8 @@ IO::use_input_connection (Connection& c, void* src)
        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();
                
@@ -2188,8 +2200,8 @@ IO::use_output_connection (Connection& c, void* src)
        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();
                        
@@ -2359,7 +2371,8 @@ IO::MIDIGainControl::send_feedback (gain_t gain)
                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));
@@ -2408,7 +2421,7 @@ IO::setup_peak_meters ()
 
        while (_peak_power.size() < limit) {
                _peak_power.push_back (0);
-               _stored_peak_power.push_back (0);
+               _visible_peak_power.push_back (0);
        }
 }
 
@@ -2431,23 +2444,52 @@ IO::state_factory (std::string why) const
        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);
+               }
        }
 }
 
@@ -2480,7 +2522,7 @@ IO::save_automation (const string& path)
        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;
        }
 
@@ -2519,7 +2561,7 @@ IO::load_automation (const string& path)
                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;
                }
        }
@@ -2534,16 +2576,16 @@ IO::load_automation (const string& path)
                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;
                        }
 
@@ -2551,7 +2593,7 @@ IO::load_automation (const string& path)
                }
 
                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;
                }
 
@@ -2583,7 +2625,7 @@ IO::load_automation (const string& path)
 void
 IO::clear_automation ()
 {
-       LockMonitor lm (automation_lock, __LINE__, __FILE__);
+       Glib::Mutex::Lock lm (automation_lock);
        _gain_automation_curve.clear ();
        _panner->clear_automation ();
 }
@@ -2594,7 +2636,7 @@ IO::set_gain_automation_state (AutoState state)
        bool changed = false;
 
        {
-               LockMonitor lm (automation_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (automation_lock);
 
                if (state != _gain_automation_curve.automation_state()) {
                        changed = true;
@@ -2619,7 +2661,7 @@ IO::set_gain_automation_style (AutoStyle style)
        bool changed = false;
 
        {
-               LockMonitor lm (automation_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (automation_lock);
 
                if (style != _gain_automation_curve.automation_style()) {
                        changed = true;
@@ -2647,7 +2689,7 @@ IO::set_gain (gain_t val, void *src)
        if (val>1.99526231f) val=1.99526231f;
 
        {
-               LockMonitor dm (declick_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock dm (declick_lock);
                _desired_gain = val;
        }