From bf411d3730526af0bb984f6bb3dd4035d6070bc4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 22 Nov 2010 17:15:32 +0000 Subject: [PATCH] Simplify strip silence dialogue threading, hopefully fixing #3560 in the process. git-svn-id: svn://localhost/ardour2/branches/3.0@8068 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/strip_silence_dialog.cc | 203 ++++++++++------------------ gtk2_ardour/strip_silence_dialog.h | 51 ++++--- 2 files changed, 97 insertions(+), 157 deletions(-) diff --git a/gtk2_ardour/strip_silence_dialog.cc b/gtk2_ardour/strip_silence_dialog.cc index d0f806e71a..48b69901e7 100644 --- a/gtk2_ardour/strip_silence_dialog.cc +++ b/gtk2_ardour/strip_silence_dialog.cc @@ -43,13 +43,6 @@ using namespace ARDOUR; using namespace std; using namespace ArdourCanvas; -Glib::StaticMutex StripSilenceDialog::run_lock; -Glib::Cond* StripSilenceDialog::thread_waiting = 0; -Glib::Cond* StripSilenceDialog::thread_run = 0; -bool StripSilenceDialog::thread_should_exit = false; -InterThreadInfo StripSilenceDialog::itt; -StripSilenceDialog* StripSilenceDialog::current = 0; - /** Construct Strip silence dialog box */ StripSilenceDialog::StripSilenceDialog (Session* s, list > const & regions) : ArdourDialog (_("Strip Silence")) @@ -58,16 +51,10 @@ StripSilenceDialog::StripSilenceDialog (Session* s, listsignal_value_changed().connect (sigc::mem_fun (*this, &StripSilenceDialog::threshold_changed)); - _minimum_length.ValueChanged.connect (sigc::mem_fun (*this, &StripSilenceDialog::maybe_start_silence_detection)); + _minimum_length.ValueChanged.connect (sigc::mem_fun (*this, &StripSilenceDialog::restart_thread)); create_waves (); update_silence_rects (); update_threshold_line (); - maybe_start_silence_detection (); + /* Create a thread which runs while the dialogue is open to compute the silence regions */ + Completed.connect (_completed_connection, MISSING_INVALIDATOR, ui_bind (&StripSilenceDialog::update, this), gui_context ()); + _thread_should_finish = false; + pthread_create (&_thread, 0, StripSilenceDialog::_detection_thread_work, this); } StripSilenceDialog::~StripSilenceDialog () { + /* Terminate our thread */ + + _lock.lock (); + _interthread_info.cancel = true; + _thread_should_finish = true; + _lock.unlock (); + + _run_cond.signal (); + pthread_join (_thread, 0); + for (list::iterator i = _waves.begin(); i != _waves.end(); ++i) { delete *i; } @@ -240,6 +240,9 @@ StripSilenceDialog::resize_silence_rects () { int n = 0; + /* Lock so that we don't contend with the detection thread for access to the silence regions */ + Glib::Mutex::Lock lm (_lock); + for (list::iterator i = _waves.begin(); i != _waves.end(); ++i) { list >::const_iterator j; @@ -263,7 +266,9 @@ void StripSilenceDialog::update_threshold_line () { int n = 0; - + + /* Don't need to lock here as we're not reading the _waves silence details */ + for (list::iterator i = _waves.begin(); i != _waves.end(); ++i) { (*i)->threshold_line->property_x1() = 0; (*i)->threshold_line->property_x2() = _wave_width; @@ -277,6 +282,15 @@ StripSilenceDialog::update_threshold_line () ++n; } +void +StripSilenceDialog::update () +{ + update_silence_rects (); + update_threshold_line (); + /* XXX: first one only?! */ + update_stats (_waves.front()->silence); +} + void StripSilenceDialog::update_silence_rects () { @@ -284,6 +298,9 @@ StripSilenceDialog::update_silence_rects () uint32_t max_segments = 0; uint32_t sc; + /* Lock so that we don't contend with the detection thread for access to the silence regions */ + Glib::Mutex::Lock lm (_lock); + for (list::iterator i = _waves.begin(); i != _waves.end(); ++i) { for (list::iterator j = (*i)->silence_rects.begin(); j != (*i)->silence_rects.end(); ++j) { delete *j; @@ -346,141 +363,69 @@ StripSilenceDialog::update_silence_rects () } } -bool -StripSilenceDialog::_detection_done (void* arg) -{ - StripSilenceDialog* ssd = (StripSilenceDialog*) arg; - return ssd->detection_done (); -} - -bool -StripSilenceDialog::detection_done () -{ - get_window()->set_cursor (Gdk::Cursor (Gdk::LEFT_PTR)); - update_silence_rects (); - return false; -} - -void* +void * StripSilenceDialog::_detection_thread_work (void* arg) { - StripSilenceDialog* ssd = (StripSilenceDialog*) arg; - return ssd->detection_thread_work (); + StripSilenceDialog* d = reinterpret_cast (arg); + return d->detection_thread_work (); } -void* +/** Body of our silence detection thread */ +void * StripSilenceDialog::detection_thread_work () { ARDOUR_UI::instance()->register_thread ("gui", pthread_self(), "silence", 32); - - while (1) { - run_lock.lock (); - thread_waiting->signal (); - thread_run->wait (run_lock); + /* Hold this lock when we are doing work */ + _lock.lock (); + + while (1) { + for (list::iterator i = _waves.begin(); i != _waves.end(); ++i) { + (*i)->silence = (*i)->region->find_silence (dB_to_coefficient (threshold ()), minimum_length (), _interthread_info); + if (_interthread_info.cancel) { + break; + } + } - if (thread_should_exit) { - thread_waiting->signal (); - run_lock.unlock (); - break; - } + if (!_interthread_info.cancel) { + Completed (); /* EMIT SIGNAL */ + } - if (current) { - StripSilenceDialog* ssd = current; - run_lock.unlock (); - - for (list::iterator i = ssd->_waves.begin(); i != ssd->_waves.end(); ++i) { - (*i)->silence = (*i)->region->find_silence (dB_to_coefficient (ssd->threshold ()), ssd->minimum_length (), ssd->itt); - ssd->update_stats ((*i)->silence); - } - - if (!ssd->itt.cancel) { - g_idle_add ((gboolean (*)(void*)) StripSilenceDialog::_detection_done, ssd); - } - } else { - run_lock.unlock (); - } + /* Our work is done; sleep until there is more to do. + * The lock is released while we are waiting. + */ + _run_cond.wait (_lock); - } - - return 0; -} + if (_thread_should_finish) { + _lock.unlock (); + return 0; + } + } -void -StripSilenceDialog::threshold_changed () -{ - update_threshold_line (); - maybe_start_silence_detection (); + return 0; } void -StripSilenceDialog::maybe_start_silence_detection () +StripSilenceDialog::restart_thread () { - if (!restart_queued) { - restart_queued = true; - Glib::signal_idle().connect (sigc::mem_fun (*this, &StripSilenceDialog::start_silence_detection)); - } -} - -bool -StripSilenceDialog::start_silence_detection () -{ - Glib::Mutex::Lock lm (run_lock); - restart_queued = false; - - if (!itt.thread) { - - itt.done = false; - itt.cancel = false; - itt.progress = 0.0; - current = this; - - pthread_create (&itt.thread, 0, StripSilenceDialog::_detection_thread_work, this); - /* wait for it to get started */ - thread_waiting->wait (run_lock); - - } else { - - /* stop whatever the thread is doing */ - - itt.cancel = 1; - current = 0; - - while (!itt.done) { - thread_run->signal (); - thread_waiting->wait (run_lock); - } - } + /* Cancel any current run */ + _interthread_info.cancel = true; + /* Block until the thread waits() */ + _lock.lock (); + /* Reset the flag */ + _interthread_info.cancel = false; + _lock.unlock (); - itt.cancel = false; - itt.done = false; - itt.progress = 0.0; - current = this; - - /* and start it up (again) */ - - thread_run->signal (); - - /* change cursor */ - - get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH)); - - /* don't call again until needed */ - - return false; + /* And re-awake the thread */ + _run_cond.signal (); } void -StripSilenceDialog::stop_thread () +StripSilenceDialog::threshold_changed () { - Glib::Mutex::Lock lm (run_lock); - - itt.cancel = true; - thread_should_exit = true; - thread_run->signal (); - thread_waiting->wait (run_lock); - itt.thread = 0; + update_threshold_line (); + restart_thread (); } void diff --git a/gtk2_ardour/strip_silence_dialog.h b/gtk2_ardour/strip_silence_dialog.h index 3b800eb115..c9b31578b9 100644 --- a/gtk2_ardour/strip_silence_dialog.h +++ b/gtk2_ardour/strip_silence_dialog.h @@ -43,17 +43,21 @@ public: nframes_t minimum_length () const; nframes_t fade_length () const; - static void stop_thread (); private: + typedef std::list > SilenceResult; + void create_waves (); void peaks_ready (); void canvas_allocation (Gtk::Allocation &); void update_silence_rects (); void resize_silence_rects (); + void update (); void update_threshold_line (); + void update_stats (SilenceResult const &); void threshold_changed (); void update_progress_gui (float); + void restart_thread (); Gtk::SpinButton _threshold; AudioClock _minimum_length; @@ -62,32 +66,23 @@ private: Gtk::Label _shortest_silence_label; Gtk::Label _shortest_audible_label; Gtk::ProgressBar _progress_bar; - typedef std::list > SilenceResult; struct Wave { - boost::shared_ptr region; - ArdourCanvas::WaveView* view; - std::list silence_rects; - ArdourCanvas::SimpleLine* threshold_line; - double samples_per_unit; - SilenceResult silence; - - Wave (ArdourCanvas::Group *, boost::shared_ptr); - ~Wave (); + boost::shared_ptr region; + ArdourCanvas::WaveView* view; + std::list silence_rects; + ArdourCanvas::SimpleLine* threshold_line; + double samples_per_unit; + SilenceResult silence; + + Wave (ArdourCanvas::Group *, boost::shared_ptr); + ~Wave (); }; ArdourCanvas::Canvas* _canvas; std::list _waves; int _wave_width; int _wave_height; - bool restart_queued; - - static ARDOUR::InterThreadInfo itt; - static bool thread_should_exit; - static Glib::Cond *thread_run; - static Glib::Cond *thread_waiting; - static Glib::StaticMutex run_lock; - static StripSilenceDialog* current; ARDOUR::framecnt_t max_audible; ARDOUR::framecnt_t min_audible; @@ -95,14 +90,14 @@ private: ARDOUR::framecnt_t min_silence; PBD::ScopedConnection* _peaks_ready_connection; - - static bool _detection_done (void*); - static void* _detection_thread_work (void*); - - bool detection_done (); - void* detection_thread_work (); - bool start_silence_detection (); - void maybe_start_silence_detection (); - void update_stats (const SilenceResult&); + pthread_t _thread; ///< thread to compute silence in the background + static void * _detection_thread_work (void *); + void * detection_thread_work (); + Glib::Mutex _lock; ///< lock held while the thread is doing work + Glib::Cond _run_cond; ///< condition to wake the thread + bool _thread_should_finish; ///< true if the thread should terminate + PBD::Signal0 Completed; ///< emitted when a silence detection has completed + PBD::ScopedConnection _completed_connection; + ARDOUR::InterThreadInfo _interthread_info; }; -- 2.30.2