make strip silence work (again?)
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 9 Dec 2010 16:31:05 +0000 (16:31 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 9 Dec 2010 16:31:05 +0000 (16:31 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@8226 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/editor_ops.cc
gtk2_ardour/region_view.cc
gtk2_ardour/strip_silence_dialog.cc
gtk2_ardour/strip_silence_dialog.h
libs/ardour/ardour/strip_silence.h
libs/ardour/ardour/types.h
libs/ardour/audioregion.cc
libs/ardour/audiosource.cc
libs/ardour/strip_silence.cc

index 4ad205c425ae952aadbd4a431d43efec37404828..798496af743789ff3e7436244e0979434964adda 100644 (file)
@@ -4556,10 +4556,12 @@ Editor::strip_region_silence ()
        StripSilenceDialog d (_session, audio_only);
        int const r = d.run ();
 
-       if (r == Gtk::RESPONSE_OK) {
-               StripSilence s (*_session, d.threshold (), d.minimum_length (), d.fade_length ());
+        d.drop_rects ();
+       
+        if (r == Gtk::RESPONSE_OK) {
+               StripSilence s (*_session, d.silences(), d.fade_length());
                apply_filter (s, _("strip silence"), &d);
-       }
+       } 
 }
 
 Command*
index 76fa158f9db36c0f2d0c0b598a700aae1315090f..85770d731eac8a32ab8f17deaec2098a65498a9c 100644 (file)
@@ -24,7 +24,6 @@
 #include <gtkmm.h>
 
 #include <gtkmm2ext/gtk_ui.h>
-#include "pbd/stacktrace.h"
 
 #include "ardour/playlist.h"
 #include "ardour/audioregion.h"
@@ -224,43 +223,77 @@ void
 RegionView::set_silent_frames (const AudioIntervalResult& silences)
 {
         framecnt_t shortest = max_framecnt;
+        framecnt_t shortest_audible = max_framecnt;
+        bool seen_audible = false;
 
        /* remove old silent frames */
         drop_silent_frames ();
 
         if (!silences.empty()) {
+
                 uint32_t const color = ARDOUR_UI::config()->canvasvar_Silence.get();
+                framecnt_t last_end;
+
+                if (silences.front().first != 0) {
+                        /* use initial non-silent segment as shortest */
+                        shortest_audible = silences.front().first;
+                        seen_audible = true;
+                }
                 
                 for (AudioIntervalResult::const_iterator i = silences.begin(); i != silences.end(); ++i) {
-                        
+
+                        if ((*i).first > last_end) {
+                                /* (audible) gap between the end of the last interval and this one */
+                                shortest_audible = min (shortest_audible, (*i).first - last_end);
+                                seen_audible = true;
+                        }
+
                         
                         ArdourCanvas::SimpleRect* cr = new ArdourCanvas::SimpleRect (*group);
                         _silent_frames.push_back (cr);
-                        cr->property_x1() = trackview.editor().frame_to_pixel ((*i).first);
+
+                        /* coordinates for the rect are relative to the regionview origin */
+
+                        cr->property_x1() = trackview.editor().frame_to_pixel ((*i).first - _region->start());
                         cr->property_y1() = 1;
                         cr->property_y2() = _height - 2;
                         cr->property_outline_pixels() = 0;
                         cr->property_fill_color_rgba () = color;
-                        cr->property_x2() = trackview.editor().frame_to_pixel ((*i).first + (*i).second);
 
-                        if ((*i).second < shortest) {
+                        last_end = (*i).second;
+
+                        cr->property_x2() = trackview.editor().frame_to_pixel ((*i).second - _region->start());
+
+                        if (((*i).second - (*i).first) < shortest) {
                                 shortest= (*i).second;
                         }
                 }
                 
+                if (last_end != _region->length()) {
+                        shortest_audible = min (shortest_audible, _region->last_frame() - last_end);
+                        seen_audible = true;
+                }
+
                 _silence_text = new ArdourCanvas::NoEventText (*group);
                 _silence_text->property_font_desc() = *(get_font_for_style (N_("VerboseCanvasCusor")));
                 _silence_text->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SilenceText.get();                                                
                 _silence_text->property_anchor() = ANCHOR_NW;
 
-                /* both positions are relative to the RV start */
+                /* both positions are relative to the region start offset in source */
                 
-                _silence_text->property_x() = trackview.editor().frame_to_pixel (silences.front().first) + 10.0;
+                _silence_text->property_x() = trackview.editor().frame_to_pixel (silences.front().first - _region->start()) + 10.0;
                 _silence_text->property_y() = 20.0;
 
                 double ms;
                 char const * sunits;
+                char const * noun;
                 
+                if (silences.size() > 1) {
+                        noun = _("silent segments");
+                } else {
+                        noun = _("silent segment");
+                }
+
                 ms = (float) shortest/_region->session().frame_rate();
                 
                 /* ms are now in seconds */
@@ -275,11 +308,29 @@ RegionView::set_silent_frames (const AudioIntervalResult& silences)
                         sunits = _("secs");
                 }
 
+                if (seen_audible) {
+                        /* ms are now in seconds */
+                        double ma = shortest_audible / _region->session().frame_rate();
+                        char const * aunits;
+
+                        if (ma >= 60.0) {
+                                aunits = _("minutes");
+                                ma /= 60.0;
+                        } else if (ma < 1.0) {
+                                aunits = _("msecs");
+                                ma *= 1000.0;
+                        } else {
+                                aunits = _("secs");
+                        }
 
-                
-                _silence_text->property_text() = string_compose (_("%1 silent segments, shortest = %2 %3"),
-                                                                 silences.size(), ms, sunits).c_str();
-        }
+                        _silence_text->property_text() = string_compose (_("%1 %2, shortest = %3 %4\n  (shortest audible segment = %5 %6)"),
+                                                                         silences.size(), noun, 
+                                                                         ms, sunits, ma, aunits).c_str();
+                } else {
+                        _silence_text->property_text() = string_compose (_("%1 %2, shortest = %3 %4"),
+                                                                         silences.size(), noun, ms, sunits).c_str();
+                }
+        } 
 }
 
 void
@@ -298,6 +349,7 @@ RegionView::drop_silent_frames ()
                delete *i;
        }
         _silent_frames.clear ();
+
         delete _silence_text;
         _silence_text = 0;
 }
index da01387ffdec7731597efb07bea1b5496f287b9a..3e62e4247a9ee17fd910597d332f29c2cae0803f 100644 (file)
@@ -94,37 +94,12 @@ StripSilenceDialog::StripSilenceDialog (Session* s, list<RegionView*> const & v)
 
        hbox->pack_start (*table);
 
-       table = Gtk::manage (new Gtk::Table (3, 2));
-       table->set_spacings (6);
-       
-       n = 0;
-       
-       table->attach (*Gtk::manage (new Gtk::Label (_("Silent segments:"), 1, 0.5)), 3, 4, n, n + 1, Gtk::FILL);
-        table->attach (_segment_count_label, 5, 6, n, n + 1, Gtk::FILL);
-       _segment_count_label.set_alignment (0, 0.5);
-       ++n;
-
-       table->attach (*Gtk::manage (new Gtk::Label (_("Shortest silence:"), 1, 0.5)), 3, 4, n, n + 1, Gtk::FILL);
-        table->attach (_shortest_silence_label, 5, 6, n, n + 1, Gtk::FILL);
-       _shortest_silence_label.set_alignment (0, 0.5);
-       ++n;
-
-       table->attach (*Gtk::manage (new Gtk::Label (_("Shortest audible:"), 1, 0.5)), 3, 4, n, n + 1, Gtk::FILL);
-        table->attach (_shortest_audible_label, 5, 6, n, n + 1, Gtk::FILL);
-       _shortest_audible_label.set_alignment (0, 0.5);
-       ++n;
-       
-       hbox->pack_start (*table);
-
-       /* dummy label for padding */
-       hbox->pack_start (*Gtk::manage (new Gtk::Label ("")), true, true);
-
        get_vbox()->pack_start (*hbox, false, false);
 
        add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
        add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_OK);
 
-       get_vbox()->pack_start (_progress_bar, true, true);
+       get_vbox()->pack_start (_progress_bar, true, true, 12);
 
        show_all ();
 
@@ -155,11 +130,28 @@ StripSilenceDialog::~StripSilenceDialog ()
        _run_cond.signal ();
        pthread_join (_thread, 0);
        
+       delete _peaks_ready_connection;
+}
+
+AudioIntervalMap
+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);
+        }
+
+        return m;
+}
+
+void
+StripSilenceDialog::drop_rects ()
+{
         for (list<ViewInterval>::iterator v = views.begin(); v != views.end(); ++v) {
                 (*v).view->drop_silent_frames ();
         }
-       
-       delete _peaks_ready_connection;
 }
 
 void
@@ -187,75 +179,18 @@ StripSilenceDialog::update_threshold_line ()
 void
 StripSilenceDialog::update ()
 {
-        cerr << "UPDATE!\n";
        update_threshold_line ();
-       /* XXX: first one only?! */
-       // update_stats (_waves.front()->silence);
-
        update_silence_rects ();
-        cerr << "UPDATE done\n";
 }
 
 void
 StripSilenceDialog::update_silence_rects ()
 {
-        uint32_t max_segments = 0;
-
        /* Lock so that we don't contend with the detection thread for access to the silence regions */
        Glib::Mutex::Lock lm (_lock);
-        
         for (list<ViewInterval>::iterator v = views.begin(); v != views.end(); ++v) {
                 (*v).view->set_silent_frames ((*v).intervals);
-                max_segments = max (max_segments, (uint32_t) (*v).intervals.size());
        }
-
-#if 0
-        cerr << "minaudible in update " << min_audible << " minsilence = " << min_silence << endl;
-
-        if (min_audible > 0) {
-                float ms, ma;
-                char const * aunits;
-                char const * sunits;
-
-                ma = (float) min_audible/_session->frame_rate();
-                ms = (float) min_silence/_session->frame_rate();
-
-                /* ma and ms are now in seconds */
-
-                if (ma >= 60.0) {
-                        aunits = _("minutes");
-                        //ma /= 60.0;
-                } else if (min_audible < _session->frame_rate()) {
-                        aunits = _("msecs");
-                        ma *= 1000.0;
-                } else {
-                        aunits = _("seconds");
-                }
-
-                if (ms >= 60.0) {
-                        sunits = _("minutes");
-                        //ms /= 60.0;
-                } else if (min_silence < _session->frame_rate()) {
-                        sunits = _("ms");
-                        ms *= 1000.0;
-                } else {
-                        sunits = _("s");
-                }
-
-                _segment_count_label.set_text (string_compose ("%1", max_segments));
-               if (max_segments > 0) {
-                       _shortest_silence_label.set_text (string_compose ("%1 %2", ms, sunits));
-                       _shortest_audible_label.set_text (string_compose ("%1 %2", ma, aunits));
-               } else {
-                       _shortest_silence_label.set_text ("");
-                       _shortest_audible_label.set_text ("");
-               }
-        } else {
-                _segment_count_label.set_text (_("Full silence"));
-               _shortest_silence_label.set_text ("");
-               _shortest_audible_label.set_text ("");
-        }
-#endif
 }
 
 void *
@@ -337,77 +272,6 @@ StripSilenceDialog::threshold_changed ()
        restart_thread ();
 }
 
-void
-StripSilenceDialog::update_stats (const AudioIntervalResult& res)
-{
-        if (res.empty()) {
-                return;
-        }
-
-        max_silence = 0;
-        min_silence = max_framepos;
-        max_audible = 0;
-        min_audible = max_framepos;
-        
-        AudioIntervalResult::const_iterator cur;
-        bool saw_silence = false;
-        bool saw_audible = false;
-
-        cur = res.begin();
-
-        framepos_t start = 0;
-        framepos_t end;
-        bool in_silence;
-
-        if (cur->first == 0) {
-                /* initial segment, starting at zero, is silent */
-                end = cur->second;
-                in_silence = true;
-        } else {
-                /* initial segment, starting at zero, is audible */
-                end = cur->first;
-                in_silence = false;
-        }
-
-        while (cur != res.end()) {
-
-                framecnt_t interval_duration;
-
-                interval_duration = end - start;
-
-                if (in_silence) {
-                        saw_silence = true;
-                        cerr << "Silent duration: " << interval_duration << endl;
-
-                        max_silence = max (max_silence, interval_duration);
-                        min_silence = min (min_silence, interval_duration);
-                } else {
-                        saw_audible = true;
-                        cerr << "Audible duration: " << interval_duration << endl;
-
-                        max_audible = max (max_audible, interval_duration);
-                        min_audible = min (min_audible, interval_duration);
-                }
-
-                start = end;
-                ++cur;
-                end = cur->first;
-                in_silence = !in_silence;
-        }
-
-        if (!saw_silence) {
-                min_silence = 0;
-                max_silence = 0;
-        }
-
-        if (!saw_audible) {
-                min_audible = 0;
-                max_audible = 0;
-        }
-
-        cerr << "max aud: " << max_audible << " min aud: " << min_audible << " max sil: " << max_silence << " min sil: " << min_silence << endl;
-}
-
 framecnt_t
 StripSilenceDialog::minimum_length () const
 {
index 62e58e7db5174699c70cf125429aedf89d061856..9ac32b25f6083efa8a9e209eea0811d59cd5f3eb 100644 (file)
@@ -42,6 +42,10 @@ public:
                return _threshold.get_value ();
        }
 
+        void drop_rects ();
+
+        ARDOUR::AudioIntervalMap silences ();
+        
        ARDOUR::framecnt_t minimum_length () const;
         ARDOUR::framecnt_t fade_length () const;
 
@@ -61,9 +65,6 @@ private:
        Gtk::SpinButton _threshold;
        AudioClock      _minimum_length;
         AudioClock      _fade_length;
-        Gtk::Label      _segment_count_label;
-       Gtk::Label      _shortest_silence_label;
-       Gtk::Label      _shortest_audible_label;
        Gtk::ProgressBar _progress_bar;
 
         struct ViewInterval {
@@ -75,11 +76,6 @@ private:
 
         std::list<ViewInterval> views;
 
-        ARDOUR::framecnt_t max_audible;
-        ARDOUR::framecnt_t min_audible;
-        ARDOUR::framecnt_t max_silence;
-        ARDOUR::framecnt_t min_silence;
-
        PBD::ScopedConnection* _peaks_ready_connection;
 
        bool _destroying;
index 91374be88a59370e737c6b73520fdc1932b44fef..ff1d1b7f17c4c652b289a149a429ac87d821a99c 100644 (file)
 namespace ARDOUR {
 
 /// A filter to strip silence from regions
-class StripSilence : public Filter {
-
-public:
-       StripSilence (Session &, double, framecnt_t, framecnt_t);
+class StripSilence : public Filter 
+{
+  public:
+       StripSilence (Session &, const AudioIntervalMap&, framecnt_t fade_length);
 
        int run (boost::shared_ptr<ARDOUR::Region>, Progress* progress = 0);
 
 private:
-       double _threshold; ///< silence threshold, in dBFS
-       framecnt_t _minimum_length; ///< minimum length to be considered silence, in samples
+        AudioIntervalMap _smap;
        framecnt_t _fade_length; ///< fade in/out to use on trimmed regions, in samples
 };
 
index cae2d5bcf75f2b58192c243bfed2fb72c07674b9..92739c3cd6be058fda75007dc67279cdbc18ebda 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <istream>
 #include <vector>
+#include <map>
 #include <boost/shared_ptr.hpp>
 #include <sys/types.h>
 #include <stdint.h>
@@ -46,6 +47,7 @@ namespace ARDOUR {
        class Source;
        class AudioSource;
        class Route;
+        class Region;
 
        typedef jack_default_audio_sample_t Sample;
        typedef float                       pan_t;
@@ -74,6 +76,8 @@ namespace ARDOUR {
 
         // a set of (time) intervals: first of pair is the offset within the region, second is the length of the interval
         typedef std::list<std::pair<frameoffset_t,framecnt_t> > AudioIntervalResult;
+        // associate a set of intervals with regions (e.g. for silence detection)
+        typedef std::map<boost::shared_ptr<ARDOUR::Region>,AudioIntervalResult> AudioIntervalMap;
 
        struct IOChange {
 
index 84709d7bb2d0bdc6df3e3b99c3d4532348f94b7a..5c213bfb7cacac75d7f7b7637c72378e02d21d2b 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <set>
 
+#include <boost/scoped_array.hpp>
 
 #include <glibmm/thread.h>
 
@@ -1498,15 +1499,15 @@ in this and future transient-detection operations.\n\
  *
  *  @param threshold Threshold below which signal is considered silence (as a sample value)
  *  @param min_length Minimum length of silent period to be reported.
- *  @return Silent intervals
+ *  @return Silent intervals, measured relative to the region start in the source
  */
 
 AudioIntervalResult
 AudioRegion::find_silence (Sample threshold, framecnt_t min_length, InterThreadInfo& itt) const
 {
        framecnt_t const block_size = 64 * 1024;
-       Sample loudest[block_size];
-       Sample buf[block_size];
+       boost::scoped_array<Sample> loudest (new Sample[block_size]);
+        boost::scoped_array<Sample> buf (new Sample[block_size]);
 
        framepos_t pos = _start;
        framepos_t const end = _start + _length - 1;
@@ -1520,10 +1521,10 @@ AudioRegion::find_silence (Sample threshold, framecnt_t min_length, InterThreadI
        while (pos < end && !itt.cancel) {
 
                /* fill `loudest' with the loudest absolute sample at each instant, across all channels */
-               memset (loudest, 0, sizeof (Sample) * block_size);
+               memset (loudest.get(), 0, sizeof (Sample) * block_size);
                for (uint32_t n = 0; n < n_channels(); ++n) {
 
-                       read_raw_internal (buf, pos, block_size, n);
+                       read_raw_internal (buf.get(), pos, block_size, n);
                        for (framecnt_t i = 0; i < block_size; ++i) {
                                loudest[i] = max (loudest[i], abs (buf[i]));
                        }
index 38261f3cbb662a275dc6a184e7f187388d34b085..b993a093b50b0eda3087bee4ac25154c4e08c9f9 100644 (file)
@@ -238,7 +238,7 @@ AudioSource::initialize_peakfile (bool newfile, string audio_path)
 
                /* we found it in the peaks dir, so check it out */
 
-               if (statbuf.st_size == 0 || ((framecnt_t) statbuf.st_size < ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
+               if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
                        // empty
                        _peaks_built = false;
                } else {
index cf03c2df8ba95b8e54bd473d851209f7f4419845..cd7ab879e7e6bd4fee9af90d242f28f992b141ad 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2009 Paul Davis
+    Copyright (C) 2009-2010 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -35,8 +35,10 @@ using namespace ARDOUR;
  *  @param fade_length Length of fade in/out to apply to trimmed regions, in samples.
  */
 
-StripSilence::StripSilence (Session & s, double threshold, framecnt_t minimum_length, framecnt_t fade_length)
-       : Filter (s), _threshold (threshold), _minimum_length (minimum_length), _fade_length (fade_length)
+StripSilence::StripSilence (Session & s, const AudioIntervalMap& sm, framecnt_t fade_length)
+       : Filter (s)
+        , _smap (sm)
+        , _fade_length (fade_length)
 {
 
 }
@@ -51,15 +53,19 @@ StripSilence::run (boost::shared_ptr<Region> r, Progress* progress)
         */
        boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
         InterThreadInfo itt;
-        
+        AudioIntervalMap::const_iterator sm;
+
        if (!region) {
                results.push_back (r);
                return -1;
        }
 
-       /* find periods of silence in the region */
-       std::list<std::pair<frameoffset_t, framecnt_t> > const silence =
-               region->find_silence (dB_to_coefficient (_threshold), _minimum_length, itt);
+        if ((sm = _smap.find (r)) == _smap.end()) {
+               results.push_back (r);
+               return -1;
+        }
+
+        const AudioIntervalResult& silence = sm->second;
 
        if (silence.size () == 1 && silence.front().first == 0 && silence.front().second == region->length() - 1) {
                /* the region is all silence, so just return with nothing */
@@ -72,19 +78,21 @@ StripSilence::run (boost::shared_ptr<Region> r, Progress* progress)
                return 0;
        }
 
-       std::list<std::pair<framepos_t, framecnt_t > >::const_iterator s = silence.begin ();
+        AudioIntervalResult::const_iterator s = silence.begin ();
         PBD::PropertyList plist;
-        framepos_t start = 0;
+        framepos_t start;
         framepos_t end;
         bool in_silence;
         boost::shared_ptr<AudioRegion> copy;
 
-        if (s->first == 0) {
-                /* initial segment, starting at zero, is silent */
+        start = r->start();
+
+        if (s->first == start) {
+                /* segment starting at zero is silent */
                 end = s->second;
                 in_silence = true;
         } else {
-                /* initial segment, starting at zero, is audible */
+                /* segment starting at zero is audible, and begins at the start of the region in the source */
                 end = s->first;
                 in_silence = false;
         }
@@ -92,42 +100,44 @@ StripSilence::run (boost::shared_ptr<Region> r, Progress* progress)
        int n = 0;
        int const N = silence.size ();
 
-        while (s != silence.end()) {
+        while (start < r->start() + r->length()) {
 
                 framecnt_t interval_duration;
 
                 interval_duration = end - start;
 
-
                 if (!in_silence && interval_duration > 0) {
 
                         plist.clear ();
                         plist.add (Properties::length, interval_duration);
-                        plist.add (Properties::position, region->position() + start);
+                        plist.add (Properties::position, r->position() + (start - r->start()));
 
                         copy = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create 
-                                                                         (region, start, plist));
+                                                                         (region, (start - r->start()), plist));
 
                         copy->set_name (RegionFactory::new_region_name (region->name ()));
 
-                        std::cerr << "New silent delineated region called " << copy->name()
-                                  << " @ " << copy->start() << " length = " << copy->length() << " pos = " << 
-                                copy->position() << std::endl;
-
                         copy->set_fade_in_active (true);
                         copy->set_fade_in (FadeLinear, _fade_length);
                         results.push_back (copy);
                 }
 
                 start = end;
-                ++s;
-                end = s->first;
                 in_silence = !in_silence;
+                ++s;
+
+                if (s == silence.end()) {
+                        end = r->start() + r->length();
+                } else {
+                        end = s->first;
+                }
 
-               if (progress) {
+               ++n;
+
+               if (progress && (n <= N)) {
                        progress->set_progress (float (n) / N);
                }
-               ++n;
+
         }
 
        return 0;