BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

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:
Msrc/analyzer_base.cpp | 78+++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/analyzer_base.hpp | 40++++++++++++++++++++++++++++++----------
Msrc/dsp/analyzer.hpp | 2++
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) {