From 459c43951238fd771231f840733468b84079dcdc Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 29 Apr 2009 17:01:14 +0000 Subject: First cut of option to strip silence from audio regions, as per mantis #1623 git-svn-id: svn://localhost/ardour2/branches/3.0@5010 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/SConscript | 1 + gtk2_ardour/editor.cc | 1 + gtk2_ardour/editor.h | 1 + gtk2_ardour/editor_ops.cc | 41 ++++++++++++++++++++++- gtk2_ardour/wscript | 1 + libs/ardour/SConscript | 1 + libs/ardour/ardour/audioregion.h | 3 +- libs/ardour/ardour/crossfade.h | 2 +- libs/ardour/audioregion.cc | 71 ++++++++++++++++++++++++++++++++++++++-- libs/ardour/crossfade.cc | 2 +- libs/ardour/region.cc | 1 + libs/ardour/wscript | 1 + 12 files changed, 119 insertions(+), 7 deletions(-) diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index 0d0161d456..f09df7263a 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -242,6 +242,7 @@ simplerect.cc splash.cc startup.cc streamview.cc +strip_silence_dialog.cc tape_region_view.cc tempo_dialog.cc tempo_lines.cc diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index b129009a9c..346df2064d 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -2052,6 +2052,7 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr regi items.push_back (SeparatorElem()); } + items.push_back (MenuElem (_("Strip silence..."), mem_fun (*this, &Editor::strip_region_silence))); items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region))); items.push_back (SeparatorElem()); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 82f63792fc..167ad65b1f 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1191,6 +1191,7 @@ class Editor : public PublicEditor void audition_playlist_region_via_route (boost::shared_ptr, ARDOUR::Route&); void split_multichannel_region(); void reverse_region (); + void strip_region_silence (); void normalize_region (); void denormalize_region (); void adjust_region_scale_amplitude (bool up); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 5826033072..66286b62f0 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -54,6 +54,7 @@ #include "ardour/transient_detector.h" #include "ardour/dB.h" #include "ardour/quantize.h" +#include "ardour/strip_silence.h" #include "ardour_ui.h" #include "editor.h" @@ -73,6 +74,7 @@ #include "gui_thread.h" #include "keyboard.h" #include "utils.h" +#include "strip_silence_dialog.h" #include "i18n.h" @@ -4660,6 +4662,22 @@ Editor::reverse_region () apply_filter (rev, _("reverse regions")); } +void +Editor::strip_region_silence () +{ + if (!session) { + return; + } + + StripSilenceDialog d; + int const r = d.run (); + + if (r == Gtk::RESPONSE_OK) { + StripSilence s (*session, d.threshold (), d.minimum_length (), d.fade_length ()); + apply_filter (s, _("strip silence")); + } +} + void Editor::quantize_region () @@ -4707,7 +4725,28 @@ Editor::apply_filter (Filter& filter, string command) if (arv->audio_region()->apply (filter) == 0) { XMLNode &before = playlist->get_state(); - playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position()); + + if (filter.results.empty ()) { + + /* no regions returned; remove the old one */ + playlist->remove_region (arv->region ()); + + } else { + + std::vector >::iterator res = filter.results.begin (); + + /* first region replaces the old one */ + playlist->replace_region (arv->region(), *res, (*res)->position()); + ++res; + + /* add the rest */ + while (res != filter.results.end()) { + playlist->add_region (*res, (*res)->position()); + ++res; + } + + } + XMLNode &after = playlist->get_state(); session->add_command(new MementoCommand(*playlist, &before, &after)); } else { diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 4624440ad6..92a3650a28 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -197,6 +197,7 @@ def build(bld): splash.cc startup.cc streamview.cc + strip_silence_dialog.cc tape_region_view.cc tempo_dialog.cc tempo_lines.cc diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index d30c276840..27cffdff9d 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -159,6 +159,7 @@ sndfileimportable.cc sndfilesource.cc source.cc source_factory.cc +strip_silence.cc svn_revision.cc tape_file_matcher.cc template_utils.cc diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index 917578191f..b2e2aa3eef 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -106,7 +106,7 @@ class AudioRegion : public Region virtual nframes_t master_read_at (Sample *buf, Sample *mixdown_buf, float *gain_buf, sframes_t position, nframes_t cnt, uint32_t chan_n=0) const; - virtual nframes_t read_raw_internal (Sample*, sframes_t, nframes_t) const; + virtual nframes_t read_raw_internal (Sample*, sframes_t, nframes_t, int channel) const; XMLNode& state (bool); int set_state (const XMLNode&); @@ -162,6 +162,7 @@ class AudioRegion : public Region void resume_fade_out (); int get_transients (AnalysisFeatureList&, bool force_new = false); + std::list > find_silence (Sample, nframes_t) const; private: friend class RegionFactory; diff --git a/libs/ardour/ardour/crossfade.h b/libs/ardour/ardour/crossfade.h index bd3ee914f9..4afa38126c 100644 --- a/libs/ardour/ardour/crossfade.h +++ b/libs/ardour/ardour/crossfade.h @@ -170,7 +170,7 @@ class Crossfade : public ARDOUR::AudioRegion bool update (); protected: - nframes_t read_raw_internal (Sample*, sframes_t, nframes_t) const; + nframes_t read_raw_internal (Sample*, sframes_t, nframes_t, int) const; }; diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 085296281c..b3fd239c59 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -1062,9 +1062,9 @@ AudioRegion::separate_by_channel (Session& session, vectorread (buf, pos, cnt); + return audio_source()->read (buf, pos, cnt, channel); } int @@ -1184,7 +1184,7 @@ AudioRegion::normalize_to (float target_dB) /* read it in */ - if (read_raw_internal (buf, fpos, to_read) != to_read) { + if (read_raw_internal (buf, fpos, to_read, 0) != to_read) { return; } @@ -1438,6 +1438,71 @@ then quit ardour and restart.")); return 0; } +/** Find areas of `silence' within a region. + * + * @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 periods; first of pair is the offset within the region, second is the length of the period + */ + +std::list > +AudioRegion::find_silence (Sample threshold, nframes_t min_length) const +{ + nframes_t const block_size = 64 * 1024; + Sample loudest[block_size]; + Sample buf[block_size]; + + nframes_t pos = _start; + nframes_t const end = _start + _length - 1; + + std::list > silent_periods; + + bool in_silence = false; + nframes_t silence_start = 0; + bool silence; + + while (pos < end) { + + nframes_t const to_read = min (end - pos, block_size); + + /* fill `loudest' with the loudest absolute sample at each instant, across all channels */ + memset (loudest, 0, sizeof (Sample) * block_size); + for (uint32_t n = 0; n < n_channels(); ++n) { + + read_raw_internal (buf, pos, block_size, n); + for (nframes_t i = 0; i < block_size; ++i) { + loudest[i] = max (loudest[i], abs (buf[i])); + } + } + + /* now look for silence */ + for (nframes_t i = 0; i < block_size; ++i) { + silence = abs (loudest[i]) < threshold; + if (silence && !in_silence) { + /* non-silence to silence */ + in_silence = true; + silence_start = pos + i; + } else if (!silence && in_silence) { + /* silence to non-silence */ + in_silence = false; + if (pos + i - 1 - silence_start >= min_length) { + silent_periods.push_back (std::make_pair (silence_start, pos + i - 1)); + } + } + } + + pos += block_size; + } + + if (in_silence && end - 1 - silence_start >= min_length) { + /* last block was silent, so finish off the last period */ + silent_periods.push_back (std::make_pair (silence_start, end)); + } + + return silent_periods; +} + + extern "C" { int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit) diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc index 8aad53765a..c258a9bf73 100644 --- a/libs/ardour/crossfade.cc +++ b/libs/ardour/crossfade.cc @@ -271,7 +271,7 @@ Crossfade::initialize () } nframes_t -Crossfade::read_raw_internal (Sample* buf, sframes_t start, nframes_t cnt) const +Crossfade::read_raw_internal (Sample* buf, sframes_t start, nframes_t cnt, int channel) const { // FIXME: Why is this disabled? #if 0 diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index dcca313c79..a90a2b244d 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -1638,3 +1638,4 @@ Region::invalidate_transients () _transients.clear (); } + diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 342ca79a0a..b087e194c2 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -198,6 +198,7 @@ def build(bld): sndfilesource.cc source.cc source_factory.cc + strip_silence.cc svn_revision.cc tape_file_matcher.cc template_utils.cc -- cgit v1.2.3