Use atomics for inhop and ratio, and read inhop once at start of consume in case it changes within

This commit is contained in:
Chris Cannam
2022-05-25 14:10:41 +01:00
parent 7d91fdb1b6
commit 630a790ef8
2 changed files with 35 additions and 24 deletions

View File

@@ -92,6 +92,13 @@ R3StretcherImpl::R3StretcherImpl(Parameters parameters,
calculateHop(); calculateHop();
m_prevOuthop = int(round(m_inhop * getEffectiveRatio())); m_prevOuthop = int(round(m_inhop * getEffectiveRatio()));
if (!m_inhop.is_lock_free()) {
m_parameters.logger("WARNING: std::atomic<int> is not lock-free");
}
if (!m_timeRatio.is_lock_free()) {
m_parameters.logger("WARNING: std::atomic<double> is not lock-free");
}
} }
void void
@@ -113,19 +120,19 @@ R3StretcherImpl::calculateHop()
{ {
double ratio = getEffectiveRatio(); double ratio = getEffectiveRatio();
double proposedOuthop = 256; double proposedOuthop = 256;
double inhop = 1.0;
if (ratio > 1.0) { if (ratio > 1.0) {
double inhop = proposedOuthop / ratio; inhop = proposedOuthop / ratio;
if (inhop < 1.0) { if (inhop < 1.0) {
m_parameters.logger("WARNING: Extreme ratio yields ideal inhop < 1, results may be suspect"); m_parameters.logger("WARNING: Extreme ratio yields ideal inhop < 1, results may be suspect");
m_inhop = 1; inhop = 1.0;
} else {
m_inhop = int(round(inhop));
} }
} else { } else {
double inhop = std::min(proposedOuthop / ratio, 340.0); inhop = std::min(proposedOuthop / ratio, 340.0);
m_inhop = int(round(inhop));
} }
m_inhop = int(round(inhop));
} }
double double
@@ -237,19 +244,21 @@ void
R3StretcherImpl::consume() R3StretcherImpl::consume()
{ {
double ratio = getEffectiveRatio(); double ratio = getEffectiveRatio();
int inhop = m_inhop;
int longest = m_guideConfiguration.longestFftSize; int longest = m_guideConfiguration.longestFftSize;
int channels = m_parameters.channels; int channels = m_parameters.channels;
m_calculator->setDebugLevel(3); // m_calculator->setDebugLevel(3);
int outhop = m_calculator->calculateSingle(ratio, int outhop = m_calculator->calculateSingle(ratio,
1.0 / m_pitchScale, 1.0 / m_pitchScale,
1.f, 1.f,
m_inhop, inhop,
longest, longest,
longest); longest);
std::cout << "outhop = " << outhop << std::endl; // std::cout << "outhop = " << outhop << std::endl;
while (m_channelData.at(0)->outbuf->getWriteSpace() >= outhop) { while (m_channelData.at(0)->outbuf->getWriteSpace() >= outhop) {
@@ -273,7 +282,7 @@ R3StretcherImpl::consume()
// Analysis // Analysis
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
analyseChannel(c, m_prevOuthop); analyseChannel(c, inhop, m_prevOuthop);
} }
// Phase update. This is synchronised across all channels // Phase update. This is synchronised across all channels
@@ -294,7 +303,7 @@ R3StretcherImpl::consume()
m_channelAssembly.phase.data(), m_channelAssembly.phase.data(),
m_guideConfiguration, m_guideConfiguration,
m_channelAssembly.guidance.data(), m_channelAssembly.guidance.data(),
m_inhop, inhop,
outhop); outhop);
} }
@@ -333,11 +342,11 @@ R3StretcherImpl::consume()
} }
int readSpace = cd->inbuf->getReadSpace(); int readSpace = cd->inbuf->getReadSpace();
if (readSpace < m_inhop) { if (readSpace < inhop) {
// This should happen only when draining // This should happen only when draining
cd->inbuf->skip(readSpace); cd->inbuf->skip(readSpace);
} else { } else {
cd->inbuf->skip(m_inhop); cd->inbuf->skip(inhop);
} }
} }
} }
@@ -346,7 +355,7 @@ R3StretcherImpl::consume()
} }
void void
R3StretcherImpl::analyseChannel(int c, int prevOuthop) R3StretcherImpl::analyseChannel(int c, int inhop, int prevOuthop)
{ {
int longest = m_guideConfiguration.longestFftSize; int longest = m_guideConfiguration.longestFftSize;
int classify = m_guideConfiguration.classificationFftSize; int classify = m_guideConfiguration.classificationFftSize;
@@ -377,16 +386,18 @@ R3StretcherImpl::analyseChannel(int c, int prevOuthop)
(buf + offset, it.second->timeDomain.data()); (buf + offset, it.second->timeDomain.data());
} }
// The classification scale has a one-hop readahead (note // The classification scale has a one-hop readahead, so populate
// that inhop is fixed), so populate its current data from // its current data from the readahead and the readahead from
// the readahead and the readahead from further down the // further down the long unwindowed frame.
// long unwindowed frame.
//!!! (This causes us to get out of sync when inhop changes - is
//!!! it better to vary outhop?)
auto &classifyScale = cd->scales.at(classify); auto &classifyScale = cd->scales.at(classify);
ClassificationReadaheadData &readahead = cd->readahead; ClassificationReadaheadData &readahead = cd->readahead;
m_scaleData.at(classify)->analysisWindow.cut m_scaleData.at(classify)->analysisWindow.cut
(buf + (longest - classify) / 2 + m_inhop, (buf + (longest - classify) / 2 + inhop,
readahead.timeDomain.data()); readahead.timeDomain.data());
// Finally window the longest scale // Finally window the longest scale
@@ -485,7 +496,7 @@ R3StretcherImpl::analyseChannel(int c, int prevOuthop)
(classifyScale->mag.data(), 3, nullptr, (classifyScale->mag.data(), 3, nullptr,
classifyScale->troughs.data()); classifyScale->troughs.data());
double instantaneousRatio = double(prevOuthop) / double(m_inhop); double instantaneousRatio = double(prevOuthop) / double(inhop);
m_guide.calculate(instantaneousRatio, m_guide.calculate(instantaneousRatio,
classifyScale->mag.data(), classifyScale->mag.data(),
classifyScale->troughs.data(), classifyScale->troughs.data(),

View File

@@ -181,8 +181,8 @@ protected:
Parameters m_parameters; Parameters m_parameters;
double m_timeRatio; std::atomic<double> m_timeRatio;
double m_pitchScale; std::atomic<double> m_pitchScale;
std::vector<std::shared_ptr<ChannelData>> m_channelData; std::vector<std::shared_ptr<ChannelData>> m_channelData;
std::map<int, std::shared_ptr<ScaleData>> m_scaleData; std::map<int, std::shared_ptr<ScaleData>> m_scaleData;
@@ -192,13 +192,13 @@ protected:
Peak<double, std::less<double>> m_troughPicker; Peak<double, std::less<double>> m_troughPicker;
std::unique_ptr<StretchCalculator> m_calculator; std::unique_ptr<StretchCalculator> m_calculator;
std::unique_ptr<Resampler> m_resampler; std::unique_ptr<Resampler> m_resampler;
int m_inhop; std::atomic<int> m_inhop;
int m_prevOuthop; int m_prevOuthop;
bool m_draining; bool m_draining;
void consume(); void consume();
void calculateHop(); void calculateHop();
void analyseChannel(int channel, int prevOuthop); void analyseChannel(int channel, int inhop, int prevOuthop);
void synthesiseChannel(int channel, int outhop); void synthesiseChannel(int channel, int outhop);
double getEffectiveRatio() const { double getEffectiveRatio() const {