MacVST Program/Preset support
[ardour.git] / gtk2_ardour / strip_silence_dialog.cc
index daa540d0393ac5cbf08ba0551cb926b5c0819bbc..5fa115d69265d9655ddc1d8978a4d09d5f733971 100644 (file)
 #include <gtkmm/table.h>
 #include <gtkmm/label.h>
 #include <gtkmm/stock.h>
 #include <gtkmm/table.h>
 #include <gtkmm/label.h>
 #include <gtkmm/stock.h>
-#include "ardour/audioregion.h"
-#include "ardour/audiosource.h"
 
 
+#include "ardour/audioregion.h"
 #include "ardour/dB.h"
 #include "ardour/dB.h"
+#include "ardour/logmeter.h"
 #include "ardour_ui.h"
 #include "ardour_ui.h"
-#include "ardour/session.h"
 
 
+#include "audio_clock.h"
 #include "gui_thread.h"
 #include "strip_silence_dialog.h"
 #include "gui_thread.h"
 #include "strip_silence_dialog.h"
-#include "canvas_impl.h"
 #include "region_view.h"
 #include "region_view.h"
-#include "simpleline.h"
-#include "waveview.h"
-#include "simplerect.h"
 #include "rgb_macros.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;
@@ -48,19 +43,20 @@ 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 (X_("silence duration"), true, "SilenceDurationClock", true, false, true, false)
-        , _fade_length (X_("silence duration"), true, "SilenceDurationClock", 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);
-        
+
        Gtk::Table* table = Gtk::manage (new Gtk::Table (3, 3));
        table->set_spacings (6);
 
        Gtk::Table* table = Gtk::manage (new Gtk::Table (3, 3));
        table->set_spacings (6);
 
@@ -68,52 +64,57 @@ 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;
        ++n;
-        
+
        _threshold.set_digits (1);
        _threshold.set_increments (1, 10);
        _threshold.set_range (-120, 0);
        _threshold.set_value (-60);
        _threshold.set_digits (1);
        _threshold.set_increments (1, 10);
        _threshold.set_range (-120, 0);
        _threshold.set_value (-60);
+       _threshold.set_activates_default ();
 
        table->attach (*Gtk::manage (new Gtk::Label (_("Minimum length"), 1, 0.5)), 0, 1, n, n + 1, Gtk::FILL);
 
        table->attach (*Gtk::manage (new Gtk::Label (_("Minimum length"), 1, 0.5)), 0, 1, n, n + 1, Gtk::FILL);
-       table->attach (_minimum_length, 1, 2, n, n + 1, Gtk::FILL);
+       table->attach (*_minimum_length, 1, 2, n, n + 1, Gtk::FILL);
        ++n;
        ++n;
-       
-        _minimum_length.set_session (s);
-        _minimum_length.set_mode (AudioClock::Frames);
-        _minimum_length.set (1000, true);
 
 
-        /* Add this back when we finally do something with it */
-        /*
+       _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 ();
 
 
        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, ui_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);
 }
@@ -122,35 +123,63 @@ 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 ();
 
        _run_cond.signal ();
        pthread_join (_thread, 0);
        _thread_should_finish = true;
        _lock.unlock ();
 
        _run_cond.signal ();
        pthread_join (_thread, 0);
-       
-       delete _peaks_ready_connection;
+
+       delete _minimum_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
@@ -164,7 +193,7 @@ StripSilenceDialog::update_threshold_line ()
        for (list<Wave*>::iterator i = _waves.begin(); i != _waves.end(); ++i) {
                (*i)->threshold_line->property_x1() = 0;
                (*i)->threshold_line->property_x2() = _wave_width;
        for (list<Wave*>::iterator i = _waves.begin(); i != _waves.end(); ++i) {
                (*i)->threshold_line->property_x1() = 0;
                (*i)->threshold_line->property_x2() = _wave_width;
-               
+
                double const y = alt_log_meter (_threshold.get_value());
 
                (*i)->threshold_line->property_y1() = (n + 1 - y) * _wave_height;
                double const y = alt_log_meter (_threshold.get_value());
 
                (*i)->threshold_line->property_y1() = (n + 1 - y) * _wave_height;
@@ -180,17 +209,20 @@ 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
 StripSilenceDialog::update_silence_rects ()
 {
        /* Lock so that we don't contend with the detection thread for access to the silence regions */
 }
 
 void
 StripSilenceDialog::update_silence_rects ()
 {
        /* Lock so that we don't contend with the detection thread for access to the silence regions */
-       Glib::Mutex::Lock lm (_lock);
-        double const y = _threshold.get_value();
+       Glib::Threads::Mutex::Lock lm (_lock);
+       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);
        }
 }
 
        }
 }
 
@@ -205,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 ();
 
        /* Hold this lock when we are doing work */
        _lock.lock ();
-       
+
        while (1) {
        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 */
                }
@@ -249,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;
 
@@ -276,15 +322,15 @@ 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 _minimum_length.current_duration (views.front().view->region()->position());
+       return std::max((framecnt_t)0, _fade_length->current_duration (views.front().view->region()->position()));
 }
 }
-               
+
 void
 StripSilenceDialog::update_progress_gui (float p)
 {
 void
 StripSilenceDialog::update_progress_gui (float p)
 {