commit 137b225415e389067bc945b7094f5212d15b39da
parent 0ea03ef1285261ae14fc658c98fafd58499ebaef
Author: Matt Demanett <matt@demanett.net>
Date: Sun, 3 Dec 2017 21:41:46 -0500
Analyzer: add Quality control to panel; high mode uses 4096 fft; redesign power switch.
Diffstat:
7 files changed, 123 insertions(+), 13 deletions(-)
diff --git a/benchmarks/analyzer.cpp b/benchmarks/analyzer.cpp
@@ -25,6 +25,18 @@ static void BM_HanningWindowApply(benchmark::State& state) {
}
BENCHMARK(BM_HanningWindowApply);
+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_CompileTimeFFT1024(benchmark::State& state) {
FFT1024 fft;
const int n = 1024;
@@ -37,8 +49,8 @@ static void BM_CompileTimeFFT1024(benchmark::State& state) {
}
BENCHMARK(BM_CompileTimeFFT1024);
-static void BM_RuntimeFFT1024(benchmark::State& state) {
- const int n = 1024;
+static void BM_RuntimeFFT4096(benchmark::State& state) {
+ const int n = 4096;
ffft::FFTReal<float> fft(n);
float in[n];
std::fill_n(in, n, 1.1);
@@ -47,7 +59,19 @@ static void BM_RuntimeFFT1024(benchmark::State& state) {
fft.do_fft(out, in);
}
}
-BENCHMARK(BM_RuntimeFFT1024);
+BENCHMARK(BM_RuntimeFFT4096);
+
+static void BM_CompileTimeFFT4096(benchmark::State& state) {
+ FFT4096 fft;
+ const int n = 4096;
+ float in[n];
+ std::fill_n(in, n, 1.1);
+ float out[n] {};
+ for (auto _ : state) {
+ fft.do_fft(out, in);
+ }
+}
+BENCHMARK(BM_CompileTimeFFT4096);
static void BM_SpectrumAnalyzerStep(benchmark::State& state) {
SpectrumAnalyzer sa(
diff --git a/res/Analyzer-src.svg b/res/Analyzer-src.svg
Binary files differ.
diff --git a/res/Analyzer.svg b/res/Analyzer.svg
Binary files differ.
diff --git a/src/Analyzer.cpp b/src/Analyzer.cpp
@@ -77,6 +77,7 @@ struct Analyzer : Module {
enum ParamsIds {
RANGE_PARAM,
SMOOTH_PARAM,
+ QUALITY_PARAM,
POWER_PARAM,
NUM_PARAMS
};
@@ -98,10 +99,17 @@ struct Analyzer : Module {
};
enum LightsIds {
+ QUALITY_HIGH_LIGHT,
+ QUALITY_GOOD_LIGHT,
+ POWER_ON_LIGHT,
NUM_LIGHTS
};
- const SpectrumAnalyzer::Size _size = SpectrumAnalyzer::SIZE_1024;
+ enum Quality {
+ QUALITY_HIGH,
+ QUALITY_GOOD
+ };
+
int _averageN;
ChannelAnalyzer* _channelA = NULL;
ChannelAnalyzer* _channelB = NULL;
@@ -109,6 +117,7 @@ struct Analyzer : Module {
ChannelAnalyzer* _channelD = NULL;
float _range = 0.0;
float _smooth = 0.0;
+ Quality _quality = QUALITY_GOOD;
const int _binAverageN = 2;
Analyzer() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
@@ -120,6 +129,7 @@ struct Analyzer : Module {
virtual void reset() override;
void resetChannels();
+ SpectrumAnalyzer::Size size();
virtual void step() override;
void stepChannel(ChannelAnalyzer*& channelPointer, bool running, Input& input, Output& output);
};
@@ -147,6 +157,17 @@ void Analyzer::resetChannels() {
}
}
+SpectrumAnalyzer::Size Analyzer::size() {
+ switch (_quality) {
+ case QUALITY_HIGH: {
+ return SpectrumAnalyzer::SIZE_4096;
+ }
+ case QUALITY_GOOD: {
+ return SpectrumAnalyzer::SIZE_1024;
+ }
+ }
+}
+
void Analyzer::step() {
_range = clampf(params[RANGE_PARAM].value, 0.1, 1.0);
@@ -156,18 +177,28 @@ void Analyzer::step() {
resetChannels();
}
+ Quality quality = ((int)params[QUALITY_PARAM].value) == 2 ? QUALITY_HIGH : QUALITY_GOOD;
+ if (_quality != quality) {
+ _quality = quality;
+ resetChannels();
+ }
+
bool running = params[POWER_PARAM].value == 1.0;
stepChannel(_channelA, running, inputs[SIGNALA_INPUT], outputs[SIGNALA_OUTPUT]);
stepChannel(_channelB, running, inputs[SIGNALB_INPUT], outputs[SIGNALB_OUTPUT]);
stepChannel(_channelC, running, inputs[SIGNALC_INPUT], outputs[SIGNALC_OUTPUT]);
stepChannel(_channelD, running, inputs[SIGNALD_INPUT], outputs[SIGNALD_OUTPUT]);
+
+ lights[QUALITY_HIGH_LIGHT].value = running && quality == QUALITY_HIGH;
+ lights[QUALITY_GOOD_LIGHT].value = running && quality == QUALITY_GOOD;
+ lights[POWER_ON_LIGHT].value = running;
}
void Analyzer::stepChannel(ChannelAnalyzer*& channelPointer, bool running, Input& input, Output& output) {
if (running && input.active) {
if (!channelPointer) {
channelPointer = new ChannelAnalyzer(
- _size,
+ size(),
SpectrumAnalyzer::OVERLAP_2,
SpectrumAnalyzer::WINDOW_HAMMING,
engineGetSampleRate(),
@@ -284,7 +315,7 @@ void AnalyzerDisplay::drawHeader(NVGcontext* vg) {
char s[sLen];
int x = _insetAround + 2;
- int n = snprintf(s, sLen, "Peaks (+/-%0.1f):", engineGetSampleRate() / (float)(_module->_size / (2 * _module->_binAverageN)));
+ int n = snprintf(s, sLen, "Peaks (+/-%0.1f):", engineGetSampleRate() / (float)(_module->size() / (2 * _module->_binAverageN)));
drawText(vg, s, x, _insetTop + textY);
x += n * charPx - 2;
@@ -423,7 +454,7 @@ void AnalyzerDisplay::drawXAxisLine(NVGcontext* vg, float hz, float maxHz) {
}
void AnalyzerDisplay::drawGraph(NVGcontext* vg, float* bins, int binsN, NVGcolor color) {
- const int pointsN = roundf(_module->_range*(_module->_size/2));
+ const int pointsN = roundf(_module->_range*(_module->size()/2));
nvgSave(vg);
nvgScissor(vg, _insetLeft, _insetTop, _graphSize.x, _graphSize.y);
nvgStrokeColor(vg, color);
@@ -507,7 +538,8 @@ AnalyzerWidget::AnalyzerWidget() {
// generated by svg_widgets.rb
auto rangeParamPosition = Vec(35.08, 271.08);
auto smoothParamPosition = Vec(109.08, 271.08);
- auto powerParamPosition = Vec(272.9, 279.9);
+ auto qualityParamPosition = Vec(186.02, 298.02);
+ auto powerParamPosition = Vec(259.02, 298.02);
auto signalaInputPosition = Vec(13.5, 323.0);
auto signalbInputPosition = Vec(86.5, 323.0);
@@ -518,11 +550,16 @@ AnalyzerWidget::AnalyzerWidget() {
auto signalbOutputPosition = Vec(115.5, 323.0);
auto signalcOutputPosition = Vec(189.5, 323.0);
auto signaldOutputPosition = Vec(262.5, 323.0);
+
+ auto qualityHighLightPosition = Vec(179.0, 274.0);
+ auto qualityGoodLightPosition = Vec(179.0, 289.0);
+ auto powerOnLightPosition = Vec(252.0, 289.0);
// end generated by svg_widgets.rb
addParam(createParam<OneTenKnob>(rangeParamPosition, module, Analyzer::RANGE_PARAM, 0.1, 1.0, 0.5));
addParam(createParam<IntegerOneTenKnob>(smoothParamPosition, module, Analyzer::SMOOTH_PARAM, 1.0, 10.0, 5.0));
- addParam(createParam<CKSS>(powerParamPosition, module, Analyzer::POWER_PARAM, 0.0, 1.0, 1.0));
+ addParam(createParam<Button9Toggle2>(qualityParamPosition, module, Analyzer::QUALITY_PARAM, 1.0, 2.0, 1.0));
+ addParam(createParam<Button9Toggle2>(powerParamPosition, module, Analyzer::POWER_PARAM, 0.0, 1.0, 1.0));
addInput(createInput<PJ301MPort>(signalaInputPosition, module, Analyzer::SIGNALA_INPUT));
addInput(createInput<PJ301MPort>(signalbInputPosition, module, Analyzer::SIGNALB_INPUT));
@@ -533,4 +570,8 @@ AnalyzerWidget::AnalyzerWidget() {
addOutput(createOutput<PJ301MPort>(signalbOutputPosition, module, Analyzer::SIGNALB_OUTPUT));
addOutput(createOutput<PJ301MPort>(signalcOutputPosition, module, Analyzer::SIGNALC_OUTPUT));
addOutput(createOutput<PJ301MPort>(signaldOutputPosition, module, Analyzer::SIGNALD_OUTPUT));
+
+ addChild(createLight<TinyLight<GreenLight>>(qualityHighLightPosition, module, Analyzer::QUALITY_HIGH_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(qualityGoodLightPosition, module, Analyzer::QUALITY_GOOD_LIGHT));
+ addChild(createLight<TinyLight<GreenLight>>(powerOnLightPosition, module, Analyzer::POWER_ON_LIGHT));
}
diff --git a/src/BogaudioModules.hpp b/src/BogaudioModules.hpp
@@ -63,6 +63,14 @@ struct Button18 : SVGSwitch, MomentarySwitch {
}
};
+struct Button9Toggle2 : SVGSwitch, ToggleSwitch {
+ Button9Toggle2() {
+ addFrame(SVG::load(assetPlugin(plugin, "res/button_9px.svg")));
+ addFrame(SVG::load(assetPlugin(plugin, "res/button_9px.svg")));
+ box.size = Vec(9, 9);
+ }
+};
+
struct Button9Toggle3 : SVGSwitch, ToggleSwitch {
Button9Toggle3() {
addFrame(SVG::load(assetPlugin(plugin, "res/button_9px.svg")));
diff --git a/src/dsp/analyzer.cpp b/src/dsp/analyzer.cpp
@@ -6,16 +6,32 @@
using namespace bogaudio::dsp;
-typedef ffft::FFTRealFixLen<10> FFT;
+
+typedef ffft::FFTRealFixLen<10> FIXED_FFT1024;
FFT1024::FFT1024() {
- _fft = new FFT();
+ _fft = new FIXED_FFT1024();
}
FFT1024::~FFT1024() {
- delete (FFT*)_fft;
+ delete (FIXED_FFT1024*)_fft;
}
void FFT1024::do_fft(float* out, float* in) {
- ((FFT*)_fft)->do_fft(out, in);
+ ((FIXED_FFT1024*)_fft)->do_fft(out, in);
+}
+
+
+typedef ffft::FFTRealFixLen<12> FIXED_FFT4096;
+
+FFT4096::FFT4096() {
+ _fft = new FIXED_FFT4096();
+}
+
+FFT4096::~FFT4096() {
+ delete (FIXED_FFT4096*)_fft;
+}
+
+void FFT4096::do_fft(float* out, float* in) {
+ ((FIXED_FFT4096*)_fft)->do_fft(out, in);
}
diff --git a/src/dsp/analyzer.hpp b/src/dsp/analyzer.hpp
@@ -55,6 +55,15 @@ struct FFT1024 {
};
+struct FFT4096 {
+ void* _fft = NULL;
+ FFT4096();
+ ~FFT4096();
+
+ void do_fft(float* out, float* in);
+};
+
+
struct SpectrumAnalyzer : OverlappingBuffer<float> {
enum Size {
SIZE_128 = 128,
@@ -81,6 +90,7 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
const float _sampleRate;
ffft::FFTReal<float>* _fft;
FFT1024* _fft1024;
+ FFT4096* _fft4096;
Window* _window;
float* _windowOut;
float* _fftOut;
@@ -95,6 +105,7 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
, _sampleRate(sampleRate)
, _fft(NULL)
, _fft1024(NULL)
+ , _fft4096(NULL)
, _window(NULL)
, _windowOut(NULL)
, _fftOut(new float[_size])
@@ -106,6 +117,10 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
_fft1024 = new FFT1024();
break;
}
+ case SIZE_4096: {
+ _fft4096 = new FFT4096();
+ break;
+ }
default: {
_fft = new ffft::FFTReal<float>(size);
}
@@ -135,6 +150,9 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
if (_fft1024) {
delete _fft1024;
}
+ if (_fft4096) {
+ delete _fft4096;
+ }
if (_window) {
delete _window;
@@ -153,6 +171,9 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
if (_fft1024) {
_fft1024->do_fft(_fftOut, input);
}
+ else if (_fft4096) {
+ _fft4096->do_fft(_fftOut, input);
+ }
else {
_fft->do_fft(_fftOut, input);
}