BogaudioModules

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

commit c9b4b39514938f9ac50bc8ae4706f31eca3cef45
parent 6ab2359b98a1b06fa9ddbb0ee8acf098a6f112c4
Author: Matt Demanett <matt@demanett.net>
Date:   Sun,  3 Dec 2017 02:08:41 -0500

Create benchmarks (performance tests) on dsp routines; some trivial optimization; bug fixes.

Diffstat:
M.gitignore | 1+
MMakefile | 9++++++++-
Abenchmarks/analyzer.cpp | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abenchmarks/buffer.cpp | 20++++++++++++++++++++
Abenchmarks/main.cpp | 4++++
Abenchmarks/noise.cpp | 38++++++++++++++++++++++++++++++++++++++
Msrc/Analyzer.cpp | 4++--
Msrc/dsp/analyzer.hpp | 38++++++++++++++++++--------------------
Msrc/dsp/buffer.hpp | 6++++++
Msrc/dsp/noise.hpp | 2+-
10 files changed, 202 insertions(+), 24 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -32,3 +32,4 @@ *.app dist/ +benchmark diff --git a/Makefile b/Makefile @@ -1,9 +1,16 @@ SOURCES = $(wildcard src/*.cpp src/dsp/*cpp) +CXXFLAGS += -Isrc/dsp include ../../plugin.mk -CXXFLAGS += -Isrc/dsp +BENCHMARK_SOURCES = $(wildcard benchmarks/*.cpp src/dsp/*cpp) +BENCHMARK_OBJECTS = $(patsubst %, build/%.o, $(BENCHMARK_SOURCES)) +benchmark: $(BENCHMARK_OBJECTS) + $(CXX) -o $@ $^ ../../build/src/util.cpp.o -lbenchmark +benchmark_clean: + rm -f benchmark +clean: benchmark_clean dist: all mkdir -p dist/BogaudioModules diff --git a/benchmarks/analyzer.cpp b/benchmarks/analyzer.cpp @@ -0,0 +1,104 @@ + +#include <benchmark/benchmark.h> + +#include <dsp.hpp> + +using namespace bogaudio::dsp; + +static void BM_HanningWindowInit(benchmark::State& state) { + for (auto _ : state) { + delete new HanningWindow(1024); + } +} +BENCHMARK(BM_HanningWindowInit); + +static void BM_HanningWindowApply(benchmark::State& state) { + const int n = 1024; + HanningWindow w(n); + float in[n]; + std::fill_n(in, n, 1.1); + float out[n] {}; + for (auto _ : state) { + w.apply(in, out); + in[0] = out[0]; // prevents the call from being optimized away? + } +} +BENCHMARK(BM_HanningWindowApply); + +static void BM_CompileTimeFFT1024(benchmark::State& state) { + FFT1024 fft; + const int n = 1024; + float in[n]; + std::fill_n(in, n, 1.1); + float out[n] {}; + for (auto _ : state) { + fft.do_fft(out, in); + } +} +BENCHMARK(BM_CompileTimeFFT1024); + +static void BM_RuntimeFFT1024(benchmark::State& state) { + const int n = 1024; + ffft::FFTReal<float> fft(n); + float in[n]; + std::fill_n(in, n, 1.1); + float out[n] {}; + for (auto _ : state) { + fft.do_fft(out, in); + } +} +BENCHMARK(BM_RuntimeFFT1024); + +static void BM_SpectrumAnalyzerStep(benchmark::State& state) { + SpectrumAnalyzer sa( + SpectrumAnalyzer::SIZE_1024, + SpectrumAnalyzer::OVERLAP_1, + SpectrumAnalyzer::WINDOW_HANNING, + 44100.0 + ); + float in[8] = { 0.0, 0.7, 1.0, 0.7, 0.0, -0.7, -1.0, -0.7 }; + int i = 0; + for (auto _ : state) { + sa.step(in[i]); + i = ++i % 8; + } +} +BENCHMARK(BM_SpectrumAnalyzerStep); + +static void BM_SpectrumAnalyzerProcess(benchmark::State& state) { + SpectrumAnalyzer sa( + SpectrumAnalyzer::SIZE_1024, + SpectrumAnalyzer::OVERLAP_1, + SpectrumAnalyzer::WINDOW_HANNING, + 44100.0 + ); + float in[8] = { 0.0, 0.7, 1.0, 0.7, 0.0, -0.7, -1.0, -0.7 }; + for (int i = 0; i < 1024; ++i) { + sa.step(in[i % 8]); + } + + for (auto _ : state) { + sa.process(sa._samples); + } +} +BENCHMARK(BM_SpectrumAnalyzerProcess); + +static void BM_SpectrumAnalyzerGetMagnitudes(benchmark::State& state) { + SpectrumAnalyzer sa( + SpectrumAnalyzer::SIZE_1024, + SpectrumAnalyzer::OVERLAP_1, + SpectrumAnalyzer::WINDOW_HANNING, + 44100.0 + ); + const int nBins = 256; + float bins[nBins]; + float in[8] = { 0.0, 0.7, 1.0, 0.7, 0.0, -0.7, -1.0, -0.7 }; + for (int i = 0; i < 1024; ++i) { + sa.step(in[i % 8]); + } + + for (auto _ : state) { + sa.getMagnitudes(bins, nBins); + } +} +BENCHMARK(BM_SpectrumAnalyzerGetMagnitudes); diff --git a/benchmarks/buffer.cpp b/benchmarks/buffer.cpp @@ -0,0 +1,20 @@ + +#include <benchmark/benchmark.h> + +#include <dsp.hpp> + +using namespace bogaudio::dsp; + +struct BMOverlappingBuffer : OverlappingBuffer<float> { + BMOverlappingBuffer(int size, int o) : OverlappingBuffer(size, o) {} + virtual void process(float* samples) {} +}; + +static void BM_OverlappingBuffer(benchmark::State& state) { + BMOverlappingBuffer b(1024, 2); + int i = 0; + for (auto _ : state) { + b.step(i++); + } +} +BENCHMARK(BM_OverlappingBuffer); diff --git a/benchmarks/main.cpp b/benchmarks/main.cpp @@ -0,0 +1,4 @@ + +#include <benchmark/benchmark.h> + +BENCHMARK_MAIN(); diff --git a/benchmarks/noise.cpp b/benchmarks/noise.cpp @@ -0,0 +1,38 @@ + +#include <benchmark/benchmark.h> + +#include <dsp.hpp> + +using namespace bogaudio::dsp; + +static void BM_WhiteNoise(benchmark::State& state) { + WhiteNoiseGenerator g; + for (auto _ : state) { + g.next(); + } +} +BENCHMARK(BM_WhiteNoise); + +static void BM_PinkNoise(benchmark::State& state) { + PinkNoiseGenerator g; + for (auto _ : state) { + g.next(); + } +} +BENCHMARK(BM_PinkNoise); + +static void BM_RedNoise(benchmark::State& state) { + RedNoiseGenerator g; + for (auto _ : state) { + g.next(); + } +} +BENCHMARK(BM_RedNoise); + +static void BM_GaussianNoise(benchmark::State& state) { + GaussianNoiseGenerator g; + for (auto _ : state) { + g.next(); + } +} +BENCHMARK(BM_GaussianNoise); diff --git a/src/Analyzer.cpp b/src/Analyzer.cpp @@ -21,10 +21,10 @@ struct ChannelAnalyzer : bogaudio::dsp::SpectrumAnalyzer { : bogaudio::dsp::SpectrumAnalyzer(size, overlap, windowType, sampleRate) , _averageN(averageN) , _binsN(size / 2) + , _bins(new float[size] {}) + , _frames(new float[_averageN * _binsN] {}) , _currentFrame(0) { - _bins = new float[size] { 0.0 }; - _frames = new float[_averageN * _binsN] { 0.0 }; } virtual ~ChannelAnalyzer() { delete[] _bins; diff --git a/src/dsp/analyzer.hpp b/src/dsp/analyzer.hpp @@ -13,18 +13,18 @@ struct Window { Window(int size) : _size(size) - , _window(new float[_size] { 0.0 }) + , _window(new float[_size] {}) , _sum(0.0) {} virtual ~Window() { delete[] _window; } - virtual float sum() { + float sum() { return _sum; } - virtual void apply(float* in, float* out) { + void apply(float* in, float* out) { for (int i = 0; i < _size; ++i) { out[i] = in[i] * _window[i]; } @@ -164,31 +164,29 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> { const int bands = _size / 2; const int binWidth = bands / nBins; - const float normalization = powf(_window ? _window->sum() : _size, 2.0); + const float invBinWidth = 1.0 / (float)binWidth; + const float normalization = 2.0 / powf(_window ? _window->sum() : _size, 2.0); for (int bin = 0; bin < nBins; ++bin) { float sum = 0.0; int binEnd = bin * binWidth + binWidth; for (int i = binEnd - binWidth; i < binEnd; ++i) { - float power = powf(_fftOut[i], 2.0) + powf(_fftOut[i + bands], 2.0); - power *= 2.0; - power /= normalization; - sum += power; + sum += (_fftOut[i]*_fftOut[i] + _fftOut[i + bands]*_fftOut[i + bands]) * normalization; } - bins[bin] = sum / (float)binWidth; // FIXME: averaging is the way to go? + bins[bin] = sum * invBinWidth; } } - void getFrequencies(float* bins, int nBins) { - assert(nBins <= _size / 2); - assert(_size % nBins == 0); - - const int bands = _size / 2; - const int binWidth = bands / nBins; - const float fundamental = _sampleRate / (float)_size; - for (int bin = 0; bin < nBins; ++bin) { - bins[bin] = roundf(bin*binWidth*fundamental + binWidth*fundamental/2.0); - } - } + // void getFrequencies(float* bins, int nBins) { + // assert(nBins <= _size / 2); + // assert(_size % nBins == 0); + // + // const int bands = _size / 2; + // const int binWidth = bands / nBins; + // const float fundamental = _sampleRate / (float)_size; + // for (int bin = 0; bin < nBins; ++bin) { + // bins[bin] = roundf(bin*binWidth*fundamental + binWidth*fundamental/2.0); + // } + // } }; } // namespace dsp diff --git a/src/dsp/buffer.hpp b/src/dsp/buffer.hpp @@ -1,6 +1,9 @@ #include <algorithm> +namespace bogaudio { +namespace dsp { + template<typename T> struct OverlappingBuffer { const int _size; @@ -47,3 +50,6 @@ struct OverlappingBuffer { return false; } }; + +} // namespace dsp +} // namespace bogaudio diff --git a/src/dsp/noise.hpp b/src/dsp/noise.hpp @@ -7,7 +7,7 @@ struct NoiseGenerator : Generator {}; struct WhiteNoiseGenerator : NoiseGenerator { const uint32_t _mask = -1; const float _randMax = powf(2.0, 31) - 1; - int _last = 0; // rack::randomu32(); + int _last = rack::randomu32(); virtual float _next() { // don't use this for cryptography.