Files
librubberband/src/StretcherChannelData.cpp

303 lines
8.1 KiB
C++
Raw Normal View History

2007-11-06 21:41:16 +00:00
/* -*- 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-2010 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.
*/
2007-11-06 21:41:16 +00:00
#include "StretcherChannelData.h"
#include "dsp/Resampler.h"
2007-11-06 21:41:16 +00:00
#include "system/Allocators.h"
2007-11-06 21:41:16 +00:00
namespace RubberBand
{
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
size_t fftSize,
size_t outbufSize)
2007-11-06 21:41:16 +00:00
{
std::set<size_t> s;
construct(s, windowSize, fftSize, outbufSize);
2007-11-06 21:41:16 +00:00
}
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &sizes,
size_t initialWindowSize,
size_t initialFftSize,
size_t outbufSize)
2007-11-06 21:41:16 +00:00
{
construct(sizes, initialWindowSize, initialFftSize, outbufSize);
2007-11-06 21:41:16 +00:00
}
void
RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
size_t initialWindowSize,
size_t initialFftSize,
2007-11-06 21:41:16 +00:00
size_t outbufSize)
{
size_t maxSize = initialWindowSize;
if (initialFftSize > maxSize) maxSize = initialFftSize;
2007-11-06 21:41:16 +00: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
}
// max possible size of the real "half" of freq data
size_t realSize = maxSize / 2 + 1;
2007-11-06 21:41:16 +00:00
// std::cerr << "ChannelData::construct([" << windowSizes.size() << "], " << maxSize << ", " << 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);
mag = allocate<double>(realSize);
phase = allocate<double>(realSize);
prevPhase = allocate<double>(realSize);
prevError = allocate<double>(realSize);
unwrappedPhase = allocate<double>(realSize);
envelope = allocate<double>(realSize);
freqPeak = new size_t[realSize];
2007-11-06 21:41:16 +00:00
fltbuf = allocate<float>(maxSize);
2007-11-06 21:41:16 +00:00
accumulator = allocate<float>(maxSize);
windowAccumulator = allocate<float>(maxSize);
2007-11-06 21:41:16 +00:00
for (std::set<size_t>::const_iterator i = sizes.begin();
i != sizes.end(); ++i) {
ffts[*i] = new FFT(*i);
2007-11-06 21:41:16 +00:00
ffts[*i]->initDouble();
}
fft = ffts[initialFftSize];
2007-11-06 21:41:16 +00:00
dblbuf = fft->getDoubleTimeBuffer();
2007-11-06 21:41:16 +00:00
resampler = 0;
resamplebuf = 0;
resamplebufSize = 0;
reset();
for (size_t i = 0; i < realSize; ++i) {
freqPeak[i] = 0;
}
for (size_t i = 0; i < initialFftSize; ++i) {
dblbuf[i] = 0.0;
}
for (size_t i = 0; i < maxSize; ++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
}
2007-11-06 21:41:16 +00:00
void
RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
size_t fftSize)
2007-11-06 21:41:16 +00:00
{
size_t maxSize = std::max(windowSize, fftSize);
size_t realSize = maxSize / 2 + 1;
size_t oldMax = inbuf->getSize();
2007-11-06 21:41:16 +00: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
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
ffts[fftSize] = new FFT(fftSize);
ffts[fftSize]->initDouble();
2007-11-06 21:41:16 +00:00
}
fft = ffts[fftSize];
2007-11-06 21:41:16 +00:00
dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < maxSize; ++i) {
dblbuf[i] = 0.0;
}
2007-11-06 21:41:16 +00:00
for (size_t i = 0; i < realSize; ++i) {
mag[i] = 0.0;
phase[i] = 0.0;
prevPhase[i] = 0.0;
prevError[i] = 0.0;
2007-11-06 21:41:16 +00:00
unwrappedPhase[i] = 0.0;
freqPeak[i] = 0;
}
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)
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
mag = reallocate<double>(mag, oldMax, realSize);
phase = reallocate<double>(phase, oldMax, realSize);
prevPhase = reallocate<double>(prevPhase, oldMax, realSize);
prevError = reallocate<double>(prevError, oldMax, realSize);
unwrappedPhase = reallocate<double>(unwrappedPhase, oldMax, realSize);
envelope = reallocate<double>(envelope, oldMax, realSize);
2007-11-06 21:41:16 +00:00
delete[] freqPeak;
2007-11-06 21:41:16 +00:00
freqPeak = new size_t[realSize];
deallocate(fltbuf);
fltbuf = allocate<float>(maxSize);
2007-11-06 21:41:16 +00:00
// But we do want to preserve data in these
float *newAcc = allocate<float>(maxSize);
v_copy(newAcc, accumulator, oldMax);
deallocate(accumulator);
2007-11-06 21:41:16 +00:00
accumulator = newAcc;
newAcc = allocate<float>(maxSize);
v_copy(newAcc, windowAccumulator, oldMax);
deallocate(windowAccumulator);
2007-11-06 21:41:16 +00:00
windowAccumulator = newAcc;
//!!! and resampler?
for (size_t i = 0; i < realSize; ++i) {
freqPeak[i] = 0;
}
for (size_t i = 0; i < maxSize; ++i) {
fltbuf[i] = 0.f;
2007-11-06 21:41:16 +00:00
}
if (ffts.find(fftSize) == ffts.end()) {
ffts[fftSize] = new FFT(fftSize);
ffts[fftSize]->initDouble();
2007-11-06 21:41:16 +00:00
}
fft = ffts[fftSize];
dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < fftSize; ++i) {
dblbuf[i] = 0.0;
}
2007-11-06 21:41:16 +00:00
}
void
RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize)
2007-11-06 21:41:16 +00:00
{
size_t oldSize = outbuf->getSize();
// 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;
}
}
void
RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz)
{
resamplebuf = reallocate<float>(resamplebuf, resamplebufSize, sz);
resamplebufSize = sz;
}
RubberBandStretcher::Impl::ChannelData::~ChannelData()
2007-11-06 21:41:16 +00:00
{
delete resampler;
deallocate(resamplebuf);
2007-11-06 21:41:16 +00:00
delete inbuf;
delete outbuf;
deallocate(mag);
deallocate(phase);
deallocate(prevPhase);
deallocate(prevError);
deallocate(unwrappedPhase);
deallocate(envelope);
2007-11-06 21:41:16 +00:00
delete[] freqPeak;
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
RubberBandStretcher::Impl::ChannelData::reset()
2007-11-06 21:41:16 +00:00
{
inbuf->reset();
outbuf->reset();
if (resampler) resampler->reset();
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;
chunkCount = 0;
2007-11-06 21:41:16 +00:00
inCount = 0;
inputSize = -1;
outCount = 0;
unchanged = true;
2007-11-06 21:41:16 +00:00
draining = false;
outputComplete = false;
}
}