commit 744514d29b89f5569fff6abd164cb1a7bc8f6e25
parent e8943a6c4d539b9edb12315489e752bdad598a80
Author: Matt Demanett <matt@demanett.net>
Date: Tue, 4 Jun 2019 23:06:00 -0400
Fix dodgy synchronization in analyzers. #56
Diffstat:
3 files changed, 73 insertions(+), 47 deletions(-)
diff --git a/src/analyzer_base.cpp b/src/analyzer_base.cpp
@@ -11,37 +11,11 @@ ChannelAnalyzer::~ChannelAnalyzer() {
_worker.join();
delete[] _workerBuf;
delete[] _stepBuf;
- delete[] _bins0;
- delete[] _bins1;
if (_averagedBins) {
delete _averagedBins;
}
}
-float ChannelAnalyzer::getPeak() {
- float max = 0.0f;
- int maxBin = 0;
- const float* bins = getBins();
- for (int bin = 0; bin < _binsN; ++bin) {
- if (bins[bin] > max) {
- max = bins[bin];
- maxBin = bin;
- }
- }
-
- const int bandsPerBin = _analyzer._size / _binsN;
- const float fWidth = (_analyzer._sampleRate / 2.0f) / (float)(_analyzer._size / bandsPerBin);
- float sum = 0.0f;
- float sumWeights = 0.0f;
- int i = std::max(0, maxBin - 1);
- int j = std::max(_binsN - 1, maxBin + 1);
- for (; i <= j; ++i) {
- sum += bins[i] * fWidth * i;
- sumWeights += bins[i];
- }
- return sum / sumWeights;
-}
-
void ChannelAnalyzer::step(float sample) {
_stepBuf[_stepBufI++] = sample;
if (_stepBufI >= _stepBufN) {
@@ -89,6 +63,7 @@ void ChannelAnalyzer::work() {
_analyzer.getMagnitudes(bins, _binsN);
}
_currentBins = bins;
+ _currentOutBuf = _currentBins;
}
while (_workerBufReadI != _workerBufWriteI) {
@@ -128,6 +103,9 @@ void AnalyzerCore::setParams(int averageN, Quality quality, Window window) {
}
void AnalyzerCore::resetChannels() {
+ _size = size();
+ _binsN = _size / _binAverageN;
+
std::lock_guard<std::mutex> lock(_channelsMutex);
for (int i = 0; i < _nChannels; ++i) {
if (_channels[i]) {
@@ -180,6 +158,31 @@ SpectrumAnalyzer::WindowType AnalyzerCore::window() {
}
}
+float AnalyzerCore::getPeak(int channel) {
+ assert(channel >= 0 && channel < _nChannels);
+ float max = 0.0f;
+ int maxBin = 0;
+ const float* bins = getBins(channel);
+ for (int bin = 0; bin < _binsN; ++bin) {
+ if (bins[bin] > max) {
+ max = bins[bin];
+ maxBin = bin;
+ }
+ }
+
+ const int bandsPerBin = _size / _binsN;
+ const float fWidth = (APP->engine->getSampleRate() / 2.0f) / (float)(_size / bandsPerBin);
+ float sum = 0.0f;
+ float sumWeights = 0.0f;
+ int i = std::max(0, maxBin - 1);
+ int j = std::max(_binsN - 1, maxBin + 1);
+ for (; i <= j; ++i) {
+ sum += bins[i] * fWidth * i;
+ sumWeights += bins[i];
+ }
+ return sum / sumWeights;
+}
+
void AnalyzerCore::stepChannel(int channelIndex, Input& input) {
assert(channelIndex >= 0);
assert(channelIndex < _nChannels);
@@ -188,12 +191,15 @@ void AnalyzerCore::stepChannel(int channelIndex, Input& input) {
if (!_channels[channelIndex]) {
std::lock_guard<std::mutex> lock(_channelsMutex);
_channels[channelIndex] = new ChannelAnalyzer(
- size(),
+ _size,
_overlap,
window(),
APP->engine->getSampleRate(),
_averageN,
- _binAverageN
+ _binAverageN,
+ _outBufs + 2 * channelIndex * _outBufferN,
+ _outBufs + (2 * channelIndex + 1) * _outBufferN,
+ _currentOutBufs[channelIndex]
);
}
_channels[channelIndex]->step(input.getVoltage());
@@ -235,9 +241,8 @@ void AnalyzerDisplay::draw(const DrawArgs& args) {
drawXAxis(args, strokeWidth, rangeMinHz, rangeMaxHz);
if (_module) {
for (int i = 0; i < _module->_core._nChannels; ++i) {
- ChannelAnalyzer* channel = _module->_core._channels[i];
- if (channel) {
- drawGraph(args, channel->getBins(), channel->_binsN, _channelColors[i % channelColorsN], strokeWidth, rangeMinHz, rangeMaxHz, rangeDb);
+ if (_module->_core._channels[i]) {
+ drawGraph(args, _module->_core.getBins(i), _module->_core._binsN, _channelColors[i % channelColorsN], strokeWidth, rangeMinHz, rangeMaxHz, rangeDb);
}
}
}
@@ -266,7 +271,7 @@ void AnalyzerDisplay::drawHeader(const DrawArgs& args) {
char s[sLen];
int x = _insetAround + 2;
- int n = snprintf(s, sLen, "Peaks (+/-%0.1f):", (APP->engine->getSampleRate() / 2.0f) / (float)(_module->_core.size() / _module->_core._binAverageN));
+ int n = snprintf(s, sLen, "Peaks (+/-%0.1f):", (APP->engine->getSampleRate() / 2.0f) / (float)(_module->_core._size / _module->_core._binAverageN));
drawText(args, s, x, _insetTop + textY);
x += n * charPx - 0;
@@ -276,9 +281,8 @@ void AnalyzerDisplay::drawHeader(const DrawArgs& args) {
spacing = 20;
}
for (int i = 0; i < _module->_core._nChannels; ++i) {
- ChannelAnalyzer* channel = _module->_core._channels[i];
- if (channel) {
- snprintf(s, sLen, "%c:%7.1f", 'A' + i, channel->getPeak());
+ if (_module->_core._channels[i]) {
+ snprintf(s, sLen, "%c:%7.1f", 'A' + i, _module->_core.getPeak(i));
drawText(args, s, x, _insetTop + textY, 0.0, &_channelColors[i % channelColorsN]);
}
x += 9 * charPx + spacing;
@@ -461,9 +465,9 @@ void AnalyzerDisplay::drawGraph(
float rangeDb
) {
float range = (rangeMaxHz - rangeMinHz) / (0.5f * APP->engine->getSampleRate());
- int pointsN = roundf(range * (_module->_core.size() / 2));
+ int pointsN = roundf(range * (_module->_core._size / 2));
range = rangeMinHz / (0.5f * APP->engine->getSampleRate());
- int pointsOffset = roundf(range * (_module->_core.size() / 2));
+ int pointsOffset = roundf(range * (_module->_core._size / 2));
nvgSave(args.vg);
nvgScissor(args.vg, _insetLeft, _insetTop, _graphSize.x, _graphSize.y);
nvgStrokeColor(args.vg, color);
diff --git a/src/analyzer_base.hpp b/src/analyzer_base.hpp
@@ -18,7 +18,8 @@ struct ChannelAnalyzer {
int _binsN;
float* _bins0;
float* _bins1;
- std::atomic<const float*> _currentBins;
+ float* _currentBins;
+ std::atomic<float*>& _currentOutBuf;
AveragingBuffer<float>* _averagedBins;
const int _stepBufN;
float* _stepBuf;
@@ -38,13 +39,17 @@ struct ChannelAnalyzer {
SpectrumAnalyzer::WindowType windowType,
float sampleRate,
int averageN,
- int binSize
+ int binSize,
+ float* outBuf1,
+ float* outBuf2,
+ std::atomic<float*>& currentOutBuf
)
: _analyzer(size, overlap, windowType, sampleRate, false)
, _binsN(size / binSize)
- , _bins0(new float[_binsN] {})
- , _bins1(new float[_binsN] {})
+ , _bins0(outBuf1)
+ , _bins1(outBuf2)
, _currentBins(_bins0)
+ , _currentOutBuf(currentOutBuf)
, _averagedBins(averageN == 1 ? NULL : new AveragingBuffer<float>(_binsN, averageN))
, _stepBufN(size / overlap)
, _stepBuf(new float[_stepBufN] {})
@@ -57,8 +62,6 @@ struct ChannelAnalyzer {
}
virtual ~ChannelAnalyzer();
- inline const float* getBins() { return _currentBins; }
- float getPeak();
void step(float sample);
void work();
};
@@ -78,26 +81,44 @@ struct AnalyzerCore {
int _nChannels;
ChannelAnalyzer** _channels;
+ SpectrumAnalyzer::Size _size;
+ const int _binAverageN = 2;
+ const int _outBufferN = SpectrumAnalyzer::maxSize / _binAverageN;
+ int _binsN;
+ float* _outBufs;
+ std::atomic<float*>* _currentOutBufs;
int _averageN = 1;
Quality _quality = QUALITY_GOOD;
Window _window = WINDOW_KAISER;
const SpectrumAnalyzer::Overlap _overlap = SpectrumAnalyzer::OVERLAP_2;
- const int _binAverageN = 2;
std::mutex _channelsMutex;
AnalyzerCore(int nChannels)
: _nChannels(nChannels)
, _channels(new ChannelAnalyzer*[_nChannels] {})
- {}
+ , _outBufs(new float[2 * nChannels * _outBufferN] {})
+ , _currentOutBufs(new std::atomic<float*>[nChannels])
+ {
+ for (int i = 0; i < nChannels; ++i) {
+ _currentOutBufs[i] = _outBufs + 2 * i * _outBufferN;
+ }
+ }
virtual ~AnalyzerCore() {
resetChannels();
delete[] _channels;
+ delete[] _outBufs;
+ delete[] _currentOutBufs;
}
void setParams(int averageN, Quality quality, Window window);
void resetChannels();
SpectrumAnalyzer::Size size();
SpectrumAnalyzer::WindowType window();
+ inline float* getBins(int i) {
+ assert(i >= 0 && i < _nChannels);
+ return _currentOutBufs[i];
+ }
+ float getPeak(int channel);
void stepChannel(int channelIndex, Input& input);
};
@@ -107,8 +128,7 @@ struct AnalyzerBase : Module {
float _rangeDb = 80.0f;
AnalyzerCore _core;
- AnalyzerBase(int nChannels, int np, int ni, int no, int nl) : _core(nChannels)
- {
+ AnalyzerBase(int nChannels, int np, int ni, int no, int nl) : _core(nChannels) {
config(np, ni, no, nl);
}
};
diff --git a/src/dsp/analyzer.hpp b/src/dsp/analyzer.hpp
@@ -128,6 +128,7 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
SIZE_8192 = 8192,
SIZE_16384 = 16384
};
+ static constexpr Size maxSize = SIZE_16384;
enum Overlap {
OVERLAP_1 = 1,
@@ -171,6 +172,7 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
, _windowOut(NULL)
, _fftOut(new float[_size])
{
+ assert(size <= maxSize);
assert(_sampleRate > size);
switch (size) {