committed RWlock fixes to libardour. added hw monitoring fixes from nick_m. minor...
authorJesse Chappell <jesse@essej.net>
Fri, 6 Jan 2006 04:59:17 +0000 (04:59 +0000)
committerJesse Chappell <jesse@essej.net>
Fri, 6 Jan 2006 04:59:17 +0000 (04:59 +0000)
git-svn-id: svn://localhost/trunk/ardour2@244 d708f5d6-7413-0410-9779-e7cbd77b26cf

26 files changed:
gtk2_ardour/option_editor.cc
libs/ardour/ardour/configuration.h
libs/ardour/ardour/diskstream.h
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/ardour/session_diskstream.h
libs/ardour/ardour/session_route.h
libs/ardour/audio_track.cc
libs/ardour/configuration.cc
libs/ardour/diskstream.cc
libs/ardour/io.cc
libs/ardour/panner.cc
libs/ardour/plugin.cc
libs/ardour/route.cc
libs/ardour/session.cc
libs/ardour/session_butler.cc
libs/ardour/session_click.cc
libs/ardour/session_events.cc
libs/ardour/session_export.cc
libs/ardour/session_feedback.cc
libs/ardour/session_midi.cc
libs/ardour/session_process.cc
libs/ardour/session_state.cc
libs/ardour/session_transport.cc
libs/midi++2/alsa_sequencer_midiport.cc
libs/pbd3/pbd/lockmonitor.h

index 9126303c52e783dbe8e716bc509c39c4089f0a72..049bf5331be2f69ae2e503e68312f30ccb1f8532 100644 (file)
@@ -1753,6 +1753,9 @@ void
 OptionEditor::hw_monitor_clicked ()
 {
        Config->set_use_hardware_monitoring (hw_monitor_button.get_active());
+       if (session) {
+               session->reset_input_monitor_state ();
+       }
 }
 
 void
index 0c4202764669cda3797aa2d03c2073bfdaae0448..140490d46d47fff8567c1a727a6b5acfeb606cb0 100644 (file)
@@ -117,6 +117,9 @@ class Configuration : public Stateful
 
        string get_midi_port_name();
        void   set_midi_port_name(string);
+
+       uint32_t get_midi_feedback_interval_ms();
+       void set_midi_feedback_interval_ms (uint32_t);
        
        bool get_use_hardware_monitoring();
        void set_use_hardware_monitoring(bool);
@@ -238,6 +241,8 @@ class Configuration : public Stateful
        bool          use_vst; /* always per-user */
        bool          quieten_at_speed;
        bool          quieten_at_speed_is_user;
+       uint32_t      midi_feedback_interval_ms;
+       bool          midi_feedback_interval_ms_is_user;
 
        XMLNode *key_node;
        bool     user_configuration;
index 3c9aa0e0f62223434fef3d8dee4ae4bccefd1f7a..0cdbfd17241883a2ab33f0636bb0beb745688ca7 100644 (file)
@@ -305,7 +305,6 @@ class DiskStream : public Stateful, public sigc::trackable
        id_t              _id;
 
        atomic_t                 _record_enabled;
-       bool                      rec_monitoring_off_for_roll;
        AudioPlaylist*           _playlist;
        double                   _visible_speed;
        double                   _actual_speed;
index 8f4028c99fd0b33a1612b1d13170e8a853f6eb0e..9c0edcdad4a3a28634221777ac4c19c562d140ee 100644 (file)
@@ -140,14 +140,14 @@ class Route : public IO
        void flush_redirects ();
 
        template<class T> void foreach_redirect (T *obj, void (T::*func)(Redirect *)) {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
                for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
                        (obj->*func) (*i);
                }
        }
 
        Redirect *nth_redirect (uint32_t n) {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
                RedirectList::iterator i;
                for (i = _redirects.begin(); i != _redirects.end() && n; ++i, --n);
                if (i == _redirects.end()) {
@@ -288,7 +288,7 @@ class Route : public IO
        jack_nframes_t           _roll_delay;
        jack_nframes_t           _own_latency;
        RedirectList             _redirects;
-       PBD::NonBlockingLock      redirect_lock;
+       PBD::NonBlockingRWLock      redirect_lock;
        IO                      *_control_outs;
        PBD::NonBlockingLock      control_outs_lock;
        RouteGroup              *_edit_group;
index b58b0a926b15a4678486f551c2fcf6968265c679..88f629e5168b9b660db5bd2dd53e0d4ccf67d98b 100644 (file)
@@ -273,7 +273,7 @@ class Session : public sigc::trackable, public Stateful
        typedef list<DiskStream *> DiskStreamList;
 
        Session::DiskStreamList disk_streams() const {
-               LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
                return diskstreams; /* XXX yes, force a copy */
        }
 
@@ -283,7 +283,7 @@ class Session : public sigc::trackable, public Stateful
        typedef slist<Route *> RouteList;
 
        RouteList get_routes() const {
-               LockMonitor rlock (route_lock, __LINE__, __FILE__);
+               RWLockMonitor rlock (route_lock, false, __LINE__, __FILE__);
                return routes; /* XXX yes, force a copy */
        }
 
@@ -410,6 +410,7 @@ class Session : public sigc::trackable, public Stateful
        void set_auto_play (bool yn);
        void set_auto_return (bool yn);
        void set_auto_input (bool yn);
+       void reset_input_monitor_state ();
        void set_input_auto_connect (bool yn);
        void set_output_auto_connect (AutoConnectOption);
        void set_punch_in (bool yn);
@@ -993,7 +994,7 @@ class Session : public sigc::trackable, public Stateful
        Location*                end_location;
        Slave                  *_slave;
        SlaveSource             _slave_type;
-       float                   _transport_speed;
+       volatile float          _transport_speed;
        volatile float          _desired_transport_speed;
        float                   _last_transport_speed;
        jack_nframes_t          _last_slave_transport_frame;
@@ -1473,7 +1474,7 @@ class Session : public sigc::trackable, public Stateful
        /* disk-streams */
 
        DiskStreamList  diskstreams; 
-       mutable PBD::Lock diskstream_lock;
+       mutable PBD::NonBlockingRWLock diskstream_lock;
        uint32_t dstream_buffer_size;
        void add_diskstream (DiskStream*);
        int  load_diskstreams (const XMLNode&);
@@ -1481,7 +1482,7 @@ class Session : public sigc::trackable, public Stateful
        /* routes stuff */
 
        RouteList       routes;
-       mutable PBD::NonBlockingLock route_lock;
+       mutable PBD::NonBlockingRWLock route_lock;
        void   add_route (Route*);
 
        int load_routes (const XMLNode&);
@@ -1685,6 +1686,7 @@ class Session : public sigc::trackable, public Stateful
        Sample*         click_emphasis_data;
        jack_nframes_t  click_length;
        jack_nframes_t  click_emphasis_length;
+       mutable PBD::NonBlockingRWLock click_lock;
 
        static const Sample         default_click[];
        static const jack_nframes_t default_click_length;
index 55c79f549f2ef9d7f96816d64797dff678e3fb86..24693c579356a0b8b386f1eaa21d2a9daf6a0638 100644 (file)
@@ -29,7 +29,7 @@ namespace ARDOUR {
 template<class T> void 
 Session::foreach_diskstream (T *obj, void (T::*func)(DiskStream&)) 
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); i++) {
                if (!(*i)->hidden()) {
                        (obj->*func) (**i);
index 0b126531dc9d6f26fa52dd29169b8b227bcb4d4b..f3c8e3f5fbc936fdbf1d096cd02ded52db8503f4 100644 (file)
@@ -35,7 +35,7 @@ Session::foreach_route (T *obj, void (T::*func)(Route&))
        RouteList public_order;
 
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                public_order = routes;
        }
 
@@ -53,7 +53,7 @@ Session::foreach_route (T *obj, void (T::*func)(Route*))
        RouteList public_order;
 
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                public_order = routes;
        }
 
@@ -72,7 +72,7 @@ Session::foreach_route (T *obj, void (T::*func)(Route&, A), A arg1)
        RouteList public_order;
 
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                public_order = routes;
        }
 
index 75f930bf8deb0b6ec2cfd669a0c98d0e6d1cfa0c..1d3f32ae6be5fb8b5f826e2dd8741b874a010b3a 100644 (file)
@@ -574,8 +574,15 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram
        Sample* tmpb;
        jack_nframes_t transport_frame;
 
-       automation_snapshot (start_frame);
-
+       {
+               TentativeRWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
+               if (lm.locked()) {
+                       // automation snapshot can also be called from the non-rt context
+                       // and it uses the redirect list, so we take the lock out here
+                       automation_snapshot (start_frame);
+               }
+       }
+       
        if (n_outputs() == 0 && _redirects.empty()) {
                return 0;
        }
@@ -649,11 +656,12 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram
                        }
                }
 
-               /* don't waste time with automation if we're recording */
+               /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
 
-               if (!diskstream->record_enabled()) {
+               if (!diskstream->record_enabled() && _session.transport_rolling()) {
+                       TentativeLockMonitor am (automation_lock, __LINE__, __FILE__);
                        
-                       if (gain_automation_playback()) {
+                       if (am.locked() && gain_automation_playback()) {
                                apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
                        }
                }
@@ -683,7 +691,7 @@ AudioTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jac
 
        _silent = true;
        apply_gain_automation = false;
-       
+
        silence (nframes, offset);
 
        return diskstream->process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input);
@@ -721,7 +729,7 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, uint32_t nbufs, jack_nframes
        vector<Sample*>::iterator bi;
        Sample * b;
        
-       LockMonitor rlock (redirect_lock, __LINE__, __FILE__);
+       RWLockMonitor rlock (redirect_lock, false, __LINE__, __FILE__);
                
        if (diskstream->playlist()->read (buffers[0], mix_buffer, gain_buffer, start, nframes) != nframes) {
                return -1;
@@ -890,7 +898,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
        _freeze_record.have_mementos = true;
 
        {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
                
                for (RedirectList::iterator r = _redirects.begin(); r != _redirects.end(); ++r) {
                        
@@ -947,7 +955,7 @@ AudioTrack::unfreeze ()
 
                } else {
 
-                       LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+                       RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__); // should this be a write lock? jlc
                        for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
                                for (vector<FreezeRecordInsertInfo*>::iterator ii = _freeze_record.insert_info.begin(); ii != _freeze_record.insert_info.end(); ++ii) {
                                        if ((*ii)->id == (*i)->id()) {
index 4003946576a821ff4a47f2fb31e7d70c512019ac..0de30a3538fe2215efa945ef1b4e7e3d6424bb9b 100644 (file)
@@ -207,6 +207,11 @@ Configuration::state (bool user_only)
                node->add_child_nocopy(option_node("disk-choice-space-threshold", string(buf)));
        }
 
+       if (!user_only || midi_feedback_interval_ms_is_user) {
+               snprintf(buf, sizeof(buf), "%" PRIu32, midi_feedback_interval_ms);
+               node->add_child_nocopy(option_node("midi-feedback-interval-ms", string(buf)));
+       }
+
        if (!user_only || mute_affects_pre_fader_is_user) {
                node->add_child_nocopy(option_node("mute-affects-pre-fader", mute_affects_pre_fader?"yes":"no"));
        }
@@ -422,6 +427,8 @@ Configuration::set_state (const XMLNode& root)
                                        if (sscanf (option_value.c_str(), "%f", &v) == 1) {
                                                set_quieten_at_speed (v);
                                        }
+                               } else if (option_name == "midi-feedback-interval-ms") {
+                                       set_midi_feedback_interval_ms (atoi (option_value.c_str()));
                                }
                        }
                        
@@ -472,13 +479,15 @@ Configuration::set_defaults ()
        stop_recording_on_xrun = false;
        verify_remove_last_capture = true;
        stop_at_session_end = true;
-       seamless_looping = false;
+       seamless_looping = true;
        auto_xfade = true;
        no_new_session_dialog = false;
        timecode_source_is_synced = true;
        use_vst = true; /* if we build with VST_SUPPORT, otherwise no effect */
        quieten_at_speed = true;
 
+       midi_feedback_interval_ms = 100;
+       
        // this is about 5 minutes at 48kHz, 4 bytes/sample
        disk_choice_space_threshold = 57600000;
 
@@ -514,6 +523,7 @@ Configuration::set_defaults ()
        no_new_session_dialog_is_user = false;
        timecode_source_is_synced_is_user = false;
        quieten_at_speed_is_user = false;
+       midi_feedback_interval_ms_is_user = false;
 }
 
 Configuration::MidiPortDescriptor::MidiPortDescriptor (const XMLNode& node)
@@ -832,6 +842,21 @@ Configuration::set_midi_port_name (string name)
        }
 }
 
+uint32_t
+Configuration::get_midi_feedback_interval_ms ()
+{
+       return midi_feedback_interval_ms;
+}
+
+void
+Configuration::set_midi_feedback_interval_ms (uint32_t val)
+{
+       midi_feedback_interval_ms = val;
+       if (user_configuration) {
+               midi_feedback_interval_ms_is_user = true;
+       }
+}
+
 bool
 Configuration::get_use_hardware_monitoring()
 {
index 351fdde33f1b8ae7952b8a4a766ab629f798f64f..d0b0415c8ccb6761d7f068597388184f914bab40 100644 (file)
@@ -128,7 +128,6 @@ DiskStream::init (Flag f)
        _alignment_style = ExistingMaterial;
        _persistent_alignment_style = ExistingMaterial;
        first_input_change = true;
-       rec_monitoring_off_for_roll = false;
        _playlist = 0;
        i_am_the_modifier = 0;
        atomic_set (&_record_enabled, 0);
@@ -735,16 +734,6 @@ DiskStream::process (jack_nframes_t transport_frame, jack_nframes_t nframes, jac
        if (can_record && !_last_capture_regions.empty()) {
                _last_capture_regions.clear ();
        }
-       
-       if (rec_nframes) {
-
-               if (Config->get_use_hardware_monitoring() && re && rec_monitoring_off_for_roll && rec_monitors_input) {
-                       for (c = channels.begin(); c != channels.end(); ++c) {
-                               (*c).source->ensure_monitor_input (true);
-                       }
-                       rec_monitoring_off_for_roll = false;
-               }
-       }
 
        if (nominally_recording || rec_nframes) {
 
@@ -807,6 +796,7 @@ DiskStream::process (jack_nframes_t transport_frame, jack_nframes_t nframes, jac
 
                } else {
 
+
                        /* we can't use the capture buffer as the playback buffer, because
                           we recorded only a part of the current process' cycle data
                           for capture.
@@ -1685,24 +1675,6 @@ DiskStream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture
 void
 DiskStream::finish_capture (bool rec_monitors_input)
 {
-       if (Config->get_use_hardware_monitoring() && record_enabled()) {
-               if (rec_monitors_input) {
-                       if (rec_monitoring_off_for_roll) {
-                               for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
-                                       (*chan).source->ensure_monitor_input (true);
-                               }
-                               rec_monitoring_off_for_roll = false;
-                       }
-               } else {
-                       if (!rec_monitoring_off_for_roll) {
-                               for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
-                                       (*chan).source->ensure_monitor_input (false);
-                               }
-                               rec_monitoring_off_for_roll = true;
-                       }
-               }
-       }
-
        was_recording = false;
        
        if (capture_captured == 0) {
@@ -1732,6 +1704,8 @@ DiskStream::finish_capture (bool rec_monitors_input)
 void
 DiskStream::set_record_enabled (bool yn, void* src)
 {
+        bool rolling = _session.transport_speed() != 0.0f;
+
        if (!recordable() || !_session.record_enabling_legal()) {
                return;
        }
@@ -1765,10 +1739,10 @@ DiskStream::set_record_enabled (bool yn, void* src)
                if (yn) {
                        atomic_set (&_record_enabled, 1);
                        capturing_sources.clear ();
-                       if (Config->get_use_hardware_monitoring()) {
+                       if (Config->get_use_hardware_monitoring())  {
                                for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
                                        if ((*chan).source) {
-                                               (*chan).source->request_monitor_input (true);
+                                               (*chan).source->request_monitor_input (!(_session.get_auto_input() && rolling));
                                        }
                                        capturing_sources.push_back ((*chan).write_source);
                                }
index b2d3337dcb5642478b73d88880a2adcc66b4df1c..6b6773c49d85139c49761e06486eba12c9624dab 100644 (file)
@@ -2358,7 +2358,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));
index 130db16191aadf95d4a375da29e6b5dbe699ea4b..85feed6be906416b2f19a85da172c81a8b360987 100644 (file)
@@ -109,7 +109,8 @@ StreamPanner::MIDIControl::send_feedback (pan_t value)
                if (get_control_info (ch, ev, additional)) {
                        data.controller_number = additional;
                        data.value = val;
-
+                       last_written = val;
+                       
                        sp.get_parent().session().send_midi_message (get_port(), ev, ch, data);
                }
 
index 042e1561304a6faeb6267c9f9404f815290ee70b..059cf133a5ccb59a5d9fae8b864971c044a90d1c 100644 (file)
@@ -162,7 +162,8 @@ Plugin::MIDIPortControl::send_feedback (float value)
                if (get_control_info (ch, ev, additional)) {
                        data.controller_number = additional;
                        data.value = val;
-
+                       last_written = val;
+                       
                        plugin.session().send_midi_message (get_port(), ev, ch, data);
                }
        }
index 03059c6c82fa86c615787b3426418716484d37b5..6e07ef90f26d6c899d9b574f3517ebbf74588d38 100644 (file)
@@ -314,7 +314,7 @@ Route::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
           -------------------------------------------------------------------------------------------------- */
 
        if (with_redirects) {
-               TentativeLockMonitor rm (redirect_lock, __LINE__, __FILE__);
+               TentativeRWLockMonitor rm (redirect_lock, false, __LINE__, __FILE__);
                if (rm.locked()) {
                        if (mute_gain > 0 || !_mute_affects_pre_fader) {
                                for (i = _redirects.begin(); i != _redirects.end(); ++i) {
@@ -428,7 +428,7 @@ Route::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
                                }
                        }
                        
-                       if (apply_gain_automation) {
+                       if (apply_gain_automation && _session.transport_rolling()) {
                                _effective_gain = gab[nframes-1];
                        }
                        
@@ -483,7 +483,7 @@ Route::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
 
        if (post_fader_work) {
 
-               TentativeLockMonitor rm (redirect_lock, __LINE__, __FILE__);
+               TentativeRWLockMonitor rm (redirect_lock, false, __LINE__, __FILE__);
                if (rm.locked()) {
                        if (mute_gain > 0 || !_mute_affects_post_fader) {
                                for (i = _redirects.begin(); i != _redirects.end(); ++i) {
@@ -755,7 +755,7 @@ Route::add_redirect (Redirect *redirect, void *src, uint32_t* err_streams)
        }
 
        {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, true, __LINE__, __FILE__);
 
                PluginInsert* pi;
                PortInsert* porti;
@@ -816,7 +816,7 @@ Route::add_redirects (const RedirectList& others, void *src, uint32_t* err_strea
        }
 
        {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, true, __LINE__, __FILE__);
 
                RedirectList::iterator existing_end = _redirects.end();
                --existing_end;
@@ -861,7 +861,7 @@ Route::clear_redirects (void *src)
        }
 
        {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, true, __LINE__, __FILE__);
 
                for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
                        delete *i;
@@ -891,7 +891,7 @@ Route::remove_redirect (Redirect *redirect, void *src, uint32_t* err_streams)
        redirect_max_outs = 0;
 
        {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, true, __LINE__, __FILE__);
                RedirectList::iterator i;
                bool removed = false;
 
@@ -970,7 +970,7 @@ Route::remove_redirect (Redirect *redirect, void *src, uint32_t* err_streams)
 int
 Route::reset_plugin_counts (uint32_t* lpc)
 {
-       LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (redirect_lock, true, __LINE__, __FILE__);
        return _reset_plugin_counts (lpc);
 }
 
@@ -1140,7 +1140,7 @@ Route::copy_redirects (const Route& other, Placement placement, uint32_t* err_st
        RedirectList to_be_deleted;
 
        {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, true, __LINE__, __FILE__);
                RedirectList::iterator tmp;
                RedirectList the_copy;
 
@@ -1219,7 +1219,7 @@ Route::copy_redirects (const Route& other, Placement placement, uint32_t* err_st
 void
 Route::all_redirects_flip ()
 {
-       LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
 
        if (_redirects.empty()) {
                return;
@@ -1235,7 +1235,7 @@ Route::all_redirects_flip ()
 void
 Route::all_redirects_active (bool state)
 {
-       LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (redirect_lock, false,  __LINE__, __FILE__);
 
        if (_redirects.empty()) {
                return;
@@ -1257,7 +1257,7 @@ Route::sort_redirects (uint32_t* err_streams)
 {
        {
                RedirectSorter comparator;
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, true, __LINE__, __FILE__);
                uint32_t old_rmo = redirect_max_outs;
 
                /* the sweet power of C++ ... */
@@ -1736,7 +1736,7 @@ Route::silence (jack_nframes_t nframes, jack_nframes_t offset)
                }
 
                { 
-                       TentativeLockMonitor lm (redirect_lock, __LINE__, __FILE__);
+                       TentativeRWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
                        
                        if (lm.locked()) {
                                for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
@@ -1935,12 +1935,13 @@ Route::transport_stopped (bool abort_ignored, bool did_locate, bool can_flush_re
 {
        jack_nframes_t now = _session.transport_frame();
 
-       if (!did_locate) {
-               automation_snapshot (now);
-       }
-
        {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
+
+               if (!did_locate) {
+                       automation_snapshot (now);
+               }
+
                for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
                        
                        if (Config->get_plugins_stop_with_transport() && can_flush_redirects) {
@@ -2014,7 +2015,7 @@ Route::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes
        }
 
        apply_gain_automation = false;
-
+       
        if (n_inputs()) {
                passthru (start_frame, end_frame, nframes, offset, 0, false);
        } else {
@@ -2053,8 +2054,15 @@ int
 Route::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset, int declick,
             bool can_record, bool rec_monitors_input)
 {
-       automation_snapshot (_session.transport_frame());
-
+       {
+               TentativeRWLockMonitor lm(redirect_lock, false, __LINE__, __FILE__);
+               if (lm.locked()) {
+                       // automation snapshot can also be called from the non-rt context
+                       // and it uses the redirect list, so we take the lock out here
+                       automation_snapshot (_session.transport_frame());
+               }
+       }
+               
        if ((n_outputs() == 0 && _redirects.empty()) || n_inputs() == 0 || !_active) {
                silence (nframes, offset);
                return 0;
@@ -2067,12 +2075,13 @@ Route::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t
        }
 
        _silent = false;
+
        apply_gain_automation = false;
 
        { 
                TentativeLockMonitor am (automation_lock, __LINE__, __FILE__);
                
-               if (am.locked()) {
+               if (am.locked() && _session.transport_rolling()) {
                        
                        jack_nframes_t start_frame = end_frame - nframes;
                        
@@ -2162,7 +2171,7 @@ Route::send_all_midi_feedback ()
        if (_session.get_midi_feedback()) {
 
                {
-                       LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+                       RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
                        for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
                                (*i)->send_all_midi_feedback ();
                        }
@@ -2182,7 +2191,7 @@ Route::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize)
        buf = _midi_mute_control.write_feedback (buf, bufsize, _muted);
 
        {
-               LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
                for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
                        buf = (*i)->write_midi_feedback (buf, bufsize);
                }
@@ -2198,7 +2207,7 @@ Route::flush_redirects ()
           this is called from the RT audio thread.
        */
 
-       LockMonitor lm (redirect_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (redirect_lock, false, __LINE__, __FILE__);
 
        for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
                (*i)->deactivate ();
@@ -2333,7 +2342,8 @@ Route::MIDIToggleControl::send_feedback (bool value)
                if (get_control_info (ch, ev, additional)) {
                        data.controller_number = additional;
                        data.value = val;
-
+                       last_written = value;
+                       
                        route._session.send_midi_message (get_port(), ev, ch, data);
                }
        }
index ab218e48044fc2a9ac86cc29d46cdcfc964a0128..f811fbd0af42e8f8bd684edff026f84fa400e737 100644 (file)
@@ -541,7 +541,7 @@ Session::set_worst_io_latencies (bool take_lock)
        }
 
        if (take_lock) {
-               route_lock.lock ();
+               route_lock.read_lock ();
        }
        
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
@@ -933,11 +933,51 @@ Session::set_auto_input (bool yn)
 {
        if (auto_input != yn) {
                auto_input = yn;
+               
+               if (Config->get_use_hardware_monitoring() && transport_rolling()) {
+                       /* auto-input only makes a difference if we're rolling */
+
+                       /* Even though this can called from RT context we are using
+                          a non-tentative rwlock here,  because the action must occur.
+                          The rarity and short potential lock duration makes this "OK"
+                       */
+                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               if ((*i)->record_enabled ()) {
+                                       //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (!auto_input);   
+                               }
+                       }
+               }
+
                set_dirty();
                ControlChanged (AutoInput);
        }
 }
 
+void
+Session::reset_input_monitor_state ()
+{
+       if (transport_rolling()) {
+               RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                       if ((*i)->record_enabled ()) {
+                               //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
+                               (*i)->monitor_input (Config->get_use_hardware_monitoring() && !auto_input);
+                       }
+               }
+       } else {
+               RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                       if ((*i)->record_enabled ()) {
+                               //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
+                               (*i)->monitor_input (Config->get_use_hardware_monitoring());
+                       }
+               }
+       }
+}
+
+
 void
 Session::set_input_auto_connect (bool yn)
 {
@@ -1192,6 +1232,22 @@ Session::enable_record ()
                atomic_set (&_record_status, Recording);
                _last_record_location = _transport_frame;
                send_mmc_in_another_thread (MIDI::MachineControl::cmdRecordStrobe);
+
+               if (Config->get_use_hardware_monitoring() && auto_input) {
+                       /* Even though this can be called from RT context we are using
+                          a non-tentative rwlock here,  because the action must occur.
+                          The rarity and short potential lock duration makes this "OK"
+                       */
+                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+                       
+                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               if ((*i)->record_enabled ()) {
+                                       //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (true);   
+                               }
+                       }
+               }
+
                RecordEnabled ();
        }
 }
@@ -1202,8 +1258,25 @@ Session::disable_record ()
        if (atomic_read (&_record_status) != Disabled) {
                atomic_set (&_record_status, Disabled);
                send_mmc_in_another_thread (MIDI::MachineControl::cmdRecordExit);
+
+               if (Config->get_use_hardware_monitoring() && auto_input) {
+                       /* Even though this can be called from RT context we are using
+                          a non-tentative rwlock here,  because the action must occur.
+                          The rarity and short potential lock duration makes this "OK"
+                       */
+                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+                       
+                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               if ((*i)->record_enabled ()) {
+                                       //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (false);   
+                               }
+                       }
+               }
+               
                RecordDisabled ();
                remove_pending_capture_state ();
+
        }
 }
 
@@ -1211,6 +1284,21 @@ void
 Session::step_back_from_record ()
 {
        atomic_set (&_record_status, Enabled);
+
+       if (Config->get_use_hardware_monitoring()) {
+               /* Even though this can be called from RT context we are using
+                  a non-tentative rwlock here,  because the action must occur.
+                  The rarity and short potential lock duration makes this "OK"
+               */
+               RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+               
+               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                       if (auto_input && (*i)->record_enabled ()) {
+                               //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
+                               (*i)->monitor_input (false);   
+                       }
+               }
+       }
 }
 
 void
@@ -1320,7 +1408,8 @@ Session::set_block_size (jack_nframes_t nframes)
        */
 
        { 
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
+               RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
                vector<Sample*>::iterator i;
                uint32_t np;
                        
@@ -1381,7 +1470,8 @@ Session::set_default_fade (float steepness, float fade_msecs)
        default_fade_steepness = steepness;
 
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               // jlc, WTF is this!
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                AudioRegion::set_default_fade (steepness, fade_frames);
        }
 
@@ -1532,7 +1622,7 @@ Session::new_audio_track (int input_channels, int output_channels)
        /* count existing audio tracks */
 
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        if (dynamic_cast<AudioTrack*>(*i) != 0) {
                                if (!(*i)->hidden()) {
@@ -1646,7 +1736,7 @@ Session::new_audio_route (int input_channels, int output_channels)
        /* count existing audio busses */
 
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        if (dynamic_cast<AudioTrack*>(*i) == 0) {
                                if (!(*i)->hidden()) {
@@ -1729,7 +1819,7 @@ void
 Session::add_route (Route* route)
 {
        { 
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, true, __LINE__, __FILE__);
                routes.push_front (route);
                resort_routes(0);
        }
@@ -1756,8 +1846,11 @@ Session::add_route (Route* route)
 void
 Session::add_diskstream (DiskStream* dstream)
 {
+       /* need to do this in case we're rolling at the time, to prevent false underruns */
+       dstream->do_refill(0, 0);
+       
        { 
-               LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (diskstream_lock, true, __LINE__, __FILE__);
                diskstreams.push_back (dstream);
        }
 
@@ -1785,7 +1878,7 @@ void
 Session::remove_route (Route& route)
 {
        {       
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, true, __LINE__, __FILE__);
                routes.remove (&route);
                
                /* deleting the master out seems like a dumb
@@ -1813,7 +1906,7 @@ Session::remove_route (Route& route)
        }
 
        {
-               LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (diskstream_lock, true, __LINE__, __FILE__);
 
                AudioTrack* at;
 
@@ -1849,7 +1942,7 @@ Session::route_solo_changed (void* src, Route* route)
                return;
        }
        
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
        bool is_track;
        
        is_track = (dynamic_cast<AudioTrack*>(route) != 0);
@@ -2045,14 +2138,14 @@ Session::catch_up_on_solo ()
           basis, but needs the global overview that only the session
           has.
        */
-        LockMonitor lm (route_lock, __LINE__, __FILE__);
+        RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
        update_route_solo_state();
 }      
                
 Route *
 Session::route_by_name (string name)
 {
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                if ((*i)->name() == name) {
@@ -2094,7 +2187,7 @@ Session::find_current_end ()
 DiskStream *
 Session::diskstream_by_name (string name)
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
 
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                if ((*i)->name() == name) {
@@ -2108,7 +2201,7 @@ Session::diskstream_by_name (string name)
 DiskStream *
 Session::diskstream_by_id (id_t id)
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
 
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                if ((*i)->id() == id) {
@@ -2433,6 +2526,8 @@ Session::remove_last_capture ()
 {
        list<Region*> r;
 
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
+       
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                list<Region*>& l = (*i)->last_capture_regions();
                
@@ -2830,19 +2925,13 @@ Session::old_peak_path_from_audio_path (string audio_path)
 void
 Session::set_all_solo (bool yn)
 {
-       /* XXX this copy is not safe: the Routes within the list
-          can still be deleted after the Route lock is released.
-       */
-
-       RouteList copy;
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
-               copy = routes;
-       }
-
-       for (RouteList::iterator i = copy.begin(); i != copy.end(); ++i) {
-               if (!(*i)->hidden()) {
-                       (*i)->set_solo (yn, this);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
+               
+               for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
+                       if (!(*i)->hidden()) {
+                               (*i)->set_solo (yn, this);
+                       }
                }
        }
 
@@ -2852,15 +2941,13 @@ Session::set_all_solo (bool yn)
 void
 Session::set_all_mute (bool yn)
 {
-       RouteList copy;
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
-               copy = routes;
-       }
-
-       for (RouteList::iterator i = copy.begin(); i != copy.end(); ++i) {
-               if (!(*i)->hidden()) {
-                       (*i)->set_mute (yn, this);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
+               
+               for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
+                       if (!(*i)->hidden()) {
+                               (*i)->set_mute (yn, this);
+                       }
                }
        }
 
@@ -2870,7 +2957,7 @@ Session::set_all_mute (bool yn)
 uint32_t
 Session::n_diskstreams () const
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
        uint32_t n = 0;
 
        for (DiskStreamList::const_iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
@@ -2884,7 +2971,7 @@ Session::n_diskstreams () const
 void 
 Session::foreach_diskstream (void (DiskStream::*func)(void)) 
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                if (!(*i)->hidden()) {
                        ((*i)->*func)();
@@ -2903,8 +2990,8 @@ Session::graph_reordered ()
                return;
        }
 
-       LockMonitor lm1 (route_lock, __LINE__, __FILE__);
-       LockMonitor lm2 (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm1 (route_lock, true, __LINE__, __FILE__);
+       RWLockMonitor lm2 (diskstream_lock, false, __LINE__, __FILE__);
 
        resort_routes (0);
 
@@ -2932,7 +3019,7 @@ Session::record_enable_all ()
 void
 Session::record_enable_change_all (bool yn)
 {
-       LockMonitor lm1 (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm1 (route_lock, false, __LINE__, __FILE__);
        
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                AudioTrack* at;
@@ -3181,8 +3268,9 @@ Session::remove_named_selection (NamedSelection* named_selection)
 void
 Session::reset_native_file_format ()
 {
-       LockMonitor lm1 (route_lock, __LINE__, __FILE__);
-       LockMonitor lm2 (diskstream_lock, __LINE__, __FILE__);
+       // jlc - WHY take routelock?
+       //RWLockMonitor lm1 (route_lock, true, __LINE__, __FILE__);
+       RWLockMonitor lm2 (diskstream_lock, false, __LINE__, __FILE__);
 
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                (*i)->reset_write_sources (false);
@@ -3192,7 +3280,7 @@ Session::reset_native_file_format ()
 bool
 Session::route_name_unique (string n) const
 {
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
        
        for (RouteList::const_iterator i = routes.begin(); i != routes.end(); ++i) {
                if ((*i)->name() == n) {
@@ -3269,7 +3357,7 @@ Session::add_instant_xml (XMLNode& node, const std::string& dir)
 int
 Session::freeze (InterThreadInfo& itt)
 {
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
 
@@ -3438,7 +3526,7 @@ uint32_t
 Session::ntracks () const
 {
        uint32_t n = 0;
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
 
        for (RouteList::const_iterator i = routes.begin(); i != routes.end(); ++i) {
                if (dynamic_cast<AudioTrack*> (*i)) {
@@ -3453,7 +3541,7 @@ uint32_t
 Session::nbusses () const
 {
        uint32_t n = 0;
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
 
        for (RouteList::const_iterator i = routes.begin(); i != routes.end(); ++i) {
                if (dynamic_cast<AudioTrack*> (*i) == 0) {
index df867c8267b4378110d5df01200bf30a17104480..12a838b5dd8d8573e2b5566c7668b6e69b585176 100644 (file)
@@ -254,6 +254,8 @@ Session::butler_thread_work ()
 
                gettimeofday (&begin, 0);
 
+               RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+               
                for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) {
                        
                        // cerr << "rah fondr " << (*i)->io()->name () << endl;
@@ -394,7 +396,7 @@ Session::overwrite_some_buffers (DiskStream* ds)
 
        } else {
 
-               LockMonitor dm (diskstream_lock, __LINE__, __FILE__);
+               RWLockMonitor dm (diskstream_lock, false, __LINE__, __FILE__);
                for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                        (*i)->set_pending_overwrite (true);
                }
index 250adfe4cc0c6e94f706e1657b3cc9501fab32d4..c9777500a26a8aaea1f09331236b42690bc17074 100644 (file)
@@ -46,8 +46,10 @@ Session::click (jack_nframes_t start, jack_nframes_t nframes, jack_nframes_t off
        if (_click_io == 0) {
                return;
        }
+
+       TentativeRWLockMonitor clickm (click_lock, true, __LINE__, __FILE__);
        
-       if (_transport_speed != 1.0 || !_clicking || click_data == 0) {
+       if (!clickm.locked() || _transport_speed != 1.0 || !_clicking || click_data == 0) {
                _click_io->silence (nframes, offset);
                return;
        } 
@@ -207,7 +209,7 @@ Session::setup_click_sounds (int which)
 void
 Session::clear_clicks ()
 {
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (click_lock, true, __LINE__, __FILE__);
 
        for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
                delete *i;
index 68555dbe4044a0505d59d725a814b2d97f8e2e33..2aeace81f4317d1d14df567237047c34d4904c44 100644 (file)
@@ -342,12 +342,6 @@ Session::process_event (Event* ev)
        case Event::PunchIn:
                // cerr << "PunchIN at " << transport_frame() << endl;
                if (punch_in && record_status() == Enabled) {
-                       {
-                               LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
-                               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
-                                       (*i)->punch_in();
-                               }
-                       }
                        enable_record ();
                }
                remove = false;
index a80ee69e564a4ce30d1f0e7e8aba600d032df667..0ccea59b81ccc66845bda18d4c342c3dcecc3882 100644 (file)
@@ -485,7 +485,7 @@ Session::prepare_to_export (AudioExportSpecification& spec)
        /* take everyone out of awrite to avoid disasters */
 
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        (*i)->protect_automation ();
                }
@@ -494,7 +494,7 @@ Session::prepare_to_export (AudioExportSpecification& spec)
        /* get everyone to the right position */
 
        {
-               LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
                for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                        if ((*i)-> seek (spec.start_frame, true)) {
                                error << string_compose (_("%1: cannot seek to %2 for export"),
index c2198aa55d172843a33930ba08c6e57a7cd5e318..2e6d0cd80ba9d441b0dedf8a2b7a6fdd20a66529 100644 (file)
@@ -124,7 +124,7 @@ Session::feedback_thread_work ()
 
        if (active_feedback) {
                /* XXX use Config->feedback_interval_usecs()*/;
-               timeout = 250;
+               timeout = max (5, (int) Config->get_midi_feedback_interval_ms());
        } else {
                timeout = -1;
        }
@@ -162,7 +162,7 @@ Session::feedback_thread_work ()
                                        switch ((FeedbackRequest::Type) req) {
                                        
                                        case FeedbackRequest::Start:
-                                               timeout = 250;
+                                               timeout = max (5, (int) Config->get_midi_feedback_interval_ms());
                                                active_feedback++;
                                                break;
                                                
@@ -193,7 +193,7 @@ Session::feedback_thread_work ()
                        }
                }
                
-               if (!active_feedback) {
+               if (!active_feedback || transport_stopped()) {
                        continue;
                }
 
@@ -224,7 +224,7 @@ Session::feedback_generic_midi_function ()
        MIDI::byte* end = buf;
 
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        end = (*i)->write_midi_feedback (end, bsize);
@@ -236,10 +236,11 @@ Session::feedback_generic_midi_function ()
                return 0;
        } 
        
-       // cerr << "MIDI feedback: write " << (int32_t) (end - buf) << " of " << buf << " to midi port\n";
-
        deliver_midi (_midi_port, buf, (int32_t) (end - buf));
 
+       //cerr << "MIDI feedback: wrote " << (int32_t) (end - buf) << " to midi port\n";
+               
+
        return 0;
 }
        
index f9c8d57e62f8544d529c84b9777c51c7afd73695..18d8b3672b1a46ab71a2fe4e3a57c5987f67da9b 100644 (file)
@@ -51,7 +51,7 @@ using namespace MIDI;
 MachineControl::CommandSignature MMC_CommandSignature;
 MachineControl::ResponseSignature MMC_ResponseSignature;
 
-MultiAllocSingleReleasePool Session::MIDIRequest::pool ("midi", sizeof (Session::MIDIRequest), 256);
+MultiAllocSingleReleasePool Session::MIDIRequest::pool ("midi", sizeof (Session::MIDIRequest), 1024);
 
 int
 Session::use_config_midi_ports ()
@@ -110,7 +110,7 @@ Session::set_midi_control (bool yn)
        poke_midi_thread ();
 
        if (_midi_port) {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        (*i)->reset_midi_control (_midi_port, midi_control);
                }
@@ -478,7 +478,7 @@ Session::send_all_midi_feedback ()
 {
        if (midi_feedback) {
                // send out current state of all routes
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        (*i)->send_all_midi_feedback ();
                }
index 01e75a4749e3e77e8598782c022419c97117ee00..5bcd595eccdae69158f62f866351e34c2832051b 100644 (file)
@@ -280,11 +280,13 @@ Session::process_with_events (jack_nframes_t nframes)
        end_frame = _transport_frame + nframes;
 
        {
-               TentativeLockMonitor rm (route_lock, __LINE__, __FILE__);
+               TentativeRWLockMonitor rm (route_lock, false, __LINE__, __FILE__);
+               TentativeRWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+       
                Event* this_event;
                Events::iterator the_next_one;
 
-               if (!rm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) {
+               if (!rm.locked() || !dsm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) {
                        no_roll (nframes, 0);
                        return;
                }
@@ -543,9 +545,11 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset)
                if (slave_state == Waiting) {
 
                        // cerr << "waiting at " << slave_transport_frame << endl;
-
-                       if (slave_transport_frame >= slave_wait_end) {
+                       TentativeRWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+                               
+                       if (dsm.locked() && slave_transport_frame >= slave_wait_end) {
                                // cerr << "\tstart at " << _transport_frame << endl;
+
                                slave_state = Running;
 
                                bool ok = true;
@@ -662,7 +666,13 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset)
                */
 
                bool need_butler;
+               
+               TentativeRWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+               if (!dsm.locked()) {
+                       goto noroll;
+               }
 
+               
                prepare_diskstreams ();
                silent_process_routes (nframes, offset);
                commit_diskstreams (nframes, need_butler);
@@ -708,9 +718,10 @@ Session::process_without_events (jack_nframes_t nframes)
        long frames_moved;
        
        {
-               TentativeLockMonitor rm (route_lock, __LINE__, __FILE__);
+               TentativeRWLockMonitor rm (route_lock, false, __LINE__, __FILE__);
+               TentativeRWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
 
-               if (!rm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) {
+               if (!rm.locked() || !dsm.locked() || (post_transport_work & (PostTransportLocate|PostTransportStop))) {
                        no_roll (nframes, 0);
                        return;
                }
@@ -779,7 +790,7 @@ Session::process_without_events (jack_nframes_t nframes)
 void
 Session::process_audition (jack_nframes_t nframes)
 {
-       TentativeLockMonitor rm (route_lock, __LINE__, __FILE__);
+       TentativeRWLockMonitor rm (route_lock, false, __LINE__, __FILE__);
        Event* ev;
 
        if (rm.locked()) {
index 98a48fb44a3280fd2beac18804eb82a6cd0f9409..53ca23a366175f2833a34861d2b80d300b173bab 100644 (file)
@@ -1344,7 +1344,7 @@ Session::state(bool full_state)
        child = node->add_child ("DiskStreams");
 
        { 
-               LockMonitor dl (diskstream_lock, __LINE__, __FILE__);
+               RWLockMonitor dl (diskstream_lock, false, __LINE__, __FILE__);
                for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                        if (!(*i)->hidden()) {
                                child->add_child_nocopy ((*i)->get_state());
@@ -1366,7 +1366,7 @@ Session::state(bool full_state)
 
        child = node->add_child ("Routes");
        {
-               LockMonitor lm (route_lock, __LINE__, __FILE__);
+               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
                
                RoutePublicOrderSorter cmp;
                RouteList public_order(routes);
@@ -2313,7 +2313,7 @@ Session::load_route_groups (const XMLNode& node, bool edit)
 void
 Session::swap_configuration(Configuration** new_config)
 {
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, true, __LINE__, __FILE__); // jlc - WHY?
        Configuration* tmp = *new_config;
        *new_config = Config;
        Config = tmp;
@@ -2323,7 +2323,7 @@ Session::swap_configuration(Configuration** new_config)
 void
 Session::copy_configuration(Configuration* new_config)
 {
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, true, __LINE__, __FILE__);
        new_config = new Configuration(*Config);
 }
 
@@ -2474,7 +2474,7 @@ Session::GlobalRouteBooleanState
 Session::get_global_route_boolean (bool (Route::*method)(void) const)
 {
        GlobalRouteBooleanState s;
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                if (!(*i)->hidden()) {
@@ -2494,7 +2494,7 @@ Session::GlobalRouteMeterState
 Session::get_global_route_metering ()
 {
        GlobalRouteMeterState s;
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                if (!(*i)->hidden()) {
index 342b6e1a5279e6ca5a838b134240431c62eb7760..82b067a288c54fe23782955479ad33413cf13fe9 100644 (file)
@@ -192,14 +192,18 @@ Session::realtime_stop (bool abort)
        disable_record ();
 
        reset_slave_state ();
-
+               
        _transport_speed = 0;
+
        transport_sub_state = (auto_return ? AutoReturning : 0);
 }
 
 void
 Session::butler_transport_work ()
 {
+       RWLockMonitor rm (route_lock, false, __LINE__, __FILE__);
+       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+               
        if (post_transport_work & PostTransportCurveRealloc) {
                for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
                        (*i)->curve_reallocate();
@@ -253,7 +257,7 @@ Session::butler_transport_work ()
 void
 Session::non_realtime_set_speed ()
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
 
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                (*i)->non_realtime_set_speed ();
@@ -263,7 +267,7 @@ Session::non_realtime_set_speed ()
 void
 Session::non_realtime_overwrite ()
 {
-       LockMonitor lm (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
 
        for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                if ((*i)->pending_overwrite) {
@@ -448,7 +452,7 @@ Session::set_auto_loop (bool yn)
 {
        /* Called from event-handling context */
        
-       if (actively_recording() || _locations.auto_loop_location() == 0) {
+       if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) {
                return;
        }
        
@@ -603,18 +607,51 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b
 
        } else {
 
-               /* XXX i don't know where else to put this. something has to clear the
-                  current clicks, and without deadlocking. clear_clicks() takes
-                  the route lock which would deadlock in this context.
-               */
+               /* this is functionally what clear_clicks() does but with a tentative lock */
 
-               for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
-                       delete *i;
-               }
+               TentativeRWLockMonitor clickm (click_lock, true, __LINE__, __FILE__);
+       
+               if (clickm.locked()) {
+                       
+                       for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
+                               delete *i;
+                       }
                
-               clicks.clear ();
+                       clicks.clear ();
+               }
        }
 
+       if (with_roll) {
+               /* switch from input if we're going to roll */
+               if (Config->get_use_hardware_monitoring()) {
+                       /* Even though this is called from RT context we are using
+                          a non-tentative rwlock here,  because the action must occur.
+                          The rarity and short potential lock duration makes this "OK"
+                       */
+                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               if ((*i)->record_enabled ()) {
+                                       cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (!auto_input);
+                               }
+                       }
+               }
+       } else {
+               /* otherwise we're going to stop, so do the opposite */
+               if (Config->get_use_hardware_monitoring()) {
+                       /* Even though this is called from RT context we are using
+                          a non-tentative rwlock here,  because the action must occur.
+                          The rarity and short potential lock duration makes this "OK"
+                       */
+                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               if ((*i)->record_enabled ()) {
+                                       cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (true);
+                               }
+                       }
+               }
+       }
 
        /* cancel autoloop if transport pos outside of loop range */
        if (auto_loop) {
@@ -644,6 +681,21 @@ Session::set_transport_speed (float speed, bool abort)
 
        if (transport_rolling() && speed == 0.0) {
 
+               if (Config->get_use_hardware_monitoring())
+               {
+                       /* Even though this is called from RT context we are using
+                          a non-tentative rwlock here,  because the action must occur.
+                          The rarity and short potential lock duration makes this "OK"
+                       */
+                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               if ((*i)->record_enabled ()) {
+                                       //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (true);     
+                               }
+                       }
+               }
+
                if (synced_to_jack ()) {
                        _engine.transport_stop ();
                } else {
@@ -652,6 +704,20 @@ Session::set_transport_speed (float speed, bool abort)
 
        } else if (transport_stopped() && speed == 1.0) {
 
+               if (Config->get_use_hardware_monitoring()) {
+                       /* Even though this is called from RT context we are using
+                          a non-tentative rwlock here,  because the action must occur.
+                          The rarity and short potential lock duration makes this "OK"
+                       */
+                       RWLockMonitor dsm (diskstream_lock, false, __LINE__, __FILE__);
+                       for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+                               if (auto_input && (*i)->record_enabled ()) {
+                                       //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
+                                       (*i)->monitor_input (false);    
+                               }
+                       }
+               }
+
                if (synced_to_jack()) {
                        _engine.transport_start ();
                } else {
@@ -690,7 +756,7 @@ Session::set_transport_speed (float speed, bool abort)
                
                _last_transport_speed = _transport_speed;
                _transport_speed = speed;
-
+               
                for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
                        if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
                                post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
@@ -1102,8 +1168,8 @@ Session::update_latency_compensation (bool with_stop, bool abort)
                return;
        }
 
-       LockMonitor lm (route_lock, __LINE__, __FILE__);
-       LockMonitor lm2 (diskstream_lock, __LINE__, __FILE__);
+       RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
+       RWLockMonitor lm2 (diskstream_lock, false, __LINE__, __FILE__);
        _worst_track_latency = 0;
 
        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
index e0f6ad33e933d6249640d9a452752c4de2b21dc6..fca6707efdacbbad72c06b1e3a9a8123f6ec9df4 100644 (file)
@@ -83,13 +83,15 @@ int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen)
 {
        TR_FN ();
        int R;
+       int totwritten = 0;
        snd_midi_event_reset_encode (encoder);
        int nwritten = snd_midi_event_encode (encoder, msg, msglen, &SEv);
        TR_VAL (nwritten);
-       if (0 < nwritten) {
+       while (0 < nwritten) {
                if (0 <= (R = snd_seq_event_output (seq, &SEv))  &&
                    0 <= (R = snd_seq_drain_output (seq))) {
                        bytes_written += nwritten;
+                       totwritten += nwritten;
                        if (output_parser) {
                                output_parser->raw_preparse (*output_parser, msg, nwritten);
                                for (int i = 0; i < nwritten; i++) {
@@ -97,13 +99,23 @@ int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen)
                                }
                                output_parser->raw_postparse (*output_parser, msg, nwritten);
                        }
-                       return nwritten;
                } else {
                        TR_VAL(R);
                        return R;
                }
-       } else
-               return nwritten;
+
+               msglen -= nwritten;
+               msg += nwritten;
+               if (msglen > 0) {
+                       nwritten = snd_midi_event_encode (encoder, msg, msglen, &SEv);
+                       TR_VAL(nwritten);
+               }
+               else {
+                       break;
+               }
+       }
+
+       return totwritten;
 }
 
 int ALSA_SequencerMidiPort::read (byte *buf, size_t max)
index 8fad66f83ea7004314ae5b9fabab013b8e1078ba..c91a041e9b7d9a4ccd7980148ccbc369ad29eebf 100644 (file)
@@ -57,6 +57,31 @@ class NonBlockingLock : public Lock {
        int unlock() { return pthread_mutex_unlock (&_mutex); }
 };
 
+class RWLock { 
+  public:
+       RWLock() { pthread_rwlock_init (&_mutex, 0); } 
+       virtual ~RWLock() { pthread_rwlock_destroy(&_mutex); }
+
+       virtual int write_lock () { return pthread_rwlock_wrlock (&_mutex); }
+       virtual int read_lock () { return pthread_rwlock_rdlock (&_mutex); }
+       virtual int unlock() { return pthread_rwlock_unlock (&_mutex); }
+
+       pthread_rwlock_t *mutex() { return &_mutex; }
+
+  protected:
+       pthread_rwlock_t _mutex;
+};
+
+class NonBlockingRWLock : public RWLock {      
+  public:
+       NonBlockingRWLock() {}
+       ~NonBlockingRWLock(){}
+       
+       int write_trylock () { return pthread_rwlock_trywrlock (&_mutex); }
+       int read_trylock () { return pthread_rwlock_tryrdlock (&_mutex); }
+};
+
+
 class LockMonitor 
 {
   public:
@@ -189,6 +214,112 @@ class SpinLockMonitor
 #endif
 };
 
+
+class RWLockMonitor 
+{
+  public:
+       RWLockMonitor (RWLock& lck, bool write, unsigned long l, const char *f) 
+               : lock (lck)
+#ifdef DEBUG_LOCK_MONITOR
+               , line (l), file (f) 
+#endif
+               {
+
+#ifdef DEBUG_LOCK_MONITOR
+                       unsigned long long when;
+                       when = get_cycles();
+                       cerr << when << " lock " << &lock << " at " << line << " in " << file << endl;
+#endif
+                       if (write) {
+                               lock.write_lock ();
+                       } else {
+                               lock.read_lock ();
+                       }
+#ifdef DEBUG_LOCK_MONITOR
+                       when = get_cycles();
+                       cerr << '\t' << when 
+                            << " locked: " 
+                            << &lock << " at " 
+                            << line << " in " << file << endl;
+#endif
+               }
+       
+       ~RWLockMonitor () {
+               lock.unlock ();
+#ifdef DEBUG_LOCK_MONITOR
+               unsigned long long when;
+               when = get_cycles();
+               cerr << '\t' << when << ' ' 
+                    << " UNLOCKED "
+                    << &lock << " at " 
+                    << line << " in " << file << endl;
+#endif
+       }
+  private:
+       RWLock& lock;
+#ifdef DEBUG_LOCK_MONITOR
+       unsigned long line;
+       const char * file;
+#endif
+};
+
+class TentativeRWLockMonitor 
+{
+  public:
+       TentativeRWLockMonitor (NonBlockingRWLock& lck, bool write, unsigned long l, const char *f) 
+               : lock (lck)
+#ifdef DEBUG_LOCK_MONITOR
+               , line (l), file (f) 
+#endif
+               {
+
+#ifdef DEBUG_LOCK_MONITOR
+                       unsigned long long when;
+                       when = get_cycles();
+                       cerr << when << " tentative lock " << &lock << " at " << line << " in " << file << endl;
+#endif
+                       if (write) {
+                               _locked = (lock.write_trylock() == 0);
+                       } else {
+                               _locked = (lock.read_trylock() == 0);
+                       }
+
+#ifdef DEBUG_LOCK_MONITOR
+                       when = get_cycles();
+                       cerr << '\t' << when << ' ' 
+                            << _locked 
+                            << " lock: " 
+                            << &lock << " at " 
+                            << line << " in " << file << endl;
+#endif
+               }
+
+       ~TentativeRWLockMonitor () {
+               if (_locked) {
+                       lock.unlock ();
+#ifdef DEBUG_LOCK_MONITOR
+                       unsigned long long when;
+                       when = get_cycles();
+                       cerr << '\t' << when << ' ' 
+                            << " UNLOCKED "
+                            << &lock << " at " 
+                            << line << " in " << file << endl;
+#endif
+               }
+       }
+       
+       bool locked() { return _locked; }
+
+  private:
+       NonBlockingRWLock& lock;
+       bool _locked;
+#ifdef DEBUG_LOCK_MONITOR
+       unsigned long line;
+       const char * file;
+#endif
+};
+
+
 } /* namespace */
 
 #endif /* __pbd_lockmonitor_h__*/