summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSampo Savolainen <v2@iki.fi>2008-03-04 17:56:17 +0000
committerSampo Savolainen <v2@iki.fi>2008-03-04 17:56:17 +0000
commitf45474e68831f3724457a0fb9d9d83b3d64408e0 (patch)
tree13bffe3cfa4baec9feae44df8ae13eb6f5dc5381
parent5f5c3fe8d2c3cf1bf91cce2dbdc37373c3c2f103 (diff)
Improvements on the FFT analysis tool
- Enable FFT analysis by default - FFT graph is now in cairo - The window is now a window instead of a dialog - Analysis window can be resized - The view can be switched between normalized and an absolute value - The minimum and maximum values for a graph can be shown git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@3135 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--SConstruct4
-rw-r--r--gtk2_ardour/analysis_window.cc49
-rw-r--r--gtk2_ardour/analysis_window.h20
-rw-r--r--gtk2_ardour/fft_graph.cc220
-rw-r--r--gtk2_ardour/fft_graph.h18
-rw-r--r--gtk2_ardour/fft_result.cc89
-rw-r--r--gtk2_ardour/fft_result.h11
7 files changed, 301 insertions, 110 deletions
diff --git a/SConstruct b/SConstruct
index b68a45d621..804fa6bf91 100644
--- a/SConstruct
+++ b/SConstruct
@@ -38,7 +38,7 @@ opts.AddOptions(
EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'leopard', 'none' ), ignorecase=2),
BoolOption('DMALLOC', 'Compile and link using the dmalloc library', 0),
BoolOption('EXTRA_WARN', 'Compile with -Wextra, -ansi, and -pedantic. Might break compilation. For pedants', 0),
- BoolOption('FFT_ANALYSIS', 'Include FFT analysis window', 0),
+ BoolOption('FFT_ANALYSIS', 'Include FFT analysis window', 1),
BoolOption('FPU_OPTIMIZATION', 'Build runtime checked assembler code', 1),
BoolOption('LIBLO', 'Compile with support for liblo library', 1),
BoolOption('NLS', 'Set to turn on i18n support', 1),
@@ -527,7 +527,7 @@ if env['FFT_ANALYSIS']:
conf = Configure(libraries['fftw3'])
if conf.CheckHeader ('fftw3.h') == False:
- print ('FFT Analysis cannot be compiled without the FFTW3 headers, which do not seem to be installed')
+ print ('Ardour cannot be compiled without the FFTW3 headers, which do not seem to be installed')
sys.exit (1)
conf.Finish()
diff --git a/gtk2_ardour/analysis_window.cc b/gtk2_ardour/analysis_window.cc
index 957dde3d1f..ae557f4c10 100644
--- a/gtk2_ardour/analysis_window.cc
+++ b/gtk2_ardour/analysis_window.cc
@@ -41,8 +41,10 @@
using namespace ARDOUR;
using namespace PBD;
-AnalysisWindow::AnalysisWindow()
- : ArdourDialog(_("analysis window")),
+AnalysisWindow::AnalysisWindow() :
+
+ show_minmax_button (_("Show frequency power range")),
+ show_normalized_button (_("Normalize values")),
source_selection_label (_("Signal source")),
source_selection_ranges_rb (_("Selected ranges")),
@@ -52,8 +54,11 @@ AnalysisWindow::AnalysisWindow()
display_model_composite_separate_rb (_("Composite graphs for each track")),
display_model_composite_all_tracks_rb (_("Composite graph of all tracks")),
- fft_graph (2048)
+ fft_graph (16384)
{
+ set_name(_("FFT analysis window"));
+ set_title(_("FFT analysis window"));
+
track_list_ready = false;
// Left side: track list + controls
@@ -124,17 +129,31 @@ AnalysisWindow::AnalysisWindow()
bind ( mem_fun(*this, &AnalysisWindow::display_model_changed), &display_model_composite_all_tracks_rb));
}
- vbox.pack_start(hseparator2, false, false);
+ // Analyze button
refresh_button.set_name("EditorGTKButton");
- refresh_button.set_label(_("Analyze data"));
+ refresh_button.set_label(_("Re-analyze data"));
refresh_button.signal_clicked().connect ( bind ( mem_fun(*this, &AnalysisWindow::analyze_data), &refresh_button));
vbox.pack_start(refresh_button, false, false, 10);
+
+
+ // Feature checkboxes
+
+ // minmax
+ show_minmax_button.signal_toggled().connect( mem_fun(*this, &AnalysisWindow::show_minmax_changed));
+ vbox.pack_start(show_minmax_button, false, false);
+
+ // normalize
+ show_normalized_button.signal_toggled().connect( mem_fun(*this, &AnalysisWindow::show_normalized_changed));
+ vbox.pack_start(show_normalized_button, false, false);
+
+
- hbox.pack_start(vbox);
+
+ hbox.pack_start(vbox, Gtk::PACK_SHRINK);
// Analysis window on the right
fft_graph.ensure_style();
@@ -144,11 +163,9 @@ AnalysisWindow::AnalysisWindow()
// And last we pack the hbox
- get_vbox()->pack_start(hbox);
-
+ add(hbox);
+ show_all();
track_list.show_all();
-
- get_vbox()->show_all();
}
AnalysisWindow::~AnalysisWindow()
@@ -157,6 +174,18 @@ AnalysisWindow::~AnalysisWindow()
}
void
+AnalysisWindow::show_minmax_changed()
+{
+ fft_graph.set_show_minmax(show_minmax_button.get_active());
+}
+
+void
+AnalysisWindow::show_normalized_changed()
+{
+ fft_graph.set_show_normalized(show_normalized_button.get_active());
+}
+
+void
AnalysisWindow::set_rangemode()
{
source_selection_ranges_rb.set_active(true);
diff --git a/gtk2_ardour/analysis_window.h b/gtk2_ardour/analysis_window.h
index cd1243bb6a..45752c4a34 100644
--- a/gtk2_ardour/analysis_window.h
+++ b/gtk2_ardour/analysis_window.h
@@ -31,6 +31,7 @@
#include <gtkmm/label.h>
#include <gtkmm/liststore.h>
#include <gtkmm/separator.h>
+#include <gtkmm/window.h>
#include <gtkmm2ext/dndtreeview.h>
@@ -42,7 +43,7 @@
#include "fft_result.h"
-class AnalysisWindow : public ArdourDialog
+class AnalysisWindow : public Gtk::Window
{
public:
AnalysisWindow ();
@@ -55,12 +56,18 @@ class AnalysisWindow : public ArdourDialog
void analyze ();
+ const void set_session(ARDOUR::Session *session) { _session = session; };
+
private:
+ ARDOUR::Session *_session;
+
void clear_tracklist();
void source_selection_changed (Gtk::RadioButton *);
void display_model_changed (Gtk::RadioButton *);
+ void show_minmax_changed ();
+ void show_normalized_changed ();
void analyze_data (Gtk::Button *);
@@ -88,7 +95,8 @@ class AnalysisWindow : public ArdourDialog
Gtk::TreeView track_list;
Gtk::Label source_selection_label;
-
+
+
Gtk::RadioButton source_selection_ranges_rb;
Gtk::RadioButton source_selection_regions_rb;
@@ -98,9 +106,13 @@ class AnalysisWindow : public ArdourDialog
Gtk::RadioButton display_model_composite_separate_rb;
Gtk::RadioButton display_model_composite_all_tracks_rb;
- Gtk::HSeparator hseparator2;
-
Gtk::Button refresh_button;
+
+
+ Gtk::CheckButton show_minmax_button;
+ Gtk::CheckButton show_normalized_button;
+
+
// The graph
FFTGraph fft_graph;
diff --git a/gtk2_ardour/fft_graph.cc b/gtk2_ardour/fft_graph.cc
index e7a0fd75b6..077c1e162c 100644
--- a/gtk2_ardour/fft_graph.cc
+++ b/gtk2_ardour/fft_graph.cc
@@ -51,6 +51,9 @@ FFTGraph::FFTGraph(int windowSize)
_a_window = 0;
+ _show_minmax = false;
+ _show_normalized = false;
+
setWindowSize(windowSize);
}
@@ -151,23 +154,6 @@ FFTGraph::prepareResult(Gdk::Color color, string trackname)
return res;
}
-void
-FFTGraph::analyze(float *window, float *composite)
-{
- int i;
- // Copy the data and apply the hanning window
- for (i = 0; i < _windowSize; i++) {
- _in[i] = window[ i ] * _hanning[ i ];
- }
-
- fftwf_execute(_plan);
-
- composite[0] += (_out[0] * _out[0]);
-
- for (i=1; i < _dataSize - 1; i++) { // TODO: check with Jesse whether this is really correct
- composite[i] += (_out[i] * _out[i]) + (_out[_windowSize-i] * _out[_windowSize-i]);
- }
-}
void
FFTGraph::set_analysis_window(AnalysisWindow *a_window)
@@ -198,17 +184,18 @@ FFTGraph::draw_scales(Glib::RefPtr<Gdk::Window> window)
window->draw_line(white, h_margin, v_margin, h_margin, height - v_margin );
// Line 2
- window->draw_line(white, width - h_margin, v_margin, width - h_margin, height - v_margin );
+ window->draw_line(white, width - h_margin + 1, v_margin, width - h_margin + 1, height - v_margin );
// Line 3
window->draw_line(white, h_margin, height - v_margin, width - h_margin, height - v_margin );
#define DB_METRIC_LENGTH 8
- // Line 5
+ // Line 4
window->draw_line(white, h_margin - DB_METRIC_LENGTH, v_margin, h_margin, v_margin );
- // Line 6
- window->draw_line(white, width - h_margin, v_margin, width - h_margin + DB_METRIC_LENGTH, v_margin );
+ // Line 5
+ window->draw_line(white, width - h_margin + 1, v_margin, width - h_margin + DB_METRIC_LENGTH, v_margin );
+
if (graph_gc == 0) {
@@ -229,8 +216,24 @@ FFTGraph::draw_scales(Glib::RefPtr<Gdk::Window> window)
// Draw logscale
int logscale_pos = 0;
int position_on_scale;
+
+
+/* TODO, write better scales and change the log function so that octaves are of equal pixel length
+ float scale_points[10] = { 55.0, 110.0, 220.0, 440.0, 880.0, 1760.0, 3520.0, 7040.0, 14080.0, 28160.0 };
+
+ for (int x = 0; x < 10; x++) {
+
+ // i = 0.. _dataSize-1
+ float freq_at_bin = (SR/2.0) * ((double)i / (double)_dataSize);
+
+
+
+ freq_at_pixel = FFT_START * exp( FFT_RANGE * pixel / (double)(currentScaleWidth - 1) );
+ }
+ */
+
for (int x = 1; x < 8; x++) {
- position_on_scale = (int)floor( (double)scaleWidth*(double)x/8.0);
+ position_on_scale = (int)floor( (double)currentScaleWidth*(double)x/8.0);
while (_logScale[logscale_pos] < position_on_scale)
logscale_pos++;
@@ -251,7 +254,7 @@ FFTGraph::draw_scales(Glib::RefPtr<Gdk::Window> window)
layout->set_text(label);
- window->draw_line(graph_gc, coord, v_margin, coord, height - v_margin);
+ window->draw_line(graph_gc, coord, v_margin, coord, height - v_margin - 1);
int width, height;
layout->get_pixel_size (width, height);
@@ -268,12 +271,19 @@ FFTGraph::redraw()
Glib::Mutex::Lock lm (_a_window->track_list_lock);
draw_scales(get_window());
+
if (_a_window == 0)
return;
if (!_a_window->track_list_ready)
return;
+
+ cairo_t *cr;
+ cr = gdk_cairo_create(GDK_DRAWABLE(get_window()->gobj()));
+ cairo_set_line_width(cr, 1.5);
+ cairo_translate(cr, (float)v_margin + 1.0, (float)h_margin);
+
// Find "session wide" min & max
@@ -300,17 +310,24 @@ FFTGraph::redraw()
max = res->maximum();
}
}
-
- int graph_height = height - 2 * h_margin;
- if (graph_gc == 0) {
- graph_gc = GC::create( get_window() );
+ if (!_show_normalized) {
+ min = -150.0f;
+ max = 0.0f;
}
-
- double pixels_per_db = (double)graph_height / (double)(max - min);
+ //int graph_height = height - 2 * h_margin;
+
+ float fft_pane_size_w = (float)(width - 2*v_margin) - 1.0;
+ float fft_pane_size_h = (float)(height - 2*h_margin);
+
+ double pixels_per_db = (double)fft_pane_size_h / (double)(max - min);
+
+ cairo_rectangle(cr, 0.0, 0.0, fft_pane_size_w, fft_pane_size_h);
+ cairo_clip(cr);
+
for (TreeIter i = track_rows.begin(); i != track_rows.end(); i++) {
TreeModel::Row row = *i;
@@ -326,72 +343,104 @@ FFTGraph::redraw()
if (res->minimum() == res->maximum()) {
continue;
}
+
+ float mpp;
- std::string name = row[_a_window->tlcols.trackname];
+ if (_show_minmax) {
+ mpp = -1000000.0;
+
+ cairo_set_source_rgba(cr, res->get_color().get_red_p(), res->get_color().get_green_p(), res->get_color().get_blue_p(), 0.30);
+ cairo_move_to(cr, 0.5f + (float)_logScale[0], 0.5f + (float)( fft_pane_size_h - (int)floor( (res->maxAt(0) - min) * pixels_per_db) ));
+
+ // Draw the line of maximum values
+ for (int x = 1; x < res->length(); x++) {
+ if (res->maxAt(x) > mpp)
+ mpp = res->maxAt(x);
+ mpp = fmax(mpp, min);
+ mpp = fmin(mpp, max);
+
+ // If the next point on the log scale is at the same location,
+ // don't draw yet
+ if (x + 1 < res->length() && _logScale[x] == _logScale[x + 1]) {
+ continue;
+ }
+
+ float X = 0.5f + (float)_logScale[x];
+ float Y = 0.5f + (float)( fft_pane_size_h - (int)floor( (mpp - min) * pixels_per_db) );
+
+ cairo_line_to(cr, X, Y);
+
+ mpp = -1000000.0;
+ }
+
+ mpp = +10000000.0;
+ // Draw back to the start using the minimum value
+ for (int x = res->length()-1; x >= 0; x--) {
+ if (res->minAt(x) < mpp)
+ mpp = res->minAt(x);
+ mpp = fmax(mpp, min);
+ mpp = fmin(mpp, max);
+
+ // If the next point on the log scale is at the same location,
+ // don't draw yet
+ if (x - 1 > 0 && _logScale[x] == _logScale[x - 1]) {
+ continue;
+ }
+
+ float X = 0.5f + (float)_logScale[x];
+ float Y = 0.5f + (float)( fft_pane_size_h - (int)floor( (mpp - min) * pixels_per_db) );
+
+ cairo_line_to(cr, X, Y );
+
+ mpp = +10000000.0;
+ }
+
+ cairo_close_path(cr);
+
+ cairo_fill(cr);
+ }
+
+
// Set color from track
- graph_gc->set_rgb_fg_color( res->get_color() );
+ cairo_set_source_rgb(cr, res->get_color().get_red_p(), res->get_color().get_green_p(), res->get_color().get_blue_p());
- float mpp = -1000000.0;
- int prevx = 0;
- float prevSample = min;
-
- for (int x = 0; x < res->length() - 1; x++) {
+ mpp = -1000000.0;
+
+ cairo_move_to(cr, 0.5, fft_pane_size_h-0.5);
+
+ for (int x = 0; x < res->length(); x++) {
- if (res->sampleAt(x) > mpp)
- mpp = res->sampleAt(x);
+
+ if (res->avgAt(x) > mpp)
+ mpp = res->avgAt(x);
+ mpp = fmax(mpp, min);
+ mpp = fmin(mpp, max);
// If the next point on the log scale is at the same location,
// don't draw yet
- if (x + 1 < res->length() &&
- _logScale[x] == _logScale[x + 1]) {
+ if (x + 1 < res->length() && _logScale[x] == _logScale[x + 1]) {
continue;
}
- get_window()->draw_line(
- graph_gc,
- v_margin + 1 + prevx,
- graph_height - (int)floor( (prevSample - min) * pixels_per_db) + h_margin - 1,
- v_margin + 1 + _logScale[x],
- graph_height - (int)floor( (mpp - min) * pixels_per_db) + h_margin - 1);
-
- prevx = _logScale[x];
- prevSample = mpp;
-
+ cairo_line_to(cr, 0.5f + (float)_logScale[x], 0.5f + (float)( fft_pane_size_h - (int)floor( (mpp - min) * pixels_per_db) ));
mpp = -1000000.0;
-
}
+
+ cairo_stroke(cr);
}
+ cairo_destroy(cr);
}
void
FFTGraph::on_size_request(Gtk::Requisition* requisition)
{
- width = scaleWidth + h_margin * 2;
- height = scaleHeight + 2 + v_margin * 2;
+ width = max(requisition->width, minScaleWidth + h_margin * 2);
+ height = max(requisition->height, minScaleHeight + 2 + v_margin * 2);
- if (_logScale != 0) {
- free(_logScale);
- }
- _logScale = (int *) malloc(sizeof(int) * _dataSize);
-
- float SR = 44100;
- float FFT_START = SR/(double)_dataSize;
- float FFT_END = SR/2.0;
- float FFT_RANGE = log( FFT_END / FFT_START);
- float pixel = 0;
- for (int i = 0; i < _dataSize; i++) {
- float freq_at_bin = (SR/2.0) * ((double)i / (double)_dataSize);
- float freq_at_pixel = FFT_START * exp( FFT_RANGE * pixel / (double)scaleWidth );
- while (freq_at_bin > freq_at_pixel) {
- pixel++;
- freq_at_pixel = FFT_START * exp( FFT_RANGE * pixel / (double)scaleWidth );
- }
- _logScale[i] = (int)floor(pixel);
-//printf("logscale at %d = %3.3f, freq_at_pixel %3.3f, freq_at_bin %3.3f, scaleWidth %d\n", i, pixel, freq_at_pixel, freq_at_bin, scaleWidth);
- }
+ update_size();
requisition->width = width;;
requisition->height = height;
@@ -403,7 +452,32 @@ FFTGraph::on_size_allocate(Gtk::Allocation & alloc)
width = alloc.get_width();
height = alloc.get_height();
+ update_size();
+
DrawingArea::on_size_allocate (alloc);
+}
+
+void
+FFTGraph::update_size()
+{
+ currentScaleWidth = width - h_margin*2;
+ currentScaleHeight = height - 2 - v_margin*2;
+ float SR = 44100;
+ float FFT_START = SR/(double)_dataSize;
+ float FFT_END = SR/2.0;
+ float FFT_RANGE = log( FFT_END / FFT_START);
+ float pixel = 0;
+ for (int i = 0; i < _dataSize; i++) {
+ float freq_at_bin = (SR/2.0) * ((double)i / (double)_dataSize);
+ float freq_at_pixel;
+ pixel--;
+ do {
+ pixel++;
+ freq_at_pixel = FFT_START * exp( FFT_RANGE * pixel / (double)(currentScaleWidth - 1) );
+ } while (freq_at_bin > freq_at_pixel);
+
+ _logScale[i] = (int)floor(pixel);
+ }
}
diff --git a/gtk2_ardour/fft_graph.h b/gtk2_ardour/fft_graph.h
index 73636b989d..bbf7774741 100644
--- a/gtk2_ardour/fft_graph.h
+++ b/gtk2_ardour/fft_graph.h
@@ -54,27 +54,34 @@ class FFTGraph : public Gtk::DrawingArea
void on_size_allocate(Gtk::Allocation & alloc);
FFTResult *prepareResult(Gdk::Color color, std::string trackname);
+ const void set_show_minmax (bool v) { _show_minmax = v; redraw(); };
+ const void set_show_normalized (bool v) { _show_normalized = v; redraw(); };
+
private:
+ void update_size();
+
void setWindowSize_internal(int windowSize);
void draw_scales(Glib::RefPtr<Gdk::Window> window);
- static const int scaleWidth = 512;
- static const int scaleHeight = 420;
+ static const int minScaleWidth = 512;
+ static const int minScaleHeight = 420;
+
+ int currentScaleWidth;
+ int currentScaleHeight;
static const int h_margin = 20;
static const int v_margin = 20;
+ Glib::RefPtr<Gdk::GC> graph_gc;
int width;
int height;
- void analyze(float *window, float *composite);
int _windowSize;
int _dataSize;
Glib::RefPtr<Pango::Layout> layout;
- Glib::RefPtr<Gdk::GC> graph_gc;
AnalysisWindow *_a_window;
fftwf_plan _plan;
@@ -84,6 +91,9 @@ class FFTGraph : public Gtk::DrawingArea
float *_hanning;
int *_logScale;
+ bool _show_minmax;
+ bool _show_normalized;
+
friend class FFTResult;
};
diff --git a/gtk2_ardour/fft_result.cc b/gtk2_ardour/fft_result.cc
index f5acef92ed..d692b9152b 100644
--- a/gtk2_ardour/fft_result.cc
+++ b/gtk2_ardour/fft_result.cc
@@ -37,8 +37,16 @@ FFTResult::FFTResult(FFTGraph *graph, Gdk::Color color, string trackname)
_averages = 0;
- _data = (float *) malloc(sizeof(float) * _dataSize);
- memset(_data,0,sizeof(float) * _dataSize);
+ _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;
+ }
_color = color;
_trackname = trackname;
@@ -47,7 +55,34 @@ FFTResult::FFTResult(FFTGraph *graph, Gdk::Color color, string trackname)
void
FFTResult::analyzeWindow(float *window)
{
- _graph->analyze(window, _data);
+ float *_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 ];
+ }
+
+ fftwf_execute(_graph->_plan);
+
+ 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
+
+ if (_data_min[i] > b) _data_min[i] = b;
+ if (_data_max[i] < b ) _data_max[i] = b;
+ }
+
+
_averages++;
}
@@ -59,21 +94,27 @@ FFTResult::finalize()
_maximum = 0.0;
return;
}
-
+
// Average & scale
for (int i = 0; i < _dataSize; i++) {
- _data[i] /= _averages;
- _data[i] = 10.0f * log10f(_data[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]);
}
// find min & max
- _minimum = _maximum = _data[0];
+ _minimum = _maximum = _data_avg[0];
for (int i = 1; i < _dataSize; i++) {
- if (_data[i] < _minimum && !isinf(_data[i])) {
- _minimum = _data[i];
- } else if (_data[i] > _maximum && !isinf(_data[i])) {
- _maximum = _data[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];
}
}
@@ -82,16 +123,36 @@ FFTResult::finalize()
FFTResult::~FFTResult()
{
- free(_data);
+ free(_data_avg);
+ free(_data_min);
+ free(_data_max);
}
float
-FFTResult::sampleAt(int x)
+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[x];
+ return _data_max[x];
}
diff --git a/gtk2_ardour/fft_result.h b/gtk2_ardour/fft_result.h
index c8f17dc01c..c6c952db1c 100644
--- a/gtk2_ardour/fft_result.h
+++ b/gtk2_ardour/fft_result.h
@@ -41,7 +41,9 @@ class FFTResult
const int length() { return _dataSize; }
- float sampleAt(int x);
+ float avgAt(int x);
+ float maxAt(int x);
+ float minAt(int x);
const float minimum() { return _minimum; }
const float maximum() { return _maximum; }
@@ -53,10 +55,13 @@ class FFTResult
int _averages;
- float* _data;
+ float* _data_avg;
+ float* _data_max;
+ float* _data_min;
+
float* _work;
- int _windowSize;
+ int _windowSize;
int _dataSize;
float _minimum;