From 1e2cae8e2d6675bc8b3377596c9267083299af13 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Wed, 2 Jul 2008 21:20:22 +0000 Subject: [PATCH] * Add library API version to headers * Add phase reset on silence (doesn't appear to make much difference) * Fix mistake in LRDF file --- Makefile.in | 2 + rubberband/RubberBandStretcher.h | 3 ++ rubberband/rubberband-c.h | 3 ++ src/SilentAudioCurve.cpp | 69 ++++++++++++++++++++++++++++++++ src/SilentAudioCurve.h | 38 ++++++++++++++++++ src/StretcherImpl.cpp | 50 ++++++++++++++++++----- src/StretcherImpl.h | 3 ++ src/StretcherProcess.cpp | 32 ++++++++------- src/ladspa/ladspa-rubberband.rdf | 2 + 9 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 src/SilentAudioCurve.cpp create mode 100644 src/SilentAudioCurve.h diff --git a/Makefile.in b/Makefile.in index fd36f1b..89bf9d3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -55,6 +55,7 @@ LIBRARY_INCLUDES := \ src/Resampler.h \ src/RingBuffer.h \ src/Scavenger.h \ + src/SilentAudioCurve.h \ src/SpectralDifferenceAudioCurve.h \ src/StretchCalculator.h \ src/StretcherImpl.h \ @@ -73,6 +74,7 @@ LIBRARY_SOURCES := \ src/Resampler.cpp \ src/rubberband-c.cpp \ src/RubberBandStretcher.cpp \ + src/SilentAudioCurve.cpp \ src/SpectralDifferenceAudioCurve.cpp \ src/StretchCalculator.cpp \ src/StretcherImpl.cpp \ diff --git a/rubberband/RubberBandStretcher.h b/rubberband/RubberBandStretcher.h index 8ddc867..2358d95 100644 --- a/rubberband/RubberBandStretcher.h +++ b/rubberband/RubberBandStretcher.h @@ -14,6 +14,9 @@ #ifndef _RUBBERBANDSTRETCHER_H_ #define _RUBBERBANDSTRETCHER_H_ + +#define RUBBERBAND_API_MAJOR_VERSION 2 +#define RUBBERBAND_API_MINOR_VERSION 0 #include diff --git a/rubberband/rubberband-c.h b/rubberband/rubberband-c.h index 8fe92bb..d32dac7 100644 --- a/rubberband/rubberband-c.h +++ b/rubberband/rubberband-c.h @@ -19,6 +19,9 @@ extern "C" { #endif +#define RUBBERBAND_API_MAJOR_VERSION 2 +#define RUBBERBAND_API_MINOR_VERSION 0 + /** * This is a C-linkage interface to the Rubber Band time stretcher. * diff --git a/src/SilentAudioCurve.cpp b/src/SilentAudioCurve.cpp new file mode 100644 index 0000000..b445646 --- /dev/null +++ b/src/SilentAudioCurve.cpp @@ -0,0 +1,69 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007-2008 Chris Cannam. + + 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 the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "SilentAudioCurve.h" + +#include + +namespace RubberBand +{ + +SilentAudioCurve::SilentAudioCurve(size_t sampleRate, size_t windowSize) : + AudioCurve(sampleRate, windowSize) +{ +} + +SilentAudioCurve::~SilentAudioCurve() +{ +} + +void +SilentAudioCurve::reset() +{ +} + +void +SilentAudioCurve::setWindowSize(size_t newSize) +{ + m_windowSize = newSize; +} + +float +SilentAudioCurve::process(const float *R__ mag, size_t) +{ + const int hs = m_windowSize / 2; + static float threshold = powf(10.f, -6); + + for (int i = 0; i <= hs; ++i) { + if (mag[i] > threshold) return 0.f; + } + + return 1.f; +} + +float +SilentAudioCurve::process(const double *R__ mag, size_t) +{ + const int hs = m_windowSize / 2; + static double threshold = pow(10.0, -6); + + for (int i = 0; i <= hs; ++i) { + if (mag[i] > threshold) return 0.f; + } + + return 1.f; +} + +} + diff --git a/src/SilentAudioCurve.h b/src/SilentAudioCurve.h new file mode 100644 index 0000000..ec7009a --- /dev/null +++ b/src/SilentAudioCurve.h @@ -0,0 +1,38 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007-2008 Chris Cannam. + + 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 the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _SILENT_AUDIO_CURVE_H_ +#define _SILENT_AUDIO_CURVE_H_ + +#include "AudioCurve.h" + +namespace RubberBand +{ + +class SilentAudioCurve : public AudioCurve +{ +public: + SilentAudioCurve(size_t sampleRate, size_t windowSize); + virtual ~SilentAudioCurve(); + + virtual void setWindowSize(size_t newSize); + + virtual float process(const float *R__ mag, size_t increment); + virtual float process(const double *R__ mag, size_t increment); + virtual void reset(); +}; + +} + +#endif diff --git a/src/StretcherImpl.cpp b/src/StretcherImpl.cpp index 47b0d90..71f4ee6 100644 --- a/src/StretcherImpl.cpp +++ b/src/StretcherImpl.cpp @@ -16,6 +16,7 @@ #include "PercussiveAudioCurve.h" #include "HighFrequencyAudioCurve.h" #include "SpectralDifferenceAudioCurve.h" +#include "SilentAudioCurve.h" #include "ConstantAudioCurve.h" #include "StretchCalculator.h" #include "StretcherChannelData.h" @@ -72,6 +73,7 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate, m_studyFFT(0), m_spaceAvailable("space"), m_inputDuration(0), + m_silentHistory(0), m_lastProcessOutputIncrements(16), m_lastProcessPhaseResetDf(16), m_phaseResetAudioCurve(0), @@ -163,6 +165,7 @@ RubberBandStretcher::Impl::~Impl() delete m_phaseResetAudioCurve; delete m_stretchAudioCurve; + delete m_silentAudioCurve; delete m_stretchCalculator; delete m_studyFFT; @@ -196,7 +199,9 @@ RubberBandStretcher::Impl::reset() m_mode = JustCreated; if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset(); if (m_stretchAudioCurve) m_stretchAudioCurve->reset(); + if (m_silentAudioCurve) m_silentAudioCurve->reset(); m_inputDuration = 0; + m_silentHistory = 0; if (m_threaded) m_threadSetMutex.unlock(); @@ -361,8 +366,8 @@ RubberBandStretcher::Impl::calculateSizes() outputIncrement /= 2; inputIncrement = int(outputIncrement / r); } - size_t minwin = roundUp(lrint(outputIncrement * windowIncrRatio)); - if (windowSize < minwin) windowSize = minwin; + size_t minwin = roundUp(lrint(outputIncrement * windowIncrRatio)); + if (windowSize < minwin) windowSize = minwin; if (rsb) { // cerr << "adjusting window size from " << windowSize; @@ -546,12 +551,17 @@ RubberBandStretcher::Impl::configure() } } - delete m_phaseResetAudioCurve; - m_phaseResetAudioCurve = new PercussiveAudioCurve(m_sampleRate, - m_windowSize); + // stretchAudioCurve is unused in RT mode; phaseResetAudioCurve, + // silentAudioCurve and stretchCalculator however are used in all + // modes - // stretchAudioCurve unused in RT mode; phaseResetAudioCurve and - // stretchCalculator however are used in all modes + delete m_phaseResetAudioCurve; + m_phaseResetAudioCurve = new PercussiveAudioCurve + (m_sampleRate, m_windowSize); + + delete m_silentAudioCurve; + m_silentAudioCurve = new SilentAudioCurve + (m_sampleRate, m_windowSize); if (!m_realtime) { delete m_stretchAudioCurve; @@ -602,6 +612,7 @@ RubberBandStretcher::Impl::reconfigure() calculateStretch(); m_phaseResetDf.clear(); m_stretchDf.clear(); + m_silence.clear(); m_inputDuration = 0; } configure(); @@ -782,8 +793,8 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool consumed += writable; } - while ((inbuf.getReadSpace() >= m_windowSize) || - (final && (inbuf.getReadSpace() >= m_windowSize/2))) { + while ((inbuf.getReadSpace() >= int(m_windowSize)) || + (final && (inbuf.getReadSpace() >= int(m_windowSize/2)))) { // We know we have at least m_windowSize samples available // in m_inbuf. We need to peek m_windowSize of them for @@ -811,6 +822,11 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool df = m_stretchAudioCurve->process(cd.fltbuf, m_increment); m_stretchDf.push_back(df); + df = m_silentAudioCurve->process(cd.fltbuf, m_increment); + bool silent = (df > 0.f); + if (silent) cerr << "silence found at " << m_inputDuration << endl; + m_silence.push_back(silent); + // cout << df << endl; // We have augmented the input by m_windowSize/2 so @@ -892,6 +908,20 @@ RubberBandStretcher::Impl::calculateStretch() m_phaseResetDf, m_stretchDf); + int history = 0; + for (size_t i = 0; i < increments.size(); ++i) { + if (i >= m_silence.size()) break; + if (m_silence[i]) ++history; + else history = 0; + if (history >= (m_windowSize / m_increment) && increments[i] >= 0) { + increments[i] = -increments[i]; +// if (m_debugLevel > 1) { + std::cerr << "phase reset on silence (silent history == " + << history << ")" << std::endl; +// } + } + } + if (m_outputIncrements.empty()) m_outputIncrements = increments; else { for (size_t i = 0; i < increments.size(); ++i) { @@ -1055,7 +1085,7 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo */ } - if (!allConsumed) cerr << "process looping" << endl; +// if (!allConsumed) cerr << "process looping" << endl; } diff --git a/src/StretcherImpl.h b/src/StretcherImpl.h index 9601205..996c61b 100644 --- a/src/StretcherImpl.h +++ b/src/StretcherImpl.h @@ -166,6 +166,8 @@ protected: size_t m_inputDuration; std::vector m_phaseResetDf; std::vector m_stretchDf; + std::vector m_silence; + int m_silentHistory; class ChannelData; std::vector m_channelData; @@ -177,6 +179,7 @@ protected: AudioCurve *m_phaseResetAudioCurve; AudioCurve *m_stretchAudioCurve; + AudioCurve *m_silentAudioCurve; StretchCalculator *m_stretchCalculator; float m_freq0; diff --git a/src/StretcherProcess.cpp b/src/StretcherProcess.cpp index 26c3773..9ff6bee 100644 --- a/src/StretcherProcess.cpp +++ b/src/StretcherProcess.cpp @@ -147,8 +147,6 @@ RubberBandStretcher::Impl::consumeChannel(size_t c, const float *input, } -// std::cerr << "resampling on INPUT" << std::endl; - toWrite = cd.resampler->resample(&input, &cd.resamplebuf, samples, @@ -445,10 +443,12 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn, // be apparent. float df = 0.f; + bool silent = false; if (m_channels == 1) { df = m_phaseResetAudioCurve->process(cd.mag, m_increment); + silent = (m_silentAudioCurve->process(cd.mag, m_increment) > 0.f); } else { @@ -464,7 +464,8 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn, } df = m_phaseResetAudioCurve->process(tmp, m_increment); - } + silent = (m_silentAudioCurve->process(tmp, m_increment) > 0.f); + } int incr = m_stretchCalculator->calculateSingle (getEffectiveRatio(), df, m_increment); @@ -499,6 +500,17 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn, } cd.prevIncrement = shiftIncrementRtn; + + if (silent) ++m_silentHistory; + else m_silentHistory = 0; + + if (m_silentHistory >= (m_windowSize / m_increment) && !phaseReset) { + phaseReset = true; + if (m_debugLevel > 1) { + std::cerr << "calculateIncrements: phase reset on silence (silent history == " + << m_silentHistory << ")" << std::endl; + } + } } bool @@ -852,12 +864,9 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel) dblbuf[i] /= denom; } - //!!! calculate this value -- the divisor should be the highest fundamental frequency we expect to find, plus a bit const int cutoff = m_sampleRate / 700; -// const int cutoff = 1000; -// const int cutoff = 20; -// cerr <<"cutoff = "<< cutoff << ", m_sampleRate/cutoff = " << m_sampleRate/cutoff << ", m_sampleRate/700 = " << m_sampleRate/700 << endl; +// cerr <<"cutoff = "<< cutoff << ", m_sampleRate/cutoff = " << m_sampleRate/cutoff << endl; dblbuf[0] /= 2; dblbuf[cutoff-1] /= 2; @@ -880,7 +889,7 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel) // scaling up, we want a new envelope that is lower by the pitch factor for (int target = 0; target <= hs; ++target) { int source = lrint(target * m_pitchScale); - if (source > m_windowSize) { + if (source > int(m_windowSize)) { envelope[target] = 0.0; } else { envelope[target] = envelope[source]; @@ -897,7 +906,6 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel) for (int i = 0; i <= hs; ++i) { mag[i] *= envelope[i]; -// mag[i] = envelope[i]; } cd.unchanged = false; @@ -957,10 +965,8 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel) // our ffts produced unscaled results for (i = 0; i < sz; ++i) { - fltbuf[i] = fltbuf[i] / float(sz * cd.oversample); + fltbuf[i] = fltbuf[i] / denom; } -// } else { -// cerr << "unchanged on channel " << channel << endl; } m_window->cut(fltbuf); @@ -1030,8 +1036,6 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo } -// std::cerr << "resampling on OUTPUT" << std::endl; - size_t outframes = cd.resampler->resample(&cd.accumulator, &cd.resamplebuf, si, diff --git a/src/ladspa/ladspa-rubberband.rdf b/src/ladspa/ladspa-rubberband.rdf index c2df663..23a3cef 100644 --- a/src/ladspa/ladspa-rubberband.rdf +++ b/src/ladspa/ladspa-rubberband.rdf @@ -10,3 +10,5 @@ + +