diff --git a/gtk2_ardour/strip_silence_dialog.cc b/gtk2_ardour/strip_silence_dialog.cc index 2be04f7fcb..56210c9373 100644 --- a/gtk2_ardour/strip_silence_dialog.cc +++ b/gtk2_ardour/strip_silence_dialog.cc @@ -17,6 +17,8 @@ */ +#include + #include #include #include @@ -34,17 +36,32 @@ #include "i18n.h" 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 (std::list > const & regions) - : ArdourDialog (_("Strip Silence")), _wave_width (640), _wave_height (64) + : ArdourDialog (_("Strip Silence")) + , _wave_width (640) + , _wave_height (64) + , restart_queued (false) { + if (thread_waiting == 0) { + thread_waiting = new Glib::Cond; + thread_run = new Glib::Cond; + } + for (std::list >::const_iterator i = regions.begin(); i != regions.end(); ++i) { Wave w; w.region = *i; - w.view = 0; - w.samples_per_unit = 1; _waves.push_back (w); } @@ -91,18 +108,15 @@ StripSilenceDialog::StripSilenceDialog (std::listpack_start (*table, false, false); - Gtk::VBox* v = Gtk::manage (new Gtk::VBox); - Gtk::Button* b = Gtk::manage (new Gtk::Button (_("Update display"))); - b->signal_clicked().connect (sigc::mem_fun (*this, &StripSilenceDialog::update_silence_rects)); - v->pack_start (*b, false, false); - hbox->pack_start (*v, false, false); + _segment_count_label.set_text (_("Silent segments: none")); + hbox->pack_start (_segment_count_label, false, false); - get_vbox()->add (*hbox); + get_vbox()->pack_start (*hbox, false, false); add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_OK); - _canvas = new ArdourCanvas::CanvasAA (); + _canvas = new CanvasAA (); _canvas->signal_size_allocate().connect (sigc::mem_fun (*this, &StripSilenceDialog::canvas_allocation)); _canvas->set_size_request (_wave_width, _wave_height * _waves.size ()); @@ -110,6 +124,9 @@ StripSilenceDialog::StripSilenceDialog (std::listsignal_value_changed().connect (sigc::mem_fun (*this, &StripSilenceDialog::maybe_start_silence_detection)); + _minimum_length.get_adjustment()->signal_value_changed().connect (sigc::mem_fun (*this, &StripSilenceDialog::maybe_start_silence_detection)); + create_waves (); update_silence_rects (); } @@ -119,7 +136,7 @@ StripSilenceDialog::~StripSilenceDialog () { for (std::list::iterator i = _waves.begin(); i != _waves.end(); ++i) { delete i->view; - for (std::list::iterator j = i->silence_rects.begin(); j != i->silence_rects.end(); ++j) { + for (std::list::iterator j = i->silence_rects.begin(); j != i->silence_rects.end(); ++j) { delete *j; } } @@ -165,32 +182,67 @@ StripSilenceDialog::peaks_ready () void StripSilenceDialog::canvas_allocation (Gtk::Allocation& alloc) { + int n = 0; + _canvas->set_scroll_region (0.0, 0.0, alloc.get_width(), alloc.get_height()); _wave_width = alloc.get_width (); + _wave_height = alloc.get_height (); + + for (std::list::iterator i = _waves.begin(); i != _waves.end(); ++i, ++n) { + i->samples_per_unit = ((double) i->region->length() / _wave_width); + + if (i->view) { + i->view->property_y() = n * _wave_height; + i->view->property_samples_per_unit() = i->samples_per_unit; + i->view->property_height() = _wave_height; + } + } + + redraw_silence_rects (); +} + +void +StripSilenceDialog::redraw_silence_rects () +{ + int n = 0; for (std::list::iterator i = _waves.begin(); i != _waves.end(); ++i) { - i->samples_per_unit = ((double) i->region->length() / _wave_width); - } + + std::list >::const_iterator j; + std::list::iterator r; + + for (j = i->silence.begin(), r = i->silence_rects.begin(); + j != i->silence.end() && r != i->silence_rects.end(); ++j, ++r) { + (*r)->property_x1() = j->first / i->samples_per_unit; + (*r)->property_x2() = j->second / i->samples_per_unit; + (*r)->property_y1() = n * _wave_height; + (*r)->property_y2() = (n + 1) * _wave_height; + (*r)->property_outline_pixels() = 0; + (*r)->property_fill_color_rgba() = RGBA_TO_UINT (128, 128, 128, 128); + } + + ++n; + } } void StripSilenceDialog::update_silence_rects () { int n = 0; + uint32_t max_segments = 0; + uint32_t sc; for (std::list::iterator i = _waves.begin(); i != _waves.end(); ++i) { - for (std::list::iterator j = i->silence_rects.begin(); j != i->silence_rects.end(); ++j) { + for (std::list::iterator j = i->silence_rects.begin(); j != i->silence_rects.end(); ++j) { delete *j; } - i->silence_rects.clear (); + i->silence_rects.clear (); + sc = 0; - std::list > const silence = - i->region->find_silence (dB_to_coefficient (threshold ()), minimum_length ()); - - for (std::list >::const_iterator j = silence.begin(); j != silence.end(); ++j) { + for (std::list >::const_iterator j = i->silence.begin(); j != i->silence.end(); ++j) { - ArdourCanvas::SimpleRect* r = new ArdourCanvas::SimpleRect (*(_canvas->root())); + SimpleRect* r = new SimpleRect (*(_canvas->root())); r->property_x1() = j->first / i->samples_per_unit; r->property_x2() = j->second / i->samples_per_unit; r->property_y1() = n * _wave_height; @@ -198,9 +250,152 @@ StripSilenceDialog::update_silence_rects () r->property_outline_pixels() = 0; r->property_fill_color_rgba() = RGBA_TO_UINT (128, 128, 128, 128); i->silence_rects.push_back (r); - + sc++; } + max_segments = max (max_segments, sc); ++n; } + + _segment_count_label.set_text (string_compose (_("Silent segments: %1"), max_segments)); +} + +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* +StripSilenceDialog::_detection_thread_work (void* arg) +{ + StripSilenceDialog* ssd = (StripSilenceDialog*) arg; + return ssd->detection_thread_work (); +} + +void* +StripSilenceDialog::detection_thread_work () +{ + ARDOUR_UI::instance()->register_thread ("gui", pthread_self(), "silence", 32); + + cerr << pthread_self() << ": thread exists\n"; + + while (1) { + + run_lock.lock (); + cerr << pthread_self() << ": thread notes that its waiting\n"; + thread_waiting->signal (); + cerr << pthread_self() << ": thread waits to run\n"; + thread_run->wait (run_lock); + + cerr << pthread_self() << ": silence thread active\n"; + + if (thread_should_exit) { + thread_waiting->signal (); + run_lock.unlock (); + cerr << pthread_self() << ": silence thread exited\n"; + break; + } + + if (current) { + StripSilenceDialog* ssd = current; + run_lock.unlock (); + + for (std::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); + } + + if (!ssd->itt.cancel) { + g_idle_add ((gboolean (*)(void*)) StripSilenceDialog::_detection_done, ssd); + } + } + + cerr << pthread_self() << ": silence iteration done\n"; + } + + return 0; +} + +void +StripSilenceDialog::maybe_start_silence_detection () +{ + 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 */ + cerr << "Wait for new thread to be ready\n"; + thread_waiting->wait (run_lock); + cerr << "\tits ready\n"; + + } else { + + /* stop whatever the thread is doing */ + + itt.cancel = 1; + current = 0; + + while (!itt.done) { + cerr << "tell existing thread to stop\n"; + thread_run->signal (); + cerr << "wait for existing thread to stop\n"; + thread_waiting->wait (run_lock); + cerr << "its stopped\n"; + } + } + + + itt.cancel = false; + itt.done = false; + itt.progress = 0.0; + current = this; + + /* and start it up (again) */ + + cerr << "signal thread to run again\n"; + thread_run->signal (); + + /* change cursor */ + + get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH)); + + /* don't call again until needed */ + + return false; +} + +void +StripSilenceDialog::stop_thread () +{ + Glib::Mutex::Lock lm (run_lock); + + itt.cancel = true; + thread_should_exit = true; + thread_run->signal (); + thread_waiting->wait (run_lock); } diff --git a/gtk2_ardour/strip_silence_dialog.h b/gtk2_ardour/strip_silence_dialog.h index 927764e57c..2084d74de2 100644 --- a/gtk2_ardour/strip_silence_dialog.h +++ b/gtk2_ardour/strip_silence_dialog.h @@ -18,6 +18,9 @@ */ #include +#include + +#include "ardour/types.h" #include "ardour_dialog.h" #include "canvas.h" @@ -44,27 +47,50 @@ public: return _fade_length.get_value_as_int (); } + static void stop_thread (); + private: void create_waves (); void peaks_ready (); void canvas_allocation (Gtk::Allocation &); void update_silence_rects (); + void redraw_silence_rects (); Gtk::SpinButton _threshold; Gtk::SpinButton _minimum_length; Gtk::SpinButton _fade_length; + Gtk::Label _segment_count_label; struct Wave { - boost::shared_ptr region; - ArdourCanvas::WaveView* view; - std::list silence_rects; - double samples_per_unit; + boost::shared_ptr region; + ArdourCanvas::WaveView* view; + std::list silence_rects; + double samples_per_unit; + std::list >silence; + + Wave() : view (0), samples_per_unit (1) { } }; 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; 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 (); };