Some work on resampler delay
This commit is contained in:
@@ -213,6 +213,10 @@ R3LiveShifter::createResamplers()
|
|||||||
resamplerParameters.dynamism = Resampler::RatioOftenChanging;
|
resamplerParameters.dynamism = Resampler::RatioOftenChanging;
|
||||||
resamplerParameters.ratioChange = Resampler::SmoothRatioChange;
|
resamplerParameters.ratioChange = Resampler::SmoothRatioChange;
|
||||||
|
|
||||||
|
int debug = m_log.getDebugLevel();
|
||||||
|
if (debug > 0) --debug;
|
||||||
|
resamplerParameters.debugLevel = debug;
|
||||||
|
|
||||||
m_inResampler = std::unique_ptr<Resampler>
|
m_inResampler = std::unique_ptr<Resampler>
|
||||||
(new Resampler(resamplerParameters, m_parameters.channels));
|
(new Resampler(resamplerParameters, m_parameters.channels));
|
||||||
|
|
||||||
@@ -235,15 +239,18 @@ R3LiveShifter::getFormantScale() const
|
|||||||
size_t
|
size_t
|
||||||
R3LiveShifter::getPreferredStartPad() const
|
R3LiveShifter::getPreferredStartPad() const
|
||||||
{
|
{
|
||||||
//!!!???
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
R3LiveShifter::getStartDelay() const
|
R3LiveShifter::getStartDelay() const
|
||||||
{
|
{
|
||||||
|
//!!! need a principled way - measure it in ctor perhaps
|
||||||
int resamplerDelay = 32;
|
int resamplerDelay = 32;
|
||||||
int fixed = getWindowSourceSize() / 2 + resamplerDelay;
|
#ifdef HAVE_LIBSAMPLERATE
|
||||||
|
resamplerDelay = 47;
|
||||||
|
#endif
|
||||||
|
int fixed = getWindowSourceSize() / 2 + resamplerDelay * 2;
|
||||||
int variable = getWindowSourceSize() / 2;
|
int variable = getWindowSourceSize() / 2;
|
||||||
if (m_contractThenExpand) {
|
if (m_contractThenExpand) {
|
||||||
if (m_pitchScale < 1.0) {
|
if (m_pitchScale < 1.0) {
|
||||||
@@ -305,7 +312,6 @@ R3LiveShifter::shift(const float *const *input, float *const *output)
|
|||||||
m_log.log(2, "R3LiveShifter::shift: initially in outbuf", m_channelData[0]->outbuf->getReadSpace());
|
m_log.log(2, "R3LiveShifter::shift: initially in outbuf", m_channelData[0]->outbuf->getReadSpace());
|
||||||
|
|
||||||
int pad = 0;
|
int pad = 0;
|
||||||
int resamplerDelay = 32;
|
|
||||||
if (m_firstProcess) {
|
if (m_firstProcess) {
|
||||||
if (m_contractThenExpand) {
|
if (m_contractThenExpand) {
|
||||||
pad = getWindowSourceSize();
|
pad = getWindowSourceSize();
|
||||||
@@ -315,7 +321,6 @@ R3LiveShifter::shift(const float *const *input, float *const *output)
|
|||||||
} else {
|
} else {
|
||||||
pad = getWindowSourceSize() / 2;
|
pad = getWindowSourceSize() / 2;
|
||||||
}
|
}
|
||||||
pad += resamplerDelay;
|
|
||||||
m_log.log(2, "R3LiveShifter::shift: extending input with pre-pad", incount, pad);
|
m_log.log(2, "R3LiveShifter::shift: extending input with pre-pad", incount, 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);
|
||||||
@@ -336,7 +341,7 @@ R3LiveShifter::shift(const float *const *input, float *const *output)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int requiredInOutbuf = int(ceil(incount / outRatio)) + resamplerDelay;
|
int requiredInOutbuf = int(ceil(incount / outRatio));
|
||||||
generate(requiredInOutbuf);
|
generate(requiredInOutbuf);
|
||||||
|
|
||||||
int got = readOut(output, incount, 0);
|
int got = readOut(output, incount, 0);
|
||||||
@@ -420,6 +425,16 @@ R3LiveShifter::readIn(const float *const *input)
|
|||||||
|
|
||||||
m_log.log(2, "R3LiveShifter::readIn: writing to inbuf from resampled data, former read space and samples being added", m_channelData[0]->inbuf->getReadSpace(), resampleOutput);
|
m_log.log(2, "R3LiveShifter::readIn: writing to inbuf from resampled data, former read space and samples being added", m_channelData[0]->inbuf->getReadSpace(), resampleOutput);
|
||||||
|
|
||||||
|
if (m_firstProcess) {
|
||||||
|
int expected = floor(incount * inRatio);
|
||||||
|
if (resampleOutput < expected) {
|
||||||
|
m_log.log(2, "R3LiveShifter::readIn: resampler left us short on first process, pre-padding output: expected and obtained", expected, resampleOutput);
|
||||||
|
for (int c = 0; c < m_parameters.channels; ++c) {
|
||||||
|
m_channelData[c]->inbuf->zero(expected - resampleOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int c = 0; c < m_parameters.channels; ++c) {
|
for (int c = 0; c < m_parameters.channels; ++c) {
|
||||||
m_channelData[c]->inbuf->write
|
m_channelData[c]->inbuf->write
|
||||||
(m_channelData.at(c)->resampled.data(),
|
(m_channelData.at(c)->resampled.data(),
|
||||||
@@ -646,7 +661,18 @@ R3LiveShifter::readOut(float *const *output, int outcount, int origin)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (resampledCount < outcount) {
|
if (resampledCount < outcount) {
|
||||||
m_log.log(0, "R3LiveShifter::readOut: WARNING: Failed to obtain enough samples from resampler", resampledCount, outcount);
|
if (m_firstProcess) {
|
||||||
|
m_log.log(2, "R3LiveShifter::readOut: resampler left us short on first process, pre-padding output: expected and obtained", outcount, resampledCount);
|
||||||
|
int prepad = outcount - resampledCount;
|
||||||
|
for (int c = 0; c < m_parameters.channels; ++c) {
|
||||||
|
v_move(m_channelAssembly.mixdown.data()[c] + prepad,
|
||||||
|
m_channelAssembly.mixdown.data()[c], resampledCount);
|
||||||
|
v_zero(m_channelAssembly.mixdown.data()[c], prepad);
|
||||||
|
}
|
||||||
|
resampledCount = outcount;
|
||||||
|
} else {
|
||||||
|
m_log.log(0, "R3LiveShifter::readOut: WARNING: Failed to obtain enough samples from resampler", resampledCount, outcount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useMidSide()) {
|
if (useMidSide()) {
|
||||||
|
|||||||
@@ -300,6 +300,10 @@ R3Stretcher::createResampler()
|
|||||||
resamplerParameters.ratioChange = Resampler::SuddenRatioChange;
|
resamplerParameters.ratioChange = Resampler::SuddenRatioChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int debug = m_log.getDebugLevel();
|
||||||
|
if (debug > 0) --debug;
|
||||||
|
resamplerParameters.debugLevel = debug;
|
||||||
|
|
||||||
m_resampler = std::unique_ptr<Resampler>
|
m_resampler = std::unique_ptr<Resampler>
|
||||||
(new Resampler(resamplerParameters, m_parameters.channels));
|
(new Resampler(resamplerParameters, m_parameters.channels));
|
||||||
|
|
||||||
|
|||||||
@@ -52,18 +52,19 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged)
|
|||||||
int n = 100000;
|
int n = 100000;
|
||||||
float freq = 440.f;
|
float freq = 440.f;
|
||||||
int rate = 44100;
|
int rate = 44100;
|
||||||
|
|
||||||
|
if (printDebug) {
|
||||||
|
RubberBandLiveShifter::setDefaultDebugLevel(2);
|
||||||
|
}
|
||||||
|
|
||||||
RubberBandLiveShifter shifter
|
RubberBandLiveShifter shifter
|
||||||
(rate, 1, RubberBandLiveShifter::OptionPitchModeB);
|
(rate, 1, RubberBandLiveShifter::OptionPitchModeB);
|
||||||
|
|
||||||
//!!!
|
//!!!
|
||||||
shifter.setPitchScale(2.0);
|
// shifter.setPitchScale(2.0);
|
||||||
|
|
||||||
if (printDebug) {
|
|
||||||
shifter.setDebugLevel(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
int blocksize = shifter.getBlockSize();
|
int blocksize = shifter.getBlockSize();
|
||||||
BOOST_TEST(blocksize == 2560);
|
BOOST_TEST(blocksize == 512);
|
||||||
|
|
||||||
n = (n / blocksize + 1) * blocksize;
|
n = (n / blocksize + 1) * blocksize;
|
||||||
|
|
||||||
@@ -80,6 +81,8 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged)
|
|||||||
|
|
||||||
int delay = shifter.getStartDelay();
|
int delay = shifter.getStartDelay();
|
||||||
|
|
||||||
|
std::cerr << "delay reported as " << delay << std::endl;
|
||||||
|
|
||||||
// We now have n samples of a simple sinusoid with stretch factor
|
// We now have n samples of a simple sinusoid with stretch factor
|
||||||
// 1.0; obviously we expect the output to be essentially the same
|
// 1.0; obviously we expect the output to be essentially the same
|
||||||
// thing. It will have lower precision for a while at the start
|
// thing. It will have lower precision for a while at the start
|
||||||
@@ -106,18 +109,21 @@ BOOST_AUTO_TEST_CASE(sinusoid_unchanged)
|
|||||||
tt::tolerance(0.001f) << tt::per_element());
|
tt::tolerance(0.001f) << tt::per_element());
|
||||||
|
|
||||||
if (printDebug) {
|
if (printDebug) {
|
||||||
// The initial # is to allow grep on the test output
|
// The prefix is to allow grep on the test output
|
||||||
std::cout << "#sample\tV" << std::endl;
|
|
||||||
for (int i = 0; i < int(out.size()); ++i) {
|
|
||||||
std::cout << "#" << i << "\t" << out[i] << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (printDebug) {
|
std::cout << "IN,sample,V" << std::endl;
|
||||||
// The initial @ is to allow grep on the test output
|
for (int i = 0; i < int(in.size()); ++i) {
|
||||||
std::cout << "@sample\tV" << std::endl;
|
std::cout << "IN," << i << "," << in[i] << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "OUT,sample,V" << std::endl;
|
||||||
|
for (int i = 0; i < int(out.size()); ++i) {
|
||||||
|
std::cout << "OUT," << i << "," << out[i] << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "DIFF,V" << std::endl;
|
||||||
for (int i = 0; i + delay < int(in.size()); ++i) {
|
for (int i = 0; i + delay < int(in.size()); ++i) {
|
||||||
std::cout << "@" << i << "\t" << out[i + delay] - in[i] << std::endl;
|
std::cout << "DIFF," << i << "," << out[i + delay] - in[i] << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user