From 1b3b42403bf7324b1b35adc7aa7695dcde39c07b Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 22 May 2016 19:29:08 +0200 Subject: overhaul region/range spectrum analysis --- gtk2_ardour/fft_result.cc | 180 +++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 97 deletions(-) (limited to 'gtk2_ardour/fft_result.cc') diff --git a/gtk2_ardour/fft_result.cc b/gtk2_ardour/fft_result.cc index a83b65e854..b4a82c2586 100644 --- a/gtk2_ardour/fft_result.cc +++ b/gtk2_ardour/fft_result.cc @@ -1,22 +1,21 @@ /* - Copyright (C) 2006 Paul Davis - Written by Sampo Savolainen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * Copyright (C) 2006, 2016 Paul Davis + * Written by Sampo Savolainen & Robin Gareus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ #include "fft_result.h" #include "fft_graph.h" @@ -24,8 +23,7 @@ #include #include #include - -#include +#include using namespace std; @@ -35,18 +33,24 @@ FFTResult::FFTResult(FFTGraph *graph, Gdk::Color color, string trackname) _windowSize = _graph->windowSize(); _dataSize = _windowSize / 2; - _averages = 0; - - _data_avg = (float *) malloc(sizeof(float) * _dataSize); - memset(_data_avg,0,sizeof(float) * _dataSize); - - _data_min = (float *) malloc(sizeof(float) * _dataSize); - _data_max = (float *) malloc(sizeof(float) * _dataSize); - - for (int i = 0; i < _dataSize; i++) { - _data_min[i] = FLT_MAX; - _data_max[i] = FLT_MIN; + _min_flat = _max_flat = 0.0; + _min_prop = _max_prop = 0.0; + + _data_flat_avg = (float *) malloc (sizeof(float) * _dataSize); + _data_flat_min = (float *) malloc (sizeof(float) * _dataSize); + _data_flat_max = (float *) malloc (sizeof(float) * _dataSize); + _data_prop_avg = (float *) malloc (sizeof(float) * _dataSize); + _data_prop_min = (float *) malloc (sizeof(float) * _dataSize); + _data_prop_max = (float *) malloc (sizeof(float) * _dataSize); + + for (unsigned int i = 0; i < _dataSize; i++) { + _data_flat_min[i] = FLT_MAX; + _data_flat_max[i] = FLT_MIN; + _data_flat_avg[i] = 0; + _data_prop_min[i] = FLT_MAX; + _data_prop_max[i] = FLT_MIN; + _data_prop_avg[i] = 0; } _color = color; @@ -56,34 +60,31 @@ FFTResult::FFTResult(FFTGraph *graph, Gdk::Color color, string trackname) void FFTResult::analyzeWindow(float *window) { - float *_hanning = _graph->_hanning; + float const * const _hanning = _graph->_hanning; float *_in = _graph->_in; float *_out = _graph->_out; - int i; // Copy the data and apply the hanning window - for (i = 0; i < _windowSize; i++) { - _in[i] = window[ i ] * _hanning[ i ]; + for (unsigned int i = 0; i < _windowSize; ++i) { + _in[i] = window[i] * _hanning[i]; } fftwf_execute(_graph->_plan); + // calculate signal power per bin float b = _out[0] * _out[0]; - _data_avg[0] += b; - if (b < _data_min[0]) _data_min[0] = b; - if (b > _data_max[0]) _data_max[0] = b; - - for (i=1; i < _dataSize - 1; i++) { // TODO: check with Jesse whether this is really correct - b = (_out[i] * _out[i]); - - _data_avg[i] += b; // + (_out[_windowSize-i] * _out[_windowSize-i]);, TODO: thanks to Stefan Kost + _data_flat_avg[0] += b; + if (b < _data_flat_min[0]) _data_flat_min[0] = b; + if (b > _data_flat_max[0]) _data_flat_max[0] = b; - if (_data_min[i] > b) _data_min[i] = b; - if (_data_max[i] < b ) _data_max[i] = b; + for (unsigned int i = 1; i < _dataSize - 1; ++i) { + b = (_out[i] * _out[i]) + (_out[_windowSize - i] * _out[_windowSize - i]); + _data_flat_avg[i] += b; + if (_data_flat_min[i] > b) _data_flat_min[i] = b; + if (_data_flat_max[i] < b ) _data_flat_max[i] = b; } - _averages++; } @@ -91,32 +92,43 @@ void FFTResult::finalize() { if (_averages == 0) { - _minimum = 0.0; - _maximum = 0.0; + _min_flat = _max_flat = 0.0; + _min_prop = _max_prop = 0.0; return; } // Average & scale - for (int i = 0; i < _dataSize; i++) { - _data_avg[i] /= _averages; - _data_avg[i] = 10.0f * log10f(_data_avg[i]); - - _data_min[i] = 10.0f * log10f(_data_min[i]); - if (_data_min[i] < -10000.0f) { - _data_min[i] = -10000.0f; - } - _data_max[i] = 10.0f * log10f(_data_max[i]); + for (unsigned int i = 0; i < _dataSize - 1; ++i) { + _data_flat_avg[i] /= _averages; + // proportional, pink spectrum @ -18dB + _data_prop_avg[i] = _data_flat_avg [i] * i / 63.096f; + _data_prop_min[i] = _data_flat_min [i] * i / 63.096f; + _data_prop_max[i] = _data_flat_max [i] * i / 63.096f; + } + + _data_prop_avg[0] = _data_flat_avg [0] / 63.096f; + _data_prop_min[0] = _data_flat_min [0] / 63.096f; + _data_prop_max[0] = _data_flat_max [0] / 63.096f; + + // calculate power + for (unsigned int i = 0; i < _dataSize - 1; ++i) { + _data_flat_min[i] = power_to_db (_data_flat_min[i]); + _data_flat_max[i] = power_to_db (_data_flat_max[i]); + _data_flat_avg[i] = power_to_db (_data_flat_avg[i]); + _data_prop_min[i] = power_to_db (_data_prop_min[i]); + _data_prop_max[i] = power_to_db (_data_prop_max[i]); + _data_prop_avg[i] = power_to_db (_data_prop_avg[i]); } // find min & max - _minimum = _maximum = _data_avg[0]; - - for (int i = 1; i < _dataSize; i++) { - if (_data_avg[i] < _minimum && !isinf(_data_avg[i])) { - _minimum = _data_avg[i]; - } else if (_data_avg[i] > _maximum && !isinf(_data_avg[i])) { - _maximum = _data_avg[i]; - } + _min_flat = _max_flat = _data_flat_avg[0]; + _min_prop = _max_prop = _data_prop_avg[0]; + + for (unsigned int i = 1; i < _dataSize - 1; ++i) { + _min_flat = std::min (_min_flat, _data_flat_avg[i]); + _max_flat = std::max (_max_flat, _data_flat_avg[i]); + _min_prop = std::min (_min_prop, _data_prop_avg[i]); + _max_prop = std::max (_max_prop, _data_prop_avg[i]); } _averages = 0; @@ -124,36 +136,10 @@ FFTResult::finalize() FFTResult::~FFTResult() { - free(_data_avg); - free(_data_min); - free(_data_max); + free(_data_flat_avg); + free(_data_flat_min); + free(_data_flat_max); + free(_data_prop_avg); + free(_data_prop_min); + free(_data_prop_max); } - - -float -FFTResult::avgAt(int x) -{ - if (x < 0 || x>= _dataSize) - return 0.0f; - - return _data_avg[x]; -} - -float -FFTResult::minAt(int x) -{ - if (x < 0 || x>= _dataSize) - return 0.0f; - - return _data_min[x]; -} - -float -FFTResult::maxAt(int x) -{ - if (x < 0 || x>= _dataSize) - return 0.0f; - - return _data_max[x]; -} - -- cgit v1.2.3