correct name of Midi-UI thread memory-pool and request-queue
[ardour.git] / gtk2_ardour / strip_silence_dialog.cc
index d37fbb6585ebea29391b61f5ab9e89e47d25668a..71d25d648e8807e8e5be4e4be1e21dc4f4f5340c 100644 (file)
@@ -43,16 +43,17 @@ using namespace ArdourCanvas;
 StripSilenceDialog::StripSilenceDialog (Session* s, list<RegionView*> const & v)
        : ArdourDialog (_("Strip Silence"))
        , ProgressReporter ()
 StripSilenceDialog::StripSilenceDialog (Session* s, list<RegionView*> const & v)
        : ArdourDialog (_("Strip Silence"))
        , ProgressReporter ()
-        , _minimum_length (new AudioClock (X_("silence duration"), true, "", true, false, true, false))
-        , _fade_length (new AudioClock (X_("silence duration"), true, "", true, false, true, false))
-       , _peaks_ready_connection (0)
+       , _minimum_length (new AudioClock (X_("silence duration"), true, "", true, false, true, false))
+       , _fade_length (new AudioClock (X_("silence duration"), true, "", true, false, true, false))
        , _destroying (false)
        , _destroying (false)
+       , analysis_progress_cur (0)
+       , analysis_progress_max (0)
 {
 {
-        set_session (s);
+       set_session (s);
 
 
-        for (list<RegionView*>::const_iterator r = v.begin(); r != v.end(); ++r) {
-                views.push_back (ViewInterval (*r));
-        }
+       for (list<RegionView*>::const_iterator r = v.begin(); r != v.end(); ++r) {
+               views.push_back (ViewInterval (*r));
+       }
 
        Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox);
 
 
        Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox);
 
@@ -76,38 +77,44 @@ StripSilenceDialog::StripSilenceDialog (Session* s, list<RegionView*> const & v)
        table->attach (*_minimum_length, 1, 2, n, n + 1, Gtk::FILL);
        ++n;
 
        table->attach (*_minimum_length, 1, 2, n, n + 1, Gtk::FILL);
        ++n;
 
-        _minimum_length->set_session (s);
-        _minimum_length->set_mode (AudioClock::Frames);
-        _minimum_length->set (1000, true);
+       _minimum_length->set_session (s);
+       _minimum_length->set_mode (AudioClock::Frames);
+       _minimum_length->set (1000, true);
 
        table->attach (*Gtk::manage (new Gtk::Label (_("Fade length"), 1, 0.5)), 0, 1, n, n + 1, Gtk::FILL);
 
        table->attach (*Gtk::manage (new Gtk::Label (_("Fade length"), 1, 0.5)), 0, 1, n, n + 1, Gtk::FILL);
-        table->attach (*_fade_length, 1, 2, n, n + 1, Gtk::FILL);
+       table->attach (*_fade_length, 1, 2, n, n + 1, Gtk::FILL);
        ++n;
 
        ++n;
 
-        _fade_length->set_session (s);
-        _fade_length->set_mode (AudioClock::Frames);
-        _fade_length->set (64, true);
+       _fade_length->set_session (s);
+       _fade_length->set_mode (AudioClock::Frames);
+       _fade_length->set (64, true);
 
        hbox->pack_start (*table);
 
        get_vbox()->pack_start (*hbox, false, false);
 
 
        hbox->pack_start (*table);
 
        get_vbox()->pack_start (*hbox, false, false);
 
-       add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
-       add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_OK);
+       cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+       apply_button = add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_OK);
        set_default_response (Gtk::RESPONSE_OK);
 
        get_vbox()->pack_start (_progress_bar, true, true, 12);
 
        show_all ();
 
        set_default_response (Gtk::RESPONSE_OK);
 
        get_vbox()->pack_start (_progress_bar, true, true, 12);
 
        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::restart_thread));
+       _threshold.get_adjustment()->signal_value_changed().connect (sigc::mem_fun (*this, &StripSilenceDialog::threshold_changed));
+       _minimum_length->ValueChanged.connect (sigc::mem_fun (*this, &StripSilenceDialog::restart_thread));
+       _fade_length->ValueChanged.connect (sigc::mem_fun (*this, &StripSilenceDialog::restart_thread));
 
        update_silence_rects ();
        update_threshold_line ();
 
 
        update_silence_rects ();
        update_threshold_line ();
 
+       _progress_bar.set_text (_("Analyzing"));
+       update_progress_gui (0);
+       apply_button->set_sensitive (false);
+       progress_idle_connection = Glib::signal_idle().connect (sigc::mem_fun (*this, &StripSilenceDialog::idle_update_progress));
+
        /* Create a thread which runs while the dialogue is open to compute the silence regions */
        /* Create a thread which runs while the dialogue is open to compute the silence regions */
-       Completed.connect (_completed_connection, MISSING_INVALIDATOR, boost::bind (&StripSilenceDialog::update, this), gui_context ());
+       Completed.connect (_completed_connection, invalidator(*this), boost::bind (&StripSilenceDialog::update, this), gui_context ());
        _thread_should_finish = false;
        pthread_create (&_thread, 0, StripSilenceDialog::_detection_thread_work, this);
 }
        _thread_should_finish = false;
        pthread_create (&_thread, 0, StripSilenceDialog::_detection_thread_work, this);
 }
@@ -116,11 +123,11 @@ StripSilenceDialog::StripSilenceDialog (Session* s, list<RegionView*> const & v)
 StripSilenceDialog::~StripSilenceDialog ()
 {
        _destroying = true;
 StripSilenceDialog::~StripSilenceDialog ()
 {
        _destroying = true;
+       progress_idle_connection.disconnect();
 
        /* Terminate our thread */
 
        /* Terminate our thread */
-
-       _lock.lock ();
        _interthread_info.cancel = true;
        _interthread_info.cancel = true;
+       _lock.lock ();
        _thread_should_finish = true;
        _lock.unlock ();
 
        _thread_should_finish = true;
        _lock.unlock ();
 
@@ -129,25 +136,50 @@ StripSilenceDialog::~StripSilenceDialog ()
 
        delete _minimum_length;
        delete _fade_length;
 
        delete _minimum_length;
        delete _fade_length;
+}
 
 
-       delete _peaks_ready_connection;
+bool
+StripSilenceDialog::idle_update_progress()
+{
+       if (analysis_progress_max > 0) {
+               // AudioRegion::find_silence() has
+               // itt.progress = (end - pos) / length
+               // not sure if that's intentional, but let's use (1. - val)
+               float rp = std::min(1.f, std::max (0.f, (1.f - _interthread_info.progress)));
+               float p = analysis_progress_cur / (float) analysis_progress_max
+                       + rp / (float) analysis_progress_max;
+               update_progress_gui (p);
+       }
+       return !_destroying;
 }
 
 void
 StripSilenceDialog::silences (AudioIntervalMap& m)
 {
 }
 
 void
 StripSilenceDialog::silences (AudioIntervalMap& m)
 {
-        for (list<ViewInterval>::iterator v = views.begin(); v != views.end(); ++v) {
-                pair<boost::shared_ptr<Region>,AudioIntervalResult> newpair (v->view->region(), v->intervals);
-                m.insert (newpair);
-        }
+       for (list<ViewInterval>::iterator v = views.begin(); v != views.end(); ++v) {
+               pair<boost::shared_ptr<Region>,AudioIntervalResult> newpair (v->view->region(), v->intervals);
+               m.insert (newpair);
+       }
 }
 
 void
 StripSilenceDialog::drop_rects ()
 {
 }
 
 void
 StripSilenceDialog::drop_rects ()
 {
-        for (list<ViewInterval>::iterator v = views.begin(); v != views.end(); ++v) {
-                v->view->drop_silent_frames ();
-        }
+       // called by parent when starting to progess (dialog::run returned),
+       // but before the dialog is destoyed.
+
+       _interthread_info.cancel = true;
+
+       /* Block until the thread is idle */
+       _lock.lock ();
+       _lock.unlock ();
+
+       for (list<ViewInterval>::iterator v = views.begin(); v != views.end(); ++v) {
+               v->view->drop_silent_frames ();
+       }
+
+       cancel_button->set_sensitive (false);
+       apply_button->set_sensitive (false);
 }
 
 void
 }
 
 void
@@ -177,6 +209,9 @@ StripSilenceDialog::update ()
 {
        update_threshold_line ();
        update_silence_rects ();
 {
        update_threshold_line ();
        update_silence_rects ();
+       _progress_bar.set_text ("");
+       update_progress_gui (0);
+       apply_button->set_sensitive(true);
 }
 
 void
 }
 
 void
@@ -184,10 +219,10 @@ StripSilenceDialog::update_silence_rects ()
 {
        /* Lock so that we don't contend with the detection thread for access to the silence regions */
        Glib::Threads::Mutex::Lock lm (_lock);
 {
        /* Lock so that we don't contend with the detection thread for access to the silence regions */
        Glib::Threads::Mutex::Lock lm (_lock);
-        double const y = _threshold.get_value();
+       double const y = _threshold.get_value();
 
 
-        for (list<ViewInterval>::iterator v = views.begin(); v != views.end(); ++v) {
-                v->view->set_silent_frames (v->intervals, y);
+       for (list<ViewInterval>::iterator v = views.begin(); v != views.end(); ++v) {
+               v->view->set_silent_frames (v->intervals, y);
        }
 }
 
        }
 }
 
@@ -202,24 +237,31 @@ StripSilenceDialog::_detection_thread_work (void* arg)
 void *
 StripSilenceDialog::detection_thread_work ()
 {
 void *
 StripSilenceDialog::detection_thread_work ()
 {
-        ARDOUR_UI::instance()->register_thread ("gui", pthread_self(), "silence", 32);
+       ARDOUR_UI::instance()->register_thread ("gui", pthread_self(), "silence", 32);
 
        /* Hold this lock when we are doing work */
        _lock.lock ();
 
        while (1) {
 
        /* Hold this lock when we are doing work */
        _lock.lock ();
 
        while (1) {
+               analysis_progress_cur = 0;
+               analysis_progress_max = views.size();
                for (list<ViewInterval>::iterator i = views.begin(); i != views.end(); ++i) {
                for (list<ViewInterval>::iterator i = views.begin(); i != views.end(); ++i) {
-                        boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i).view->region());
+                       boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i).view->region());
 
 
-                        if (ar) {
-                                i->intervals = ar->find_silence (dB_to_coefficient (threshold ()), minimum_length (), _interthread_info);
-                        }
+                       if (ar) {
+                               i->intervals = ar->find_silence (dB_to_coefficient (threshold ()), minimum_length (), fade_length(), _interthread_info);
+                       }
 
                        if (_interthread_info.cancel) {
                                break;
                        }
 
                        if (_interthread_info.cancel) {
                                break;
                        }
+                       ++analysis_progress_cur;
+                       _interthread_info.progress = 1.0;
+                       ARDOUR::GUIIdle ();
                }
 
                }
 
+               analysis_progress_max = 0;
+
                if (!_interthread_info.cancel) {
                        Completed (); /* EMIT SIGNAL */
                }
                if (!_interthread_info.cancel) {
                        Completed (); /* EMIT SIGNAL */
                }
@@ -246,10 +288,14 @@ StripSilenceDialog::restart_thread ()
                   method to be called after our destructor has finished executing.
                   If this happens, bad things follow; _lock cannot be locked and
                   Ardour hangs.  So if we are destroying, just bail early.
                   method to be called after our destructor has finished executing.
                   If this happens, bad things follow; _lock cannot be locked and
                   Ardour hangs.  So if we are destroying, just bail early.
-               */
+                  */
                return;
        }
 
                return;
        }
 
+       _progress_bar.set_text (_("Analyzing"));
+       update_progress_gui (0);
+       apply_button->set_sensitive (false);
+
        /* Cancel any current run */
        _interthread_info.cancel = true;
 
        /* Cancel any current run */
        _interthread_info.cancel = true;
 
@@ -273,13 +319,13 @@ StripSilenceDialog::threshold_changed ()
 framecnt_t
 StripSilenceDialog::minimum_length () const
 {
 framecnt_t
 StripSilenceDialog::minimum_length () const
 {
-        return _minimum_length->current_duration (views.front().view->region()->position());
+       return std::max((framecnt_t)1, _minimum_length->current_duration (views.front().view->region()->position()));
 }
 
 framecnt_t
 StripSilenceDialog::fade_length () const
 {
 }
 
 framecnt_t
 StripSilenceDialog::fade_length () const
 {
-        return _fade_length->current_duration (views.front().view->region()->position());
+       return std::max((framecnt_t)0, _fade_length->current_duration (views.front().view->region()->position()));
 }
 
 void
 }
 
 void