2007-11-06 21:41:16 +00:00
|
|
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
|
|
|
|
|
2008-05-22 16:54:27 +00:00
|
|
|
/*
|
2012-09-09 16:57:42 +01:00
|
|
|
Rubber Band Library
|
2008-05-22 16:54:27 +00:00
|
|
|
An audio time-stretching and pitch-shifting library.
|
2012-09-09 16:57:42 +01:00
|
|
|
Copyright 2007-2012 Particular Programs Ltd.
|
|
|
|
|
|
2008-05-22 16:54:27 +00:00
|
|
|
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.
|
2012-09-09 16:57:42 +01:00
|
|
|
|
|
|
|
|
Alternatively, if you have a valid commercial licence for the
|
|
|
|
|
Rubber Band Library obtained by agreement with the copyright
|
|
|
|
|
holders, you may redistribute and/or modify it under the terms
|
|
|
|
|
described in that licence.
|
|
|
|
|
|
|
|
|
|
If you wish to distribute code using the Rubber Band Library
|
|
|
|
|
under terms other than those of the GNU General Public License,
|
|
|
|
|
you must obtain a valid commercial licence before doing so.
|
2008-05-22 16:54:27 +00:00
|
|
|
*/
|
|
|
|
|
|
2007-11-06 21:41:16 +00:00
|
|
|
#include "StretcherChannelData.h"
|
|
|
|
|
|
2009-09-17 13:01:21 +00:00
|
|
|
#include "dsp/Resampler.h"
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2009-09-17 13:01:21 +00:00
|
|
|
#include "system/Allocators.h"
|
2008-05-22 16:54:27 +00:00
|
|
|
|
2007-11-06 21:41:16 +00:00
|
|
|
namespace RubberBand
|
|
|
|
|
{
|
2008-07-08 15:00:22 +00:00
|
|
|
|
2008-07-01 10:25:17 +00:00
|
|
|
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
|
2010-05-16 10:44:38 +01:00
|
|
|
size_t fftSize,
|
|
|
|
|
size_t outbufSize)
|
2007-11-06 21:41:16 +00:00
|
|
|
{
|
|
|
|
|
std::set<size_t> s;
|
2010-05-16 10:44:38 +01:00
|
|
|
construct(s, windowSize, fftSize, outbufSize);
|
2007-11-06 21:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &sizes,
|
2007-11-18 21:38:18 +00:00
|
|
|
size_t initialWindowSize,
|
2010-05-16 10:44:38 +01:00
|
|
|
size_t initialFftSize,
|
|
|
|
|
size_t outbufSize)
|
2007-11-06 21:41:16 +00:00
|
|
|
{
|
2010-05-16 10:44:38 +01:00
|
|
|
construct(sizes, initialWindowSize, initialFftSize, outbufSize);
|
2007-11-06 21:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2010-05-16 10:44:38 +01:00
|
|
|
RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
|
2007-11-18 21:38:18 +00:00
|
|
|
size_t initialWindowSize,
|
2010-05-16 10:44:38 +01:00
|
|
|
size_t initialFftSize,
|
2007-11-06 21:41:16 +00:00
|
|
|
size_t outbufSize)
|
|
|
|
|
{
|
2011-11-25 11:11:59 +00:00
|
|
|
size_t maxSize = initialWindowSize * 2;
|
2010-05-16 10:44:38 +01:00
|
|
|
if (initialFftSize > maxSize) maxSize = initialFftSize;
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2011-11-25 11:11:59 +00:00
|
|
|
// std::cerr << "ChannelData::construct: initialWindowSize = " << initialWindowSize << ", initialFftSize = " << initialFftSize << ", outbufSize = " << outbufSize << std::endl;
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
// std::set is ordered by value
|
|
|
|
|
std::set<size_t>::const_iterator i = sizes.end();
|
|
|
|
|
if (i != sizes.begin()) {
|
|
|
|
|
--i;
|
|
|
|
|
if (*i > maxSize) maxSize = *i;
|
2007-11-06 21:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
// max possible size of the real "half" of freq data
|
|
|
|
|
size_t realSize = maxSize / 2 + 1;
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2011-11-25 11:11:59 +00:00
|
|
|
// std::cerr << "ChannelData::construct([" << sizes.size() << "], " << maxSize << ", " << realSize << ", " << outbufSize << ")" << std::endl;
|
2007-11-06 21:41:16 +00:00
|
|
|
|
|
|
|
|
if (outbufSize < maxSize) outbufSize = maxSize;
|
|
|
|
|
|
|
|
|
|
inbuf = new RingBuffer<float>(maxSize);
|
|
|
|
|
outbuf = new RingBuffer<float>(outbufSize);
|
|
|
|
|
|
2011-01-07 21:46:36 +00:00
|
|
|
mag = allocate_and_zero<process_t>(realSize);
|
|
|
|
|
phase = allocate_and_zero<process_t>(realSize);
|
|
|
|
|
prevPhase = allocate_and_zero<process_t>(realSize);
|
|
|
|
|
prevError = allocate_and_zero<process_t>(realSize);
|
|
|
|
|
unwrappedPhase = allocate_and_zero<process_t>(realSize);
|
|
|
|
|
envelope = allocate_and_zero<process_t>(realSize);
|
2008-05-22 16:54:27 +00:00
|
|
|
|
2011-01-07 21:46:36 +00:00
|
|
|
fltbuf = allocate_and_zero<float>(maxSize);
|
2011-03-19 12:41:38 +00:00
|
|
|
dblbuf = allocate_and_zero<process_t>(maxSize);
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2011-01-07 21:46:36 +00:00
|
|
|
accumulator = allocate_and_zero<float>(maxSize);
|
|
|
|
|
windowAccumulator = allocate_and_zero<float>(maxSize);
|
|
|
|
|
interpolator = allocate_and_zero<float>(maxSize);
|
2010-05-29 22:07:54 +01:00
|
|
|
interpolatorScale = 0;
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
for (std::set<size_t>::const_iterator i = sizes.begin();
|
|
|
|
|
i != sizes.end(); ++i) {
|
|
|
|
|
ffts[*i] = new FFT(*i);
|
2011-01-07 21:46:36 +00:00
|
|
|
if (sizeof(process_t) == sizeof(double)) {
|
|
|
|
|
ffts[*i]->initDouble();
|
|
|
|
|
} else {
|
|
|
|
|
ffts[*i]->initFloat();
|
|
|
|
|
}
|
2007-11-06 21:41:16 +00:00
|
|
|
}
|
2010-05-16 10:44:38 +01:00
|
|
|
fft = ffts[initialFftSize];
|
2007-11-06 21:41:16 +00:00
|
|
|
|
|
|
|
|
resampler = 0;
|
|
|
|
|
resamplebuf = 0;
|
|
|
|
|
resamplebufSize = 0;
|
|
|
|
|
|
|
|
|
|
reset();
|
|
|
|
|
|
2008-11-26 22:31:55 +00:00
|
|
|
// Avoid dividing opening sample (which will be discarded anyway) by zero
|
|
|
|
|
windowAccumulator[0] = 1.f;
|
2007-11-06 21:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
|
2007-11-06 21:41:16 +00:00
|
|
|
void
|
2010-05-16 10:44:38 +01:00
|
|
|
RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
|
|
|
|
|
size_t fftSize)
|
2007-11-06 21:41:16 +00:00
|
|
|
{
|
2011-11-25 11:11:59 +00:00
|
|
|
// std::cerr << "ChannelData::setSizes: windowSize = " << windowSize << ", fftSize = " << fftSize << std::endl;
|
|
|
|
|
|
|
|
|
|
size_t maxSize = 2 * std::max(windowSize, fftSize);
|
2010-05-16 10:44:38 +01:00
|
|
|
size_t realSize = maxSize / 2 + 1;
|
|
|
|
|
size_t oldMax = inbuf->getSize();
|
2011-03-19 12:41:38 +00:00
|
|
|
size_t oldReal = oldMax / 2 + 1;
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
if (oldMax >= maxSize) {
|
2007-11-06 21:41:16 +00:00
|
|
|
|
|
|
|
|
// no need to reallocate buffers, just reselect fft
|
|
|
|
|
|
|
|
|
|
//!!! we can't actually do this without locking against the
|
|
|
|
|
//process thread, can we? we need to zero the mag/phase
|
|
|
|
|
//buffers without interference
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
if (ffts.find(fftSize) == ffts.end()) {
|
2007-11-06 21:41:16 +00:00
|
|
|
//!!! this also requires a lock, but it shouldn't occur in
|
|
|
|
|
//RT mode with proper initialisation
|
2010-05-16 10:44:38 +01:00
|
|
|
ffts[fftSize] = new FFT(fftSize);
|
2011-01-07 21:46:36 +00:00
|
|
|
if (sizeof(process_t) == sizeof(double)) {
|
|
|
|
|
ffts[fftSize]->initDouble();
|
|
|
|
|
} else {
|
|
|
|
|
ffts[fftSize]->initFloat();
|
|
|
|
|
}
|
2007-11-06 21:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
fft = ffts[fftSize];
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2011-03-19 12:41:38 +00:00
|
|
|
v_zero(fltbuf, maxSize);
|
2011-01-07 21:46:36 +00:00
|
|
|
v_zero(dblbuf, maxSize);
|
|
|
|
|
|
|
|
|
|
v_zero(mag, realSize);
|
|
|
|
|
v_zero(phase, realSize);
|
|
|
|
|
v_zero(prevPhase, realSize);
|
|
|
|
|
v_zero(prevError, realSize);
|
|
|
|
|
v_zero(unwrappedPhase, realSize);
|
2007-11-06 21:41:16 +00:00
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//!!! at this point we need a lock in case a different client
|
|
|
|
|
//thread is calling process() -- we need this lock even if we
|
|
|
|
|
//aren't running in threaded mode ourselves -- if we're in RT
|
|
|
|
|
//mode, then the process call should trylock and fail if the lock
|
|
|
|
|
//is unavailable (since this should never normally be the case in
|
|
|
|
|
//general use in RT mode)
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
RingBuffer<float> *newbuf = inbuf->resized(maxSize);
|
2007-11-06 21:41:16 +00:00
|
|
|
delete inbuf;
|
|
|
|
|
inbuf = newbuf;
|
|
|
|
|
|
|
|
|
|
// We don't want to preserve data in these arrays
|
|
|
|
|
|
2011-03-19 12:41:38 +00:00
|
|
|
mag = reallocate_and_zero(mag, oldReal, realSize);
|
|
|
|
|
phase = reallocate_and_zero(phase, oldReal, realSize);
|
|
|
|
|
prevPhase = reallocate_and_zero(prevPhase, oldReal, realSize);
|
|
|
|
|
prevError = reallocate_and_zero(prevError, oldReal, realSize);
|
|
|
|
|
unwrappedPhase = reallocate_and_zero(unwrappedPhase, oldReal, realSize);
|
|
|
|
|
envelope = reallocate_and_zero(envelope, oldReal, realSize);
|
|
|
|
|
fltbuf = reallocate_and_zero(fltbuf, oldMax, maxSize);
|
|
|
|
|
dblbuf = reallocate_and_zero(dblbuf, oldMax, maxSize);
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2011-03-19 12:41:38 +00:00
|
|
|
interpolator = reallocate_and_zero<float>(interpolator, oldMax, maxSize);
|
2008-05-22 16:54:27 +00:00
|
|
|
|
2007-11-06 21:41:16 +00:00
|
|
|
// But we do want to preserve data in these
|
|
|
|
|
|
2011-03-19 12:41:38 +00:00
|
|
|
accumulator = reallocate_and_zero_extension
|
|
|
|
|
(accumulator, oldMax, maxSize);
|
2007-11-06 21:41:16 +00:00
|
|
|
|
2011-03-19 12:41:38 +00:00
|
|
|
windowAccumulator = reallocate_and_zero_extension
|
|
|
|
|
(windowAccumulator, oldMax, maxSize);
|
2010-05-29 22:07:54 +01:00
|
|
|
|
|
|
|
|
interpolatorScale = 0;
|
2007-11-06 21:41:16 +00:00
|
|
|
|
|
|
|
|
//!!! and resampler?
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
if (ffts.find(fftSize) == ffts.end()) {
|
|
|
|
|
ffts[fftSize] = new FFT(fftSize);
|
2011-01-07 21:46:36 +00:00
|
|
|
if (sizeof(process_t) == sizeof(double)) {
|
|
|
|
|
ffts[fftSize]->initDouble();
|
|
|
|
|
} else {
|
|
|
|
|
ffts[fftSize]->initFloat();
|
|
|
|
|
}
|
2007-11-06 21:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-16 10:44:38 +01:00
|
|
|
fft = ffts[fftSize];
|
2007-11-06 21:41:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2008-07-01 10:25:17 +00:00
|
|
|
RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize)
|
2007-11-06 21:41:16 +00:00
|
|
|
{
|
|
|
|
|
size_t oldSize = outbuf->getSize();
|
|
|
|
|
|
2007-11-20 20:17:13 +00:00
|
|
|
// std::cerr << "ChannelData::setOutbufSize(" << outbufSize << ") [from " << oldSize << "]" << std::endl;
|
2007-11-06 21:41:16 +00:00
|
|
|
|
|
|
|
|
if (oldSize < outbufSize) {
|
|
|
|
|
|
|
|
|
|
//!!! at this point we need a lock in case a different client
|
|
|
|
|
//thread is calling process()
|
|
|
|
|
|
|
|
|
|
RingBuffer<float> *newbuf = outbuf->resized(outbufSize);
|
|
|
|
|
delete outbuf;
|
|
|
|
|
outbuf = newbuf;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-22 16:54:27 +00:00
|
|
|
void
|
2008-07-01 10:25:17 +00:00
|
|
|
RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz)
|
2008-05-22 16:54:27 +00:00
|
|
|
{
|
2011-01-07 21:46:36 +00:00
|
|
|
resamplebuf = reallocate_and_zero<float>(resamplebuf, resamplebufSize, sz);
|
2008-05-22 16:54:27 +00:00
|
|
|
resamplebufSize = sz;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-01 10:25:17 +00:00
|
|
|
RubberBandStretcher::Impl::ChannelData::~ChannelData()
|
2007-11-06 21:41:16 +00:00
|
|
|
{
|
|
|
|
|
delete resampler;
|
2008-05-22 16:54:27 +00:00
|
|
|
|
2009-09-17 13:01:21 +00:00
|
|
|
deallocate(resamplebuf);
|
2007-11-06 21:41:16 +00:00
|
|
|
|
|
|
|
|
delete inbuf;
|
|
|
|
|
delete outbuf;
|
2008-05-22 16:54:27 +00:00
|
|
|
|
2009-09-17 13:01:21 +00:00
|
|
|
deallocate(mag);
|
|
|
|
|
deallocate(phase);
|
|
|
|
|
deallocate(prevPhase);
|
|
|
|
|
deallocate(prevError);
|
|
|
|
|
deallocate(unwrappedPhase);
|
|
|
|
|
deallocate(envelope);
|
|
|
|
|
deallocate(accumulator);
|
|
|
|
|
deallocate(windowAccumulator);
|
|
|
|
|
deallocate(fltbuf);
|
2007-11-06 21:41:16 +00:00
|
|
|
|
|
|
|
|
for (std::map<size_t, FFT *>::iterator i = ffts.begin();
|
|
|
|
|
i != ffts.end(); ++i) {
|
|
|
|
|
delete i->second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2008-07-01 10:25:17 +00:00
|
|
|
RubberBandStretcher::Impl::ChannelData::reset()
|
2007-11-06 21:41:16 +00:00
|
|
|
{
|
|
|
|
|
inbuf->reset();
|
|
|
|
|
outbuf->reset();
|
|
|
|
|
|
|
|
|
|
if (resampler) resampler->reset();
|
|
|
|
|
|
2009-01-28 11:19:00 +00:00
|
|
|
size_t size = inbuf->getSize();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < size; ++i) {
|
|
|
|
|
accumulator[i] = 0.f;
|
|
|
|
|
windowAccumulator[i] = 0.f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Avoid dividing opening sample (which will be discarded anyway) by zero
|
|
|
|
|
windowAccumulator[0] = 1.f;
|
|
|
|
|
|
2007-11-06 21:41:16 +00:00
|
|
|
accumulatorFill = 0;
|
|
|
|
|
prevIncrement = 0;
|
2007-11-18 21:38:18 +00:00
|
|
|
chunkCount = 0;
|
2007-11-06 21:41:16 +00:00
|
|
|
inCount = 0;
|
|
|
|
|
inputSize = -1;
|
|
|
|
|
outCount = 0;
|
2010-05-29 22:07:54 +01:00
|
|
|
interpolatorScale = 0;
|
2008-05-22 16:54:27 +00:00
|
|
|
unchanged = true;
|
2007-11-06 21:41:16 +00:00
|
|
|
draining = false;
|
|
|
|
|
outputComplete = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|