Use doubles throughout (simpler, faster)

This commit is contained in:
Chris Cannam
2022-05-24 15:39:28 +01:00
parent 49ac04ceab
commit c4a78b4b55
7 changed files with 71 additions and 69 deletions

View File

@@ -138,8 +138,13 @@ public:
* necessary to empty the buffer. If fewer than n are available, * necessary to empty the buffer. If fewer than n are available,
* the remainder will be zeroed out. Returns the number of * the remainder will be zeroed out. Returns the number of
* samples actually read. * samples actually read.
*
* This is a template function, taking an argument S for the target
* sample type, which is permitted to differ from T if the two
* types are compatible for arithmetic operations.
*/ */
int peek(T *const R__ destination, int n) const; template <typename S>
int peek(S *const R__ destination, int n) const;
/** /**
* Read one sample from the buffer, if available, without * Read one sample from the buffer, if available, without
@@ -384,8 +389,9 @@ RingBuffer<T>::readOne()
} }
template <typename T> template <typename T>
template <typename S>
int int
RingBuffer<T>::peek(T *const R__ destination, int n) const RingBuffer<T>::peek(S *const R__ destination, int n) const
{ {
int w = m_writer; int w = m_writer;
int r = m_reader; int r = m_reader;
@@ -394,7 +400,6 @@ RingBuffer<T>::peek(T *const R__ destination, int n) const
if (n > available) { if (n > available) {
std::cerr << "WARNING: RingBuffer::peek: " << n << " requested, only " std::cerr << "WARNING: RingBuffer::peek: " << n << " requested, only "
<< available << " available" << std::endl; << available << " available" << std::endl;
memset(destination + available, 0, (n - available) * sizeof(T));
n = available; n = available;
} }
if (n == 0) return n; if (n == 0) return n;
@@ -403,10 +408,10 @@ RingBuffer<T>::peek(T *const R__ destination, int n) const
const T *const R__ bufbase = m_buffer + r; const T *const R__ bufbase = m_buffer + r;
if (here >= n) { if (here >= n) {
v_copy(destination, bufbase, n); v_convert(destination, bufbase, n);
} else { } else {
v_copy(destination, bufbase, here); v_convert(destination, bufbase, here);
v_copy(destination + here, m_buffer, n - here); v_convert(destination + here, m_buffer, n - here);
} }
return n; return n;

View File

@@ -50,11 +50,11 @@ public:
int verticalFilterLength; int verticalFilterLength;
double harmonicThreshold; double harmonicThreshold;
double percussiveThreshold; double percussiveThreshold;
float silenceThreshold; double silenceThreshold;
Parameters(int _binCount, int _horizontalFilterLength, Parameters(int _binCount, int _horizontalFilterLength,
int _horizontalFilterLag, int _verticalFilterLength, int _horizontalFilterLag, int _verticalFilterLength,
double _harmonicThreshold, double _percussiveThreshold, double _harmonicThreshold, double _percussiveThreshold,
float _silenceThreshold) : double _silenceThreshold) :
binCount(_binCount), binCount(_binCount),
horizontalFilterLength(_horizontalFilterLength), horizontalFilterLength(_horizontalFilterLength),
horizontalFilterLag(_horizontalFilterLag), horizontalFilterLag(_horizontalFilterLag),
@@ -66,21 +66,21 @@ public:
BinClassifier(Parameters parameters) : BinClassifier(Parameters parameters) :
m_parameters(parameters), m_parameters(parameters),
m_vFilter(new MovingMedian<float>(m_parameters.verticalFilterLength)), m_vFilter(new MovingMedian<double>(m_parameters.verticalFilterLength)),
m_vfQueue(parameters.horizontalFilterLag) m_vfQueue(parameters.horizontalFilterLag)
{ {
int n = m_parameters.binCount; int n = m_parameters.binCount;
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
m_hFilters.push_back(std::make_shared<MovingMedian<float>> m_hFilters.push_back(std::make_shared<MovingMedian<double>>
(m_parameters.horizontalFilterLength)); (m_parameters.horizontalFilterLength));
} }
m_hf = allocate_and_zero<float>(n); m_hf = allocate_and_zero<double>(n);
m_vf = allocate_and_zero<float>(n); m_vf = allocate_and_zero<double>(n);
for (int i = 0; i < m_parameters.horizontalFilterLag; ++i) { for (int i = 0; i < m_parameters.horizontalFilterLag; ++i) {
float *entry = allocate_and_zero<float>(n); double *entry = allocate_and_zero<double>(n);
m_vfQueue.write(&entry, 1); m_vfQueue.write(&entry, 1);
} }
} }
@@ -88,7 +88,7 @@ public:
~BinClassifier() ~BinClassifier()
{ {
while (m_vfQueue.getReadSpace() > 0) { while (m_vfQueue.getReadSpace() > 0) {
float *entry = m_vfQueue.readOne(); double *entry = m_vfQueue.readOne();
deallocate(entry); deallocate(entry);
} }
@@ -96,7 +96,7 @@ public:
deallocate(m_vf); deallocate(m_vf);
} }
void classify(const float *const mag, Classification *classification) { void classify(const double *const mag, Classification *classification) {
const int n = m_parameters.binCount; const int n = m_parameters.binCount;
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
@@ -105,10 +105,10 @@ public:
} }
v_copy(m_vf, mag, n); v_copy(m_vf, mag, n);
MovingMedian<float>::filter(*m_vFilter, m_vf); MovingMedian<double>::filter(*m_vFilter, m_vf);
if (m_parameters.horizontalFilterLag > 0) { if (m_parameters.horizontalFilterLag > 0) {
float *lagged = m_vfQueue.readOne(); double *lagged = m_vfQueue.readOne();
m_vfQueue.write(&m_vf, 1); m_vfQueue.write(&m_vf, 1);
m_vf = lagged; m_vf = lagged;
} }
@@ -134,13 +134,13 @@ public:
protected: protected:
Parameters m_parameters; Parameters m_parameters;
std::vector<std::shared_ptr<MovingMedian<float>>> m_hFilters; std::vector<std::shared_ptr<MovingMedian<double>>> m_hFilters;
std::unique_ptr<MovingMedian<float>> m_vFilter; std::unique_ptr<MovingMedian<double>> m_vFilter;
// We manage the queued frames through pointer swapping, hence // We manage the queued frames through pointer swapping, hence
// bare pointers here // bare pointers here
float *m_hf; double *m_hf;
float *m_vf; double *m_vf;
RingBuffer<float *> m_vfQueue; RingBuffer<double *> m_vfQueue;
BinClassifier(const BinClassifier &) =delete; BinClassifier(const BinClassifier &) =delete;
BinClassifier &operator=(const BinClassifier &) =delete; BinClassifier &operator=(const BinClassifier &) =delete;

View File

@@ -62,7 +62,7 @@ public:
{ {
} }
Segmentation segment(const float *const mag) { Segmentation segment(const double *const mag) {
int n = m_classifierParameters.binCount; int n = m_classifierParameters.binCount;
m_classifier.classify(mag, m_classification.data()); m_classifier.classify(mag, m_classification.data());
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {

View File

@@ -35,9 +35,9 @@ class Guide
public: public:
struct FftBand { struct FftBand {
int fftSize; int fftSize;
float f0; double f0;
float f1; double f1;
FftBand(int _s, float _f0, float _f1) : FftBand(int _s, double _f0, double _f1) :
fftSize(_s), f0(_f0), f1(_f1) { } fftSize(_s), f0(_f0), f1(_f1) { }
FftBand() : FftBand() :
fftSize(0), f0(0.f), f1(0.f) { } fftSize(0), f0(0.f), f1(0.f) { }
@@ -45,10 +45,10 @@ public:
struct PhaseLockBand { struct PhaseLockBand {
int p; int p;
float beta; double beta;
float f0; double f0;
float f1; double f1;
PhaseLockBand(int _p, float _beta, float _f0, float _f1) : PhaseLockBand(int _p, double _beta, double _f0, double _f1) :
p(_p), beta(_beta), f0(_f0), f1(_f1) { } p(_p), beta(_beta), f0(_f0), f1(_f1) { }
PhaseLockBand() : PhaseLockBand() :
p(0), beta(1.0), f0(0.f), f1(0.f) { } p(0), beta(1.0), f0(0.f), f1(0.f) { }
@@ -56,9 +56,9 @@ public:
struct Range { struct Range {
bool present; bool present;
float f0; double f0;
float f1; double f1;
Range(bool _present, float _f0, float _f1) : Range(bool _present, double _f0, double _f1) :
present(_present), f0(_f0), f1(_f1) { } present(_present), f0(_f0), f1(_f1) { }
Range() : Range() :
present(false), f0(0.f), f1(0.f) { } present(false), f0(0.f), f1(0.f) { }
@@ -76,9 +76,9 @@ public:
struct BandLimits { struct BandLimits {
int fftSize; int fftSize;
float f0min; double f0min;
float f1max; double f1max;
BandLimits(int _fftSize, float _f0min, float _f1max) : BandLimits(int _fftSize, double _f0min, double _f1max) :
fftSize(_fftSize), f0min(_f0min), f1max(_f1max) { } fftSize(_fftSize), f0min(_f0min), f1max(_f1max) { }
BandLimits() : BandLimits() :
fftSize(0), f0min(0.f), f1max(0.f) { } fftSize(0), f0min(0.f), f1max(0.f) { }
@@ -132,9 +132,9 @@ public:
} }
void calculate(double ratio, void calculate(double ratio,
const float *const magnitudes, const double *const magnitudes,
const int *const troughs, const int *const troughs,
const float *const prevMagnitudes, const double *const prevMagnitudes,
const BinSegmenter::Segmentation &segmentation, const BinSegmenter::Segmentation &segmentation,
const BinSegmenter::Segmentation &prevSegmentation, const BinSegmenter::Segmentation &prevSegmentation,
const BinSegmenter::Segmentation &nextSegmentation, const BinSegmenter::Segmentation &nextSegmentation,
@@ -272,17 +272,17 @@ protected:
return value; return value;
} }
bool checkPotentialKick(const float *const magnitudes, bool checkPotentialKick(const double *const magnitudes,
const float *const prevMagnitudes) const { const double *const prevMagnitudes) const {
int b = binForFrequency(200.0); int b = binForFrequency(200.0);
float here = 0.0, there = 0.0; double here = 0.0, there = 0.0;
for (int i = 1; i <= b; ++i) { for (int i = 1; i <= b; ++i) {
here += magnitudes[i]; here += magnitudes[i];
} }
for (int i = 1; i <= b; ++i) { for (int i = 1; i <= b; ++i) {
there += prevMagnitudes[i]; there += prevMagnitudes[i];
} }
return (here > 10.e-3f && here > there * 1.4f); return (here > 10.e-3 && here > there * 1.4);
} }
double snapToTrough(double f, const int *const troughs) const { double snapToTrough(double f, const int *const troughs) const {

View File

@@ -55,8 +55,9 @@ public:
m_currentPeaks = allocate_and_zero_channels<int>(ch, m_blockSize); m_currentPeaks = allocate_and_zero_channels<int>(ch, m_blockSize);
m_prevPeaks = allocate_and_zero_channels<int>(ch, m_blockSize); m_prevPeaks = allocate_and_zero_channels<int>(ch, m_blockSize);
m_greatestChannel = allocate_and_zero<int>(m_blockSize); m_greatestChannel = allocate_and_zero<int>(m_blockSize);
m_prevInMag = allocate_and_zero_channels<float>(ch, m_blockSize); //!!! there is also a prevMag in R3StretcherImpl which could be passed in to here instead
m_prevInPhase = allocate_and_zero_channels<float>(ch, m_blockSize); m_prevInMag = allocate_and_zero_channels<double>(ch, m_blockSize);
m_prevInPhase = allocate_and_zero_channels<double>(ch, m_blockSize);
m_prevOutPhase = allocate_and_zero_channels<double>(ch, m_blockSize); m_prevOutPhase = allocate_and_zero_channels<double>(ch, m_blockSize);
m_unlocked = allocate_and_zero_channels<double>(ch, m_blockSize); m_unlocked = allocate_and_zero_channels<double>(ch, m_blockSize);
} }
@@ -73,8 +74,8 @@ public:
} }
void advance(double *const *outPhase, void advance(double *const *outPhase,
const float *const *mag, const double *const *mag,
const float *const *phase, const double *const *phase,
const Guide::Configuration &configuration, const Guide::Configuration &configuration,
const Guide::Guidance *const *guidance, const Guide::Guidance *const *guidance,
int inhop, int inhop,
@@ -245,12 +246,12 @@ public:
protected: protected:
Parameters m_parameters; Parameters m_parameters;
int m_blockSize; int m_blockSize;
Peak<float> m_peakPicker; Peak<double> m_peakPicker;
int **m_currentPeaks; int **m_currentPeaks;
int **m_prevPeaks; int **m_prevPeaks;
int *m_greatestChannel; int *m_greatestChannel;
float **m_prevInMag; double **m_prevInMag;
float **m_prevInPhase; double **m_prevInPhase;
double **m_prevOutPhase; double **m_prevOutPhase;
double **m_unlocked; double **m_unlocked;
bool m_reported; bool m_reported;

View File

@@ -240,7 +240,7 @@ R3StretcherImpl::consume()
(scale->timeDomainFrame.data(), (scale->timeDomainFrame.data(),
scale->mag.data(), scale->mag.data(),
scale->phase.data()); scale->phase.data());
v_scale(scale->mag.data(), 1.f / float(fftSize), v_scale(scale->mag.data(), 1.0 / double(fftSize),
scale->mag.size()); scale->mag.size());
} }
@@ -291,10 +291,6 @@ R3StretcherImpl::consume()
// copy to prevMag before filtering // copy to prevMag before filtering
v_copy(scale->prevMag.data(), scale->mag.data(), bufSize); v_copy(scale->prevMag.data(), scale->mag.data(), bufSize);
v_copy(scale->prevOutPhase.data(), scale->outPhase.data(), bufSize); v_copy(scale->prevOutPhase.data(), scale->outPhase.data(), bufSize);
//!!! seems wasteful
for (int i = 0; i < bufSize; ++i) {
scale->phase[i] = princarg(scale->outPhase[i]);
}
} }
for (const auto &band : cd->guidance.fftBands) { for (const auto &band : cd->guidance.fftBands) {
@@ -302,18 +298,18 @@ R3StretcherImpl::consume()
auto scale = cd->scales.at(fftSize); auto scale = cd->scales.at(fftSize);
auto scaleData = m_scaleData.at(fftSize); auto scaleData = m_scaleData.at(fftSize);
//!!! messy and v slow, but leave it until we've //!!! messy and slow, but leave it until we've
//!!! discovered whether we need a window accumulator //!!! discovered whether we need a window accumulator
//!!! (we probably do) //!!! (we probably do)
int analysisWindowSize = scaleData->analysisWindow.getSize(); int analysisWindowSize = scaleData->analysisWindow.getSize();
int synthesisWindowSize = scaleData->synthesisWindow.getSize(); int synthesisWindowSize = scaleData->synthesisWindow.getSize();
int offset = (analysisWindowSize - synthesisWindowSize) / 2; int offset = (analysisWindowSize - synthesisWindowSize) / 2;
float winscale = 0.f; double winscale = 0.0;
for (int i = 0; i < synthesisWindowSize; ++i) { for (int i = 0; i < synthesisWindowSize; ++i) {
winscale += scaleData->analysisWindow.getValue(i + offset) * winscale += scaleData->analysisWindow.getValue(i + offset) *
scaleData->synthesisWindow.getValue(i); scaleData->synthesisWindow.getValue(i);
} }
winscale = float(outhop) / winscale; winscale = double(outhop) / winscale;
double factor = m_parameters.sampleRate / double(fftSize); double factor = m_parameters.sampleRate / double(fftSize);
for (int i = 0; i < fftSize/2 + 1; ++i) { for (int i = 0; i < fftSize/2 + 1; ++i) {
@@ -333,7 +329,7 @@ R3StretcherImpl::consume()
auto scaleData = m_scaleData.at(fftSize); auto scaleData = m_scaleData.at(fftSize);
scaleData->fft.inversePolar(scale->mag.data(), scaleData->fft.inversePolar(scale->mag.data(),
scale->phase.data(), scale->outPhase.data(),
scale->timeDomainFrame.data()); scale->timeDomainFrame.data());
int synthesisWindowSize = scaleData->synthesisWindow.getSize(); int synthesisWindowSize = scaleData->synthesisWindow.getSize();

View File

@@ -127,14 +127,14 @@ protected:
int fftSize; int fftSize;
int bufSize; // size of every freq-domain array here: fftSize/2 + 1 int bufSize; // size of every freq-domain array here: fftSize/2 + 1
//!!! review later which of these we are actually using! //!!! review later which of these we are actually using!
FixedVector<float> timeDomainFrame; FixedVector<double> timeDomainFrame;
FixedVector<float> mag; FixedVector<double> mag;
FixedVector<float> phase; FixedVector<double> phase;
FixedVector<double> outPhase; //!!! "advanced"? FixedVector<double> outPhase; //!!! "advanced"?
FixedVector<int> nextTroughs; //!!! not used in every scale FixedVector<int> nextTroughs; //!!! not used in every scale
FixedVector<float> prevMag; //!!! not used in every scale FixedVector<double> prevMag; //!!! not used in every scale
FixedVector<double> prevOutPhase; FixedVector<double> prevOutPhase;
FixedVector<float> accumulator; FixedVector<double> accumulator;
ChannelScaleData(int _fftSize, int _longestFftSize) : ChannelScaleData(int _fftSize, int _longestFftSize) :
fftSize(_fftSize), fftSize(_fftSize),
@@ -161,7 +161,7 @@ protected:
BinSegmenter::Segmentation prevSegmentation; BinSegmenter::Segmentation prevSegmentation;
BinSegmenter::Segmentation nextSegmentation; BinSegmenter::Segmentation nextSegmentation;
Guide::Guidance guidance; Guide::Guidance guidance;
FixedVector<float> mixdown; FixedVector<double> mixdown;
std::unique_ptr<RingBuffer<float>> inbuf; std::unique_ptr<RingBuffer<float>> inbuf;
std::unique_ptr<RingBuffer<float>> outbuf; std::unique_ptr<RingBuffer<float>> outbuf;
ChannelData(BinSegmenter::Parameters segmenterParameters, ChannelData(BinSegmenter::Parameters segmenterParameters,
@@ -179,8 +179,8 @@ protected:
struct ChannelAssembly { struct ChannelAssembly {
// Vectors of bare pointers, used to package container data // Vectors of bare pointers, used to package container data
// from different channels into arguments for PhaseAdvance // from different channels into arguments for PhaseAdvance
FixedVector<float *> mag; FixedVector<double *> mag;
FixedVector<float *> phase; FixedVector<double *> phase;
FixedVector<Guide::Guidance *> guidance; FixedVector<Guide::Guidance *> guidance;
FixedVector<double *> outPhase; FixedVector<double *> outPhase;
ChannelAssembly(int channels) : ChannelAssembly(int channels) :
@@ -190,8 +190,8 @@ protected:
struct ScaleData { struct ScaleData {
FFT fft; FFT fft;
Window<float> analysisWindow; Window<double> analysisWindow;
Window<float> synthesisWindow; Window<double> synthesisWindow;
GuidedPhaseAdvance guided; GuidedPhaseAdvance guided;
ScaleData(GuidedPhaseAdvance::Parameters guidedParameters) : ScaleData(GuidedPhaseAdvance::Parameters guidedParameters) :
fft(guidedParameters.fftSize), fft(guidedParameters.fftSize),
@@ -210,7 +210,7 @@ protected:
Guide m_guide; Guide m_guide;
Guide::Configuration m_guideConfiguration; Guide::Configuration m_guideConfiguration;
ChannelAssembly m_channelAssembly; ChannelAssembly m_channelAssembly;
Peak<float, std::less<float>> m_troughPicker; Peak<double, std::less<double>> m_troughPicker;
std::unique_ptr<StretchCalculator> m_calculator; std::unique_ptr<StretchCalculator> m_calculator;
int m_inhop; int m_inhop;
bool m_draining; bool m_draining;