merge from thirdparty rubberband 1.3 @ 4901
[ardour2.git] / libs / rubberband / src / StretcherChannelData.cpp
blob240df230d1eb4d91828c97dc07077a4e0cd5f6a5
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
3 /*
4 Rubber Band
5 An audio time-stretching and pitch-shifting library.
6 Copyright 2007-2008 Chris Cannam.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version. See the file
12 COPYING included with this distribution for more information.
15 #include "StretcherChannelData.h"
17 #include "Resampler.h"
20 namespace RubberBand
23 RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
24 int overSample,
25 size_t outbufSize) :
26 oversample(overSample)
28 std::set<size_t> s;
29 construct(s, windowSize, outbufSize);
32 RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &windowSizes,
33 int overSample,
34 size_t initialWindowSize,
35 size_t outbufSize) :
36 oversample(overSample)
38 construct(windowSizes, initialWindowSize, outbufSize);
41 void
42 RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &windowSizes,
43 size_t initialWindowSize,
44 size_t outbufSize)
46 size_t maxSize = initialWindowSize;
48 if (!windowSizes.empty()) {
49 // std::set is ordered by value
50 std::set<size_t>::const_iterator i = windowSizes.end();
51 maxSize = *--i;
53 if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
54 if (initialWindowSize > maxSize) maxSize = initialWindowSize;
57 // max size of the real "half" of freq data
58 size_t realSize = (maxSize * oversample)/2 + 1;
60 // std::cerr << "ChannelData::construct([" << windowSizes.size() << "], " << maxSize << ", " << outbufSize << ")" << std::endl;
62 if (outbufSize < maxSize) outbufSize = maxSize;
64 inbuf = new RingBuffer<float>(maxSize);
65 outbuf = new RingBuffer<float>(outbufSize);
67 mag = allocDouble(realSize);
68 phase = allocDouble(realSize);
69 prevPhase = allocDouble(realSize);
70 prevError = allocDouble(realSize);
71 unwrappedPhase = allocDouble(realSize);
72 envelope = allocDouble(realSize);
74 freqPeak = new size_t[realSize];
76 fltbuf = allocFloat(maxSize);
78 accumulator = allocFloat(maxSize);
79 windowAccumulator = allocFloat(maxSize);
81 for (std::set<size_t>::const_iterator i = windowSizes.begin();
82 i != windowSizes.end(); ++i) {
83 ffts[*i] = new FFT(*i * oversample);
84 ffts[*i]->initDouble();
86 if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
87 ffts[initialWindowSize] = new FFT(initialWindowSize * oversample);
88 ffts[initialWindowSize]->initDouble();
90 fft = ffts[initialWindowSize];
92 dblbuf = fft->getDoubleTimeBuffer();
94 resampler = 0;
95 resamplebuf = 0;
96 resamplebufSize = 0;
98 reset();
100 for (size_t i = 0; i < realSize; ++i) {
101 freqPeak[i] = 0;
104 for (size_t i = 0; i < initialWindowSize * oversample; ++i) {
105 dblbuf[i] = 0.0;
108 for (size_t i = 0; i < maxSize; ++i) {
109 accumulator[i] = 0.f;
110 windowAccumulator[i] = 0.f;
113 // Avoid dividing opening sample (which will be discarded anyway) by zero
114 windowAccumulator[0] = 1.f;
117 void
118 RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
120 size_t oldSize = inbuf->getSize();
121 size_t realSize = (windowSize * oversample) / 2 + 1;
123 // std::cerr << "ChannelData::setWindowSize(" << windowSize << ") [from " << oldSize << "]" << std::endl;
125 if (oldSize >= windowSize) {
127 // no need to reallocate buffers, just reselect fft
129 //!!! we can't actually do this without locking against the
130 //process thread, can we? we need to zero the mag/phase
131 //buffers without interference
133 if (ffts.find(windowSize) == ffts.end()) {
134 //!!! this also requires a lock, but it shouldn't occur in
135 //RT mode with proper initialisation
136 ffts[windowSize] = new FFT(windowSize * oversample);
137 ffts[windowSize]->initDouble();
140 fft = ffts[windowSize];
142 dblbuf = fft->getDoubleTimeBuffer();
144 for (size_t i = 0; i < windowSize * oversample; ++i) {
145 dblbuf[i] = 0.0;
148 for (size_t i = 0; i < realSize; ++i) {
149 mag[i] = 0.0;
150 phase[i] = 0.0;
151 prevPhase[i] = 0.0;
152 prevError[i] = 0.0;
153 unwrappedPhase[i] = 0.0;
154 freqPeak[i] = 0;
157 return;
160 //!!! at this point we need a lock in case a different client
161 //thread is calling process() -- we need this lock even if we
162 //aren't running in threaded mode ourselves -- if we're in RT
163 //mode, then the process call should trylock and fail if the lock
164 //is unavailable (since this should never normally be the case in
165 //general use in RT mode)
167 RingBuffer<float> *newbuf = inbuf->resized(windowSize);
168 delete inbuf;
169 inbuf = newbuf;
171 // We don't want to preserve data in these arrays
173 mag = allocDouble(mag, realSize);
174 phase = allocDouble(phase, realSize);
175 prevPhase = allocDouble(prevPhase, realSize);
176 prevError = allocDouble(prevError, realSize);
177 unwrappedPhase = allocDouble(unwrappedPhase, realSize);
178 envelope = allocDouble(envelope, realSize);
180 delete[] freqPeak;
181 freqPeak = new size_t[realSize];
183 fltbuf = allocFloat(fltbuf, windowSize);
185 // But we do want to preserve data in these
187 float *newAcc = allocFloat(windowSize);
189 for (size_t i = 0; i < oldSize; ++i) newAcc[i] = accumulator[i];
191 freeFloat(accumulator);
192 accumulator = newAcc;
194 newAcc = allocFloat(windowSize);
196 for (size_t i = 0; i < oldSize; ++i) newAcc[i] = windowAccumulator[i];
198 freeFloat(windowAccumulator);
199 windowAccumulator = newAcc;
201 //!!! and resampler?
203 for (size_t i = 0; i < realSize; ++i) {
204 freqPeak[i] = 0;
207 for (size_t i = 0; i < windowSize; ++i) {
208 fltbuf[i] = 0.f;
211 if (ffts.find(windowSize) == ffts.end()) {
212 ffts[windowSize] = new FFT(windowSize * oversample);
213 ffts[windowSize]->initDouble();
216 fft = ffts[windowSize];
218 dblbuf = fft->getDoubleTimeBuffer();
220 for (size_t i = 0; i < windowSize * oversample; ++i) {
221 dblbuf[i] = 0.0;
225 void
226 RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize)
228 size_t oldSize = outbuf->getSize();
230 // std::cerr << "ChannelData::setOutbufSize(" << outbufSize << ") [from " << oldSize << "]" << std::endl;
232 if (oldSize < outbufSize) {
234 //!!! at this point we need a lock in case a different client
235 //thread is calling process()
237 RingBuffer<float> *newbuf = outbuf->resized(outbufSize);
238 delete outbuf;
239 outbuf = newbuf;
243 void
244 RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz)
246 resamplebuf = allocFloat(resamplebuf, sz);
247 resamplebufSize = sz;
250 RubberBandStretcher::Impl::ChannelData::~ChannelData()
252 delete resampler;
254 freeFloat(resamplebuf);
256 delete inbuf;
257 delete outbuf;
259 freeDouble(mag);
260 freeDouble(phase);
261 freeDouble(prevPhase);
262 freeDouble(prevError);
263 freeDouble(unwrappedPhase);
264 freeDouble(envelope);
265 delete[] freqPeak;
266 freeFloat(accumulator);
267 freeFloat(windowAccumulator);
268 freeFloat(fltbuf);
270 for (std::map<size_t, FFT *>::iterator i = ffts.begin();
271 i != ffts.end(); ++i) {
272 delete i->second;
276 void
277 RubberBandStretcher::Impl::ChannelData::reset()
279 inbuf->reset();
280 outbuf->reset();
282 if (resampler) resampler->reset();
284 size_t size = inbuf->getSize();
286 for (size_t i = 0; i < size; ++i) {
287 accumulator[i] = 0.f;
288 windowAccumulator[i] = 0.f;
291 // Avoid dividing opening sample (which will be discarded anyway) by zero
292 windowAccumulator[0] = 1.f;
294 accumulatorFill = 0;
295 prevIncrement = 0;
296 chunkCount = 0;
297 inCount = 0;
298 inputSize = -1;
299 outCount = 0;
300 unchanged = true;
301 draining = false;
302 outputComplete = false;