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,
* the remainder will be zeroed out. Returns the number of
* 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
@@ -384,8 +389,9 @@ RingBuffer<T>::readOne()
}
template <typename T>
template <typename S>
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 r = m_reader;
@@ -394,7 +400,6 @@ RingBuffer<T>::peek(T *const R__ destination, int n) const
if (n > available) {
std::cerr << "WARNING: RingBuffer::peek: " << n << " requested, only "
<< available << " available" << std::endl;
memset(destination + available, 0, (n - available) * sizeof(T));
n = available;
}
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;
if (here >= n) {
v_copy(destination, bufbase, n);
v_convert(destination, bufbase, n);
} else {
v_copy(destination, bufbase, here);
v_copy(destination + here, m_buffer, n - here);
v_convert(destination, bufbase, here);
v_convert(destination + here, m_buffer, n - here);
}
return n;

View File

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

View File

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

View File

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

View File

@@ -240,7 +240,7 @@ R3StretcherImpl::consume()
(scale->timeDomainFrame.data(),
scale->mag.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());
}
@@ -291,10 +291,6 @@ R3StretcherImpl::consume()
// copy to prevMag before filtering
v_copy(scale->prevMag.data(), scale->mag.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) {
@@ -302,18 +298,18 @@ R3StretcherImpl::consume()
auto scale = cd->scales.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
//!!! (we probably do)
int analysisWindowSize = scaleData->analysisWindow.getSize();
int synthesisWindowSize = scaleData->synthesisWindow.getSize();
int offset = (analysisWindowSize - synthesisWindowSize) / 2;
float winscale = 0.f;
double winscale = 0.0;
for (int i = 0; i < synthesisWindowSize; ++i) {
winscale += scaleData->analysisWindow.getValue(i + offset) *
scaleData->synthesisWindow.getValue(i);
}
winscale = float(outhop) / winscale;
winscale = double(outhop) / winscale;
double factor = m_parameters.sampleRate / double(fftSize);
for (int i = 0; i < fftSize/2 + 1; ++i) {
@@ -333,7 +329,7 @@ R3StretcherImpl::consume()
auto scaleData = m_scaleData.at(fftSize);
scaleData->fft.inversePolar(scale->mag.data(),
scale->phase.data(),
scale->outPhase.data(),
scale->timeDomainFrame.data());
int synthesisWindowSize = scaleData->synthesisWindow.getSize();

View File

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