Per-channel window source buffer, & connect it up
This commit is contained in:
@@ -44,7 +44,6 @@ R3Stretcher::R3Stretcher(Parameters parameters,
|
|||||||
m_parameters.options & RubberBandStretcher::OptionWindowShort),
|
m_parameters.options & RubberBandStretcher::OptionWindowShort),
|
||||||
m_log),
|
m_log),
|
||||||
m_guideConfiguration(m_guide.getConfiguration()),
|
m_guideConfiguration(m_guide.getConfiguration()),
|
||||||
m_windowSourceBuffer(getWindowSourceBufferLength()),
|
|
||||||
m_channelAssembly(m_parameters.channels),
|
m_channelAssembly(m_parameters.channels),
|
||||||
m_inhop(1),
|
m_inhop(1),
|
||||||
m_prevInhop(1),
|
m_prevInhop(1),
|
||||||
@@ -91,14 +90,15 @@ R3Stretcher::R3Stretcher(Parameters parameters,
|
|||||||
BinClassifier::Parameters classifierParameters
|
BinClassifier::Parameters classifierParameters
|
||||||
(classificationBins, 9, 1, 10, 2.0, 2.0);
|
(classificationBins, 9, 1, 10, 2.0, 2.0);
|
||||||
|
|
||||||
int inRingBufferSize = getWindowSourceBufferLength() * 2;
|
int inRingBufferSize = getWindowSourceSize() * 2;
|
||||||
int outRingBufferSize = getWindowSourceBufferLength() * 16;
|
int outRingBufferSize = getWindowSourceSize() * 16;
|
||||||
|
|
||||||
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,
|
||||||
classifierParameters,
|
classifierParameters,
|
||||||
m_guideConfiguration.longestFftSize,
|
m_guideConfiguration.longestFftSize,
|
||||||
|
getWindowSourceSize(),
|
||||||
inRingBufferSize,
|
inRingBufferSize,
|
||||||
outRingBufferSize));
|
outRingBufferSize));
|
||||||
for (int b = 0; b < m_guideConfiguration.fftBandLimitCount; ++b) {
|
for (int b = 0; b < m_guideConfiguration.fftBandLimitCount; ++b) {
|
||||||
@@ -450,7 +450,7 @@ R3Stretcher::getPreferredStartPad() const
|
|||||||
if (!isRealTime()) {
|
if (!isRealTime()) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return m_windowSourceBuffer.size() / 2;
|
return getWindowSourceSize() / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +461,7 @@ R3Stretcher::getStartDelay() const
|
|||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
double factor = 0.5 / m_pitchScale;
|
double factor = 0.5 / m_pitchScale;
|
||||||
return size_t(ceil(m_windowSourceBuffer.size() * factor));
|
return size_t(ceil(getWindowSourceSize() * factor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -535,8 +535,8 @@ R3Stretcher::getSamplesRequired() const
|
|||||||
{
|
{
|
||||||
if (available() != 0) return 0;
|
if (available() != 0) return 0;
|
||||||
int rs = m_channelData[0]->inbuf->getReadSpace();
|
int rs = m_channelData[0]->inbuf->getReadSpace();
|
||||||
if (rs < m_windowSourceBuffer.size()) {
|
if (rs < getWindowSourceSize()) {
|
||||||
return m_windowSourceBuffer.size() - rs;
|
return getWindowSourceSize() - rs;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -546,7 +546,7 @@ void
|
|||||||
R3Stretcher::setMaxProcessSize(size_t n)
|
R3Stretcher::setMaxProcessSize(size_t n)
|
||||||
{
|
{
|
||||||
size_t oldSize = m_channelData[0]->inbuf->getSize();
|
size_t oldSize = m_channelData[0]->inbuf->getSize();
|
||||||
size_t newSize = m_windowSourceBuffer.size() + n;
|
size_t newSize = getWindowSourceSize() + n;
|
||||||
|
|
||||||
if (newSize > oldSize) {
|
if (newSize > oldSize) {
|
||||||
m_log.log(1, "setMaxProcessSize: resizing from and to", oldSize, newSize);
|
m_log.log(1, "setMaxProcessSize: resizing from and to", oldSize, newSize);
|
||||||
@@ -605,7 +605,7 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
|
|||||||
// don't do this -- it's better to start with a swoosh
|
// don't do this -- it's better to start with a swoosh
|
||||||
// than introduce more latency, and we don't want gaps
|
// than introduce more latency, and we don't want gaps
|
||||||
// when the ratio changes.
|
// when the ratio changes.
|
||||||
int pad = m_windowSourceBuffer.size() / 2;
|
int pad = getWindowSourceSize() / 2;
|
||||||
m_log.log(1, "offline mode: prefilling with", pad);
|
m_log.log(1, "offline mode: prefilling with", pad);
|
||||||
for (int c = 0; c < m_parameters.channels; ++c) {
|
for (int c = 0; c < m_parameters.channels; ++c) {
|
||||||
m_channelData[c]->inbuf->zero(pad);
|
m_channelData[c]->inbuf->zero(pad);
|
||||||
@@ -737,7 +737,7 @@ R3Stretcher::consume()
|
|||||||
// the map iterators
|
// the map iterators
|
||||||
|
|
||||||
int readSpace = cd0->inbuf->getReadSpace();
|
int readSpace = cd0->inbuf->getReadSpace();
|
||||||
if (readSpace < m_windowSourceBuffer.size()) {
|
if (readSpace < getWindowSourceSize()) {
|
||||||
if (m_mode == ProcessMode::Finished) {
|
if (m_mode == ProcessMode::Finished) {
|
||||||
if (readSpace == 0) {
|
if (readSpace == 0) {
|
||||||
int fill = cd0->scales.at(longest)->accumulatorFill;
|
int fill = cd0->scales.at(longest)->accumulatorFill;
|
||||||
@@ -879,34 +879,33 @@ R3Stretcher::analyseChannel(int c, int inhop, int prevInhop, int prevOuthop)
|
|||||||
{
|
{
|
||||||
Profiler profiler("R3Stretcher::analyseChannel");
|
Profiler profiler("R3Stretcher::analyseChannel");
|
||||||
|
|
||||||
int longest = m_guideConfiguration.longestFftSize;
|
|
||||||
int classify = m_guideConfiguration.classificationFftSize;
|
|
||||||
|
|
||||||
auto &cd = m_channelData.at(c);
|
auto &cd = m_channelData.at(c);
|
||||||
process_t *buf = cd->scales.at(longest)->timeDomain.data();
|
|
||||||
|
|
||||||
//!!! review
|
int bufSize = cd->windowSource.size();
|
||||||
|
process_t *buf = cd->windowSource.data();
|
||||||
|
|
||||||
int readSpace = cd->inbuf->getReadSpace();
|
int readSpace = cd->inbuf->getReadSpace();
|
||||||
if (readSpace < longest) {
|
if (readSpace < bufSize) {
|
||||||
cd->inbuf->peek(buf, readSpace);
|
cd->inbuf->peek(buf, readSpace);
|
||||||
v_zero(buf + readSpace, longest - readSpace);
|
v_zero(buf + readSpace, bufSize - readSpace);
|
||||||
} else {
|
} else {
|
||||||
cd->inbuf->peek(buf, longest);
|
cd->inbuf->peek(buf, bufSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have a single unwindowed frame at the longest FFT size
|
// We have an unwindowed time-domain frame in buf that is as long
|
||||||
// ("scale"). Populate the shorter FFT sizes from the centre of
|
// as required for the union of all FFT sizes and readahead
|
||||||
// it, windowing as we copy. The classification scale is handled
|
// hops. Populate the various sizes from it with aligned centres,
|
||||||
// separately because it has readahead, so skip it here as well as
|
// windowing as we copy. The classification scale is handled
|
||||||
// the longest. (In practice this means we are probably only
|
// separately because it has readahead, so skip it here. (In
|
||||||
// populating one scale in multi-window mode, and none at all in
|
// single-window mode that means we do nothing here, since the
|
||||||
// single-window mode)
|
// classification scale is the only one.)
|
||||||
|
|
||||||
|
int classify = m_guideConfiguration.classificationFftSize;
|
||||||
|
|
||||||
for (auto &it: cd->scales) {
|
for (auto &it: cd->scales) {
|
||||||
int fftSize = it.first;
|
int fftSize = it.first;
|
||||||
if (fftSize == classify || fftSize == longest) continue;
|
if (fftSize == classify) continue;
|
||||||
int offset = (longest - fftSize) / 2;
|
int offset = (bufSize - fftSize) / 2;
|
||||||
m_scaleData.at(fftSize)->analysisWindow.cut
|
m_scaleData.at(fftSize)->analysisWindow.cut
|
||||||
(buf + offset, it.second->timeDomain.data());
|
(buf + offset, it.second->timeDomain.data());
|
||||||
}
|
}
|
||||||
@@ -918,28 +917,23 @@ R3Stretcher::analyseChannel(int c, int inhop, int prevInhop, int prevOuthop)
|
|||||||
ClassificationReadaheadData &readahead = cd->readahead;
|
ClassificationReadaheadData &readahead = cd->readahead;
|
||||||
|
|
||||||
m_scaleData.at(classify)->analysisWindow.cut
|
m_scaleData.at(classify)->analysisWindow.cut
|
||||||
(buf + (longest - classify) / 2 + inhop,
|
(buf + (bufSize - classify) / 2 + inhop,
|
||||||
readahead.timeDomain.data());
|
readahead.timeDomain.data());
|
||||||
|
|
||||||
// If inhop has changed since the previous frame, we'll have to
|
// If inhop has changed since the previous frame, we must populate
|
||||||
// populate the classification scale (but for analysis/resynthesis
|
// the classification scale (but for analysis/resynthesis rather
|
||||||
// rather than classification) anew rather than reuse the previous
|
// than classification) anew rather than reuse the previous
|
||||||
// readahead. Pity...
|
// frame's readahead.
|
||||||
|
|
||||||
bool haveValidReadahead = cd->haveReadahead;
|
bool haveValidReadahead = cd->haveReadahead;
|
||||||
if (inhop != prevInhop) haveValidReadahead = false;
|
if (inhop != prevInhop) haveValidReadahead = false;
|
||||||
|
|
||||||
if (!haveValidReadahead) {
|
if (!haveValidReadahead) {
|
||||||
m_scaleData.at(classify)->analysisWindow.cut
|
m_scaleData.at(classify)->analysisWindow.cut
|
||||||
(buf + (longest - classify) / 2,
|
(buf + (bufSize - classify) / 2,
|
||||||
classifyScale->timeDomain.data());
|
classifyScale->timeDomain.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally window the longest scale
|
|
||||||
if (classify != longest) {
|
|
||||||
m_scaleData.at(longest)->analysisWindow.cut(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FFT shift, forward FFT, and carry out cartesian-polar
|
// FFT shift, forward FFT, and carry out cartesian-polar
|
||||||
// conversion for each FFT size.
|
// conversion for each FFT size.
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ protected:
|
|||||||
|
|
||||||
struct ChannelData {
|
struct ChannelData {
|
||||||
std::map<int, std::shared_ptr<ChannelScaleData>> scales;
|
std::map<int, std::shared_ptr<ChannelScaleData>> scales;
|
||||||
|
FixedVector<process_t> windowSource;
|
||||||
ClassificationReadaheadData readahead;
|
ClassificationReadaheadData readahead;
|
||||||
bool haveReadahead;
|
bool haveReadahead;
|
||||||
std::unique_ptr<BinClassifier> classifier;
|
std::unique_ptr<BinClassifier> classifier;
|
||||||
@@ -203,9 +204,11 @@ protected:
|
|||||||
ChannelData(BinSegmenter::Parameters segmenterParameters,
|
ChannelData(BinSegmenter::Parameters segmenterParameters,
|
||||||
BinClassifier::Parameters classifierParameters,
|
BinClassifier::Parameters classifierParameters,
|
||||||
int longestFftSize,
|
int longestFftSize,
|
||||||
|
int windowSourceSize,
|
||||||
int inRingBufferSize,
|
int inRingBufferSize,
|
||||||
int outRingBufferSize) :
|
int outRingBufferSize) :
|
||||||
scales(),
|
scales(),
|
||||||
|
windowSource(windowSourceSize, 0.0),
|
||||||
readahead(segmenterParameters.fftSize),
|
readahead(segmenterParameters.fftSize),
|
||||||
haveReadahead(false),
|
haveReadahead(false),
|
||||||
classifier(new BinClassifier(classifierParameters)),
|
classifier(new BinClassifier(classifierParameters)),
|
||||||
@@ -297,7 +300,6 @@ protected:
|
|||||||
std::map<int, std::shared_ptr<ScaleData>> m_scaleData;
|
std::map<int, std::shared_ptr<ScaleData>> m_scaleData;
|
||||||
Guide m_guide;
|
Guide m_guide;
|
||||||
Guide::Configuration m_guideConfiguration;
|
Guide::Configuration m_guideConfiguration;
|
||||||
FixedVector<process_t> m_windowSourceBuffer;
|
|
||||||
ChannelAssembly m_channelAssembly;
|
ChannelAssembly m_channelAssembly;
|
||||||
std::unique_ptr<StretchCalculator> m_calculator;
|
std::unique_ptr<StretchCalculator> m_calculator;
|
||||||
std::unique_ptr<Resampler> m_resampler;
|
std::unique_ptr<Resampler> m_resampler;
|
||||||
@@ -377,7 +379,7 @@ protected:
|
|||||||
RubberBandStretcher::OptionWindowShort;
|
RubberBandStretcher::OptionWindowShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getWindowSourceBufferLength() const {
|
int getWindowSourceSize() const {
|
||||||
if (m_guideConfiguration.longestFftSize >
|
if (m_guideConfiguration.longestFftSize >
|
||||||
m_guideConfiguration.classificationFftSize) {
|
m_guideConfiguration.classificationFftSize) {
|
||||||
return m_guideConfiguration.longestFftSize;
|
return m_guideConfiguration.longestFftSize;
|
||||||
|
|||||||
Reference in New Issue
Block a user