Merged with trunk (painfully)
[ardour.git] / libs / ardour / io.cc
index 91cbb1cb67e1cf90923c4d8581bcfd7e8c72dbd6..fa30463bd465cac887d38b23cb1266b4016e5fd1 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>
@@ -63,13 +64,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 +129,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 +152,8 @@ IO::~IO ()
        for (i = _outputs.begin(); i != _outputs.end(); ++i) {
                _session.engine().unregister_port (*i);
        }
+
+    m_meter_connection.disconnect();
 }
 
 void
@@ -163,6 +175,8 @@ IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe
        double fractional_shift;
        double fractional_pos;
        gain_t polscale = invert_polarity ? -1.0f : 1.0f;
+
+       if (nframes == 0) return;
        
        fractional_shift = -1.0/declick;
 
@@ -378,7 +392,7 @@ IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nfram
        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;
@@ -425,7 +439,7 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_
                
        } else {
 
-               TentativeLockMonitor dm (declick_lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
                
                if (dm.locked()) {
                        dg = _desired_gain;
@@ -566,10 +580,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 */
                        
@@ -602,10 +616,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 */
                        
@@ -636,10 +650,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;
@@ -669,10 +683,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 */
                        
@@ -728,10 +742,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 */
@@ -777,10 +791,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;
@@ -828,10 +842,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 */
@@ -878,10 +892,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;
@@ -929,10 +943,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);
@@ -949,10 +963,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);
@@ -1061,8 +1075,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;
                
@@ -1169,11 +1183,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) {
@@ -1210,7 +1224,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);
@@ -1311,7 +1326,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);
@@ -1385,7 +1401,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());
@@ -2054,7 +2070,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);
@@ -2105,8 +2121,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();
                
@@ -2183,8 +2199,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();
                        
@@ -2404,7 +2420,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);
        }
 }
 
@@ -2433,17 +2449,52 @@ IO::send_state_changed ()
        return;
 }
 
+/**
+    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::grab_peak_power ()
+IO::update_meters()
 {
-       LockMonitor lm (io_lock, __LINE__, __FILE__);
+    Glib::Mutex::Lock guard (m_meter_signal_lock);
+    
+    Meter();
+}
 
+void
+IO::meter ()
+{
+       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, -200.0f);
+               }
        }
 }
 
@@ -2579,7 +2630,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 ();
 }
@@ -2590,7 +2641,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;
@@ -2615,7 +2666,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;
@@ -2643,7 +2694,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;
        }