move "logmeter.h" from gtk2_ardour into libs/ardour
[ardour.git] / gtk2_ardour / strip_silence_dialog.cc
index d37fbb6585ebea29391b61f5ab9e89e47d25668a..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,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);
 
@@ -63,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);
@@ -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,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 */
                }
@@ -246,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;
 
@@ -273,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