1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
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"
23 RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize
,
26 oversample(overSample
)
29 construct(s
, windowSize
, outbufSize
);
32 RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set
<size_t> &windowSizes
,
34 size_t initialWindowSize
,
36 oversample(overSample
)
38 construct(windowSizes
, initialWindowSize
, outbufSize
);
42 RubberBandStretcher::Impl::ChannelData::construct(const std::set
<size_t> &windowSizes
,
43 size_t initialWindowSize
,
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();
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();
100 for (size_t i
= 0; i
< realSize
; ++i
) {
104 for (size_t i
= 0; i
< initialWindowSize
* oversample
; ++i
) {
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
;
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
) {
148 for (size_t i
= 0; i
< realSize
; ++i
) {
153 unwrappedPhase
[i
] = 0.0;
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
);
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
);
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
;
203 for (size_t i
= 0; i
< realSize
; ++i
) {
207 for (size_t i
= 0; i
< windowSize
; ++i
) {
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
) {
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
);
244 RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz
)
246 resamplebuf
= allocFloat(resamplebuf
, sz
);
247 resamplebufSize
= sz
;
250 RubberBandStretcher::Impl::ChannelData::~ChannelData()
254 freeFloat(resamplebuf
);
261 freeDouble(prevPhase
);
262 freeDouble(prevError
);
263 freeDouble(unwrappedPhase
);
264 freeDouble(envelope
);
266 freeFloat(accumulator
);
267 freeFloat(windowAccumulator
);
270 for (std::map
<size_t, FFT
*>::iterator i
= ffts
.begin();
271 i
!= ffts
.end(); ++i
) {
277 RubberBandStretcher::Impl::ChannelData::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
;
302 outputComplete
= false;