ardour
plugin_eq_gui.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 Paul Davis
3  Author: Sampo Savolainen
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #include <math.h>
22 #include <iostream>
23 
24 #ifdef COMPILER_MSVC
25 #include <float.h>
26 /* isinf() & isnan() are C99 standards, which older MSVC doesn't provide */
27 #define ISINF(val) !((bool)_finite((double)val))
28 #define ISNAN(val) (bool)_isnan((double)val)
29 #else
30 #define ISINF(val) std::isinf((val))
31 #define ISNAN(val) std::isnan((val))
32 #endif
33 
34 #include <gtkmm/box.h>
35 #include <gtkmm/button.h>
36 #include <gtkmm/checkbutton.h>
37 
38 #include "ardour/audio_buffer.h"
39 #include "ardour/data_type.h"
40 #include "ardour/chan_mapping.h"
41 #include "ardour/session.h"
42 
43 #include "plugin_eq_gui.h"
44 #include "fft.h"
45 #include "ardour_ui.h"
46 #include "gui_thread.h"
47 
48 #include "i18n.h"
49 
50 using namespace ARDOUR;
51 
53  : _min_dB(-12.0)
54  , _max_dB(+12.0)
55  , _step_dB(3.0)
56  , _impulse_fft(0)
57  , _signal_input_fft(0)
58  , _signal_output_fft(0)
59  , _plugin_insert(pluginInsert)
60 {
63 
64  _log_coeff = (1.0 - 2.0 * (1000.0/(_samplerate/2.0))) / powf(1000.0/(_samplerate/2.0), 2.0);
65  _log_max = log10f(1 + _log_coeff);
66 
67  // Setup analysis drawing area
69 
70  _analysis_area = new Gtk::DrawingArea();
71  _analysis_width = 256.0;
72  _analysis_height = 256.0;
74 
75  _analysis_area->signal_expose_event().connect( sigc::mem_fun (*this, &PluginEqGui::expose_analysis_area));
76  _analysis_area->signal_size_allocate().connect( sigc::mem_fun (*this, &PluginEqGui::resize_analysis_area));
77 
78  // dB selection
79  dBScaleModel = Gtk::ListStore::create(dBColumns);
80 
81  /* this grotty-looking cast allows compilation against gtkmm 2.24.0, which
82  added a new ComboBox constructor.
83  */
84  dBScaleCombo = new Gtk::ComboBox ((Glib::RefPtr<Gtk::TreeModel> &) dBScaleModel);
85  dBScaleCombo->set_title (_("dB scale"));
86 
87 #define ADD_DB_ROW(MIN,MAX,STEP,NAME) \
88  { \
89  Gtk::TreeModel::Row row = *(dBScaleModel->append()); \
90  row[dBColumns.dBMin] = (MIN); \
91  row[dBColumns.dBMax] = (MAX); \
92  row[dBColumns.dBStep] = (STEP); \
93  row[dBColumns.name] = NAME; \
94  }
95 
96  ADD_DB_ROW( -6, +6, 1, "-6dB .. +6dB");
97  ADD_DB_ROW(-12, +12, 3, "-12dB .. +12dB");
98  ADD_DB_ROW(-24, +24, 5, "-24dB .. +24dB");
99  ADD_DB_ROW(-36, +36, 6, "-36dB .. +36dB");
100  ADD_DB_ROW(-64, +64,12, "-64dB .. +64dB");
101 
102 #undef ADD_DB_ROW
103 
104  dBScaleCombo -> pack_start(dBColumns.name);
105  dBScaleCombo -> set_active(1);
106 
107  dBScaleCombo -> signal_changed().connect( sigc::mem_fun(*this, &PluginEqGui::change_dB_scale) );
108 
109  Gtk::Label *dBComboLabel = new Gtk::Label (_("dB scale"));
110 
111  Gtk::HBox *dBSelectBin = new Gtk::HBox(false, 5);
112  dBSelectBin->add( *manage(dBComboLabel));
113  dBSelectBin->add( *manage(dBScaleCombo));
114 
115  // Phase checkbutton
116  _phase_button = new Gtk::CheckButton (_("Show phase"));
117  _phase_button->set_active(true);
118  _phase_button->signal_toggled().connect( sigc::mem_fun(*this, &PluginEqGui::redraw_scales));
119 
120  // populate table
121  attach( *manage(_analysis_area), 1, 3, 1, 2);
122  attach( *manage(dBSelectBin), 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
123  attach( *manage(_phase_button), 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
124 }
125 
127 {
128  stop_listening ();
129 
131  cairo_surface_destroy (_analysis_scale_surface);
132  }
133 
134  delete _impulse_fft;
135  _impulse_fft = 0;
136  delete _signal_input_fft;
137  _signal_input_fft = 0;
138  delete _signal_output_fft;
139  _signal_output_fft = 0;
140 
141  // all gui objects are *manage'd by the inherited Table object
142 }
143 
144 void
146 {
147  if (!_plugin) {
149  }
150 
151  _plugin->activate();
152  set_buffer_size(4096, 16384);
153  // Connect the realtime signal collection callback
155 }
156 
157 void
159 {
161  _plugin->deactivate ();
162 }
163 
164 void
166 {
167  stop_updating();
168  Gtk::Table::on_hide();
169 }
170 
171 void
173 {
174  if (_update_connection.connected()) {
175  _update_connection.disconnect();
176  }
177 }
178 
179 void
181 {
182  if (!_update_connection.connected() && is_visible()) {
183  _update_connection = Glib::signal_timeout().connect( sigc::mem_fun(this, &PluginEqGui::timeout_callback), 250);
184  }
185 }
186 
187 void
189 {
190  Gtk::Table::on_show();
191 
192  start_updating();
193 
194  Gtk::Widget *toplevel = get_toplevel();
195  if (toplevel) {
196  if (!_window_unmap_connection.connected()) {
197  _window_unmap_connection = toplevel->signal_unmap().connect( sigc::mem_fun(this, &PluginEqGui::stop_updating));
198  }
199 
200  if (!_window_map_connection.connected()) {
201  _window_map_connection = toplevel->signal_map().connect( sigc::mem_fun(this, &PluginEqGui::start_updating));
202  }
203  }
204 }
205 
206 void
208 {
209  Gtk::TreeModel::iterator iter = dBScaleCombo -> get_active();
210 
211  Gtk::TreeModel::Row row;
212 
213  if(iter && (row = *iter)) {
214  _min_dB = row[dBColumns.dBMin];
215  _max_dB = row[dBColumns.dBMax];
216  _step_dB = row[dBColumns.dBStep];
217 
218 
219  redraw_scales();
220  }
221 }
222 
223 void
225 {
226 
228  cairo_surface_destroy (_analysis_scale_surface);
230  }
231 
232  _analysis_area->queue_draw();
233 
234  // TODO: Add graph legend!
235 }
236 
237 void
238 PluginEqGui::set_buffer_size(uint32_t size, uint32_t signal_size)
239 {
240  if (_buffer_size == size && _signal_buffer_size == signal_size) {
241  return;
242  }
243 
247 
248  try {
249  _impulse_fft = new GTKArdour::FFT(size);
250  _signal_input_fft = new GTKArdour::FFT(signal_size);
251  _signal_output_fft = new GTKArdour::FFT(signal_size);
252  } catch( ... ) {
253  // Don't care about lost memory, we're screwed anyhow
254  _impulse_fft = tmp1;
255  _signal_input_fft = tmp2;
256  _signal_output_fft = tmp3;
257  throw;
258  }
259 
260  delete tmp1;
261  delete tmp2;
262  delete tmp3;
263 
264  _buffer_size = size;
265  _signal_buffer_size = signal_size;
266 
268 
270  _bufferset.ensure_buffers (*i, count.get (*i), _buffer_size);
272  }
273 
274  _bufferset.set_count (count);
276 }
277 
278 void
279 PluginEqGui::resize_analysis_area (Gtk::Allocation& size)
280 {
281  _analysis_width = (float)size.get_width();
282  _analysis_height = (float)size.get_height();
283 
285  cairo_surface_destroy (_analysis_scale_surface);
287  }
288 }
289 
290 bool
292 {
295  _plugin_insert -> collect_signal_for_analysis(_signal_buffer_size);
296  }
298 
299  return true;
300 }
301 
302 void
304 {
306 
309 
310  for (uint32_t i = 0; i < _plugin_insert->input_streams().n_audio(); ++i) {
311  _signal_input_fft ->analyze(in ->get_audio(i).data(), GTKArdour::FFT::HANN);
312  }
313 
314  for (uint32_t i = 0; i < _plugin_insert->output_streams().n_audio(); ++i) {
316  }
317 
320 
321  _signal_analysis_running = false;
322 
323  // This signals calls expose_analysis_area()
324  _analysis_area->queue_draw();
325 }
326 
327 void
329 {
330  /* Allocate some thread-local buffers so that Plugin::connect_and_run can use them */
332 
333  uint32_t inputs = _plugin->get_info()->n_inputs.n_audio();
334  uint32_t outputs = _plugin->get_info()->n_outputs.n_audio();
335 
336  // Create the impulse, can't use silence() because consecutive calls won't work
337  for (uint32_t i = 0; i < inputs; ++i) {
339  ARDOUR::Sample* d = buf.data();
340  memset(d, 0, sizeof(ARDOUR::Sample)*_buffer_size);
341  *d = 1.0;
342  }
343 
346 
347  _plugin->connect_and_run(_bufferset, in_map, out_map, _buffer_size, 0);
349  // Adding user_latency() could be interesting
350 
351  // Gather all output, taking latency into account.
352  _impulse_fft->reset();
353 
354  // Silence collect buffers to copy data to, can't use silence() because consecutive calls won't work
355  for (uint32_t i = 0; i < outputs; ++i) {
357  ARDOUR::Sample *d = buf.data();
358  memset(d, 0, sizeof(ARDOUR::Sample)*_buffer_size);
359  }
360 
361  if (f == 0) {
362  //std::cerr << "0: no latency, copying full buffer, trivial.." << std::endl;
363  for (uint32_t i = 0; i < outputs; ++i) {
364  memcpy(_collect_bufferset.get_audio(i).data(),
365  _bufferset.get_audio(i).data(), _buffer_size * sizeof(float));
366  }
367  } else {
368  //int C = 0;
369  //std::cerr << (++C) << ": latency is " << f << " frames, doing split processing.." << std::endl;
370  framecnt_t target_offset = 0;
371  framecnt_t frames_left = _buffer_size; // refaktoroi
372  do {
373  if (f >= _buffer_size) {
374  //std::cerr << (++C) << ": f (=" << f << ") is larger than buffer_size, still trying to reach the actual output" << std::endl;
375  // there is no data in this buffer regarding to the input!
376  f -= _buffer_size;
377  } else {
378  // this buffer contains either the first, last or a whole bu the output of the impulse
379  // first part: offset is 0, so we copy to the start of _collect_bufferset
380  // we start at output offset "f"
381  // .. and copy "buffer size" - "f" - "offset" frames
382 
383  framecnt_t length = _buffer_size - f - target_offset;
384 
385  //std::cerr << (++C) << ": copying " << length << " frames to _collect_bufferset.get_audio(i)+" << target_offset << " from bufferset at offset " << f << std::endl;
386  for (uint32_t i = 0; i < outputs; ++i) {
387  memcpy(_collect_bufferset.get_audio(i).data(target_offset),
388  _bufferset.get_audio(i).data() + f,
389  length * sizeof(float));
390  }
391 
392  target_offset += length;
393  frames_left -= length;
394  f = 0;
395  }
396  if (frames_left > 0) {
397  // Silence the buffers
398  for (uint32_t i = 0; i < inputs; ++i) {
400  ARDOUR::Sample *d = buf.data();
401  memset(d, 0, sizeof(ARDOUR::Sample)*_buffer_size);
402  }
403 
406  _plugin->connect_and_run(_bufferset, in_map, out_map, _buffer_size, 0);
407  }
408  } while ( frames_left > 0);
409 
410  }
411 
412 
413  for (uint32_t i = 0; i < outputs; ++i) {
415  }
416 
417  // normalize the output
419 
420  // This signals calls expose_analysis_area()
421  _analysis_area->queue_draw();
422 
424 }
425 
426 bool
428 {
430  return true;
431 }
432 
433 void
435 {
436  // TODO: check whether we need rounding
437  _analysis_scale_surface = cairo_surface_create_similar(cairo_get_target(ref_cr),
438  CAIRO_CONTENT_COLOR,
441 
442  cairo_t *cr = cairo_create (_analysis_scale_surface);
443 
444  cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
445  cairo_rectangle(cr, 0.0, 0.0, _analysis_width, _analysis_height);
446  cairo_fill(cr);
447 
448 
450  if (_phase_button->get_active()) {
452  }
453 
454  cairo_destroy(cr);
455 
456 }
457 
458 void
460 {
461  cairo_t *cr;
462 
463  cr = gdk_cairo_create(GDK_DRAWABLE(_analysis_area->get_window()->gobj()));
464 
465  if (_analysis_scale_surface == 0) {
467  }
468 
469 
470  cairo_copy_page(cr);
471 
472  cairo_set_source_surface(cr, _analysis_scale_surface, 0.0, 0.0);
473  cairo_paint(cr);
474 
475  if (_phase_button->get_active()) {
477  }
479 
480  // TODO: make this optional
482 
483  cairo_destroy(cr);
484 
485 
486 }
487 
488 #define PHASE_PROPORTION 0.5
489 
490 void
491 PluginEqGui::draw_scales_phase(Gtk::Widget */*w*/, cairo_t *cr)
492 {
493  float y;
494  cairo_font_extents_t extents;
495  cairo_font_extents(cr, &extents);
496 
497  char buf[256];
498  cairo_text_extents_t t_ext;
499 
500  for (uint32_t i = 0; i < 3; i++) {
501 
502  y = _analysis_height/2.0 - (float)i*(_analysis_height/8.0)*PHASE_PROPORTION;
503 
504  cairo_set_source_rgb(cr, .8, .9, 0.2);
505  if (i == 0) {
506  snprintf(buf,256, "0\u00b0");
507  } else {
508  snprintf(buf,256, "%d\u00b0", (i * 45));
509  }
510  cairo_text_extents(cr, buf, &t_ext);
511  cairo_move_to(cr, _analysis_width - t_ext.width - t_ext.x_bearing - 2.0, y - extents.descent);
512  cairo_show_text(cr, buf);
513 
514  if (i == 0)
515  continue;
516 
517 
518  cairo_set_source_rgba(cr, .8, .9, 0.2, 0.6/(float)i);
519  cairo_move_to(cr, 0.0, y);
520  cairo_line_to(cr, _analysis_width, y);
521 
522 
523  y = _analysis_height/2.0 + (float)i*(_analysis_height/8.0)*PHASE_PROPORTION;
524 
525  // label
526  snprintf(buf,256, "-%d\u00b0", (i * 45));
527  cairo_set_source_rgb(cr, .8, .9, 0.2);
528  cairo_text_extents(cr, buf, &t_ext);
529  cairo_move_to(cr, _analysis_width - t_ext.width - t_ext.x_bearing - 2.0, y - extents.descent);
530  cairo_show_text(cr, buf);
531 
532  // line
533  cairo_set_source_rgba(cr, .8, .9, 0.2, 0.6/(float)i);
534  cairo_move_to(cr, 0.0, y);
535  cairo_line_to(cr, _analysis_width, y);
536 
537  cairo_set_line_width (cr, 0.25 + 1.0/(float)(i+1));
538  cairo_stroke(cr);
539  }
540 }
541 
542 void
543 PluginEqGui::plot_impulse_phase(Gtk::Widget *w, cairo_t *cr)
544 {
545  float x,y;
546 
547  int prevX = 0;
548  float avgY = 0.0;
549  int avgNum = 0;
550 
551  // float width = w->get_width();
552  float height = w->get_height();
553 
554  cairo_set_source_rgba(cr, 0.95, 0.3, 0.2, 1.0);
555  for (uint32_t i = 0; i < _impulse_fft->bins()-1; i++) {
556  // x coordinate of bin i
557  x = log10f(1.0 + (float)i / (float)_impulse_fft->bins() * _log_coeff) / _log_max;
558  x *= _analysis_width;
559 
561 
562  if ( i == 0 ) {
563  cairo_move_to(cr, x, y);
564 
565  avgY = 0;
566  avgNum = 0;
567  } else if (rint(x) > prevX || i == _impulse_fft->bins()-1 ) {
568  avgY = avgY/(float)avgNum;
569  if (avgY > (height * 10.0) ) avgY = height * 10.0;
570  if (avgY < (-height * 10.0) ) avgY = -height * 10.0;
571  cairo_line_to(cr, prevX, avgY);
572  //cairo_line_to(cr, prevX, avgY/(float)avgNum);
573 
574  avgY = 0;
575  avgNum = 0;
576 
577  }
578 
579  prevX = rint(x);
580  avgY += y;
581  avgNum++;
582  }
583 
584  cairo_set_line_width (cr, 2.0);
585  cairo_stroke(cr);
586 }
587 
588 void
589 PluginEqGui::draw_scales_power(Gtk::Widget */*w*/, cairo_t *cr)
590 {
591  if (_impulse_fft == 0) {
592  return;
593  }
594 
595  static float scales[] = { 30.0, 70.0, 125.0, 250.0, 500.0, 1000.0, 2000.0, 5000.0, 10000.0, 15000.0, 20000.0, -1.0 };
596  float divisor = _samplerate / 2.0 / _impulse_fft->bins();
597  float x;
598 
599  cairo_set_line_width (cr, 1.5);
600  cairo_set_font_size(cr, 9);
601 
602  cairo_font_extents_t extents;
603  cairo_font_extents(cr, &extents);
604  // float fontXOffset = extents.descent + 1.0;
605 
606  char buf[256];
607 
608  for (uint32_t i = 0; scales[i] != -1.0; ++i) {
609  float bin = scales[i] / divisor;
610 
611  x = log10f(1.0 + bin / (float)_impulse_fft->bins() * _log_coeff) / _log_max;
612  x *= _analysis_width;
613 
614  if (scales[i] < 1000.0) {
615  snprintf(buf, 256, "%0.0f", scales[i]);
616  } else {
617  snprintf(buf, 256, "%0.0fk", scales[i]/1000.0);
618  }
619 
620  cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
621 
622  //cairo_move_to(cr, x + fontXOffset, 3.0);
623  cairo_move_to(cr, x - extents.height, 3.0);
624 
625  cairo_rotate(cr, M_PI / 2.0);
626  cairo_show_text(cr, buf);
627  cairo_rotate(cr, -M_PI / 2.0);
628  cairo_stroke(cr);
629 
630  cairo_set_source_rgb(cr, 0.3, 0.3, 0.3);
631  cairo_move_to(cr, x, _analysis_height);
632  cairo_line_to(cr, x, 0.0);
633  cairo_stroke(cr);
634  }
635 
636  float y;
637 
638  //double dashes[] = { 1.0, 3.0, 4.5, 3.0 };
639  double dashes[] = { 3.0, 5.0 };
640 
641  for (float dB = 0.0; dB < _max_dB; dB += _step_dB ) {
642  snprintf(buf, 256, "+%0.0f", dB );
643 
644  y = ( _max_dB - dB) / ( _max_dB - _min_dB );
645  //std::cerr << " y = " << y << std::endl;
646  y *= _analysis_height;
647 
648  if (dB != 0.0) {
649  cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
650  cairo_move_to(cr, 1.0, y + extents.height + 1.0);
651  cairo_show_text(cr, buf);
652  cairo_stroke(cr);
653  }
654 
655  cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
656  cairo_move_to(cr, 0, y);
657  cairo_line_to(cr, _analysis_width, y);
658  cairo_stroke(cr);
659 
660  if (dB == 0.0) {
661  cairo_set_dash(cr, dashes, 2, 0.0);
662  }
663  }
664 
665 
666 
667  for (float dB = - _step_dB; dB > _min_dB; dB -= _step_dB ) {
668  snprintf(buf, 256, "%0.0f", dB );
669 
670  y = ( _max_dB - dB) / ( _max_dB - _min_dB );
671  y *= _analysis_height;
672 
673  cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
674  cairo_move_to(cr, 1.0, y - extents.descent - 1.0);
675  cairo_show_text(cr, buf);
676  cairo_stroke(cr);
677 
678  cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
679  cairo_move_to(cr, 0, y);
680  cairo_line_to(cr, _analysis_width, y);
681  cairo_stroke(cr);
682  }
683 
684  cairo_set_dash(cr, 0, 0, 0.0);
685 
686 }
687 
688 inline float
689 power_to_dB(float a)
690 {
691  return 10.0 * log10f(a);
692 }
693 
694 void
695 PluginEqGui::plot_impulse_amplitude(Gtk::Widget *w, cairo_t *cr)
696 {
697  float x,y;
698  int prevX = 0;
699  float avgY = 0.0;
700  int avgNum = 0;
701 
702  // float width = w->get_width();
703  float height = w->get_height();
704 
705  cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
706  cairo_set_line_width (cr, 2.5);
707 
708  for (uint32_t i = 0; i < _impulse_fft->bins()-1; i++) {
709  // x coordinate of bin i
710  x = log10f(1.0 + (float)i / (float)_impulse_fft->bins() * _log_coeff) / _log_max;
711  x *= _analysis_width;
712 
713  float yCoeff = ( power_to_dB(_impulse_fft->power_at_bin(i)) - _min_dB) / (_max_dB - _min_dB);
714 
715  y = _analysis_height - _analysis_height*yCoeff;
716 
717  if ( i == 0 ) {
718  cairo_move_to(cr, x, y);
719 
720  avgY = 0;
721  avgNum = 0;
722  } else if (rint(x) > prevX || i == _impulse_fft->bins()-1 ) {
723  avgY = avgY/(float)avgNum;
724  if (avgY > (height * 10.0) ) avgY = height * 10.0;
725  if (avgY < (-height * 10.0) ) avgY = -height * 10.0;
726  cairo_line_to(cr, prevX, avgY);
727  //cairo_line_to(cr, prevX, avgY/(float)avgNum);
728 
729  avgY = 0;
730  avgNum = 0;
731 
732  }
733 
734  prevX = rint(x);
735  avgY += y;
736  avgNum++;
737  }
738 
739  cairo_stroke(cr);
740 }
741 
742 void
744 {
745  float x,y;
746 
747  int prevX = 0;
748  float avgY = 0.0;
749  int avgNum = 0;
750 
751  // float width = w->get_width();
752  float height = w->get_height();
753 
754  cairo_set_source_rgb(cr, 0.0, 1.0, 0.0);
755  cairo_set_line_width (cr, 2.5);
756 
757  for (uint32_t i = 0; i < _signal_input_fft->bins()-1; i++) {
758  // x coordinate of bin i
759  x = log10f(1.0 + (float)i / (float)_signal_input_fft->bins() * _log_coeff) / _log_max;
760  x *= _analysis_width;
761 
762  float power_out = power_to_dB(_signal_output_fft->power_at_bin(i));
763  float power_in = power_to_dB(_signal_input_fft ->power_at_bin(i));
764  float power = power_out - power_in;
765 
766  // for SaBer
767  /*
768  double p = 10.0 * log10( 1.0 + (double)_signal_output_fft->power_at_bin(i) - (double)
769  - _signal_input_fft ->power_at_bin(i));
770  //p *= 1000000.0;
771  float power = (float)p;
772 
773  if ( (i % 1000) == 0) {
774  std::cerr << i << ": " << power << std::endl;
775  }
776  */
777 
778  if (ISINF(power)) {
779  if (power < 0) {
780  power = _min_dB - 1.0;
781  } else {
782  power = _max_dB - 1.0;
783  }
784  } else if (ISNAN(power)) {
785  power = _min_dB - 1.0;
786  }
787 
788  float yCoeff = ( power - _min_dB) / (_max_dB - _min_dB);
789 
790  y = _analysis_height - _analysis_height*yCoeff;
791 
792  if ( i == 0 ) {
793  cairo_move_to(cr, x, y);
794 
795  avgY = 0;
796  avgNum = 0;
797  } else if (rint(x) > prevX || i == _impulse_fft->bins()-1 ) {
798  avgY = avgY/(float)avgNum;
799  if (avgY > (height * 10.0) ) avgY = height * 10.0;
800  if (avgY < (-height * 10.0) ) avgY = -height * 10.0;
801  cairo_line_to(cr, prevX, avgY);
802 
803  avgY = 0;
804  avgNum = 0;
805 
806  }
807 
808  prevX = rint(x);
809  avgY += y;
810  avgNum++;
811  }
812 
813  cairo_stroke(cr);
814 
815 
816 }
ARDOUR::framecnt_t _signal_buffer_size
Definition: plugin_eq_gui.h:99
void run_impulse_analysis()
float _log_coeff
Definition: plugin_eq_gui.h:95
ARDOUR::BufferSet _bufferset
float phase_at_bin(uint32_t i) const
Definition: fft.h:55
void ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capacity)
Definition: buffer_set.cc:149
void resize_analysis_area(Gtk::Allocation &)
boost::shared_ptr< ARDOUR::Plugin > _plugin
#define PHASE_PROPORTION
uint32_t bins() const
Definition: fft.h:52
Glib::RefPtr< Gtk::ListStore > dBScaleModel
float _signal_analysis_running
Definition: plugin_eq_gui.h:59
void set_count(const ChanCount &count)
Definition: buffer_set.h:93
PluginEqGui(boost::shared_ptr< ARDOUR::PluginInsert >)
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
Gtk::TreeModelColumn< float > dBMax
virtual void on_show()
uint32_t n_audio() const
Definition: chan_count.h:63
tuple f
Definition: signals.py:35
float power_at_bin(uint32_t i) const
Definition: fft.h:54
ARDOUR::framecnt_t _buffer_size
Definition: plugin_eq_gui.h:98
void reset()
Definition: fft.cc:47
framecnt_t frame_rate() const
Definition: session.h:365
AudioBuffer & get_audio(size_t i)
Definition: buffer_set.h:100
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
#define invalidator(x)
Definition: gui_thread.h:40
virtual framecnt_t signal_latency() const =0
virtual int connect_and_run(BufferSet &bufs, ChanMapping in, ChanMapping out, pframes_t nframes, framecnt_t offset)
Definition: plugin.cc:259
void redraw_analysis_area()
cairo_surface_t * _analysis_scale_surface
void plot_signal_amplitude_difference(Gtk::Widget *, cairo_t *)
#define _(Text)
Definition: i18n.h:11
void start_updating()
sigc::connection _window_unmap_connection
ChanCount n_outputs
Definition: plugin.h:64
void draw_scales_phase(Gtk::Widget *, cairo_t *)
GTKArdour::FFT * _impulse_fft
static iterator end()
Definition: data_type.h:109
void draw_scales_power(Gtk::Widget *, cairo_t *)
void redraw_scales()
void stop_listening()
int64_t framecnt_t
Definition: types.h:76
void calculate()
Definition: fft.cc:98
ChanCount output_streams() const
float Sample
Definition: types.h:54
float _analysis_height
ARDOUR::Session * the_session()
Definition: ardour_ui.h:172
sigc::connection _update_connection
#define ISINF(val)
Gtk::TreeModelColumn< float > dBStep
Definition: amp.h:29
void change_dB_scale()
ChanCount input_streams() const
float _analysis_width
Gtk::CheckButton * _phase_button
#define gui_context()
Definition: gui_thread.h:36
sigc::connection _window_map_connection
void set_buffer_size(uint32_t, uint32_t)
static ChanCount max(const ChanCount &a, const ChanCount &b)
Definition: chan_count.h:138
#define ADD_DB_ROW(MIN, MAX, STEP, NAME)
void start_listening()
float _samplerate
Definition: plugin_eq_gui.h:89
float _step_dB
Definition: plugin_eq_gui.h:93
Gtk::ComboBox * dBScaleCombo
PluginInfoPtr get_info() const
Definition: plugin.h:225
#define ISNAN(val)
virtual void activate()=0
void plot_impulse_phase(Gtk::Widget *, cairo_t *)
ChanCount n_inputs
Definition: plugin.h:63
PBD::Signal2< void, BufferSet *, BufferSet * > AnalysisDataGathered
Gtk::TreeModelColumn< float > dBMin
uint32_t get(DataType t) const
Definition: chan_count.h:59
float _log_max
Definition: plugin_eq_gui.h:96
void signal_collect_callback(ARDOUR::BufferSet *, ARDOUR::BufferSet *)
void plot_impulse_amplitude(Gtk::Widget *, cairo_t *)
boost::shared_ptr< ARDOUR::PluginInsert > _plugin_insert
virtual void deactivate()=0
Gtk::TreeModelColumn< std::string > name
void analyze(ARDOUR::Sample *, WindowingType w=NONE)
Definition: fft.cc:56
Gtk::DrawingArea * _analysis_area
void stop_updating()
GTKArdour::FFT * _signal_output_fft
PBD::ScopedConnection analysis_connection
const Sample * data(framecnt_t offset=0) const
Definition: audio_buffer.h:187
ARDOUR::BufferSet _collect_bufferset
void drop_process_buffers()
Definition: ardour_ui.cc:4662
void draw_analysis_scales(cairo_t *)
virtual void on_hide()
bool expose_analysis_area(GdkEventExpose *)
dBSelectionColumns dBColumns
float power_to_dB(float a)
void get_process_buffers()
Definition: ardour_ui.cc:4655
static iterator begin()
Definition: data_type.h:108
boost::shared_ptr< Plugin > get_impulse_analysis_plugin()
bool timeout_callback()
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64
GTKArdour::FFT * _signal_input_fft