Implement resampling

This commit is contained in:
Chris Cannam
2022-05-25 13:47:40 +01:00
parent f5b381e086
commit 54515122b2
2 changed files with 123 additions and 84 deletions

View File

@@ -29,6 +29,69 @@
namespace RubberBand {
R3StretcherImpl::R3StretcherImpl(Parameters parameters,
double initialTimeRatio,
double initialPitchScale) :
m_parameters(parameters),
m_timeRatio(initialTimeRatio),
m_pitchScale(initialPitchScale),
m_guide(Guide::Parameters(m_parameters.sampleRate, parameters.logger)),
m_guideConfiguration(m_guide.getConfiguration()),
m_channelAssembly(m_parameters.channels),
m_troughPicker(m_guideConfiguration.classificationFftSize / 2 + 1),
m_inhop(1),
m_prevOuthop(1),
m_draining(false)
{
BinSegmenter::Parameters segmenterParameters
(m_guideConfiguration.classificationFftSize,
m_parameters.sampleRate);
BinClassifier::Parameters classifierParameters
(m_guideConfiguration.classificationFftSize / 2 + 1,
9, 1, 10, 2.0, 2.0, 1.0e-7);
int inRingBufferSize = m_guideConfiguration.longestFftSize * 2;
int outRingBufferSize = m_guideConfiguration.longestFftSize * 16;
for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData.push_back(std::make_shared<ChannelData>
(segmenterParameters,
classifierParameters,
m_guideConfiguration.longestFftSize,
inRingBufferSize,
outRingBufferSize));
for (auto band: m_guideConfiguration.fftBandLimits) {
int fftSize = band.fftSize;
m_channelData[c]->scales[fftSize] =
std::make_shared<ChannelScaleData>
(fftSize, m_guideConfiguration.longestFftSize);
}
}
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);
}
m_calculator = std::unique_ptr<StretchCalculator>
(new StretchCalculator(int(round(m_parameters.sampleRate)), //!!! which is a double...
1, false)); // no fixed inputIncrement
Resampler::Parameters resamplerParameters;
resamplerParameters.quality = Resampler::FastestTolerable;
resamplerParameters.dynamism = Resampler::RatioOftenChanging;
resamplerParameters.ratioChange = Resampler::SmoothRatioChange;
resamplerParameters.initialSampleRate = m_parameters.sampleRate;
resamplerParameters.maxBufferSize = m_guideConfiguration.longestFftSize; //!!!???
m_resampler = std::unique_ptr<Resampler>
(new Resampler(resamplerParameters, m_parameters.channels));
calculateHop();
}
void
R3StretcherImpl::setTimeRatio(double ratio)
{
@@ -180,6 +243,7 @@ R3StretcherImpl::consume()
{
double ratio = getEffectiveRatio();
int longest = m_guideConfiguration.longestFftSize;
int channels = m_parameters.channels;
m_calculator->setDebugLevel(3);
@@ -213,7 +277,7 @@ R3StretcherImpl::consume()
// Analysis
for (int c = 0; c < m_parameters.channels; ++c) {
for (int c = 0; c < channels; ++c) {
analyseChannel(c, m_prevOuthop);
}
@@ -221,7 +285,7 @@ R3StretcherImpl::consume()
for (auto &it : m_channelData[0]->scales) {
int fftSize = it.first;
for (int c = 0; c < m_parameters.channels; ++c) {
for (int c = 0; c < channels; ++c) {
auto &cd = m_channelData.at(c);
auto &scale = cd->scales.at(fftSize);
m_channelAssembly.mag[c] = scale->mag.data();
@@ -241,9 +305,46 @@ R3StretcherImpl::consume()
// Resynthesis
for (int c = 0; c < m_parameters.channels; ++c) {
for (int c = 0; c < channels; ++c) {
synthesiseChannel(c, outhop);
}
// Resample
int resampledCount = 0;
if (m_resampler) {
for (int c = 0; c < channels; ++c) {
auto &cd = m_channelData.at(c);
m_channelAssembly.mixdown[c] = cd->mixdown.data();
m_channelAssembly.resampled[c] = cd->resampled.data();
}
resampledCount = m_resampler->resample
(m_channelAssembly.resampled.data(),
m_channelData[0]->resampled.size(),
m_channelAssembly.mixdown.data(),
outhop,
1.0 / m_pitchScale,
m_draining && readSpace < longest);
}
// Emit
for (int c = 0; c < channels; ++c) {
auto &cd = m_channelData.at(c);
if (m_resampler) {
cd->outbuf->write(cd->resampled.data(), resampledCount);
} else {
cd->outbuf->write(cd->mixdown.data(), outhop);
}
int readSpace = cd->inbuf->getReadSpace();
if (readSpace < m_inhop) {
// This should happen only when draining
cd->inbuf->skip(readSpace);
} else {
cd->inbuf->skip(m_inhop);
}
}
}
m_prevOuthop = outhop;
@@ -496,35 +597,23 @@ R3StretcherImpl::synthesiseChannel(int c, int outhop)
scale->accumulator.data() + toOffset);
}
// Mix and emit this channel
// Mix this channel and move the accumulator along
double *mixptr = cd->mixdown.data();
float *mixptr = cd->mixdown.data();
v_zero(mixptr, outhop);
for (auto &it : cd->scales) {
auto &scale = it.second;
v_add(mixptr, scale->accumulator.data(), outhop);
}
cd->outbuf->write(mixptr, outhop);
for (auto &it : cd->scales) {
int fftSize = it.first;
auto &scale = it.second;
double *accptr = scale->accumulator.data();
for (int i = 0; i < outhop; ++i) {
mixptr[i] += float(accptr[i]);
}
int n = scale->accumulator.size() - outhop;
v_move(accptr, accptr + outhop, n);
v_zero(accptr + n, outhop);
}
int readSpace = cd->inbuf->getReadSpace();
if (readSpace < m_inhop) {
// This should happen only when draining
cd->inbuf->skip(readSpace);
} else {
cd->inbuf->skip(m_inhop);
}
}
}

View File

@@ -57,64 +57,7 @@ public:
R3StretcherImpl(Parameters parameters,
double initialTimeRatio,
double initialPitchScale) :
m_parameters(parameters),
m_timeRatio(initialTimeRatio),
m_pitchScale(initialPitchScale),
m_guide(Guide::Parameters(m_parameters.sampleRate, parameters.logger)),
m_guideConfiguration(m_guide.getConfiguration()),
m_channelAssembly(m_parameters.channels),
m_troughPicker(m_guideConfiguration.classificationFftSize / 2 + 1),
m_inhop(1),
m_prevOuthop(1),
m_draining(false)
{
BinSegmenter::Parameters segmenterParameters
(m_guideConfiguration.classificationFftSize,
m_parameters.sampleRate);
BinClassifier::Parameters classifierParameters
(m_guideConfiguration.classificationFftSize / 2 + 1,
9, 1, 10, 2.0, 2.0, 1.0e-7);
int ringBufferSize = m_guideConfiguration.longestFftSize * 2;
for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData.push_back(std::make_shared<ChannelData>
(segmenterParameters,
classifierParameters,
ringBufferSize));
for (auto band: m_guideConfiguration.fftBandLimits) {
int fftSize = band.fftSize;
m_channelData[c]->scales[fftSize] =
std::make_shared<ChannelScaleData>
(fftSize, m_guideConfiguration.longestFftSize);
}
}
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);
}
m_calculator = std::unique_ptr<StretchCalculator>
(new StretchCalculator(int(round(m_parameters.sampleRate)), //!!! which is a double...
1, false)); // no fixed inputIncrement
Resampler::Parameters resamplerParameters;
resamplerParameters.quality = Resampler::FastestTolerable;
resamplerParameters.dynamism = Resampler::RatioOftenChanging;
resamplerParameters.ratioChange = Resampler::SmoothRatioChange;
resamplerParameters.initialSampleRate = m_parameters.sampleRate;
resamplerParameters.maxBufferSize = m_guideConfiguration.longestFftSize; //!!!???
m_resampler = std::unique_ptr<Resampler>
(new Resampler(resamplerParameters, m_parameters.channels));
calculateHop();
}
double initialPitchScale);
~R3StretcherImpl() { }
void reset();
@@ -189,20 +132,24 @@ protected:
BinSegmenter::Segmentation prevSegmentation;
BinSegmenter::Segmentation nextSegmentation;
Guide::Guidance guidance;
FixedVector<double> mixdown;
FixedVector<float> mixdown;
FixedVector<float> resampled;
std::unique_ptr<RingBuffer<float>> inbuf;
std::unique_ptr<RingBuffer<float>> outbuf;
ChannelData(BinSegmenter::Parameters segmenterParameters,
BinClassifier::Parameters classifierParameters,
int ringBufferSize) :
int longestFftSize,
int inRingBufferSize,
int outRingBufferSize) :
scales(),
readahead(segmenterParameters.fftSize),
segmenter(new BinSegmenter(segmenterParameters,
classifierParameters)),
segmentation(), prevSegmentation(), nextSegmentation(),
mixdown(ringBufferSize, 0.f), //!!! could be shorter (bound is the max fft size I think)
inbuf(new RingBuffer<float>(ringBufferSize)),
outbuf(new RingBuffer<float>(ringBufferSize)) { }
mixdown(longestFftSize, 0.f), // though it could be shorter
resampled(outRingBufferSize, 0.f),
inbuf(new RingBuffer<float>(inRingBufferSize)),
outbuf(new RingBuffer<float>(outRingBufferSize)) { }
};
struct ChannelAssembly {
@@ -212,9 +159,12 @@ protected:
FixedVector<double *> phase;
FixedVector<Guide::Guidance *> guidance;
FixedVector<double *> outPhase;
FixedVector<float *> mixdown;
FixedVector<float *> resampled;
ChannelAssembly(int channels) :
mag(channels, nullptr), phase(channels, nullptr),
guidance(channels, nullptr), outPhase(channels, nullptr) { }
guidance(channels, nullptr), outPhase(channels, nullptr),
mixdown(channels, nullptr), resampled(channels, nullptr) { }
};
struct ScaleData {