diff --git a/README.md b/README.md index 8552a8b..c6bcc6e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ An audio time-stretching and pitch-shifting library and utility program. Written by Chris Cannam, chris.cannam@breakfastquay.com. Published by Particular Programs Ltd t/a Breakfast Quay. -Copyright 2007-2020 Particular Programs Ltd. +Copyright 2007-2021 Particular Programs Ltd. Rubber Band is a library and utility program that permits changing the tempo and pitch of an audio recording independently of one another. diff --git a/ladspa/RubberBandPitchShifter.cpp b/ladspa/RubberBandPitchShifter.cpp index 75434c3..868d59f 100644 --- a/ladspa/RubberBandPitchShifter.cpp +++ b/ladspa/RubberBandPitchShifter.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/ladspa/RubberBandPitchShifter.h b/ladspa/RubberBandPitchShifter.h index 08a0cb6..15a1cf4 100644 --- a/ladspa/RubberBandPitchShifter.h +++ b/ladspa/RubberBandPitchShifter.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/ladspa/libmain.cpp b/ladspa/libmain.cpp index f1dbc69..8eabbb4 100644 --- a/ladspa/libmain.cpp +++ b/ladspa/libmain.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/main/main.cpp b/main/main.cpp index 8a2aa62..4231ffc 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -199,7 +199,7 @@ int main(int argc, char **argv) cerr << endl; cerr << "Rubber Band" << endl; cerr << "An audio time-stretching and pitch-shifting library and utility program." << endl; - cerr << "Copyright 2007-2020 Particular Programs Ltd." << endl; + cerr << "Copyright 2007-2021 Particular Programs Ltd." << endl; cerr << endl; cerr << " Usage: " << argv[0] << " [options] " << endl; cerr << endl; diff --git a/rubberband/RubberBandStretcher.h b/rubberband/RubberBandStretcher.h index 97b5e4a..015832b 100644 --- a/rubberband/RubberBandStretcher.h +++ b/rubberband/RubberBandStretcher.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/rubberband/rubberband-c.h b/rubberband/rubberband-c.h index 9b3b990..010d563 100644 --- a/rubberband/rubberband-c.h +++ b/rubberband/rubberband-c.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/RubberBandStretcher.cpp b/src/RubberBandStretcher.cpp index ba8b937..19d6ea1 100644 --- a/src/RubberBandStretcher.cpp +++ b/src/RubberBandStretcher.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/StretchCalculator.cpp b/src/StretchCalculator.cpp index 207aaf4..2886ec3 100644 --- a/src/StretchCalculator.cpp +++ b/src/StretchCalculator.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/StretchCalculator.h b/src/StretchCalculator.h index 32a5c76..4f4b2c0 100644 --- a/src/StretchCalculator.h +++ b/src/StretchCalculator.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/StretcherChannelData.cpp b/src/StretcherChannelData.cpp index 9a9b6c8..d7e92f8 100644 --- a/src/StretcherChannelData.cpp +++ b/src/StretcherChannelData.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/StretcherChannelData.h b/src/StretcherChannelData.h index 79768d5..9b519eb 100644 --- a/src/StretcherChannelData.h +++ b/src/StretcherChannelData.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/StretcherImpl.cpp b/src/StretcherImpl.cpp index cbf8b7b..de7f084 100644 --- a/src/StretcherImpl.cpp +++ b/src/StretcherImpl.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -672,9 +672,12 @@ RubberBandStretcher::Impl::configure() if (m_channelData[c]->resampler) continue; - m_channelData[c]->resampler = - new Resampler(Resampler::FastestTolerable, 1, 4096 * 16, - m_debugLevel); + Resampler::Parameters params; + params.quality = Resampler::FastestTolerable; + params.maxBufferSize = 4096 * 16; + params.debugLevel = m_debugLevel; + + m_channelData[c]->resampler = new Resampler(params, 1); // rbs is the amount of buffer space we think we'll need // for resampling; but allocate a sensible amount in case @@ -813,9 +816,12 @@ RubberBandStretcher::Impl::reconfigure() std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl; - m_channelData[c]->resampler = - new Resampler(Resampler::FastestTolerable, 1, m_sWindowSize, - m_debugLevel); + Resampler::Parameters params; + params.quality = Resampler::FastestTolerable; + params.maxBufferSize = m_sWindowSize; + params.debugLevel = m_debugLevel; + + m_channelData[c]->resampler = new Resampler(params, 1); size_t rbs = lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)); diff --git a/src/StretcherImpl.h b/src/StretcherImpl.h index 16feab7..213882f 100644 --- a/src/StretcherImpl.h +++ b/src/StretcherImpl.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/StretcherProcess.cpp b/src/StretcherProcess.cpp index d8c912e..b8f5a49 100644 --- a/src/StretcherProcess.cpp +++ b/src/StretcherProcess.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -217,8 +217,9 @@ RubberBandStretcher::Impl::consumeChannel(size_t c, input = inputs[c] + offset; } - toWrite = cd.resampler->resample(&input, - &cd.resamplebuf, + toWrite = cd.resampler->resample(&cd.resamplebuf, + cd.resamplebufSize, + &input, samples, 1.0 / m_pitchScale, final); @@ -1090,8 +1091,9 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo #endif #endif - size_t outframes = cd.resampler->resample(&cd.accumulator, - &cd.resamplebuf, + size_t outframes = cd.resampler->resample(&cd.resamplebuf, + cd.resamplebufSize, + &cd.accumulator, si, 1.0 / m_pitchScale, last); diff --git a/src/audiocurves/CompoundAudioCurve.cpp b/src/audiocurves/CompoundAudioCurve.cpp index d64ed58..122de96 100644 --- a/src/audiocurves/CompoundAudioCurve.cpp +++ b/src/audiocurves/CompoundAudioCurve.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/CompoundAudioCurve.h b/src/audiocurves/CompoundAudioCurve.h index efcc7a4..2cadc4d 100644 --- a/src/audiocurves/CompoundAudioCurve.h +++ b/src/audiocurves/CompoundAudioCurve.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/ConstantAudioCurve.cpp b/src/audiocurves/ConstantAudioCurve.cpp index ddf1bdc..8a941bd 100644 --- a/src/audiocurves/ConstantAudioCurve.cpp +++ b/src/audiocurves/ConstantAudioCurve.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/ConstantAudioCurve.h b/src/audiocurves/ConstantAudioCurve.h index bdba319..acdc907 100644 --- a/src/audiocurves/ConstantAudioCurve.h +++ b/src/audiocurves/ConstantAudioCurve.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/HighFrequencyAudioCurve.cpp b/src/audiocurves/HighFrequencyAudioCurve.cpp index dbe3c24..52b4d2b 100644 --- a/src/audiocurves/HighFrequencyAudioCurve.cpp +++ b/src/audiocurves/HighFrequencyAudioCurve.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/HighFrequencyAudioCurve.h b/src/audiocurves/HighFrequencyAudioCurve.h index e5c7840..eec68f8 100644 --- a/src/audiocurves/HighFrequencyAudioCurve.h +++ b/src/audiocurves/HighFrequencyAudioCurve.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/PercussiveAudioCurve.cpp b/src/audiocurves/PercussiveAudioCurve.cpp index 5d3efcb..8b63e34 100644 --- a/src/audiocurves/PercussiveAudioCurve.cpp +++ b/src/audiocurves/PercussiveAudioCurve.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/PercussiveAudioCurve.h b/src/audiocurves/PercussiveAudioCurve.h index 08605c4..8c5dde4 100644 --- a/src/audiocurves/PercussiveAudioCurve.h +++ b/src/audiocurves/PercussiveAudioCurve.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/SilentAudioCurve.cpp b/src/audiocurves/SilentAudioCurve.cpp index 06dd0c5..85f39a7 100644 --- a/src/audiocurves/SilentAudioCurve.cpp +++ b/src/audiocurves/SilentAudioCurve.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/SilentAudioCurve.h b/src/audiocurves/SilentAudioCurve.h index c9e86d4..c6a9f1b 100644 --- a/src/audiocurves/SilentAudioCurve.h +++ b/src/audiocurves/SilentAudioCurve.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/SpectralDifferenceAudioCurve.cpp b/src/audiocurves/SpectralDifferenceAudioCurve.cpp index 91fc81f..5579cc0 100644 --- a/src/audiocurves/SpectralDifferenceAudioCurve.cpp +++ b/src/audiocurves/SpectralDifferenceAudioCurve.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/audiocurves/SpectralDifferenceAudioCurve.h b/src/audiocurves/SpectralDifferenceAudioCurve.h index 06c7147..9001a05 100644 --- a/src/audiocurves/SpectralDifferenceAudioCurve.h +++ b/src/audiocurves/SpectralDifferenceAudioCurve.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/base/Profiler.cpp b/src/base/Profiler.cpp index 000ea28..b1305b3 100644 --- a/src/base/Profiler.cpp +++ b/src/base/Profiler.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/base/Profiler.h b/src/base/Profiler.h index 5b6eb6b..3a01b0e 100644 --- a/src/base/Profiler.h +++ b/src/base/Profiler.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/base/RingBuffer.h b/src/base/RingBuffer.h index 9e4b385..7ad0cdb 100644 --- a/src/base/RingBuffer.h +++ b/src/base/RingBuffer.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/base/Scavenger.h b/src/base/Scavenger.h index cff8993..e93ee07 100644 --- a/src/base/Scavenger.h +++ b/src/base/Scavenger.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/dsp/AudioCurveCalculator.cpp b/src/dsp/AudioCurveCalculator.cpp index 3979305..23252eb 100644 --- a/src/dsp/AudioCurveCalculator.cpp +++ b/src/dsp/AudioCurveCalculator.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/dsp/AudioCurveCalculator.h b/src/dsp/AudioCurveCalculator.h index 20e36b4..ad5abbd 100644 --- a/src/dsp/AudioCurveCalculator.h +++ b/src/dsp/AudioCurveCalculator.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/dsp/FFT.cpp b/src/dsp/FFT.cpp index 9334540..ba9d8fd 100644 --- a/src/dsp/FFT.cpp +++ b/src/dsp/FFT.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/dsp/FFT.h b/src/dsp/FFT.h index 2d7fe14..b3328e0 100644 --- a/src/dsp/FFT.h +++ b/src/dsp/FFT.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/dsp/MovingMedian.h b/src/dsp/MovingMedian.h index 42930f9..7eabef1 100644 --- a/src/dsp/MovingMedian.h +++ b/src/dsp/MovingMedian.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/dsp/Resampler.cpp b/src/dsp/Resampler.cpp index 24429ae..06199a4 100644 --- a/src/dsp/Resampler.cpp +++ b/src/dsp/Resampler.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -31,13 +31,12 @@ #include #include "system/Allocators.h" +#include "system/VectorOps.h" #ifdef HAVE_IPP #include #if (IPP_VERSION_MAJOR < 7) -#include -#include -#include +#error Unsupported IPP version, must be >= 7 #else #include #endif @@ -65,23 +64,27 @@ #endif #endif +using namespace std; + namespace RubberBand { -class ResamplerImpl +class Resampler::Impl { public: - virtual ~ResamplerImpl() { } + virtual ~Impl() { } - virtual int resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, + virtual int resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final) = 0; - virtual int resampleInterleaved(const float *const R__ in, - float *const R__ out, + virtual int resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final) = 0; virtual int getChannelCount() const = 0; @@ -93,23 +96,25 @@ namespace Resamplers { #ifdef HAVE_IPP -class D_IPP : public ResamplerImpl +class D_IPP : public Resampler::Impl { public: - D_IPP(Resampler::Quality quality, int channels, int maxBufferSize, - int debugLevel); + D_IPP(Resampler::Quality quality, int channels, double initialSampleRate, + int maxBufferSize, int debugLevel); ~D_IPP(); - int resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, + int resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final); - int resampleInterleaved(const float *const R__ in, - float *const R__ out, + int resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final = false); int getChannelCount() const { return m_channels; } @@ -119,8 +124,9 @@ public: protected: // to m_outbuf int doResample(int outcount, double ratio, bool final); - + IppsResamplingPolyphase_32f **m_state; + double m_initialSampleRate; float **m_inbuf; size_t m_inbufsz; float **m_outbuf; @@ -137,43 +143,38 @@ protected: void setBufSize(int); }; -D_IPP::D_IPP(Resampler::Quality quality, int channels, int maxBufferSize, - int debugLevel) : +D_IPP::D_IPP(Resampler::Quality /* quality */, + int channels, double initialSampleRate, + int maxBufferSize, int debugLevel) : m_state(0), + m_initialSampleRate(initialSampleRate), m_channels(channels), m_debugLevel(debugLevel) { if (m_debugLevel > 0) { - std::cerr << "Resampler::Resampler: using IPP implementation" - << std::endl; + cerr << "Resampler::Resampler: using IPP implementation" << endl; } - int nStep = 16; + m_window = 32; + int nStep = 64; IppHintAlgorithm hint = ippAlgHintFast; - - switch (quality) { - - case Resampler::Best: - m_window = 64; - nStep = 80; - hint = ippAlgHintAccurate; - break; - - case Resampler::FastestTolerable: - nStep = 16; - m_window = 16; - hint = ippAlgHintFast; - break; - - case Resampler::Fastest: - m_window = 24; - nStep = 64; - hint = ippAlgHintFast; - break; - } - m_factor = 8; // initial upper bound on m_ratio, may be amended later - m_history = int(m_window * 0.5 * std::max(1.0, 1.0 / m_factor)) + 1; + + // This is largely based on the IPP docs and examples. Adapted + // from the docs: + // + // m_time defines the time value for which the first output + // sample is calculated. The input vector with indices less + // than m_time [whose initial value is m_history below] + // contains the history data of filters. + // + // The history length is [(1/2) window * max(1, 1/factor) ]+1 + // where window is the size of the ideal lowpass filter + // window. The input vector must contain the same number of + // elements with indices greater than m_time + length for the + // right filter wing for the last element. + + m_history = int(m_window * 0.5 * max(1.0, 1.0 / m_factor)) + 1; m_state = new IppsResamplingPolyphase_32f *[m_channels]; @@ -185,14 +186,13 @@ D_IPP::D_IPP(Resampler::Quality quality, int channels, int maxBufferSize, m_inbuf = 0; m_outbuf = 0; m_bufsize = 0; - + setBufSize(maxBufferSize + m_history); if (m_debugLevel > 1) { - std::cerr << "bufsize = " << m_bufsize << ", window = " << m_window << ", nStep = " << nStep << ", history = " << m_history << std::endl; + cerr << "D_IPP: bufsize = " << m_bufsize << ", window = " << m_window << ", nStep = " << nStep << ", history = " << m_history << endl; } -#if (IPP_VERSION_MAJOR >= 7) int specSize = 0; ippsResamplePolyphaseGetSize_32f(float(m_window), nStep, @@ -205,17 +205,8 @@ D_IPP::D_IPP(Resampler::Quality quality, int channels, int maxBufferSize, abort(); #endif } -#endif for (int c = 0; c < m_channels; ++c) { -#if (IPP_VERSION_MAJOR < 7) - ippsResamplePolyphaseInitAlloc_32f(&m_state[c], - float(m_window), - nStep, - 0.95f, - 9.0f, - hint); -#else m_state[c] = (IppsResamplingPolyphase_32f *)ippsMalloc_8u(specSize); ippsResamplePolyphaseInit_32f(float(m_window), nStep, @@ -223,28 +214,26 @@ D_IPP::D_IPP(Resampler::Quality quality, int channels, int maxBufferSize, 9.0f, m_state[c], hint); -#endif + + if (m_debugLevel > 1) { + cerr << "D_IPP: Resampler state size = " << specSize << ", allocated at " + << m_state[c] << endl; + } m_lastread[c] = m_history; m_time[c] = m_history; } if (m_debugLevel > 1) { - std::cerr << "Resampler init done" << std::endl; + cerr << "D_IPP: Resampler init done" << endl; } } D_IPP::~D_IPP() { -#if (IPP_VERSION_MAJOR < 7) - for (int c = 0; c < m_channels; ++c) { - ippsResamplePolyphaseFree_32f(m_state[c]); - } -#else for (int c = 0; c < m_channels; ++c) { ippsFree(m_state[c]); } -#endif deallocate_channels(m_inbuf, m_channels); deallocate_channels(m_outbuf, m_channels); @@ -258,20 +247,29 @@ void D_IPP::setBufSize(int sz) { if (m_debugLevel > 1) { - std::cerr << "resize bufsize " << m_bufsize << " -> "; + if (m_bufsize > 0) { + cerr << "D_IPP: resize bufsize " << m_bufsize << " -> "; + } else { + cerr << "D_IPP: initialise bufsize to "; + } } m_bufsize = sz; if (m_debugLevel > 1) { - std::cerr << m_bufsize << std::endl; + cerr << m_bufsize << endl; } int n1 = m_bufsize + m_history + 2; - int n2 = lrintf(ceil((m_bufsize - m_history) * m_factor + 2)); if (m_debugLevel > 1) { - std::cerr << "(outbufsize = " << n2 << ")" << std::endl; + cerr << "D_IPP: inbuf allocating " << m_bufsize << " + " << m_history << " + 2 = " << n1 << endl; + } + + int n2 = (int)lrintf(ceil((m_bufsize - m_history) * m_factor + 2)); + + if (m_debugLevel > 1) { + cerr << "D_IPP: outbuf allocating (" << m_bufsize << " - " << m_history << ") * " << m_factor << " + 2 = " << n2 << endl; } m_inbuf = reallocate_and_zero_extend_channels @@ -279,21 +277,41 @@ D_IPP::setBufSize(int sz) m_outbuf = reallocate_and_zero_extend_channels (m_outbuf, m_channels, m_outbufsz, m_channels, n2); - + m_inbufsz = n1; m_outbufsz = n2; + + if (m_debugLevel > 2) { + + cerr << "D_IPP: inbuf ptr = " << m_inbuf << ", channel inbufs "; + for (int c = 0; c < m_channels; ++c) { + cerr << m_inbuf[c] << " "; + } + cerr << "at " << m_inbufsz * sizeof(float) << " bytes each" << endl; + + cerr << "D_IPP: outbuf ptr = " << m_outbuf << ", channel outbufs "; + for (int c = 0; c < m_channels; ++c) { + cerr << m_outbuf[c] << " "; + } + cerr << "at " << m_outbufsz * sizeof(float) << " bytes each" << endl; + } } int -D_IPP::resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, +D_IPP::resample(float *const R__ *const R__ out, + int outspace, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final) { if (ratio > m_factor) { m_factor = ratio; - m_history = int(m_window * 0.5 * std::max(1.0, 1.0 / m_factor)) + 1; + m_history = int(m_window * 0.5 * max(1.0, 1.0 / m_factor)) + 1; + } + + if (m_debugLevel > 2) { + cerr << "D_IPP: incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl; } for (int c = 0; c < m_channels; ++c) { @@ -309,8 +327,12 @@ D_IPP::resample(const float *const R__ *const R__ in, m_lastread[c] += incount; } - int got = doResample(int(round(incount * ratio)), ratio, final); - + if (m_debugLevel > 2) { + cerr << "D_IPP: lastread advanced to " << m_lastread[0] << endl; + } + + int got = doResample(outspace, ratio, final); + for (int c = 0; c < m_channels; ++c) { v_copy(out[c], m_outbuf[c], got); } @@ -319,15 +341,20 @@ D_IPP::resample(const float *const R__ *const R__ in, } int -D_IPP::resampleInterleaved(const float *const R__ in, - float *const R__ out, +D_IPP::resampleInterleaved(float *const R__ out, + int outspace, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final) { if (ratio > m_factor) { m_factor = ratio; - m_history = int(m_window * 0.5 * std::max(1.0, 1.0 / m_factor)) + 1; + m_history = int(m_window * 0.5 * max(1.0, 1.0 / m_factor)) + 1; + } + + if (m_debugLevel > 2) { + cerr << "D_IPP: incount = " << incount << ", ratio = " << ratio << ", est space = " << lrintf(ceil(incount * ratio)) << ", outspace = " << outspace << ", final = " << final << endl; } for (int c = 0; c < m_channels; ++c) { @@ -343,7 +370,12 @@ D_IPP::resampleInterleaved(const float *const R__ in, m_lastread[c] += incount; } - int got = doResample(int(round(incount * ratio)), ratio, final); + if (m_debugLevel > 2) { + cerr << "D_IPP: lastread advanced to " << m_lastread[0] << " after injection of " + << incount << " samples" << endl; + } + + int got = doResample(outspace, ratio, final); v_interleave(out, m_outbuf, m_channels, got); @@ -360,20 +392,20 @@ D_IPP::doResample(int outspace, double ratio, bool final) int n = m_lastread[c] - m_history - int(m_time[c]); if (c == 0 && m_debugLevel > 2) { - std::cerr << "at start, lastread = " << m_lastread[c] << ", history = " + cerr << "D_IPP: at start, lastread = " << m_lastread[c] << ", history = " << m_history << ", time = " << m_time[c] << ", therefore n = " - << n << std::endl; + << n << endl; } if (n <= 0) { if (c == 0 && m_debugLevel > 1) { - std::cerr << "not enough input samples to do anything" << std::endl; + cerr << "D_IPP: not enough input samples to do anything" << endl; } continue; } if (c == 0 && m_debugLevel > 2) { - std::cerr << "before resample call, time = " << m_time[c] << std::endl; + cerr << "D_IPP: before resample call, time = " << m_time[c] << endl; } // We're committed to not overrunning outspace, so we need to @@ -382,23 +414,13 @@ D_IPP::doResample(int outspace, double ratio, bool final) int limit = int(floor(outspace / ratio)); if (n > limit) { if (c == 0 && m_debugLevel > 1) { - std::cerr << "trimming input samples from " << n << " to " << limit + cerr << "D_IPP: trimming input samples from " << n << " to " << limit << " to avoid overrunning " << outspace << " at output" - << std::endl; + << endl; } n = limit; } -#if (IPP_VERSION_MAJOR < 7) - ippsResamplePolyphase_32f(m_state[c], - m_inbuf[c], - n, - m_outbuf[c], - ratio, - 1.0f, - &m_time[c], - &outcount); -#else ippsResamplePolyphase_32f(m_inbuf[c], n, m_outbuf[c], @@ -407,29 +429,44 @@ D_IPP::doResample(int outspace, double ratio, bool final) &m_time[c], &outcount, m_state[c]); -#endif - int t = int(round(m_time[c])); - + int t = int(floor(m_time[c])); + + int moveFrom = t - m_history; + if (c == 0 && m_debugLevel > 2) { - std::cerr << "converted " << n << " samples to " << outcount - << ", time advanced to " << t << std::endl; - std::cerr << "will move " << m_lastread[c] + m_history - t - << " unconverted samples back from index " << t - m_history - << " to 0" << std::endl; + cerr << "D_IPP: converted " << n << " samples to " << outcount + << " (nb outbufsz = " << m_outbufsz + << "), time advanced to " << m_time[c] << endl; + cerr << "D_IPP: rounding time to " << t << ", lastread = " + << m_lastread[c] << ", history = " << m_history << endl; + cerr << "D_IPP: will move " << m_lastread[c] - moveFrom + << " unconverted samples back from index " << moveFrom + << " to 0" << endl; + } + + if (moveFrom >= m_lastread[c]) { + + moveFrom = m_lastread[c]; + + if (c == 0 && m_debugLevel > 2) { + cerr << "D_IPP: number of samples to move is <= 0, " + << "not actually moving any" << endl; + } + } else { + + v_move(m_inbuf[c], + m_inbuf[c] + moveFrom, + m_lastread[c] - moveFrom); } - v_move(m_inbuf[c], - m_inbuf[c] + t - m_history, - m_lastread[c] + m_history - t); - - m_lastread[c] -= t - m_history; - m_time[c] -= t - m_history; + m_lastread[c] -= moveFrom; + m_time[c] -= moveFrom; if (c == 0 && m_debugLevel > 2) { - std::cerr << "lastread reduced to " << m_lastread[c] + cerr << "D_IPP: lastread reduced to " << m_lastread[c] << ", time reduced to " << m_time[c] - << std::endl; + << endl; } if (final && n < limit) { @@ -446,8 +483,8 @@ D_IPP::doResample(int outspace, double ratio, bool final) int additionalcount = 0; if (c == 0 && m_debugLevel > 2) { - std::cerr << "final call, padding input with " << m_history - << " zeros (symmetrical with m_history)" << std::endl; + cerr << "D_IPP: final call, padding input with " << m_history + << " zeros (symmetrical with m_history)" << endl; } for (int i = 0; i < m_history; ++i) { @@ -455,31 +492,21 @@ D_IPP::doResample(int outspace, double ratio, bool final) } if (c == 0 && m_debugLevel > 2) { - std::cerr << "before resample call, time = " << m_time[c] << std::endl; + cerr << "D_IPP: before resample call, time = " << m_time[c] << endl; } int nAdditional = m_lastread[c] - int(m_time[c]); if (n + nAdditional > limit) { if (c == 0 && m_debugLevel > 1) { - std::cerr << "trimming final input samples from " << nAdditional + cerr << "D_IPP: trimming final input samples from " << nAdditional << " to " << (limit - n) << " to avoid overrunning " << outspace << " at output" - << std::endl; + << endl; } nAdditional = limit - n; } -#if (IPP_VERSION_MAJOR < 7) - ippsResamplePolyphase_32f(m_state[c], - m_inbuf[c], - nAdditional, - m_outbuf[c], - ratio, - 1.0f, - &m_time[c], - &additionalcount); -#else ippsResamplePolyphase_32f(m_inbuf[c], nAdditional, m_outbuf[c], @@ -488,12 +515,11 @@ D_IPP::doResample(int outspace, double ratio, bool final) &m_time[c], &additionalcount, m_state[c]); -#endif if (c == 0 && m_debugLevel > 2) { - std::cerr << "converted " << n << " samples to " << additionalcount - << ", time advanced to " << m_time[c] << std::endl; - std::cerr << "outcount = " << outcount << ", additionalcount = " << additionalcount << ", sum " << outcount + additionalcount << std::endl; + cerr << "D_IPP: converted " << n << " samples to " << additionalcount + << ", time advanced to " << m_time[c] << endl; + cerr << "D_IPP: outcount = " << outcount << ", additionalcount = " << additionalcount << ", sum " << outcount + additionalcount << endl; } if (c == 0) { @@ -503,7 +529,7 @@ D_IPP::doResample(int outspace, double ratio, bool final) } if (m_debugLevel > 2) { - std::cerr << "returning " << outcount << " samples" << std::endl; + cerr << "D_IPP: returning " << outcount << " samples" << endl; } return outcount; @@ -519,23 +545,25 @@ D_IPP::reset() #ifdef HAVE_LIBSAMPLERATE -class D_SRC : public ResamplerImpl +class D_SRC : public Resampler::Impl { public: - D_SRC(Resampler::Quality quality, int channels, int maxBufferSize, - int m_debugLevel); + D_SRC(Resampler::Quality quality, int channels, double initialSampleRate, + int maxBufferSize, int m_debugLevel); ~D_SRC(); - int resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, + int resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final); - int resampleInterleaved(const float *const R__ in, - float *const R__ out, + int resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final = false); int getChannelCount() const { return m_channels; } @@ -546,27 +574,29 @@ protected: SRC_STATE *m_src; float *m_iin; float *m_iout; - float m_lastRatio; int m_channels; int m_iinsize; int m_ioutsize; + double m_prevRatio; + bool m_ratioUnset; int m_debugLevel; }; -D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize, - int debugLevel) : +D_SRC::D_SRC(Resampler::Quality quality, int channels, double, + int maxBufferSize, int debugLevel) : m_src(0), m_iin(0), m_iout(0), - m_lastRatio(1.f), m_channels(channels), m_iinsize(0), m_ioutsize(0), + m_prevRatio(1.0), + m_ratioUnset(true), m_debugLevel(debugLevel) { if (m_debugLevel > 0) { - std::cerr << "Resampler::Resampler: using libsamplerate implementation" - << std::endl; + cerr << "Resampler::Resampler: using libsamplerate implementation" + << endl; } int err = 0; @@ -576,8 +606,8 @@ D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize, channels, &err); if (err) { - std::cerr << "Resampler::Resampler: failed to create libsamplerate resampler: " - << src_strerror(err) << std::endl; + cerr << "Resampler::Resampler: failed to create libsamplerate resampler: " + << src_strerror(err) << endl; #ifndef NO_EXCEPTIONS throw Resampler::ImplementationError; #endif @@ -601,118 +631,146 @@ D_SRC::~D_SRC() } int -D_SRC::resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, +D_SRC::resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final) { - SRC_DATA data; - - int outcount = lrintf(ceilf(incount * ratio) + 10); - if (m_channels == 1) { - data.data_in = const_cast(*in); //!!!??? - data.data_out = *out; - } else { - if (incount * m_channels > m_iinsize) { - m_iin = reallocate(m_iin, m_iinsize, incount * m_channels); - m_iinsize = incount * m_channels; - } - if (outcount * m_channels > m_ioutsize) { - m_iout = reallocate(m_iout, m_ioutsize, outcount * m_channels); - m_ioutsize = outcount * m_channels; - } - v_interleave(m_iin, in, m_channels, incount); - data.data_in = m_iin; - data.data_out = m_iout; + return resampleInterleaved(*out, outcount, *in, incount, ratio, final); } - data.input_frames = incount; - data.output_frames = outcount; - data.src_ratio = ratio; - data.end_of_input = (final ? 1 : 0); - - int err = src_process(m_src, &data); - - if (err) { - std::cerr << "Resampler::process: libsamplerate error: " - << src_strerror(err) << std::endl; -#ifndef NO_EXCEPTIONS - throw Resampler::ImplementationError; -#endif + if (incount * m_channels > m_iinsize) { + m_iin = reallocate(m_iin, m_iinsize, incount * m_channels); + m_iinsize = incount * m_channels; } - - if (m_channels > 1) { - v_deinterleave(out, m_iout, m_channels, data.output_frames_gen); + if (outcount * m_channels > m_ioutsize) { + m_iout = reallocate(m_iout, m_ioutsize, outcount * m_channels); + m_ioutsize = outcount * m_channels; } + + v_interleave(m_iin, in, m_channels, incount); - m_lastRatio = ratio; + int n = resampleInterleaved(m_iout, outcount, m_iin, incount, ratio, final); - return data.output_frames_gen; + v_deinterleave(out, m_iout, m_channels, n); + + return n; } int -D_SRC::resampleInterleaved(const float *const R__ in, - float *const R__ out, +D_SRC::resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final) { SRC_DATA data; + + // libsamplerate smooths the filter change over the duration of + // the processing block to avoid artifacts due to sudden changes, + // and it uses outcount to determine how long to smooth the change + // over. This is a good thing, but it does mean (a) we should + // never pass outcount significantly longer than the actual + // expected output, and (b) when the ratio has just changed, we + // should aim to supply a shortish block next + + if (outcount > int(ceil(incount * ratio) + 5)) { + outcount = int(ceil(incount * ratio) + 5); + } - int outcount = lrintf(ceilf(incount * ratio) + 10); + if (m_ratioUnset) { + + // The first time we set a ratio, we want to do it directly + src_set_ratio(m_src, ratio); + m_ratioUnset = false; + m_prevRatio = ratio; + + } else if (ratio != m_prevRatio) { + + // If we are processing a block of appreciable length, turn it + // into two recursive calls, one for the short smoothing block + // and the other for the rest. Update m_prevRatio before doing + // this so that the calls don't themselves recurse! + m_prevRatio = ratio; + + int shortBlock = 200; + if (outcount > shortBlock * 2) { + int shortIn = int(floor(shortBlock / ratio)); + if (shortIn >= 10) { + int shortOut = + resampleInterleaved(out, shortBlock, + in, shortIn, + ratio, false); + int remainingOut = 0; + if (shortOut < outcount) { + remainingOut = + resampleInterleaved(out + shortOut * m_channels, + outcount - shortOut, + in + shortIn * m_channels, + incount - shortIn, + ratio, final); + } + return shortOut + remainingOut; + } + } + } data.data_in = const_cast(in); data.data_out = out; data.input_frames = incount; data.output_frames = outcount; + data.src_ratio = ratio; data.end_of_input = (final ? 1 : 0); - + int err = src_process(m_src, &data); if (err) { - std::cerr << "Resampler::process: libsamplerate error: " - << src_strerror(err) << std::endl; + cerr << "Resampler::process: libsamplerate error: " + << src_strerror(err) << endl; #ifndef NO_EXCEPTIONS throw Resampler::ImplementationError; #endif } - - m_lastRatio = ratio; - - return data.output_frames_gen; + + return (int)data.output_frames_gen; } void D_SRC::reset() { src_reset(m_src); + m_ratioUnset = true; } #endif /* HAVE_LIBSAMPLERATE */ #ifdef HAVE_LIBRESAMPLE -class D_Resample : public ResamplerImpl +class D_Resample : public Resampler::Impl { public: - D_Resample(Resampler::Quality quality, int channels, int maxBufferSize, - int m_debugLevel); + D_Resample(Resampler::Quality quality, int channels, double initialSampleRate, + int maxBufferSize, int m_debugLevel); ~D_Resample(); - int resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, + int resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final); - int resampleInterleaved(const float *const R__ in, - float *const R__ out, + int resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final); int getChannelCount() const { return m_channels; } @@ -723,27 +781,26 @@ protected: void *m_src; float *m_iin; float *m_iout; - float m_lastRatio; + double m_lastRatio; int m_channels; int m_iinsize; int m_ioutsize; int m_debugLevel; }; -D_Resample::D_Resample(Resampler::Quality quality, int channels, int maxBufferSize, - int debugLevel) : +D_Resample::D_Resample(Resampler::Quality quality, + int channels, double, int maxBufferSize, int debugLevel) : m_src(0), m_iin(0), m_iout(0), - m_lastRatio(1.f), m_channels(channels), m_iinsize(0), m_ioutsize(0), m_debugLevel(debugLevel) { if (m_debugLevel > 0) { - std::cerr << "Resampler::Resampler: using libresample implementation" - << std::endl; + cerr << "Resampler::Resampler: using libresample implementation" + << endl; } float min_factor = 0.125f; @@ -752,8 +809,8 @@ D_Resample::D_Resample(Resampler::Quality quality, int channels, int maxBufferSi m_src = resample_open(quality == Resampler::Best ? 1 : 0, min_factor, max_factor); if (!m_src) { - std::cerr << "Resampler::Resampler: failed to create libresample resampler: " - << std::endl; + cerr << "Resampler::Resampler: failed to create libresample resampler: " + << endl; throw Resampler::ImplementationError; //!!! of course, need to catch this! } @@ -779,10 +836,11 @@ D_Resample::~D_Resample() } int -D_Resample::resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, +D_Resample::resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final) { float *data_in; @@ -790,7 +848,7 @@ D_Resample::resample(const float *const R__ *const R__ in, int input_frames, output_frames, end_of_input, source_used; float src_ratio; - int outcount = lrintf(ceilf(incount * ratio)); + int outcount = (int)lrint(ceil(incount * ratio)); if (m_channels == 1) { data_in = const_cast(*in); //!!!??? @@ -824,8 +882,8 @@ D_Resample::resample(const float *const R__ *const R__ in, output_frames); if (output_frames_gen < 0) { - std::cerr << "Resampler::process: libresample error: " - << std::endl; + cerr << "Resampler::process: libresample error: " + << endl; throw Resampler::ImplementationError; //!!! of course, need to catch this! } @@ -833,22 +891,21 @@ D_Resample::resample(const float *const R__ *const R__ in, v_deinterleave(out, m_iout, m_channels, output_frames_gen); } - m_lastRatio = ratio; - return output_frames_gen; } int -D_Resample::resampleInterleaved(const float *const R__ in, - float *const R__ out, +D_Resample::resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final) { int input_frames, output_frames, end_of_input, source_used; float src_ratio; - int outcount = lrintf(ceilf(incount * ratio)); + int outcount = (int)lrint(ceil(incount * ratio)); input_frames = incount; output_frames = outcount; @@ -865,13 +922,11 @@ D_Resample::resampleInterleaved(const float *const R__ in, output_frames); if (output_frames_gen < 0) { - std::cerr << "Resampler::process: libresample error: " - << std::endl; + cerr << "Resampler::process: libresample error: " + << endl; throw Resampler::ImplementationError; //!!! of course, need to catch this! } - m_lastRatio = ratio; - return output_frames_gen; } @@ -884,23 +939,25 @@ D_Resample::reset() #ifdef USE_SPEEX -class D_Speex : public ResamplerImpl +class D_Speex : public Resampler::Impl { public: - D_Speex(Resampler::Quality quality, int channels, int maxBufferSize, - int debugLevel); + D_Speex(Resampler::Quality quality, int channels, double initialSampleRate, + int maxBufferSize, int debugLevel); ~D_Speex(); - int resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, + int resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final); - int resampleInterleaved(const float *const R__ in, - float *const R__ out, + int resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final = false); int getChannelCount() const { return m_channels; } @@ -909,27 +966,33 @@ public: protected: SpeexResamplerState *m_resampler; + double m_initialSampleRate; float *m_iin; float *m_iout; int m_channels; int m_iinsize; int m_ioutsize; - float m_lastratio; + double m_lastratio; bool m_initial; int m_debugLevel; - void setRatio(float); + void setRatio(double); + void doResample(const float *in, unsigned int &incount, + float *out, unsigned int &outcount, + double ratio, bool final); }; -D_Speex::D_Speex(Resampler::Quality quality, int channels, int maxBufferSize, - int debugLevel) : +D_Speex::D_Speex(Resampler::Quality quality, + int channels, double initialSampleRate, + int maxBufferSize, int debugLevel) : m_resampler(0), + m_initialSampleRate(initialSampleRate), m_iin(0), m_iout(0), m_channels(channels), m_iinsize(0), m_ioutsize(0), - m_lastratio(1), + m_lastratio(-1.0), m_initial(true), m_debugLevel(debugLevel) { @@ -937,22 +1000,23 @@ D_Speex::D_Speex(Resampler::Quality quality, int channels, int maxBufferSize, quality == Resampler::Fastest ? 0 : 4); if (m_debugLevel > 0) { - std::cerr << "Resampler::Resampler: using Speex implementation with q = " - << q - << std::endl; + cerr << "Resampler::Resampler: using Speex implementation with q = " + << q << endl; } + int rrate = int(round(m_initialSampleRate)); + int err = 0; m_resampler = speex_resampler_init_frac(m_channels, 1, 1, - 48000, 48000, // irrelevant + rrate, rrate, q, &err); if (err) { - std::cerr << "Resampler::Resampler: failed to create Speex resampler" - << std::endl; + cerr << "Resampler::Resampler: failed to create Speex resampler" + << endl; #ifndef NO_EXCEPTIONS throw Resampler::ImplementationError; #endif @@ -974,7 +1038,7 @@ D_Speex::~D_Speex() } void -D_Speex::setRatio(float ratio) +D_Speex::setRatio(double ratio) { // Speex wants a ratio of two unsigned integers, not a single // float. Let's do that. @@ -993,21 +1057,31 @@ D_Speex::setRatio(float ratio) } if (m_debugLevel > 1) { - std::cerr << "D_Speex: Desired ratio " << ratio << ", requesting ratio " - << num << "/" << denom << " = " << float(double(num)/double(denom)) - << std::endl; + cerr << "D_Speex: Desired ratio " << ratio << ", requesting ratio " + << num << "/" << denom << " = " << float(double(num)/double(denom)) + << endl; } + + int fromRate = int(round(m_initialSampleRate)); + int toRate = int(round(m_initialSampleRate * ratio)); int err = speex_resampler_set_rate_frac - (m_resampler, denom, num, 48000, 48000); - //!!! check err + (m_resampler, denom, num, fromRate, toRate); + + if (err) { + cerr << "Resampler::Resampler: failed to set rate on Speex resampler" + << endl; +#ifndef NO_EXCEPTIONS + throw Resampler::ImplementationError; +#endif + } speex_resampler_get_ratio(m_resampler, &denom, &num); if (m_debugLevel > 1) { - std::cerr << "D_Speex: Desired ratio " << ratio << ", got ratio " - << num << "/" << denom << " = " << float(double(num)/double(denom)) - << std::endl; + cerr << "D_Speex: Desired ratio " << ratio << ", got ratio " + << num << "/" << denom << " = " << float(double(num)/double(denom)) + << endl; } m_lastratio = ratio; @@ -1019,10 +1093,11 @@ D_Speex::setRatio(float ratio) } int -D_Speex::resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, +D_Speex::resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final) { if (ratio != m_lastratio) { @@ -1030,7 +1105,7 @@ D_Speex::resample(const float *const R__ *const R__ in, } unsigned int uincount = incount; - unsigned int outcount = lrintf(ceilf(incount * ratio)); //!!! inexact now + unsigned int uoutcount = outcount; float *data_in, *data_out; @@ -1038,11 +1113,11 @@ D_Speex::resample(const float *const R__ *const R__ in, data_in = const_cast(*in); data_out = *out; } else { - if (incount * m_channels > m_iinsize) { + if (int(incount * m_channels) > m_iinsize) { m_iin = reallocate(m_iin, m_iinsize, incount * m_channels); m_iinsize = incount * m_channels; } - if (outcount * m_channels > m_ioutsize) { + if (int(outcount * m_channels) > m_ioutsize) { m_iout = reallocate(m_iout, m_ioutsize, outcount * m_channels); m_ioutsize = outcount * m_channels; } @@ -1051,38 +1126,21 @@ D_Speex::resample(const float *const R__ *const R__ in, data_out = m_iout; } - int err = speex_resampler_process_interleaved_float(m_resampler, - data_in, - &uincount, - data_out, - &outcount); - -// if (incount != int(uincount)) { -// std::cerr << "Resampler: NOTE: Consumed " << uincount -// << " of " << incount << " frames" << std::endl; -// } - -// if (outcount != lrintf(ceilf(incount * ratio))) { -// std::cerr << "Resampler: NOTE: Obtained " << outcount -// << " of " << lrintf(ceilf(incount * ratio)) << " frames" -// << std::endl; -// } - - //!!! check err, respond appropriately - + doResample(data_in, uincount, data_out, uoutcount, ratio, final); if (m_channels > 1) { - v_deinterleave(out, m_iout, m_channels, outcount); + v_deinterleave(out, m_iout, m_channels, uoutcount); } - return outcount; + return uoutcount; } int -D_Speex::resampleInterleaved(const float *const R__ in, - float *const R__ out, +D_Speex::resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final) { if (ratio != m_lastratio) { @@ -1090,20 +1148,60 @@ D_Speex::resampleInterleaved(const float *const R__ in, } unsigned int uincount = incount; - unsigned int outcount = lrintf(ceilf(incount * ratio)); //!!! inexact now + unsigned int uoutcount = outcount; float *data_in = const_cast(in); float *data_out = out; - int err = speex_resampler_process_interleaved_float(m_resampler, - data_in, - &uincount, - data_out, - &outcount); + doResample(data_in, uincount, data_out, uoutcount, ratio, final); + + return uoutcount; +} -// std::cerr << "D_SPEEX: incount " << incount << " ratio " << ratio << " req " << lrintf(ceilf(incount * ratio)) << " final " << final << " output_frames_gen " << outcount << std::endl; +void +D_Speex::doResample(const float *data_in, unsigned int &uincount, + float *data_out, unsigned int &uoutcount, + double ratio, bool final) +{ + int initial_outcount = int(uoutcount); + + int err = speex_resampler_process_interleaved_float + (m_resampler, + data_in, &uincount, + data_out, &uoutcount); + + if (err) { + cerr << "Resampler::Resampler: Speex resampler returned error " + << err << endl; +#ifndef NO_EXCEPTIONS + throw Resampler::ImplementationError; +#endif + } - return outcount; + if (final) { + int actual = int(uoutcount); + int expected = std::min(initial_outcount, int(round(uincount * ratio))); + if (actual < expected) { + unsigned int final_out = expected - actual; + unsigned int final_in = (unsigned int)(round(final_out / ratio)); + if (final_in > 0) { + float *pad = allocate_and_zero(final_in * m_channels); + err = speex_resampler_process_interleaved_float + (m_resampler, + pad, &final_in, + data_out + actual * m_channels, &final_out); + deallocate(pad); + uoutcount += final_out; + if (err) { + cerr << "Resampler::Resampler: Speex resampler returned error " + << err << endl; +#ifndef NO_EXCEPTIONS + throw Resampler::ImplementationError; +#endif + } + } + } + } } void @@ -1118,12 +1216,15 @@ D_Speex::reset() } /* end namespace Resamplers */ -Resampler::Resampler(Resampler::Quality quality, int channels, - int maxBufferSize, int debugLevel) +Resampler::Resampler(Resampler::Parameters params, int channels) { m_method = -1; + + if (params.initialSampleRate == 0) { + params.initialSampleRate = 44100; + } - switch (quality) { + switch (params.quality) { case Resampler::Best: #ifdef HAVE_IPP @@ -1172,63 +1273,63 @@ Resampler::Resampler(Resampler::Quality quality, int channels, } if (m_method == -1) { - std::cerr << "Resampler::Resampler(" << quality << ", " << channels - << ", " << maxBufferSize << "): No implementation available!" - << std::endl; + cerr << "Resampler::Resampler: No implementation available!" << endl; abort(); } switch (m_method) { case 0: #ifdef HAVE_IPP - d = new Resamplers::D_IPP(quality, channels, maxBufferSize, debugLevel); + d = new Resamplers::D_IPP + (params.quality, + channels, + params.initialSampleRate, params.maxBufferSize, params.debugLevel); #else - std::cerr << "Resampler::Resampler(" << quality << ", " << channels - << ", " << maxBufferSize << "): No implementation available!" - << std::endl; + cerr << "Resampler::Resampler: No implementation available!" << endl; abort(); #endif break; case 1: #ifdef HAVE_LIBSAMPLERATE - d = new Resamplers::D_SRC(quality, channels, maxBufferSize, debugLevel); + d = new Resamplers::D_SRC + (params.quality, + channels, + params.initialSampleRate, params.maxBufferSize, params.debugLevel); #else - std::cerr << "Resampler::Resampler(" << quality << ", " << channels - << ", " << maxBufferSize << "): No implementation available!" - << std::endl; + cerr << "Resampler::Resampler: No implementation available!" << endl; abort(); #endif break; case 2: #ifdef USE_SPEEX - d = new Resamplers::D_Speex(quality, channels, maxBufferSize, debugLevel); + d = new Resamplers::D_Speex + (params.quality, + channels, + params.initialSampleRate, params.maxBufferSize, params.debugLevel); #else - std::cerr << "Resampler::Resampler(" << quality << ", " << channels - << ", " << maxBufferSize << "): No implementation available!" - << std::endl; + cerr << "Resampler::Resampler: No implementation available!" << endl; abort(); #endif break; case 3: #ifdef HAVE_LIBRESAMPLE - d = new Resamplers::D_Resample(quality, channels, maxBufferSize, debugLevel); + d = new Resamplers::D_Resample + (params.quality, + channels, + params.initialSampleRate, params.maxBufferSize, params.debugLevel); #else - std::cerr << "Resampler::Resampler(" << quality << ", " << channels - << ", " << maxBufferSize << "): No implementation available!" - << std::endl; + cerr << "Resampler::Resampler: No implementation available!" << endl; abort(); #endif break; } if (!d) { - std::cerr << "Resampler::Resampler(" << quality << ", " << channels - << ", " << maxBufferSize - << "): Internal error: No implementation selected" - << std::endl; + cerr << "Resampler::Resampler: Internal error: No implementation selected" + << endl; abort(); } } @@ -1239,21 +1340,27 @@ Resampler::~Resampler() } int -Resampler::resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, - int incount, float ratio, bool final) +Resampler::resample(float *const R__ *const R__ out, + int outcount, + const float *const R__ *const R__ in, + int incount, + double ratio, + bool final) { Profiler profiler("Resampler::resample"); - return d->resample(in, out, incount, ratio, final); + return d->resample(out, outcount, in, incount, ratio, final); } int -Resampler::resampleInterleaved(const float *const R__ in, - float *const R__ out, - int incount, float ratio, bool final) +Resampler::resampleInterleaved(float *const R__ out, + int outcount, + const float *const R__ in, + int incount, + double ratio, + bool final) { - Profiler profiler("Resampler::resample"); - return d->resampleInterleaved(in, out, incount, ratio, final); + Profiler profiler("Resampler::resampleInterleaved"); + return d->resampleInterleaved(out, outcount, in, incount, ratio, final); } int diff --git a/src/dsp/Resampler.h b/src/dsp/Resampler.h index 5b51400..4a1f723 100644 --- a/src/dsp/Resampler.h +++ b/src/dsp/Resampler.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -21,60 +21,118 @@ you must obtain a valid commercial licence before doing so. */ -#ifndef _RUBBERBAND_RESAMPLER_H_ -#define _RUBBERBAND_RESAMPLER_H_ +#ifndef RUBBERBAND_RESAMPLER_H +#define RUBBERBAND_RESAMPLER_H #include "system/sysutils.h" namespace RubberBand { -class ResamplerImpl; - class Resampler { public: enum Quality { Best, FastestTolerable, Fastest }; enum Exception { ImplementationError }; + struct Parameters { + + /** + * Resampler filter quality level. + */ + Quality quality; + + /** + * Rate of expected input prior to resampling: may be used to + * determine the filter bandwidth for the quality setting. If + * you don't know what this will be, you can provide an + * arbitrary rate (such as the default) and the resampler will + * work fine, but quality may not be as designed. + */ + double initialSampleRate; + + /** + * Bound on the maximum incount size that may be passed to the + * resample function before the resampler needs to reallocate + * its internal buffers. Default is zero, so that buffer + * allocation will happen on the first call and any subsequent + * call with a greater incount. + */ + int maxBufferSize; + + /** + * Debug output level, from 0 to 3. Controls the amount of + * debug information printed to stderr. + */ + int debugLevel; + + Parameters() : + quality(FastestTolerable), + initialSampleRate(44100), + maxBufferSize(0), + debugLevel(0) { } + }; + /** - * Construct a resampler with the given quality level and channel - * count. maxBufferSize gives a bound on the maximum incount size - * that may be passed to the resample function before the - * resampler needs to reallocate its internal buffers. + * Construct a resampler to process the given number of channels, + * with the given quality level, initial sample rate, and other + * parameters. */ - Resampler(Quality quality, int channels, int maxBufferSize = 0, - int debugLevel = 0); + Resampler(Parameters parameters, int channels); + ~Resampler(); /** * Resample the given multi-channel buffers, where incount is the - * number of frames in the input buffers. Returns the number of - * frames written to the output buffers. + * number of frames in the input buffers and outspace is the space + * available in the output buffers. Generally you want outspace to + * be at least ceil(incount * ratio). + * + * Returns the number of frames written to the output + * buffers. This may be smaller than outspace even where the ratio + * suggests otherwise, particularly at the start of processing + * where there may be a filter tail to allow for. */ - int resample(const float *const R__ *const R__ in, - float *const R__ *const R__ out, +#ifdef __GNUC__ + __attribute__((warn_unused_result)) +#endif + int resample(float *const R__ *const R__ out, + int outspace, + const float *const R__ *const R__ in, int incount, - float ratio, + double ratio, bool final = false); /** * Resample the given interleaved buffer, where incount is the * number of frames in the input buffer (i.e. it has incount * - * getChannelCount() samples). Returns the number of frames - * written to the output buffer. + * getChannelCount() samples) and outspace is the space available + * in frames in the output buffer (i.e. it has space for at least + * outspace * getChannelCount() samples). Generally you want + * outspace to be at least ceil(incount * ratio). + * + * Returns the number of frames written to the output buffer. This + * may be smaller than outspace even where the ratio suggests + * otherwise, particularly at the start of processing where there + * may be a filter tail to allow for. */ - int resampleInterleaved(const float *const R__ in, - float *const R__ out, +#ifdef __GNUC__ + __attribute__((warn_unused_result)) +#endif + int resampleInterleaved(float *const R__ out, + int outspace, + const float *const R__ in, int incount, - float ratio, + double ratio, bool final = false); int getChannelCount() const; void reset(); + class Impl; + protected: - ResamplerImpl *d; + Impl *d; int m_method; }; diff --git a/src/dsp/SampleFilter.h b/src/dsp/SampleFilter.h index eb1f471..2ce5583 100644 --- a/src/dsp/SampleFilter.h +++ b/src/dsp/SampleFilter.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/dsp/SincWindow.h b/src/dsp/SincWindow.h index 992ff40..8b5d248 100644 --- a/src/dsp/SincWindow.h +++ b/src/dsp/SincWindow.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/dsp/Window.h b/src/dsp/Window.h index e5cf464..1175fbd 100644 --- a/src/dsp/Window.h +++ b/src/dsp/Window.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/jni/RubberBandStretcherJNI.cpp b/src/jni/RubberBandStretcherJNI.cpp index de1be37..79baecb 100644 --- a/src/jni/RubberBandStretcherJNI.cpp +++ b/src/jni/RubberBandStretcherJNI.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/rubberband-c.cpp b/src/rubberband-c.cpp index 5b3538b..03dfa6b 100644 --- a/src/rubberband-c.cpp +++ b/src/rubberband-c.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/system/Allocators.cpp b/src/system/Allocators.cpp index 8bc2e3c..7dd6e37 100644 --- a/src/system/Allocators.cpp +++ b/src/system/Allocators.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/system/Allocators.h b/src/system/Allocators.h index 2f1fbbf..355bf29 100644 --- a/src/system/Allocators.h +++ b/src/system/Allocators.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -21,8 +21,8 @@ you must obtain a valid commercial licence before doing so. */ -#ifndef _RUBBERBAND_ALLOCATORS_H_ -#define _RUBBERBAND_ALLOCATORS_H_ +#ifndef RUBBERBAND_ALLOCATORS_H +#define RUBBERBAND_ALLOCATORS_H #include "VectorOps.h" diff --git a/src/system/Thread.cpp b/src/system/Thread.cpp index eb65731..3d42c2b 100644 --- a/src/system/Thread.cpp +++ b/src/system/Thread.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/system/Thread.h b/src/system/Thread.h index 6c2f295..0e342f9 100644 --- a/src/system/Thread.h +++ b/src/system/Thread.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/system/VectorOps.h b/src/system/VectorOps.h index 92694e1..a293fac 100644 --- a/src/system/VectorOps.h +++ b/src/system/VectorOps.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/system/VectorOpsComplex.cpp b/src/system/VectorOpsComplex.cpp index 80cec39..c7eab0c 100644 --- a/src/system/VectorOpsComplex.cpp +++ b/src/system/VectorOpsComplex.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/system/VectorOpsComplex.h b/src/system/VectorOpsComplex.h index 8318d37..0a78639 100644 --- a/src/system/VectorOpsComplex.h +++ b/src/system/VectorOpsComplex.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/system/sysutils.cpp b/src/system/sysutils.cpp index 3cd0d6e..71f304d 100644 --- a/src/system/sysutils.cpp +++ b/src/system/sysutils.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/system/sysutils.h b/src/system/sysutils.h index 945fc32..e05c3a5 100644 --- a/src/system/sysutils.h +++ b/src/system/sysutils.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/vamp/RubberBandVampPlugin.cpp b/vamp/RubberBandVampPlugin.cpp index 3b0e41e..c25360d 100644 --- a/vamp/RubberBandVampPlugin.cpp +++ b/vamp/RubberBandVampPlugin.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/vamp/RubberBandVampPlugin.h b/vamp/RubberBandVampPlugin.h index 3649fd5..10b5b74 100644 --- a/vamp/RubberBandVampPlugin.h +++ b/vamp/RubberBandVampPlugin.h @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/vamp/libmain.cpp b/vamp/libmain.cpp index 2a74e3c..9683444 100644 --- a/vamp/libmain.cpp +++ b/vamp/libmain.cpp @@ -3,7 +3,7 @@ /* Rubber Band Library An audio time-stretching and pitch-shifting library. - Copyright 2007-2020 Particular Programs Ltd. + Copyright 2007-2021 Particular Programs Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as