Work on proper sizing of internal buffers

This commit is contained in:
Chris Cannam
2023-06-01 10:51:20 +01:00
parent 173c7212f1
commit af6759f74b
2 changed files with 84 additions and 46 deletions

View File

@@ -105,16 +105,19 @@ R3Stretcher::initialise()
int inRingBufferSize = getWindowSourceSize() * 16;
int outRingBufferSize = getWindowSourceSize() * 16;
int hopBufferSize =
2 * std::max(m_limits.maxInhop, m_limits.maxPreferredOuthop);
m_channelData.clear();
for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData.push_back(std::make_shared<ChannelData>
(segmenterParameters,
classifierParameters,
m_guideConfiguration.longestFftSize,
getWindowSourceSize(),
inRingBufferSize,
outRingBufferSize));
outRingBufferSize,
hopBufferSize));
for (int b = 0; b < m_guideConfiguration.fftBandLimitCount; ++b) {
const auto &band = m_guideConfiguration.fftBandLimits[b];
int fftSize = band.fftSize;
@@ -636,17 +639,30 @@ R3Stretcher::getSamplesRequired() const
void
R3Stretcher::setMaxProcessSize(size_t n)
{
size_t oldSize = m_channelData[0]->inbuf->getSize();
size_t newSize = getWindowSourceSize() + n;
size_t oldInSize = m_channelData[0]->inbuf->getSize();
size_t newInSize = getWindowSourceSize() + n;
if (newSize > oldSize) {
m_log.log(1, "setMaxProcessSize: resizing from and to", oldSize, newSize);
size_t oldOutSize = m_channelData[0]->outbuf->getSize();
size_t newOutSize = newInSize;
if (newInSize > oldInSize) {
m_log.log(1, "setMaxProcessSize: resizing inbuf from and to", oldInSize, newInSize);
for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData[c]->inbuf = std::unique_ptr<RingBuffer<float>>
(m_channelData[c]->inbuf->resized(newSize));
(m_channelData[c]->inbuf->resized(newInSize));
}
} else {
m_log.log(1, "setMaxProcessSize: nothing to be done, newSize <= oldSize", newSize, oldSize);
m_log.log(1, "setMaxProcessSize: nothing to be done at inbuf, newInSize <= oldInSize", newInSize, oldInSize);
}
if (newOutSize > oldOutSize) {
m_log.log(1, "setMaxProcessSize: resizing outbuf from and to", oldOutSize, newOutSize);
for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData[c]->outbuf = std::unique_ptr<RingBuffer<float>>
(m_channelData[c]->outbuf->resized(newOutSize));
}
} else {
m_log.log(1, "setMaxProcessSize: nothing to be done at outbuf, newOutSize <= oldOutSize", newOutSize, oldOutSize);
}
}
@@ -709,17 +725,6 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
}
}
if (final) {
// We don't distinguish between Finished and "draining, but
// haven't yet delivered all the samples" because the
// distinction is meaningless internally - it only affects
// whether available() finds any samples in the buffer
m_log.log(1, "final is set, entering Finished mode");
m_mode = ProcessMode::Finished;
} else {
m_mode = ProcessMode::Processing;
}
bool resamplingBefore = false;
areWeResampling(&resamplingBefore, nullptr);
@@ -730,7 +735,7 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
m_log.log(2, "process: no samples but final specified, consuming");
consume();
consume(true);
} else while (inputIx < int(samples)) {
@@ -738,7 +743,7 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
int ws = m_channelData[0]->inbuf->getWriteSpace();
if (ws == 0) {
consume();
consume(false);
ws = m_channelData[0]->inbuf->getWriteSpace();
}
@@ -772,13 +777,16 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
prepareInput(input, inputIx, resampleInput);
bool finalHop = (final &&
inputIx + resampleInput >= int(samples));
int resampleOutput = m_resampler->resample
(m_channelAssembly.resampled.data(),
maxResampleOutput,
m_channelAssembly.input.data(),
resampleInput,
1.0 / m_pitchScale,
final);
finalHop);
inputIx += resampleInput;
@@ -804,7 +812,18 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
inputIx += toWrite;
}
consume();
consume(final && inputIx >= int(samples));
}
if (final) {
// We don't distinguish between Finished and "draining, but
// haven't yet delivered all the samples" because the
// distinction is meaningless internally - it only affects
// whether available() finds any samples in the buffer
m_log.log(1, "final is set, entering Finished mode");
m_mode = ProcessMode::Finished;
} else {
m_mode = ProcessMode::Processing;
}
}
@@ -826,6 +845,8 @@ R3Stretcher::retrieve(float *const *output, size_t samples) const
int got = samples;
m_log.log(2, "retrieve: requested, outbuf has", samples, m_channelData[0]->outbuf->getReadSpace());
for (int c = 0; c < m_parameters.channels; ++c) {
int gotHere = m_channelData[c]->outbuf->read(output[c], got);
if (gotHere < got) {
@@ -847,6 +868,8 @@ R3Stretcher::retrieve(float *const *output, size_t samples) const
}
}
m_log.log(2, "retrieve: returning, outbuf now has", got, m_channelData[0]->outbuf->getReadSpace());
return got;
}
@@ -874,7 +897,7 @@ R3Stretcher::prepareInput(const float *const *input, int ix, int n)
}
void
R3Stretcher::consume()
R3Stretcher::consume(bool final)
{
Profiler profiler("R3Stretcher::consume");
@@ -928,22 +951,22 @@ R3Stretcher::consume()
m_log.log(2, "consume: write space and outhop", cd0->outbuf->getWriteSpace(), outhop);
while (cd0->outbuf->getWriteSpace() >= outhop) {
// NB our ChannelData, ScaleData, and ChannelScaleData maps
// contain shared_ptrs; whenever we retain one of them in a
// variable, we do so by reference to avoid copying the shared_ptr
// (as that is not realtime safe). Same goes for the map iterators
while (true) {
Profiler profiler("R3Stretcher::consume/loop");
// NB our ChannelData, ScaleData, and ChannelScaleData maps
// contain shared_ptrs; whenever we retain one of them in a
// variable, we do so by reference to avoid copying the
// shared_ptr (as that is not realtime safe). Same goes for
// the map iterators
int readSpace = cd0->inbuf->getReadSpace();
int writeSpace = cd0->outbuf->getWriteSpace();
m_log.log(2, "consume: read space and window source size", readSpace, getWindowSourceSize());
m_log.log(2, "consume: read space and write space", readSpace, writeSpace);
if (readSpace < getWindowSourceSize()) {
if (m_mode == ProcessMode::Finished) {
if (final) {
if (readSpace == 0) {
int fill = cd0->scales.at(longest)->accumulatorFill;
if (fill == 0) {
@@ -958,6 +981,19 @@ R3Stretcher::consume()
}
}
while (writeSpace < outhop) {
m_log.log(0, "R3Stretcher::process: WARNING: Forced to increase output buffer size. Using smaller process blocks or an artificially larger value for setMaxProcessSize may avoid this");
size_t oldSize = m_channelData[0]->outbuf->getSize();
size_t newSize = oldSize * 2;
m_log.log(0, "R3Stretcher::process: old and new sizes", oldSize, newSize);
for (int c = 0; c < m_parameters.channels; ++c) {
auto newBuf = m_channelData[c]->outbuf->resized(newSize);
m_channelData[c]->outbuf =
std::unique_ptr<RingBuffer<float>>(newBuf);
}
writeSpace = m_channelData[0]->outbuf->getWriteSpace();
}
// Analysis
for (int c = 0; c < channels; ++c) {
@@ -1009,7 +1045,7 @@ R3Stretcher::consume()
m_channelAssembly.resampled[c] = cd->resampled.data();
}
bool final = (m_mode == ProcessMode::Finished &&
bool finalHop = (final &&
readSpace < inhop &&
cd0->scales.at(longest)->accumulatorFill <= outhop);
@@ -1019,7 +1055,7 @@ R3Stretcher::consume()
m_channelAssembly.mixdown.data(),
outhop,
1.0 / m_pitchScale,
final);
finalHop);
}
// Emit
@@ -1041,8 +1077,8 @@ R3Stretcher::consume()
int advanceCount = inhop;
if (advanceCount > readSpace) {
// This should happen only when draining (Finished)
if (m_mode != ProcessMode::Finished) {
// This should happen only when draining
if (!final) {
m_log.log(0, "R3Stretcher: WARNING: readSpace < inhop when processing is not yet finished", readSpace, inhop);
}
advanceCount = readSpace;
@@ -1074,6 +1110,8 @@ R3Stretcher::consume()
m_prevInhop = inhop;
m_prevOuthop = outhop;
}
m_log.log(2, "consume: write space reduced to", cd0->outbuf->getWriteSpace());
}
void

View File

@@ -228,10 +228,10 @@ protected:
std::unique_ptr<FormantData> formant;
ChannelData(BinSegmenter::Parameters segmenterParameters,
BinClassifier::Parameters classifierParameters,
int /*!!! longestFftSize */,
int windowSourceSize,
int inRingBufferSize,
int outRingBufferSize) :
int outRingBufferSize,
int hopBufferSize) :
scales(),
windowSource(windowSourceSize, 0.0),
readahead(segmenterParameters.fftSize),
@@ -243,8 +243,8 @@ protected:
BinClassifier::Classification::Residual),
segmenter(new BinSegmenter(segmenterParameters)),
segmentation(), prevSegmentation(), nextSegmentation(),
mixdown(inRingBufferSize, 0.f),
resampled(outRingBufferSize, 0.f),
mixdown(hopBufferSize, 0.f),
resampled(hopBufferSize, 0.f),
inbuf(new RingBuffer<float>(inRingBufferSize)),
outbuf(new RingBuffer<float>(outRingBufferSize)),
formant(new FormantData(segmenterParameters.fftSize)) { }
@@ -359,7 +359,7 @@ protected:
void initialise();
void prepareInput(const float *const *input, int ix, int n);
void consume();
void consume(bool final);
void createResampler();
void calculateHop();
void updateRatioFromMap();