move "logmeter.h" from gtk2_ardour into libs/ardour
[ardour.git] / gtk2_ardour / strip_silence_dialog.cc
index 01d6487f74b33dd2ad85752de2199aa6bdaac428..5fa115d69265d9655ddc1d8978a4d09d5f733971 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "ardour/audioregion.h"
 #include "ardour/dB.h"
 
 #include "ardour/audioregion.h"
 #include "ardour/dB.h"
+#include "ardour/logmeter.h"
 #include "ardour_ui.h"
 
 #include "audio_clock.h"
 #include "ardour_ui.h"
 
 #include "audio_clock.h"
@@ -32,8 +33,7 @@
 #include "strip_silence_dialog.h"
 #include "region_view.h"
 #include "rgb_macros.h"
 #include "strip_silence_dialog.h"
 #include "region_view.h"
 #include "rgb_macros.h"
-#include "i18n.h"
-#include "logmeter.h"
+#include "pbd/i18n.h"
 
 using namespace ARDOUR;
 using namespace std;
 
 using namespace ARDOUR;
 using namespace std;
@@ -43,15 +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))
+       , _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);
 
@@ -62,7 +64,7 @@ StripSilenceDialog::StripSilenceDialog (Session* s, list<RegionView*> const & v)
 
        table->attach (*Gtk::manage (new Gtk::Label (_("Threshold"), 1, 0.5)), 0, 1, n, n + 1, Gtk::FILL);
        table->attach (_threshold, 1, 2, n, n + 1, Gtk::FILL);
 
        table->attach (*Gtk::manage (new Gtk::Label (_("Threshold"), 1, 0.5)), 0, 1, n, n + 1, Gtk::FILL);
        table->attach (_threshold, 1, 2, n, n + 1, Gtk::FILL);
-       table->attach (*Gtk::manage (new Gtk::Label (_("dbFS"))), 2, 3, n, n + 1, Gtk::FILL);
+       table->attach (*Gtk::manage (new Gtk::Label (_("dBFS"))), 2, 3, n, n + 1, Gtk::FILL);
        ++n;
 
        _threshold.set_digits (1);
        ++n;
 
        _threshold.set_digits (1);
@@ -75,36 +77,42 @@ 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 */
        Completed.connect (_completed_connection, invalidator(*this), boost::bind (&StripSilenceDialog::update, this), gui_context ());
        _thread_should_finish = false;
        /* Create a thread which runs while the dialogue is open to compute the silence regions */
        Completed.connect (_completed_connection, invalidator(*this), boost::bind (&StripSilenceDialog::update, this), gui_context ());
        _thread_should_finish = false;
@@ -115,10 +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,21 +138,48 @@ StripSilenceDialog::~StripSilenceDialog ()
        delete _fade_length;
 }
 
        delete _fade_length;
 }
 
+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
@@ -173,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
@@ -180,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);
        }
 }
 
        }
 }
 
@@ -198,24 +237,34 @@ 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);
+       /* Do not register with all UIs, but do register with the GUI,
+          because we will need to queue some GUI (only) requests
+       */
+       ARDOUR_UI::instance()->register_thread (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 */
                }
@@ -242,10 +291,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;
 
@@ -269,13 +322,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