From bd21c474e547d49338ea0efd452895de1e147cd5 Mon Sep 17 00:00:00 2001 From: Jesse Chappell Date: Fri, 6 Jan 2006 04:59:17 +0000 Subject: committed RWlock fixes to libardour. added hw monitoring fixes from nick_m. minor alsa midi fix and update rate settings. git-svn-id: svn://localhost/trunk/ardour2@244 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/option_editor.cc | 3 + libs/ardour/ardour/configuration.h | 5 + libs/ardour/ardour/diskstream.h | 1 - libs/ardour/ardour/route.h | 6 +- libs/ardour/ardour/session.h | 12 ++- libs/ardour/ardour/session_diskstream.h | 2 +- libs/ardour/ardour/session_route.h | 6 +- libs/ardour/audio_track.cc | 26 +++-- libs/ardour/configuration.cc | 27 ++++- libs/ardour/diskstream.cc | 36 +------ libs/ardour/io.cc | 3 +- libs/ardour/panner.cc | 3 +- libs/ardour/plugin.cc | 3 +- libs/ardour/route.cc | 62 ++++++----- libs/ardour/session.cc | 178 ++++++++++++++++++++++++-------- libs/ardour/session_butler.cc | 4 +- libs/ardour/session_click.cc | 6 +- libs/ardour/session_events.cc | 6 -- libs/ardour/session_export.cc | 4 +- libs/ardour/session_feedback.cc | 13 +-- libs/ardour/session_midi.cc | 6 +- libs/ardour/session_process.cc | 25 +++-- libs/ardour/session_state.cc | 12 +-- libs/ardour/session_transport.cc | 96 ++++++++++++++--- libs/midi++2/alsa_sequencer_midiport.cc | 20 +++- libs/pbd3/pbd/lockmonitor.h | 131 +++++++++++++++++++++++ 26 files changed, 516 insertions(+), 180 deletions(-) diff --git a/gtk2_ardour/option_editor.cc b/gtk2_ardour/option_editor.cc index 9126303c52..049bf5331b 100644 --- a/gtk2_ardour/option_editor.cc +++ b/gtk2_ardour/option_editor.cc @@ -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 diff --git a/libs/ardour/ardour/configuration.h b/libs/ardour/ardour/configuration.h index 0c42027646..140490d46d 100644 --- a/libs/ardour/ardour/configuration.h +++ b/libs/ardour/ardour/configuration.h @@ -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; diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index 3c9aa0e0f6..0cdbfd1724 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -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; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 8f4028c99f..9c0edcdad4 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -140,14 +140,14 @@ class Route : public IO void flush_redirects (); template 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; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index b58b0a926b..88f629e516 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -273,7 +273,7 @@ class Session : public sigc::trackable, public Stateful typedef list 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 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; diff --git a/libs/ardour/ardour/session_diskstream.h b/libs/ardour/ardour/session_diskstream.h index 55c79f549f..24693c5793 100644 --- a/libs/ardour/ardour/session_diskstream.h +++ b/libs/ardour/ardour/session_diskstream.h @@ -29,7 +29,7 @@ namespace ARDOUR { template 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); diff --git a/libs/ardour/ardour/session_route.h b/libs/ardour/ardour/session_route.h index 0b126531dc..f3c8e3f5fb 100644 --- a/libs/ardour/ardour/session_route.h +++ b/libs/ardour/ardour/session_route.h @@ -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; } diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index 75f930bf8d..1d3f32ae6b 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -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& buffers, uint32_t nbufs, jack_nframes vector::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::iterator ii = _freeze_record.insert_info.begin(); ii != _freeze_record.insert_info.end(); ++ii) { if ((*ii)->id == (*i)->id()) { diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc index 4003946576..0de30a3538 100644 --- a/libs/ardour/configuration.cc +++ b/libs/ardour/configuration.cc @@ -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() { diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index 351fdde33f..d0b0415c8c 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -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); } diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index b2d3337dcb..6b6773c49d 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -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)); diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index 130db16191..85feed6be9 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -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); } diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 042e156130..059cf133a5 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -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); } } diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 03059c6c82..6e07ef90f2 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -314,7 +314,7 @@ Route::process_output_buffers (vector& 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& 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& 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); } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index ab218e4804..f811fbd0af 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -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::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(*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(*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(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 r; + RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__); + for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { list& 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 (*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 (*i) == 0) { diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc index df867c8267..12a838b5dd 100644 --- a/libs/ardour/session_butler.cc +++ b/libs/ardour/session_butler.cc @@ -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); } diff --git a/libs/ardour/session_click.cc b/libs/ardour/session_click.cc index 250adfe4cc..c9777500a2 100644 --- a/libs/ardour/session_click.cc +++ b/libs/ardour/session_click.cc @@ -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; diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc index 68555dbe40..2aeace81f4 100644 --- a/libs/ardour/session_events.cc +++ b/libs/ardour/session_events.cc @@ -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; diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index a80ee69e56..0ccea59b81 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -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"), diff --git a/libs/ardour/session_feedback.cc b/libs/ardour/session_feedback.cc index c2198aa55d..2e6d0cd80b 100644 --- a/libs/ardour/session_feedback.cc +++ b/libs/ardour/session_feedback.cc @@ -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; } diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index f9c8d57e62..18d8b3672b 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -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 (); } diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 01e75a4749..5bcd595ecc 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -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()) { diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 98a48fb44a..53ca23a366 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -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()) { diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 342b6e1a52..82b067a288 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -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) { diff --git a/libs/midi++2/alsa_sequencer_midiport.cc b/libs/midi++2/alsa_sequencer_midiport.cc index e0f6ad33e9..fca6707efd 100644 --- a/libs/midi++2/alsa_sequencer_midiport.cc +++ b/libs/midi++2/alsa_sequencer_midiport.cc @@ -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) diff --git a/libs/pbd3/pbd/lockmonitor.h b/libs/pbd3/pbd/lockmonitor.h index 8fad66f83e..c91a041e9b 100644 --- a/libs/pbd3/pbd/lockmonitor.h +++ b/libs/pbd3/pbd/lockmonitor.h @@ -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__*/ -- cgit v1.2.3