22 using std::min;
using std::max;
28 #include <glibmm/refptr.h>
32 #include <gtkmm/widget.h>
33 #include <gtkmm/style.h>
34 #include <gtkmm/treemodel.h>
35 #include <gtkmm/treepath.h>
60 _show_normalized =
false;
62 setWindowSize(windowSize);
70 setWindowSize_internal(windowSize);
72 setWindowSize_internal(windowSize);
81 _a_window->clear_tracklist();
84 _windowSize = windowSize;
85 _dataSize = windowSize / 2;
87 fftwf_destroy_plan(_plan);
102 if (_logScale != 0) {
112 _in = (
float *) fftwf_malloc(
sizeof(
float) * _windowSize);
113 _out = (
float *) fftwf_malloc(
sizeof(
float) * _windowSize);
116 _hanning = (
float *) malloc(
sizeof(
float) * _windowSize);
122 for (
int i=0; i < _windowSize; i++) {
123 _hanning[i]=0.81f * ( 0.5f - (0.5f * (float) cos(2.0
f * M_PI * (
float)i / (float)(_windowSize))));
127 double isum = 1.0 / sum;
129 for (
int i=0; i < _windowSize; i++) {
133 _logScale = (
int *) malloc(
sizeof(
int) * _dataSize);
135 for (
int i = 0; i < _dataSize; i++) {
138 _plan = fftwf_plan_r2r_1d(_windowSize, _in, _out, FFTW_R2HC, FFTW_ESTIMATE);
166 _a_window = a_window;
173 Glib::RefPtr<Gtk::Style> style = get_style();
174 Glib::RefPtr<Gdk::GC> black = style->get_black_gc();
175 Glib::RefPtr<Gdk::GC> white = style->get_white_gc();
177 window->draw_rectangle(black,
true, 0, 0, width, height);
189 window->draw_line(white, h_margin, v_margin, h_margin, height - v_margin );
192 window->draw_line(white, width - h_margin + 1, v_margin, width - h_margin + 1, height - v_margin );
195 window->draw_line(white, h_margin, height - v_margin, width - h_margin, height - v_margin );
197 #define DB_METRIC_LENGTH 8
199 window->draw_line(white, h_margin -
DB_METRIC_LENGTH, v_margin, h_margin, v_margin );
202 window->draw_line(white, width - h_margin + 1, v_margin, width - h_margin +
DB_METRIC_LENGTH, v_margin );
207 graph_gc = GC::create( get_window() );
212 grey.set_rgb_p(0.2, 0.2, 0.2);
214 graph_gc->set_rgb_fg_color( grey );
217 layout = create_pango_layout (
"");
218 layout->set_font_description (get_style()->get_font());
222 int logscale_pos = 0;
223 int position_on_scale;
240 for (
int x = 1; x < 8; x++) {
241 position_on_scale = (int)floor( (
double)currentScaleWidth*(double)x/8.0);
243 while (_logScale[logscale_pos] < position_on_scale)
246 int coord = (int)(v_margin + 1.0 + position_on_scale);
250 int rate_at_pos = (int)((
double)(SR/2) * (
double)logscale_pos / (double)_dataSize);
253 if (rate_at_pos < 1000)
254 snprintf(buf,32,
"%dHz",rate_at_pos);
256 snprintf(buf,32,
"%dk",(
int)floor( (
float)rate_at_pos/(
float)1000) );
258 std::string label = buf;
260 layout->set_text(label);
262 window->draw_line(graph_gc, coord, v_margin, coord, height - v_margin - 1);
265 layout->get_pixel_size (width, height);
267 window->draw_layout(white, coord - width / 2, v_margin / 2, layout);
278 draw_scales(get_window());
284 if (!_a_window->track_list_ready)
288 cr = gdk_cairo_create(GDK_DRAWABLE(get_window()->gobj()));
289 cairo_set_line_width(cr, 1.5);
290 cairo_translate(cr, (
float)v_margin + 1.0, (
float)h_margin);
295 float minf = 1000000000000.0;
296 float maxf = -1000000000000.0;
298 TreeNodeChildren track_rows = _a_window->track_list.get_model()->children();
300 for (TreeIter i = track_rows.begin(); i != track_rows.end(); i++) {
302 TreeModel::Row row = *i;
303 FFTResult *res = row[_a_window->tlcols.graph];
319 if (!_show_normalized) {
328 float fft_pane_size_w = (float)(width - 2*v_margin) - 1.0;
329 float fft_pane_size_h = (float)(height - 2*h_margin);
331 double pixels_per_db = (double)fft_pane_size_h / (
double)(maxf - minf);
333 cairo_rectangle(cr, 0.0, 0.0, fft_pane_size_w, fft_pane_size_h);
336 for (TreeIter i = track_rows.begin(); i != track_rows.end(); i++) {
338 TreeModel::Row row = *i;
341 if (!row[_a_window->tlcols.visible]) {
345 FFTResult *res = row[_a_window->tlcols.graph];
358 cairo_move_to(cr, 0.5
f + (
float)_logScale[0], 0.5
f + (
float)( fft_pane_size_h - (
int)floor( (res->
maxAt(0) - minf) * pixels_per_db) ));
361 for (
int x = 1; x < res->
length(); x++) {
362 if (res->
maxAt(x) > mpp)
364 mpp = fmax(mpp, minf);
365 mpp = fmin(mpp, maxf);
369 if (x + 1 < res->
length() && _logScale[x] == _logScale[x + 1]) {
373 float X = 0.5f + (float)_logScale[x];
374 float Y = 0.5f + (float)( fft_pane_size_h - (
int)floor( (mpp - minf) * pixels_per_db) );
376 cairo_line_to(cr, X, Y);
383 for (
int x = res->
length()-1; x >= 0; x--) {
384 if (res->
minAt(x) < mpp)
386 mpp = fmax(mpp, minf);
387 mpp = fmin(mpp, maxf);
391 if (x - 1 > 0 && _logScale[x] == _logScale[x - 1]) {
395 float X = 0.5f + (float)_logScale[x];
396 float Y = 0.5f + (float)( fft_pane_size_h - (
int)floor( (mpp - minf) * pixels_per_db) );
398 cairo_line_to(cr, X, Y );
403 cairo_close_path(cr);
415 cairo_move_to(cr, 0.5, fft_pane_size_h-0.5);
417 for (
int x = 0; x < res->
length(); x++) {
420 if (res->
avgAt(x) > mpp)
422 mpp = fmax(mpp, minf);
423 mpp = fmin(mpp, maxf);
427 if (x + 1 < res->
length() && _logScale[x] == _logScale[x + 1]) {
431 cairo_line_to(cr, 0.5
f + (
float)_logScale[x], 0.5
f + (
float)( fft_pane_size_h - (
int)floor( (mpp - minf) * pixels_per_db) ));
445 width = max(requisition->width, minScaleWidth + h_margin * 2);
446 height = max(requisition->height, minScaleHeight + 2 + v_margin * 2);
450 requisition->width = width;;
451 requisition->height = height;
457 width = alloc.get_width();
458 height = alloc.get_height();
462 DrawingArea::on_size_allocate (alloc);
468 currentScaleWidth = width - h_margin*2;
469 currentScaleHeight = height - 2 - v_margin*2;
472 float FFT_START = SR/(double)_dataSize;
473 float FFT_END = SR/2.0;
474 float FFT_RANGE = log( FFT_END / FFT_START);
476 for (
int i = 0; i < _dataSize; i++) {
477 float freq_at_bin = (SR/2.0) * ((double)i / (
double)_dataSize);
482 freq_at_pixel = FFT_START * exp( FFT_RANGE * pixel / (
double)(currentScaleWidth - 1) );
483 }
while (freq_at_bin > freq_at_pixel);
485 _logScale[i] = (int)floor(pixel);
void draw_scales(Glib::RefPtr< Gdk::Window > window)
Gdk::Color get_color() const
void on_size_request(Gtk::Requisition *requisition)
void set_analysis_window(AnalysisWindow *a_window)
void setWindowSize_internal(int windowSize)
FFTResult * prepareResult(Gdk::Color color, std::string trackname)
bool on_expose_event(GdkEventExpose *event)
void on_size_allocate(Gtk::Allocation &alloc)
void setWindowSize(int windowSize)
LIBARDOUR_API PBD::PropertyDescriptor< bool > color