Flesh out the implementation a bit

This commit is contained in:
Chris Cannam
2022-05-23 15:04:34 +01:00
parent af97c70e69
commit 5cc4833820
7 changed files with 408 additions and 48 deletions

View File

@@ -49,6 +49,7 @@ library_sources = [
'src/common/sysutils.cpp', 'src/common/sysutils.cpp',
'src/common/Thread.cpp', 'src/common/Thread.cpp',
'src/temporary.cpp', 'src/temporary.cpp',
'src/finer/R3StretcherImpl.cpp',
] ]
jni_sources = [ jni_sources = [

View File

@@ -81,6 +81,7 @@
namespace RubberBand namespace RubberBand
{ {
class R3StretcherImpl;//!!!
class RUBBERBAND_DLLEXPORT class RUBBERBAND_DLLEXPORT
RubberBandStretcher RubberBandStretcher
@@ -765,6 +766,7 @@ public:
protected: protected:
class Impl; class Impl;
Impl *m_d; Impl *m_d;
R3StretcherImpl *m_r3d;
}; };
} }

View File

@@ -22,6 +22,7 @@
*/ */
#include "faster/StretcherImpl.h" #include "faster/StretcherImpl.h"
#include "finer/R3StretcherImpl.h"
namespace RubberBand { namespace RubberBand {
@@ -32,184 +33,204 @@ RubberBandStretcher::RubberBandStretcher(size_t sampleRate,
Options options, Options options,
double initialTimeRatio, double initialTimeRatio,
double initialPitchScale) : double initialPitchScale) :
/*!!!
m_d(new Impl(sampleRate, channels, options, m_d(new Impl(sampleRate, channels, options,
initialTimeRatio, initialPitchScale)) initialTimeRatio, initialPitchScale))
*/
m_d(nullptr),
//!!! +logger
m_r3d(new R3StretcherImpl(R3StretcherImpl::Parameters
(sampleRate, channels)))
{ {
} }
RubberBandStretcher::~RubberBandStretcher() RubberBandStretcher::~RubberBandStretcher()
{ {
delete m_d; delete m_d;
delete m_r3d;
} }
void void
RubberBandStretcher::reset() RubberBandStretcher::reset()
{ {
m_d->reset(); if (m_d) m_d->reset();
else m_r3d->reset();
} }
void void
RubberBandStretcher::setTimeRatio(double ratio) RubberBandStretcher::setTimeRatio(double ratio)
{ {
m_d->setTimeRatio(ratio); if (m_d) m_d->setTimeRatio(ratio);
else m_r3d->setTimeRatio(ratio);
} }
void void
RubberBandStretcher::setPitchScale(double scale) RubberBandStretcher::setPitchScale(double scale)
{ {
m_d->setPitchScale(scale); if (m_d) m_d->setPitchScale(scale);
else m_r3d->setPitchScale(scale);
} }
double double
RubberBandStretcher::getTimeRatio() const RubberBandStretcher::getTimeRatio() const
{ {
return m_d->getTimeRatio(); if (m_d) return m_d->getTimeRatio();
else return m_r3d->getTimeRatio();
} }
double double
RubberBandStretcher::getPitchScale() const RubberBandStretcher::getPitchScale() const
{ {
return m_d->getPitchScale(); if (m_d) return m_d->getPitchScale();
else return m_r3d->getPitchScale();
} }
size_t size_t
RubberBandStretcher::getLatency() const RubberBandStretcher::getLatency() const
{ {
return m_d->getLatency(); if (m_d) return m_d->getLatency();
else return m_r3d->getLatency();
} }
void void
RubberBandStretcher::setTransientsOption(Options options) RubberBandStretcher::setTransientsOption(Options options)
{ {
m_d->setTransientsOption(options); if (m_d) m_d->setTransientsOption(options);
} }
void void
RubberBandStretcher::setDetectorOption(Options options) RubberBandStretcher::setDetectorOption(Options options)
{ {
m_d->setDetectorOption(options); if (m_d) m_d->setDetectorOption(options);
} }
void void
RubberBandStretcher::setPhaseOption(Options options) RubberBandStretcher::setPhaseOption(Options options)
{ {
m_d->setPhaseOption(options); if (m_d) m_d->setPhaseOption(options);
} }
void void
RubberBandStretcher::setFormantOption(Options options) RubberBandStretcher::setFormantOption(Options options)
{ {
m_d->setFormantOption(options); if (m_d) m_d->setFormantOption(options);
} }
void void
RubberBandStretcher::setPitchOption(Options options) RubberBandStretcher::setPitchOption(Options options)
{ {
m_d->setPitchOption(options); if (m_d) m_d->setPitchOption(options);
} }
void void
RubberBandStretcher::setExpectedInputDuration(size_t samples) RubberBandStretcher::setExpectedInputDuration(size_t samples)
{ {
m_d->setExpectedInputDuration(samples); if (m_d) m_d->setExpectedInputDuration(samples);
} }
void void
RubberBandStretcher::setMaxProcessSize(size_t samples) RubberBandStretcher::setMaxProcessSize(size_t samples)
{ {
m_d->setMaxProcessSize(samples); if (m_d) m_d->setMaxProcessSize(samples); //!!! definitely need for r3d
} }
void void
RubberBandStretcher::setKeyFrameMap(const std::map<size_t, size_t> &mapping) RubberBandStretcher::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
{ {
m_d->setKeyFrameMap(mapping); if (m_d) m_d->setKeyFrameMap(mapping);
//!!!
} }
size_t size_t
RubberBandStretcher::getSamplesRequired() const RubberBandStretcher::getSamplesRequired() const
{ {
return m_d->getSamplesRequired(); if (m_d) return m_d->getSamplesRequired();
else return m_r3d->getSamplesRequired();
} }
void void
RubberBandStretcher::study(const float *const *input, size_t samples, RubberBandStretcher::study(const float *const *input, size_t samples,
bool final) bool final)
{ {
m_d->study(input, samples, final); if (m_d) m_d->study(input, samples, final);
//!!!
} }
void void
RubberBandStretcher::process(const float *const *input, size_t samples, RubberBandStretcher::process(const float *const *input, size_t samples,
bool final) bool final)
{ {
m_d->process(input, samples, final); if (m_d) m_d->process(input, samples, final);
else m_r3d->process(input, samples, final);
} }
int int
RubberBandStretcher::available() const RubberBandStretcher::available() const
{ {
return m_d->available(); if (m_d) return m_d->available();
else return m_r3d->available();
} }
size_t size_t
RubberBandStretcher::retrieve(float *const *output, size_t samples) const RubberBandStretcher::retrieve(float *const *output, size_t samples) const
{ {
return m_d->retrieve(output, samples); if (m_d) return m_d->retrieve(output, samples);
else return m_r3d->retrieve(output, samples);
} }
float float
RubberBandStretcher::getFrequencyCutoff(int n) const RubberBandStretcher::getFrequencyCutoff(int n) const
{ {
return m_d->getFrequencyCutoff(n); if (m_d) return m_d->getFrequencyCutoff(n);
} }
void void
RubberBandStretcher::setFrequencyCutoff(int n, float f) RubberBandStretcher::setFrequencyCutoff(int n, float f)
{ {
m_d->setFrequencyCutoff(n, f); if (m_d) m_d->setFrequencyCutoff(n, f);
} }
size_t size_t
RubberBandStretcher::getInputIncrement() const RubberBandStretcher::getInputIncrement() const
{ {
return m_d->getInputIncrement(); if (m_d) return m_d->getInputIncrement();
} }
std::vector<int> std::vector<int>
RubberBandStretcher::getOutputIncrements() const RubberBandStretcher::getOutputIncrements() const
{ {
return m_d->getOutputIncrements(); if (m_d) return m_d->getOutputIncrements();
} }
std::vector<float> std::vector<float>
RubberBandStretcher::getPhaseResetCurve() const RubberBandStretcher::getPhaseResetCurve() const
{ {
return m_d->getPhaseResetCurve(); if (m_d) return m_d->getPhaseResetCurve();
} }
std::vector<int> std::vector<int>
RubberBandStretcher::getExactTimePoints() const RubberBandStretcher::getExactTimePoints() const
{ {
return m_d->getExactTimePoints(); if (m_d) return m_d->getExactTimePoints();
} }
size_t size_t
RubberBandStretcher::getChannelCount() const RubberBandStretcher::getChannelCount() const
{ {
return m_d->getChannelCount(); if (m_d) return m_d->getChannelCount();
else return m_r3d->getChannelCount();
} }
void void
RubberBandStretcher::calculateStretch() RubberBandStretcher::calculateStretch()
{ {
m_d->calculateStretch(); if (m_d) m_d->calculateStretch();
} }
void void
RubberBandStretcher::setDebugLevel(int level) RubberBandStretcher::setDebugLevel(int level)
{ {
m_d->setDebugLevel(level); if (m_d) m_d->setDebugLevel(level);
} }
void void

View File

@@ -79,6 +79,10 @@ public:
v_multiply(dst, src, m_cache, m_size); v_multiply(dst, src, m_cache, m_size);
} }
inline void cutAndAdd(const T *const R__ src, T *const R__ dst) const {
v_multiply_and_add(dst, src, m_cache, m_size);
}
inline void add(T *const R__ dst, T scale) const { inline void add(T *const R__ dst, T scale) const {
v_add_with_gain(dst, m_cache, scale, m_size); v_add_with_gain(dst, m_cache, scale, m_size);
} }

View File

@@ -235,6 +235,9 @@ protected:
bool inRange(double f, const Guide::Range &r) { bool inRange(double f, const Guide::Range &r) {
return r.present && f >= r.f0 && f < r.f1; return r.present && f >= r.f0 && f < r.f1;
} }
GuidedPhaseAdvance(const GuidedPhaseAdvance &) =delete;
GuidedPhaseAdvance &operator=(const GuidedPhaseAdvance &) =delete;
}; };
} }

View File

@@ -0,0 +1,277 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 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
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.
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.
*/
#include "R3StretcherImpl.h"
#include <array>
namespace RubberBand {
void
R3StretcherImpl::setTimeRatio(double ratio)
{
m_timeRatio = ratio;
}
void
R3StretcherImpl::setPitchScale(double scale)
{
m_pitchScale = scale;
}
double
R3StretcherImpl::getTimeRatio() const
{
return m_timeRatio;
}
double
R3StretcherImpl::getPitchScale() const
{
return m_pitchScale;
}
size_t
R3StretcherImpl::getLatency() const
{
return 0; //!!!
}
size_t
R3StretcherImpl::getChannelCount() const
{
return m_parameters.channels;
}
void
R3StretcherImpl::reset()
{
//!!!
}
size_t
R3StretcherImpl::getSamplesRequired() const
{
int longest = m_guideConfiguration.longestFftSize;
size_t rs = m_channelData[0]->inbuf->getReadSpace();
if (rs < longest) {
return longest - rs;
} else {
return 0;
}
}
void
R3StretcherImpl::process(const float *const *input, size_t samples, bool final)
{
//!!! todo: final
bool allConsumed = false;
size_t ws = m_channelData[0]->inbuf->getWriteSpace();
if (samples > ws) {
//!!! check this
m_parameters.logger("R3StretcherImpl::process: WARNING: Forced to increase input buffer size. Either setMaxProcessSize was not properly called or process is being called repeatedly without retrieve.");
size_t newSize = m_channelData[0]->inbuf->getSize() - ws + samples;
for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData[c]->inbuf =
std::unique_ptr<RingBuffer<float>>
(m_channelData[c]->inbuf->resized(newSize));
}
}
for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData[c]->inbuf->write(input[c], samples);
}
consume();
}
int
R3StretcherImpl::available() const
{
return int(m_channelData[0]->outbuf->getReadSpace());
}
size_t
R3StretcherImpl::retrieve(float *const *output, size_t samples) const
{
size_t got = samples;
for (size_t c = 0; c < m_parameters.channels; ++c) {
size_t gotHere = m_channelData[c]->outbuf->read(output[c], got);
if (gotHere < got) {
if (c > 0) {
m_parameters.logger("R3StretcherImpl::retrieve: WARNING: channel imbalance detected");
}
got = gotHere;
}
}
return got;
}
void
R3StretcherImpl::consume()
{
int inhop = 171, outhop = 256; //!!!
double ratio = double(outhop) / double(inhop);
int longest = m_guideConfiguration.longestFftSize;
int classify = m_guideConfiguration.classificationFftSize;
while (m_channelData[0]->inbuf->getReadSpace() >= longest &&
m_channelData[0]->outbuf->getWriteSpace() >= outhop) {
m_parameters.logger("consume looping");
for (int c = 0; c < m_parameters.channels; ++c) {
auto cd = m_channelData[c];
auto longestScale = cd->scales.at(longest);
cd->inbuf->read(longestScale->timeDomainFrame.data(), longest);
for (auto it: cd->scales) {
int fftSize = it.first;
auto scale = it.second;
if (fftSize == longest) continue;
int offset = (longest - fftSize) / 2;
m_scaleData.at(fftSize)->analysisWindow.cut
(longestScale->timeDomainFrame.data() + offset,
scale->timeDomainFrame.data());
}
m_scaleData.at(longest)->analysisWindow.cut
(longestScale->timeDomainFrame.data());
}
for (int c = 0; c < m_parameters.channels; ++c) {
auto cd = m_channelData[c];
//!!! There are some aspects of scaling etc handled in bsq
//!!! that are not yet here
for (auto it: cd->scales) {
int fftSize = it.first;
auto scale = it.second;
m_scaleData.at(fftSize)->fft.forwardPolar
(scale->timeDomainFrame.data(),
scale->mag.data(),
scale->phase.data());
}
}
for (int c = 0; c < m_parameters.channels; ++c) {
auto cd = m_channelData[c];
auto classifyScale = cd->scales.at(classify);
cd->prevSegmentation = cd->segmentation;
cd->segmentation = cd->segmenter->segment(classifyScale->mag.data());
m_troughPicker.findNearestAndNextPeaks
(classifyScale->mag.data(), 3, nullptr,
classifyScale->nextTroughs.data());
m_guide.calculate(ratio, classifyScale->mag.data(),
classifyScale->nextTroughs.data(),
classifyScale->prevMag.data(),
cd->segmentation,
cd->prevSegmentation,
BinSegmenter::Segmentation(), //!!!
cd->guidance);
}
for (auto it : m_channelData[0]->scales) {
int fftSize = it.first;
for (int c = 0; c < m_parameters.channels; ++c) {
auto cd = m_channelData[c];
auto classifyScale = cd->scales.at(fftSize);
m_channelAssembly.mag[c] = classifyScale->mag.data();
m_channelAssembly.phase[c] = classifyScale->phase.data();
m_channelAssembly.guidance[c] = &cd->guidance;
m_channelAssembly.outPhase[c] = classifyScale->outPhase.data();
}
m_scaleData.at(fftSize)->guided.advance
(m_channelAssembly.outPhase.data(),
m_channelAssembly.mag.data(),
m_channelAssembly.phase.data(),
m_guideConfiguration,
m_channelAssembly.guidance.data(),
inhop,
outhop);
}
for (int c = 0; c < m_parameters.channels; ++c) {
for (auto it : m_channelData[c]->scales) {
auto scale = it.second;
int bufSize = scale->bufSize;
// copy to prevMag before filtering
v_copy(scale->prevMag.data(), scale->mag.data(), bufSize);
v_copy(scale->prevOutPhase.data(), scale->outPhase.data(), bufSize);
for (int i = 0; i < bufSize; ++i) {
scale->phase[i] = princarg(scale->outPhase[i]);
}
}
}
//!!! + filter here
for (int c = 0; c < m_parameters.channels; ++c) {
for (auto it : m_channelData[c]->scales) {
int fftSize = it.first;
auto scale = it.second;
auto scaleData = m_scaleData.at(fftSize);
int bufSize = scale->bufSize;
scaleData->fft.inversePolar(scale->mag.data(),
scale->phase.data(),
scale->timeDomainFrame.data());
int synthesisWindowSize = scaleData->synthesisWindow.getSize();
int fromOffset = (fftSize - synthesisWindowSize) / 2;
int toOffset = (longest - synthesisWindowSize) / 2;
//!!! not right - accumulator is of scale data size, not full longest size - we need offset when mixing into mixdown buffer below as well
scaleData->synthesisWindow.cutAndAdd
(scale->timeDomainFrame.data() + fromOffset,
scale->accumulator.data() + toOffset);
}
}
for (int c = 0; c < m_parameters.channels; ++c) {
auto cd = m_channelData[c];
v_zero(cd->mixdown.data(), outhop);
for (auto it : cd->scales) {
auto scale = it.second;
auto &acc = scale->accumulator;
v_add(cd->mixdown.data(), acc.data(), outhop);
int n = acc.size() - outhop;
v_move(acc.data(), acc.data() + outhop, n);
v_zero(acc.data() + n, outhop);
}
m_channelData[c]->outbuf->write(cd->mixdown.data(), outhop);
m_channelData[c]->inbuf->skip(inhop);
}
}
}
}

View File

@@ -56,7 +56,9 @@ public:
R3StretcherImpl(Parameters parameters) : R3StretcherImpl(Parameters parameters) :
m_parameters(parameters), m_parameters(parameters),
m_guide(Guide::Parameters(m_parameters.sampleRate)), m_guide(Guide::Parameters(m_parameters.sampleRate)),
m_guideConfiguration(m_guide.getConfiguration()) m_guideConfiguration(m_guide.getConfiguration()),
m_channelAssembly(m_parameters.channels),
m_troughPicker(m_guideConfiguration.classificationFftSize / 2 + 1)
{ {
BinSegmenter::Parameters segmenterParameters BinSegmenter::Parameters segmenterParameters
(m_guideConfiguration.classificationFftSize, (m_guideConfiguration.classificationFftSize,
@@ -64,7 +66,9 @@ public:
BinClassifier::Parameters classifierParameters BinClassifier::Parameters classifierParameters
(m_guideConfiguration.classificationFftSize / 2 + 1, (m_guideConfiguration.classificationFftSize / 2 + 1,
9, 1, 10, 2.0, 2.0, 1.0e-7); 9, 1, 10, 2.0, 2.0, 1.0e-7);
int ringBufferSize = m_guideConfiguration.longestFftSize * 2; int ringBufferSize = m_guideConfiguration.longestFftSize * 2;
for (int c = 0; c < m_parameters.channels; ++c) { for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData.push_back(std::make_shared<ChannelData> m_channelData.push_back(std::make_shared<ChannelData>
(segmenterParameters, (segmenterParameters,
@@ -72,11 +76,18 @@ public:
ringBufferSize)); ringBufferSize));
for (auto band: m_guideConfiguration.fftBandLimits) { for (auto band: m_guideConfiguration.fftBandLimits) {
int fftSize = band.fftSize; int fftSize = band.fftSize;
m_ffts[fftSize] = std::make_shared<FFT>(fftSize);
m_channelData[c]->scales[fftSize] = m_channelData[c]->scales[fftSize] =
std::make_shared<ChannelScaleData>(fftSize); std::make_shared<ChannelScaleData>(fftSize);
} }
} }
for (auto band: m_guideConfiguration.fftBandLimits) {
int fftSize = band.fftSize;
GuidedPhaseAdvance::Parameters guidedParameters
(fftSize, m_parameters.sampleRate, m_parameters.channels,
m_parameters.logger);
m_scaleData[fftSize] = std::make_shared<ScaleData>(guidedParameters);
}
} }
~R3StretcherImpl() { } ~R3StretcherImpl() { }
@@ -89,29 +100,39 @@ public:
double getTimeRatio() const; double getTimeRatio() const;
double getPitchScale() const; double getPitchScale() const;
size_t getSamplesRequired() const;
void process(const float *const *input, size_t samples, bool final);
int available() const;
size_t retrieve(float *const *output, size_t samples) const;
size_t getLatency() const;
size_t getChannelCount() const;
protected: protected:
struct ChannelScaleData { struct ChannelScaleData {
int fftSize; int fftSize;
int bufSize; // size of every freq-domain array here: fftSize/2 + 1 int bufSize; // size of every freq-domain array here: fftSize/2 + 1
//!!! review later which of these we are actually using!
FixedVector<float> timeDomainFrame;
FixedVector<float> mag; FixedVector<float> mag;
FixedVector<float> phase; FixedVector<float> phase;
FixedVector<int> nearestPeaks; FixedVector<double> outPhase; //!!! "advanced"?
FixedVector<int> nearestTroughs; FixedVector<int> nextTroughs; //!!! not used in every scale
FixedVector<float> prevOutMag; FixedVector<float> prevMag; //!!! not used in every scale
FixedVector<double> prevOutPhase; FixedVector<double> prevOutPhase;
FixedVector<int> prevNearestPeaks; FixedVector<float> accumulator;
FixedVector<float> timeDomainFrame;
Window<float> analysisWindow;
Window<float> synthesisWindow;
ChannelScaleData(int _fftSize) : ChannelScaleData(int _fftSize) :
fftSize(_fftSize), bufSize(fftSize/2 + 1), fftSize(_fftSize),
mag(bufSize, 0.f), phase(bufSize, 0.f), bufSize(fftSize/2 + 1),
nearestPeaks(bufSize, 0), nearestTroughs(bufSize, 0), timeDomainFrame(fftSize, 0.f),
prevOutMag(bufSize, 0.f), prevOutPhase(bufSize, 0.f), mag(bufSize, 0.f),
prevNearestPeaks(bufSize, 0), timeDomainFrame(fftSize, 0.f), phase(bufSize, 0.f),
analysisWindow(HannWindow, fftSize), outPhase(bufSize, 0.f),
synthesisWindow(HannWindow, fftSize/2) nextTroughs(bufSize, 0),
prevMag(bufSize, 0.f),
prevOutPhase(bufSize, 0.f),
accumulator(fftSize, 0.f)
{ } { }
private: private:
@@ -126,8 +147,9 @@ protected:
BinSegmenter::Segmentation prevSegmentation; BinSegmenter::Segmentation prevSegmentation;
BinSegmenter::Segmentation nextSegmentation; BinSegmenter::Segmentation nextSegmentation;
Guide::Guidance guidance; Guide::Guidance guidance;
RingBuffer<float> inbuf; FixedVector<float> mixdown;
RingBuffer<float> outbuf; std::unique_ptr<RingBuffer<float>> inbuf;
std::unique_ptr<RingBuffer<float>> outbuf;
ChannelData(BinSegmenter::Parameters segmenterParameters, ChannelData(BinSegmenter::Parameters segmenterParameters,
BinClassifier::Parameters classifierParameters, BinClassifier::Parameters classifierParameters,
int ringBufferSize) : int ringBufferSize) :
@@ -135,7 +157,33 @@ protected:
segmenter(new BinSegmenter(segmenterParameters, segmenter(new BinSegmenter(segmenterParameters,
classifierParameters)), classifierParameters)),
segmentation(), prevSegmentation(), nextSegmentation(), segmentation(), prevSegmentation(), nextSegmentation(),
inbuf(ringBufferSize), outbuf(ringBufferSize) { } mixdown(ringBufferSize, 0.f), //!!! could be much shorter (bound is the max outhop)
inbuf(new RingBuffer<float>(ringBufferSize)),
outbuf(new RingBuffer<float>(ringBufferSize)) { }
};
struct ChannelAssembly {
// Vectors of bare pointers, used to package container data
// from different channels into arguments for PhaseAdvance
FixedVector<float *> mag;
FixedVector<float *> phase;
FixedVector<Guide::Guidance *> guidance;
FixedVector<double *> outPhase;
ChannelAssembly(int channels) :
mag(channels, nullptr), phase(channels, nullptr),
guidance(channels, nullptr), outPhase(channels, nullptr) { }
};
struct ScaleData {
FFT fft;
Window<float> analysisWindow;
Window<float> synthesisWindow;
GuidedPhaseAdvance guided;
ScaleData(GuidedPhaseAdvance::Parameters guidedParameters) :
fft(guidedParameters.fftSize),
analysisWindow(HannWindow, guidedParameters.fftSize),
synthesisWindow(HannWindow, guidedParameters.fftSize/2),
guided(guidedParameters) { }
}; };
Parameters m_parameters; Parameters m_parameters;
@@ -144,9 +192,13 @@ protected:
double m_pitchScale; double m_pitchScale;
std::vector<std::shared_ptr<ChannelData>> m_channelData; std::vector<std::shared_ptr<ChannelData>> m_channelData;
std::map<int, std::shared_ptr<FFT>> m_ffts; std::map<int, std::shared_ptr<ScaleData>> m_scaleData;
Guide m_guide; Guide m_guide;
Guide::Configuration m_guideConfiguration; Guide::Configuration m_guideConfiguration;
ChannelAssembly m_channelAssembly;
Peak<float, std::less<float>> m_troughPicker;
void consume();
static void logCerr(const std::string &message) { static void logCerr(const std::string &message) {
std::cerr << "RubberBandStretcher: " << message << std::endl; std::cerr << "RubberBandStretcher: " << message << std::endl;