summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2010-11-22 17:15:32 +0000
committerCarl Hetherington <carl@carlh.net>2010-11-22 17:15:32 +0000
commitbf411d3730526af0bb984f6bb3dd4035d6070bc4 (patch)
treef6da2de3ac13de90bfdfe09797b5fbfb233aa2b6
parentd000c7e79d80db424547a54f3104a305d82efb54 (diff)
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
-rw-r--r--gtk2_ardour/strip_silence_dialog.cc203
-rw-r--r--gtk2_ardour/strip_silence_dialog.h51
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<boost::shared_ptr<ARDOUR::AudioRegion> > const & regions)
: ArdourDialog (_("Strip Silence"))
@@ -58,16 +51,10 @@ StripSilenceDialog::StripSilenceDialog (Session* s, list<boost::shared_ptr<ARDOU
, _fade_length (X_("silence duration"), true, "SilenceDurationClock", true, false, true, false)
, _wave_width (640)
, _wave_height (64)
- , restart_queued (false)
, _peaks_ready_connection (0)
{
set_session (s);
- if (thread_waiting == 0) {
- thread_waiting = new Glib::Cond;
- thread_run = new Glib::Cond;
- }
-
Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox);
Gtk::Table* table = Gtk::manage (new Gtk::Table (3, 3));
@@ -149,18 +136,31 @@ StripSilenceDialog::StripSilenceDialog (Session* s, list<boost::shared_ptr<ARDOU
show_all ();
_threshold.get_adjustment()->signal_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<Wave*>::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<Wave*>::iterator i = _waves.begin(); i != _waves.end(); ++i) {
list<pair<frameoffset_t, framecnt_t> >::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<Wave*>::iterator i = _waves.begin(); i != _waves.end(); ++i) {
(*i)->threshold_line->property_x1() = 0;
(*i)->threshold_line->property_x2() = _wave_width;
@@ -278,12 +283,24 @@ StripSilenceDialog::update_threshold_line ()
}
void
+StripSilenceDialog::update ()
+{
+ update_silence_rects ();
+ update_threshold_line ();
+ /* XXX: first one only?! */
+ update_stats (_waves.front()->silence);
+}
+
+void
StripSilenceDialog::update_silence_rects ()
{
int n = 0;
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<Wave*>::iterator i = _waves.begin(); i != _waves.end(); ++i) {
for (list<SimpleRect*>::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<StripSilenceDialog*> (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<Wave*>::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<Wave*>::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<std::pair<ARDOUR::frameoffset_t,ARDOUR::framecnt_t> > 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<std::pair<ARDOUR::frameoffset_t,ARDOUR::framecnt_t> > SilenceResult;
struct Wave {
- boost::shared_ptr<ARDOUR::AudioRegion> region;
- ArdourCanvas::WaveView* view;
- std::list<ArdourCanvas::SimpleRect*> silence_rects;
- ArdourCanvas::SimpleLine* threshold_line;
- double samples_per_unit;
- SilenceResult silence;
-
- Wave (ArdourCanvas::Group *, boost::shared_ptr<ARDOUR::AudioRegion>);
- ~Wave ();
+ boost::shared_ptr<ARDOUR::AudioRegion> region;
+ ArdourCanvas::WaveView* view;
+ std::list<ArdourCanvas::SimpleRect*> silence_rects;
+ ArdourCanvas::SimpleLine* threshold_line;
+ double samples_per_unit;
+ SilenceResult silence;
+
+ Wave (ArdourCanvas::Group *, boost::shared_ptr<ARDOUR::AudioRegion>);
+ ~Wave ();
};
ArdourCanvas::Canvas* _canvas;
std::list<Wave*> _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<void> Completed; ///< emitted when a silence detection has completed
+ PBD::ScopedConnection _completed_connection;
+ ARDOUR::InterThreadInfo _interthread_info;
};