Ensure output accumulator is properly drained at finish. We rely on the calculated output count (in offline mode) to truncate properly.
This commit is contained in:
@@ -988,7 +988,7 @@ int main(int argc, char **argv)
|
|||||||
cerr << "in: " << countIn << ", out: " << countOut
|
cerr << "in: " << countIn << ", out: " << countOut
|
||||||
<< ", ratio: " << float(countOut)/float(countIn)
|
<< ", ratio: " << float(countOut)/float(countIn)
|
||||||
<< ", ideal output: " << lrint(countIn * ratio)
|
<< ", ideal output: " << lrint(countIn * ratio)
|
||||||
<< ", error: " << abs(lrint(countIn * ratio) - int(countOut))
|
<< ", error: " << int(countOut) - lrint(countIn * ratio)
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
@@ -635,6 +635,11 @@ R3Stretcher::consume()
|
|||||||
longest,
|
longest,
|
||||||
longest,
|
longest,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
if (outhop < 1) {
|
||||||
|
m_log.log(0, "R3Stretcher::consume: WARNING: outhop calculated as", outhop);
|
||||||
|
outhop = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Now inhop is the distance by which the input stream will be
|
// Now inhop is the distance by which the input stream will be
|
||||||
// advanced after our current frame has been read, and outhop is
|
// advanced after our current frame has been read, and outhop is
|
||||||
@@ -655,8 +660,10 @@ R3Stretcher::consume()
|
|||||||
if (outhop != m_prevOuthop) {
|
if (outhop != m_prevOuthop) {
|
||||||
m_log.log(2, "change in outhop", double(m_prevOuthop), double(outhop));
|
m_log.log(2, "change in outhop", double(m_prevOuthop), double(outhop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &cd0 = m_channelData.at(0);
|
||||||
|
|
||||||
while (m_channelData.at(0)->outbuf->getWriteSpace() >= outhop) {
|
while (cd0->outbuf->getWriteSpace() >= outhop) {
|
||||||
|
|
||||||
// NB our ChannelData, ScaleData, and ChannelScaleData maps
|
// NB our ChannelData, ScaleData, and ChannelScaleData maps
|
||||||
// contain shared_ptrs; whenever we retain one of them in a
|
// contain shared_ptrs; whenever we retain one of them in a
|
||||||
@@ -664,13 +671,19 @@ R3Stretcher::consume()
|
|||||||
// shared_ptr (as that is not realtime safe). Same goes for
|
// shared_ptr (as that is not realtime safe). Same goes for
|
||||||
// the map iterators
|
// the map iterators
|
||||||
|
|
||||||
int readSpace = m_channelData.at(0)->inbuf->getReadSpace();
|
int readSpace = cd0->inbuf->getReadSpace();
|
||||||
if (readSpace < longest) {
|
if (readSpace < longest) {
|
||||||
if (m_mode == ProcessMode::Finished) {
|
if (m_mode == ProcessMode::Finished) {
|
||||||
if (readSpace == 0) {
|
if (readSpace == 0) {
|
||||||
break;
|
int fill = cd0->scales.at(longest)->accumulatorFill;
|
||||||
|
if (fill == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
m_log.log(1, "finished reading input, but samples remaining in output accumulator", fill);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// await more input
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -712,17 +725,7 @@ R3Stretcher::consume()
|
|||||||
// Resynthesis
|
// Resynthesis
|
||||||
|
|
||||||
for (int c = 0; c < channels; ++c) {
|
for (int c = 0; c < channels; ++c) {
|
||||||
synthesiseChannel(c, outhop);
|
synthesiseChannel(c, outhop, readSpace == 0);
|
||||||
}
|
|
||||||
|
|
||||||
// We now have outhop samples at the start of the mixdown
|
|
||||||
// buffer, but they aren't necessarily all valid, because we
|
|
||||||
// might have had fewer than outhop at the start of inbuf
|
|
||||||
// (when finished and draining)
|
|
||||||
|
|
||||||
int validCount = outhop;
|
|
||||||
if (readSpace < outhop) {
|
|
||||||
validCount = readSpace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resample
|
// Resample
|
||||||
@@ -747,14 +750,14 @@ R3Stretcher::consume()
|
|||||||
(m_channelAssembly.resampled.data(),
|
(m_channelAssembly.resampled.data(),
|
||||||
m_channelData[0]->resampled.size(),
|
m_channelData[0]->resampled.size(),
|
||||||
m_channelAssembly.mixdown.data(),
|
m_channelAssembly.mixdown.data(),
|
||||||
validCount,
|
outhop,
|
||||||
1.0 / m_pitchScale,
|
1.0 / m_pitchScale,
|
||||||
m_mode == ProcessMode::Finished && readSpace < inhop);
|
m_mode == ProcessMode::Finished && readSpace < inhop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit
|
// Emit
|
||||||
|
|
||||||
int writeCount = validCount;
|
int writeCount = outhop;
|
||||||
if (resampling) {
|
if (resampling) {
|
||||||
writeCount = resampledCount;
|
writeCount = resampledCount;
|
||||||
}
|
}
|
||||||
@@ -792,7 +795,7 @@ R3Stretcher::consume()
|
|||||||
m_totalOutputDuration += writeCount;
|
m_totalOutputDuration += writeCount;
|
||||||
|
|
||||||
if (m_startSkip > 0) {
|
if (m_startSkip > 0) {
|
||||||
int rs = m_channelData.at(0)->outbuf->getReadSpace();
|
int rs = cd0->outbuf->getReadSpace();
|
||||||
int toSkip = std::min(m_startSkip, rs);
|
int toSkip = std::min(m_startSkip, rs);
|
||||||
for (int c = 0; c < channels; ++c) {
|
for (int c = 0; c < channels; ++c) {
|
||||||
m_channelData.at(c)->outbuf->skip(toSkip);
|
m_channelData.at(c)->outbuf->skip(toSkip);
|
||||||
@@ -1146,7 +1149,7 @@ R3Stretcher::adjustPreKick(int c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
R3Stretcher::synthesiseChannel(int c, int outhop)
|
R3Stretcher::synthesiseChannel(int c, int outhop, bool draining)
|
||||||
{
|
{
|
||||||
int longest = m_guideConfiguration.longestFftSize;
|
int longest = m_guideConfiguration.longestFftSize;
|
||||||
|
|
||||||
@@ -1229,6 +1232,18 @@ R3Stretcher::synthesiseChannel(int c, int outhop)
|
|||||||
int n = scale->accumulator.size() - outhop;
|
int n = scale->accumulator.size() - outhop;
|
||||||
v_move(accptr, accptr + outhop, n);
|
v_move(accptr, accptr + outhop, n);
|
||||||
v_zero(accptr + n, outhop);
|
v_zero(accptr + n, outhop);
|
||||||
|
|
||||||
|
if (draining) {
|
||||||
|
if (scale->accumulatorFill > outhop) {
|
||||||
|
auto newFill = scale->accumulatorFill - outhop;
|
||||||
|
m_log.log(2, "draining: reducing accumulatorFill from, to", scale->accumulatorFill, newFill);
|
||||||
|
scale->accumulatorFill = newFill;
|
||||||
|
} else {
|
||||||
|
scale->accumulatorFill = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scale->accumulatorFill = scale->accumulator.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ protected:
|
|||||||
FixedVector<process_t> prevMag;
|
FixedVector<process_t> prevMag;
|
||||||
FixedVector<process_t> pendingKick;
|
FixedVector<process_t> pendingKick;
|
||||||
FixedVector<process_t> accumulator;
|
FixedVector<process_t> accumulator;
|
||||||
|
int accumulatorFill;
|
||||||
|
|
||||||
ChannelScaleData(int _fftSize, int _longestFftSize) :
|
ChannelScaleData(int _fftSize, int _longestFftSize) :
|
||||||
fftSize(_fftSize),
|
fftSize(_fftSize),
|
||||||
@@ -141,12 +142,14 @@ protected:
|
|||||||
advancedPhase(bufSize, 0.f),
|
advancedPhase(bufSize, 0.f),
|
||||||
prevMag(bufSize, 0.f),
|
prevMag(bufSize, 0.f),
|
||||||
pendingKick(bufSize, 0.f),
|
pendingKick(bufSize, 0.f),
|
||||||
accumulator(_longestFftSize, 0.f)
|
accumulator(_longestFftSize, 0.f),
|
||||||
|
accumulatorFill(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
v_zero(prevMag.data(), prevMag.size());
|
v_zero(prevMag.data(), prevMag.size());
|
||||||
v_zero(accumulator.data(), accumulator.size());
|
v_zero(accumulator.data(), accumulator.size());
|
||||||
|
accumulatorFill = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -322,7 +325,7 @@ protected:
|
|||||||
void analyseFormant(int channel);
|
void analyseFormant(int channel);
|
||||||
void adjustFormant(int channel);
|
void adjustFormant(int channel);
|
||||||
void adjustPreKick(int channel);
|
void adjustPreKick(int channel);
|
||||||
void synthesiseChannel(int channel, int outhop);
|
void synthesiseChannel(int channel, int outhop, bool draining);
|
||||||
|
|
||||||
struct ToPolarSpec {
|
struct ToPolarSpec {
|
||||||
int magFromBin;
|
int magFromBin;
|
||||||
|
|||||||
Reference in New Issue
Block a user