ardour
gain_meter.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include <limits.h>
21 
22 #include "ardour/amp.h"
23 #include "ardour/route_group.h"
24 #include "ardour/session_route.h"
25 #include "ardour/dB.h"
26 #include "ardour/utils.h"
27 
28 #include <pangomm.h>
29 #include <gtkmm/style.h>
30 #include <gdkmm/color.h>
31 #include <gtkmm2ext/utils.h>
32 #include <gtkmm2ext/fastmeter.h>
33 #include <gtkmm2ext/gtk_ui.h>
34 #include "pbd/fastlog.h"
35 #include "pbd/stacktrace.h"
36 
37 #include "ardour_ui.h"
38 #include "gain_meter.h"
39 #include "global_signals.h"
40 #include "logmeter.h"
41 #include "gui_thread.h"
42 #include "keyboard.h"
43 #include "public_editor.h"
44 #include "utils.h"
45 #include "meter_patterns.h"
46 #include "timers.h"
47 
48 #include "ardour/session.h"
49 #include "ardour/route.h"
50 #include "ardour/meter.h"
51 #include "ardour/audio_track.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/dB.h"
54 
55 #include "i18n.h"
56 
57 using namespace ARDOUR;
58 using namespace ARDOUR_UI_UTILS;
59 using namespace PBD;
60 using namespace Gtkmm2ext;
61 using namespace Gtk;
62 using namespace std;
64 using namespace ArdourMeter;
65 
66 static void
67 reset_cursor_to_default (Gtk::Entry* widget)
68 {
69  Glib::RefPtr<Gdk::Window> win = widget->get_text_window ();
70  if (win) {
71  /* C++ doesn't provide a pointer argument version of this
72  (i.e. you cannot set to NULL to get the default/parent
73  cursor)
74  */
75  gdk_window_set_cursor (win->gobj(), 0);
76  }
77 }
78 
79 static void
80 reset_cursor_to_default_state (Gtk::StateType, Gtk::Entry* widget)
81 {
82  reset_cursor_to_default (widget);
83 }
84 
85 GainMeterBase::GainMeterBase (Session* s, bool horizontal, int fader_length, int fader_girth)
86  : gain_adjustment (gain_to_slider_position_with_max (1.0, Config->get_max_gain()), // value
87  0.0, // lower
88  1.0, // upper
89  dB_coeff_step(Config->get_max_gain()) / 10.0, // step increment
90  dB_coeff_step(Config->get_max_gain())) // page increment
91  , gain_automation_style_button ("")
92  , gain_automation_state_button ("")
93  , _data_type (DataType::AUDIO)
94 {
95  using namespace Menu_Helpers;
96 
97  set_session (s);
98 
99  ignore_toggle = false;
100  meter_menu = 0;
101  next_release_selects = false;
102  _width = Wide;
103 
104  fader_length = rint (fader_length * ARDOUR_UI::ui_scale);
105  fader_girth = rint (fader_girth * ARDOUR_UI::ui_scale);
106 
107  if (horizontal) {
108  gain_slider = manage (new HSliderController (&gain_adjustment, boost::shared_ptr<PBD::Controllable>(), fader_length, fader_girth));
109  } else {
110  gain_slider = manage (new VSliderController (&gain_adjustment, boost::shared_ptr<PBD::Controllable>(), fader_length, fader_girth));
111  }
112 
114 
115  level_meter->ButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&GainMeterBase::level_meter_button_press, this, _1));
116  meter_metric_area.signal_button_press_event().connect (sigc::mem_fun (*this, &GainMeterBase::level_meter_button_press));
117  meter_metric_area.add_events (Gdk::BUTTON_PRESS_MASK);
118 
119  gain_slider->set_tweaks (PixFader::Tweaks(PixFader::NoButtonForward | PixFader::NoVerticalScroll));
120  gain_slider->StartGesture.connect (sigc::mem_fun (*this, &GainMeter::amp_start_touch));
121  gain_slider->StopGesture.connect (sigc::mem_fun (*this, &GainMeter::amp_stop_touch));
122  gain_slider->set_name ("GainFader");
123 
124  gain_display.set_name ("MixerStripGainDisplay");
125  set_size_request_to_display_given_text (gain_display, "-80.g", 2, 6); /* note the descender */
126  gain_display.signal_activate().connect (sigc::mem_fun (*this, &GainMeter::gain_activated));
127  gain_display.signal_focus_in_event().connect (sigc::mem_fun (*this, &GainMeter::gain_focused), false);
128  gain_display.signal_focus_out_event().connect (sigc::mem_fun (*this, &GainMeter::gain_focused), false);
129  gain_display.set_alignment(0.5);
130 
131  peak_display.set_name ("MixerStripPeakDisplay");
132  set_size_request_to_display_given_text (peak_display, "-80.g", 2, 6); /* note the descender */
134  peak_display.set_text (_("-inf"));
135  peak_display.set_alignment(0.5);
136 
137  /* stuff related to the fact that the peak display is not, in
138  fact, supposed to be a text entry.
139  */
140  peak_display.set_events (peak_display.get_events() & ~(Gdk::EventMask (Gdk::LEAVE_NOTIFY_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::POINTER_MOTION_MASK)));
141  peak_display.signal_map().connect (sigc::bind (sigc::ptr_fun (reset_cursor_to_default), &peak_display));
142  peak_display.signal_state_changed().connect (sigc::bind (sigc::ptr_fun (reset_cursor_to_default_state), &peak_display));
143  peak_display.unset_flags (Gtk::CAN_FOCUS);
144  peak_display.set_editable (false);
145 
146  gain_automation_style_button.set_name ("mixer strip button");
147  gain_automation_state_button.set_name ("mixer strip button");
148 
149  ARDOUR_UI::instance()->set_tip (gain_automation_state_button, _("Fader automation mode"));
150  ARDOUR_UI::instance()->set_tip (gain_automation_style_button, _("Fader automation type"));
151 
152  gain_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
153  gain_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
154 
155  gain_automation_state_button.set_size_request(15, 15);
156  gain_automation_style_button.set_size_request(15, 15);
157 
158  gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
159  gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
160 
161  gain_astate_menu.set_name ("ArdourContextMenu");
162  gain_astyle_menu.set_name ("ArdourContextMenu");
163 
164  gain_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &GainMeterBase::gain_adjusted));
165  peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &GainMeterBase::peak_button_release), false);
166  gain_display.signal_key_press_event().connect (sigc::mem_fun(*this, &GainMeterBase::gain_key_press), false);
167 
168  ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &GainMeterBase::reset_peak_display));
169  ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &GainMeterBase::reset_route_peak_display));
170  ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &GainMeterBase::reset_group_peak_display));
171  RedrawMetrics.connect (sigc::mem_fun(*this, &GainMeterBase::redraw_metrics));
172 
173  UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &GainMeterBase::on_theme_changed));
174  ColorsChanged.connect (sigc::bind(sigc::mem_fun (*this, &GainMeterBase::color_handler), false));
175  DPIReset.connect (sigc::bind(sigc::mem_fun (*this, &GainMeterBase::color_handler), true));
176 }
177 
179 {
180  delete meter_menu;
181  delete level_meter;
182 }
183 
184 void
188 {
189  connections.clear ();
191 
192  if (!pm && !amp) {
193  level_meter->set_meter (0);
195  _meter.reset ();
196  _amp.reset ();
197  _route.reset ();
198  return;
199  }
200 
201  _meter = pm;
202  _amp = amp;
203  _route = r;
204 
205  level_meter->set_meter (pm.get());
207 
208  if (amp) {
209  amp->ConfigurationChanged.connect (
211  );
212  }
213 
215 
216  if (!_route || !_route->is_auditioner()) {
217 
218  using namespace Menu_Helpers;
219 
220  gain_astate_menu.items().clear ();
221 
222  gain_astate_menu.items().push_back (MenuElem (S_("Automation|Manual"),
223  sigc::bind (sigc::mem_fun (*(amp.get()), &Automatable::set_parameter_automation_state),
225  gain_astate_menu.items().push_back (MenuElem (_("Play"),
226  sigc::bind (sigc::mem_fun (*(amp.get()), &Automatable::set_parameter_automation_state),
228  gain_astate_menu.items().push_back (MenuElem (_("Write"),
229  sigc::bind (sigc::mem_fun (*(amp.get()), &Automatable::set_parameter_automation_state),
231  gain_astate_menu.items().push_back (MenuElem (_("Touch"),
232  sigc::bind (sigc::mem_fun (*(amp.get()), &Automatable::set_parameter_automation_state),
234 
235  connections.push_back (gain_automation_style_button.signal_button_press_event().connect (sigc::mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false));
236  connections.push_back (gain_automation_state_button.signal_button_press_event().connect (sigc::mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false));
237 
239 
242 
244  }
245 
246  amp->gain_control()->Changed.connect (model_connections, invalidator (*this), boost::bind (&GainMeterBase::gain_changed, this), gui_context());
247 
248  gain_changed ();
249  show_gain ();
251 }
252 
253 void
255 {
256  if (!_amp) {
257  return;
258  }
259 
261  return;
262  }
263 
264  ignore_toggle = true;
265 
267  _data_type = DataType::AUDIO;
268  gain_adjustment.set_lower (GAIN_COEFF_ZERO);
269  gain_adjustment.set_upper (GAIN_COEFF_UNITY);
270  gain_adjustment.set_step_increment (dB_coeff_step(Config->get_max_gain()) / 10.0);
271  gain_adjustment.set_page_increment (dB_coeff_step(Config->get_max_gain()));
273  } else {
274  _data_type = DataType::MIDI;
275  gain_adjustment.set_lower (0.0);
276  gain_adjustment.set_upper (2.0);
277  gain_adjustment.set_step_increment (1.0/128.0);
278  gain_adjustment.set_page_increment (10.0/128.0);
280  }
281 
282  ignore_toggle = false;
283 
285 
287 }
288 
289 void
291 {
293 }
294 
295 void
297 {
299 }
300 
301 void
303 {
304  int meter_width = 5;
305  uint32_t meter_channels = 0;
306  if (_meter) {
307  meter_channels = _meter->input_streams().n_total();
308  } else if (_route) {
309  meter_channels = _route->shared_peak_meter()->input_streams().n_total();
310  }
311 
312  switch (_width) {
313  case Wide:
314  //meter_ticks1_area.show();
315  //meter_ticks2_area.show();
316  meter_metric_area.show();
317  if (meter_channels == 1) {
318  meter_width = 10;
319  }
320  break;
321  case Narrow:
322  if (meter_channels > 1) {
323  meter_width = 4;
324  }
325  //meter_ticks1_area.hide();
326  //meter_ticks2_area.hide();
327  meter_metric_area.hide();
328  break;
329  }
330  level_meter->setup_meters(len, meter_width);
331 }
332 
333 void
335 {
336  level_meter->set_type(t);
337 }
338 
339 void
341 {
342  switch (_width) {
343  case Wide:
344  {
345  uint32_t meter_channels = 0;
346  if (_meter) {
347  meter_channels = _meter->input_streams().n_total();
348  } else if (_route) {
349  meter_channels = _route->shared_peak_meter()->input_streams().n_total();
350  }
351  hbox.set_homogeneous(meter_channels < 7 ? true : false);
352  }
353  break;
354  case Narrow:
355  hbox.set_homogeneous(false);
356  break;
357  }
359 }
360 
361 void
363 {
365 }
366 
367 bool
369 {
370  if (key_is_legal_for_numeric_entry (ev->keyval)) {
371  /* drop through to normal handling */
372  return false;
373  }
374  /* illegal key for gain entry */
375  return true;
376 }
377 
378 bool
380 {
381  /* reset peak label */
382 
383  if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) {
385  } else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
386  if (_route) {
388  }
389  } else {
391  }
392 
393  return true;
394 }
395 
396 void
398 {
399  _meter->reset_max();
401  max_peak = -INFINITY;
402  peak_display.set_text (_("-inf"));
403  peak_display.set_name ("MixerStripPeakDisplay");
404 }
405 
406 void
408 {
409  if (_route && _route.get() == route) {
411  }
412 }
413 
414 void
416 {
417  if (_route && group == _route->route_group()) {
419  }
420 }
421 
422 void
424 {
425  using namespace Menu_Helpers;
426 
427  if (meter_menu == 0) {
428  meter_menu = new Gtk::Menu;
429  MenuList& items = meter_menu->items();
430 
431  items.push_back (MenuElem ("-inf .. +0dBFS"));
432  items.push_back (MenuElem ("-10dB .. +0dBFS"));
433  items.push_back (MenuElem ("-4 .. +0dBFS"));
434  items.push_back (SeparatorElem());
435  items.push_back (MenuElem ("-inf .. -2dBFS"));
436  items.push_back (MenuElem ("-10dB .. -2dBFS"));
437  items.push_back (MenuElem ("-4 .. -2dBFS"));
438  }
439 
440  meter_menu->popup (1, ev->time);
441 }
442 
443 bool
444 GainMeterBase::gain_focused (GdkEventFocus* ev)
445 {
446  if (ev->in) {
447  gain_display.select_region (0, -1);
448  } else {
449  gain_display.select_region (0, 0);
450  }
451  return false;
452 }
453 
454 void
456 {
457  float f;
458 
459  {
460  // Switch to user's preferred locale so that
461  // if they use different LC_NUMERIC conventions,
462  // we will honor them.
463 
464  PBD::LocaleGuard lg ("");
465  if (sscanf (gain_display.get_text().c_str(), "%f", &f) != 1) {
466  return;
467  }
468  }
469 
470  /* clamp to displayable values */
471  if (_data_type == DataType::AUDIO) {
472  f = min (f, 6.0f);
473  _amp->set_gain (dB_to_coefficient(f), this);
474  } else {
475  f = min (fabs (f), 2.0f);
476  _amp->set_gain (f, this);
477  }
478 
479  if (gain_display.has_focus()) {
480  Gtk::Widget* w = gain_display.get_toplevel();
481  if (w) {
482  Gtk::Window* win = dynamic_cast<Gtk::Window*> (w);
483 
484  /* sigh. gtkmm doesn't wrap get_default_widget() */
485 
486  if (win) {
487  GtkWidget* f = gtk_window_get_default_widget (win->gobj());
488  if (f) {
489  gtk_widget_grab_focus (f);
490  return;
491  }
492  }
493  }
494  }
495 }
496 
497 void
499 {
500  char buf[32];
501 
502  float v = gain_adjustment.get_value();
503 
504  switch (_data_type) {
505  case DataType::AUDIO:
506  if (v == 0.0) {
507  strcpy (buf, _("-inf"));
508  } else {
509  snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (slider_position_to_gain_with_max (v, Config->get_max_gain())));
510  }
511  break;
512  case DataType::MIDI:
513  snprintf (buf, sizeof (buf), "%.1f", v);
514  break;
515  }
516 
517  gain_display.set_text (buf);
518 }
519 
520 void
522 {
523  gain_t value;
524 
525  /* convert from adjustment range (0..1) to gain coefficient */
526 
527  if (_data_type == DataType::AUDIO) {
528  value = slider_position_to_gain_with_max (gain_adjustment.get_value(), Config->get_max_gain());
529  } else {
530  value = gain_adjustment.get_value();
531  }
532 
533  if (!ignore_toggle) {
534  if (_route && _route->amp() == _amp) {
535  _route->set_gain (value, this);
536  } else {
537  _amp->set_gain (value, this);
538  }
539  }
540 
541  show_gain ();
542 }
543 
544 void
546 {
547  float value = GAIN_COEFF_ZERO;
548 
549  switch (_data_type) {
550  case DataType::AUDIO:
551  value = gain_to_slider_position_with_max (_amp->gain(), Config->get_max_gain());
552  break;
553  case DataType::MIDI:
554  value = _amp->gain ();
555  break;
556  }
557 
558  if (gain_adjustment.get_value() != value) {
559  ignore_toggle = true;
560  gain_adjustment.set_value (value);
561  ignore_toggle = false;
562  }
563 }
564 
565 void
567 {
569 }
570 
571 void
573 {
574  char tmp[256];
575  meter_metric_area.set_name (name);
576  sprintf(tmp, "Mark%sLeft", name);
577  meter_ticks1_area.set_name (tmp);
578  sprintf(tmp, "Mark%sRight", name);
579  meter_ticks2_area.set_name (tmp);
580 }
581 
582 void
584 {
585  gain_slider->set_name (name);
586 }
587 
588 void
590 {
591  bool x = !(_amp->gain_control()->alist()->automation_state() & Play);
593 }
594 
595 static MeterPoint
597 {
598  switch (mp) {
599  case MeterInput:
600  return MeterPreFader;
601  break;
602 
603  case MeterPreFader:
604  return MeterPostFader;
605  break;
606 
607  case MeterPostFader:
608  return MeterOutput;
609  break;
610 
611  case MeterOutput:
612  return MeterCustom;
613  break;
614 
615  case MeterCustom:
616  return MeterInput;
617  break;
618  }
619 
620  abort(); /*NOTREACHED*/
621  return MeterInput;
622 }
623 
624 gint
625 GainMeterBase::meter_press(GdkEventButton* ev)
626 {
627  wait_for_release = false;
628 
629  if (!_route) {
630  return FALSE;
631  }
632 
633  if (!ignore_toggle) {
634 
635  if (Keyboard::is_context_menu_event (ev)) {
636 
637  // no menu at this time.
638 
639  } else {
640 
641  if (Keyboard::is_button2_event(ev)) {
642 
643  // Primary-button2 click is the midi binding click
644  // button2-click is "momentary"
645 
646  if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
647  wait_for_release = true;
649  }
650  }
651 
652  if (_route && (ev->button == 1 || Keyboard::is_button2_event (ev))) {
653 
654  if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
655 
656  /* Primary+Tertiary-click applies change to all routes */
657 
659 
660 
661  } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
662 
663  /* Primary-click: solo mix group.
664  NOTE: Primary-button2 is MIDI learn.
665  */
666 
667  if (ev->button == 1) {
669  }
670 
671  } else {
672 
673  /* click: change just this route */
674 
675  // XXX no undo yet
676 
678  }
679  }
680  }
681  }
682 
683  return true;
684 
685 }
686 
687 gint
689 {
690  if (!ignore_toggle) {
691  if (wait_for_release) {
692  wait_for_release = false;
693 
694  if (_route) {
696  }
697  }
698  }
699 
700  return true;
701 }
702 
703 void
705 {
706  route.set_meter_point (mp);
707 }
708 
709 void
711 {
712  RouteGroup* route_group;
713 
714  if ((route_group = route.route_group ()) != 0) {
715  route_group->foreach_route (boost::bind (&Route::set_meter_point, _1, mp, false));
716  } else {
717  route.set_meter_point (mp);
718  }
719 }
720 
721 void
723 {
724  if (_route) {
725  /* WHAT? */
726  }
727 }
728 
729 void
731 {
732  _amp->gain_control()->start_touch (_amp->session().transport_frame());
733 }
734 
735 void
737 {
738  _amp->gain_control()->stop_touch (false, _amp->session().transport_frame());
739 }
740 
741 gint
743 {
744  if (ev->type == GDK_BUTTON_RELEASE) {
745  return TRUE;
746  }
747 
748  switch (ev->button) {
749  case 1:
750  gain_astate_menu.popup (1, ev->time);
751  break;
752  default:
753  break;
754  }
755 
756  return TRUE;
757 }
758 
759 gint
761 {
762  if (ev->type == GDK_BUTTON_RELEASE) {
763  return TRUE;
764  }
765 
766  switch (ev->button) {
767  case 1:
768  gain_astyle_menu.popup (1, ev->time);
769  break;
770  default:
771  break;
772  }
773  return TRUE;
774 }
775 
776 string
778 {
779  return _astate_string (state, false);
780 }
781 
782 string
784 {
785  return _astate_string (state, true);
786 }
787 
788 string
790 {
791  string sstr;
792 
793  switch (state) {
794  case ARDOUR::Off:
795  sstr = (shrt ? "M" : _("M"));
796  break;
797  case Play:
798  sstr = (shrt ? "P" : _("P"));
799  break;
800  case Touch:
801  sstr = (shrt ? "T" : _("T"));
802  break;
803  case Write:
804  sstr = (shrt ? "W" : _("W"));
805  break;
806  }
807 
808  return sstr;
809 }
810 
811 string
813 {
814  return _astyle_string (style, false);
815 }
816 
817 string
819 {
820  return _astyle_string (style, true);
821 }
822 
823 string
825 {
826  if (style & Trim) {
827  return _("Trim");
828  } else {
829  /* XXX it might different in different languages */
830 
831  return (shrt ? _("Abs") : _("Abs"));
832  }
833 }
834 
835 void
837 {
838  switch (_width) {
839  case Wide:
840  gain_automation_style_button.set_text (astyle_string(_amp->gain_control()->alist()->automation_style()));
841  break;
842  case Narrow:
844  break;
845  }
846 }
847 
848 void
850 {
852 
853  bool x;
854 
855  switch (_width) {
856  case Wide:
857  gain_automation_state_button.set_text (astate_string(_amp->gain_control()->alist()->automation_state()));
858  break;
859  case Narrow:
861  break;
862  }
863 
864  x = (_amp->gain_control()->alist()->automation_state() != ARDOUR::Off);
865 
867  ignore_toggle = true;
869  ignore_toggle = false;
870  }
871 
873 
874  /* start watching automation so that things move */
875 
876  gain_watching.disconnect();
877 
878  if (x) {
880  }
881 }
882 
883 const ChanCount
885 {
886  if (_meter) { return _meter->input_streams(); }
887  else { return ChanCount(); }
888 }
889 void
891 {
892  char buf[32];
893  float mpeak = level_meter->update_meters();
894 
895  if (mpeak > max_peak) {
896  max_peak = mpeak;
897  if (mpeak <= -200.0f) {
898  peak_display.set_text (_("-inf"));
899  } else {
900  snprintf (buf, sizeof(buf), "%.1f", mpeak);
901  peak_display.set_text (buf);
902  }
903  }
904  if (mpeak >= ARDOUR_UI::config()->get_meter_peak()) {
905  peak_display.set_name ("MixerStripPeakDisplayPeak");
906  }
907 }
908 
910 {
911  setup_meters();
912 }
913 
914 void
916 {
917  _width = w;
918  int meter_width = 5;
919  if (_width == Wide && _route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
920  meter_width = 10;
921  }
922  level_meter->setup_meters(len, meter_width);
923 }
924 
925 
926 void
928 {
929 }
930 
931 void
933 {
934  meter_metric_area.queue_draw ();
935  meter_ticks1_area.queue_draw ();
936  meter_ticks2_area.queue_draw ();
937 }
938 
939 #define PX_SCALE(pxmin, dflt) rint(std::max((double)pxmin, (double)dflt * ARDOUR_UI::ui_scale))
940 
941 GainMeter::GainMeter (Session* s, int fader_length)
942  : GainMeterBase (s, false, fader_length, 24)
943  , gain_display_box(true, 0)
944  , hbox(true, 2)
945 {
946  if (gain_display.get_parent()) {
947  gain_display.get_parent()->remove (gain_display);
948  }
949  gain_display_box.pack_start (gain_display, true, true);
950 
951  if (peak_display.get_parent()) {
952  peak_display.get_parent()->remove (gain_display);
953  }
954  gain_display_box.pack_start (peak_display, true, true);
955 
956  meter_metric_area.set_name ("AudioTrackMetrics");
957  meter_metric_area.set_size_request(PX_SCALE(24, 24), -1);
958 
959  gain_automation_style_button.set_name ("mixer strip button");
960  gain_automation_state_button.set_name ("mixer strip button");
961 
962  ARDOUR_UI::instance()->set_tip (gain_automation_state_button, _("Fader automation mode"));
963  ARDOUR_UI::instance()->set_tip (gain_automation_style_button, _("Fader automation type"));
964 
965  gain_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
966  gain_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
967 
968  gain_automation_state_button.set_size_request (PX_SCALE(12, 15), PX_SCALE(12, 15));
969  gain_automation_style_button.set_size_request (PX_SCALE(12, 15), PX_SCALE(12, 15));
970 
971  fader_vbox = manage (new Gtk::VBox());
972  fader_vbox->set_spacing (0);
973  fader_vbox->pack_start (*gain_slider, true, true);
974 
975  fader_alignment.set (0.5, 0.5, 0.0, 1.0);
977 
978  hbox.pack_start (fader_alignment, true, true);
979 
980  set_spacing (PX_SCALE(2, 2));
981 
982  pack_start (gain_display_box, Gtk::PACK_SHRINK);
983  pack_start (hbox, Gtk::PACK_SHRINK);
984 
985  meter_alignment.set (0.5, 0.5, 0.0, 1.0);
987 
988  meter_metric_area.signal_expose_event().connect (
989  sigc::mem_fun(*this, &GainMeter::meter_metrics_expose));
990 
991  meter_ticks1_area.set_size_request (PX_SCALE(3, 3), -1);
992  meter_ticks2_area.set_size_request (PX_SCALE(3, 3), -1);
993 
994  meter_ticks1_area.signal_expose_event().connect (
995  sigc::mem_fun(*this, &GainMeter::meter_ticks1_expose));
996  meter_ticks2_area.signal_expose_event().connect (
997  sigc::mem_fun(*this, &GainMeter::meter_ticks2_expose));
998 
999  meter_hbox.pack_start (meter_ticks1_area, false, false);
1000  meter_hbox.pack_start (meter_alignment, false, false);
1001  meter_hbox.pack_start (meter_ticks2_area, false, false);
1002  meter_hbox.pack_start (meter_metric_area, false, false);
1003 }
1004 #undef PX_SCALE
1005 
1007 
1008 void
1012 {
1013  if (meter_hbox.get_parent()) {
1014  hbox.remove (meter_hbox);
1015  }
1016 
1017 // if (gain_automation_state_button.get_parent()) {
1018 // fader_vbox->remove (gain_automation_state_button);
1019 // }
1020 
1021  GainMeterBase::set_controls (r, meter, amp);
1022 
1023  if (_meter) {
1024  _meter->ConfigurationChanged.connect (
1026  );
1027  _meter->TypeChanged.connect (
1028  model_connections, invalidator (*this), boost::bind (&GainMeter::meter_type_changed, this, _1), gui_context()
1029  );
1030 
1032  }
1033 
1034 
1035  if (_route) {
1036  _route->active_changed.connect (model_connections, invalidator (*this), boost::bind (&GainMeter::route_active_changed, this), gui_context ());
1037  }
1038 
1039  /*
1040  if we have a non-hidden route (ie. we're not the click or the auditioner),
1041  pack some route-dependent stuff.
1042  */
1043 
1044  hbox.pack_start (meter_hbox, true, true);
1045 
1046 // if (r && !r->is_auditioner()) {
1047 // fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
1048 // }
1049 
1050  hbox.show_all ();
1051  setup_meters ();
1052 }
1053 
1054 int
1056 {
1057  Gtk::Requisition sz;
1058  int min_w = 0;
1059  sz.width = 0;
1060  meter_metric_area.size_request (sz);
1061  min_w += sz.width;
1062  level_meter->size_request (sz);
1063  min_w += sz.width;
1064 
1065  fader_alignment.size_request (sz);
1066  if (_width == Wide)
1067  return max(sz.width * 2, min_w * 2) + 6;
1068  else
1069  return sz.width + min_w + 6;
1070 
1071 }
1072 
1073 gint
1075 {
1076  if (!_route) {
1077  if (_types.empty()) { _types.push_back(DataType::AUDIO); }
1079  }
1081 }
1082 
1083 gint
1085 {
1086  if (!_route) {
1087  if (_types.empty()) { _types.push_back(DataType::AUDIO); }
1089  }
1091 }
1092 
1093 gint
1095 {
1096  if (!_route) {
1097  if (_types.empty()) { _types.push_back(DataType::AUDIO); }
1099  }
1101 }
1102 
1103 void
1104 GainMeter::on_style_changed (const Glib::RefPtr<Gtk::Style>&)
1105 {
1106  gain_display.queue_draw();
1107  peak_display.queue_draw();
1108 }
1109 
1112 {
1113  if (_amp) {
1114  return _amp->gain_control();
1115  } else {
1117  }
1118 }
1119 
1120 bool
1122 {
1123  return static_cast<bool>(LevelMeterButtonPress (ev)); /* EMIT SIGNAL */
1124 }
1125 
1126 void
1128 {
1129  int type = 0;
1130  _types.clear ();
1131 
1132  for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1133  if (c.get (*i) > 0) {
1134  _types.push_back (*i);
1135  type |= 1 << (*i);
1136  }
1137  }
1138 
1139  if (_route
1140  && boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
1141  && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0
1142  ) {
1143  if (_route->active()) {
1144  set_meter_strip_name ("AudioBusMetrics");
1145  } else {
1146  set_meter_strip_name ("AudioBusMetricsInactive");
1147  }
1148  }
1149  else if (
1150  (type == (1 << DataType::MIDI))
1151  || (_route && boost::dynamic_pointer_cast<MidiTrack>(_route))
1152  ) {
1153  if (!_route || _route->active()) {
1154  set_meter_strip_name ("MidiTrackMetrics");
1155  } else {
1156  set_meter_strip_name ("MidiTrackMetricsInactive");
1157  }
1158  }
1159  else if (type == (1 << DataType::AUDIO)) {
1160  if (!_route || _route->active()) {
1161  set_meter_strip_name ("AudioTrackMetrics");
1162  } else {
1163  set_meter_strip_name ("AudioTrackMetricsInactive");
1164  }
1165  } else {
1166  if (!_route || _route->active()) {
1167  set_meter_strip_name ("AudioMidiTrackMetrics");
1168  } else {
1169  set_meter_strip_name ("AudioMidiTrackMetricsInactive");
1170  }
1171  }
1172 
1173  setup_meters();
1175  on_style_changed(Glib::RefPtr<Gtk::Style>());
1176 }
1177 
1178 void
1180 {
1181  if (_meter) {
1183  }
1184 }
1185 
1186 void
1188 {
1189  _route->set_meter_type(t);
1190  RedrawMetrics();
1191 }
Gtk::HBox gain_display_box
Definition: gain_meter.h:229
Gtk::Menu gain_astyle_menu
Definition: gain_meter.h:129
LevelMeterHBox * level_meter
Definition: gain_meter.h:121
ARDOUR::MeterPoint old_meter_point
Definition: gain_meter.h:181
Gtkmm2ext::FocusEntry peak_display
Definition: gain_meter.h:116
std::string _astate_string(ARDOUR::AutoState, bool)
Definition: gain_meter.cc:789
const ARDOUR::ChanCount meter_channels() const
Definition: gain_meter.cc:884
static double gain_to_slider_position(ARDOUR::gain_t g)
Definition: utils.h:83
virtual void set_meter(ARDOUR::PeakMeter *meter)
Definition: level_meter.cc:77
std::string short_astyle_string(ARDOUR::AutoStyle)
Definition: gain_meter.cc:818
ArdourButton gain_automation_state_button
Definition: gain_meter.h:126
bool next_release_selects
Definition: gain_meter.h:111
static void reset_cursor_to_default(Gtk::Entry *widget)
Definition: gain_meter.cc:67
void gain_adjusted()
Definition: gain_meter.cc:521
void meter_clear_pattern_cache(int which=7)
virtual ~GainMeter()
Definition: gain_meter.cc:1006
MeterPoint meter_point() const
Definition: route.h:187
#define PX_SCALE(pxmin, dflt)
Definition: gain_meter.cc:939
LIBGTKMM2EXT_API void set_size_request_to_display_given_text(Gtk::Widget &w, const gchar *text, gint hpadding, gint vpadding)
Definition: utils.cc:70
boost::shared_ptr< ARDOUR::Route > _route
Definition: gain_meter.h:104
void update_gain_sensitive()
Definition: gain_meter.cc:589
boost::shared_ptr< Amp > amp() const
Definition: route.h:194
ARDOUR::ChanCount _previous_amp_output_streams
Definition: gain_meter.h:193
ArdourButton gain_automation_style_button
Definition: gain_meter.h:125
void popup_meter_menu(GdkEventButton *)
Definition: gain_meter.cc:423
void gain_automation_style_changed()
Definition: gain_meter.cc:836
gint meter_ticks2_expose(GdkEventExpose *)
Definition: gain_meter.cc:1094
sigc::signal< void > DPIReset
Definition: utils.cc:68
Session & session() const
bool wait_for_release
Definition: gain_meter.h:180
void clear_meters(bool reset_highlight=true)
Definition: level_meter.cc:496
sigc::signal< void > StartGesture
Definition: pixfader.h:40
virtual void set_type(ARDOUR::MeterType)
Definition: gain_meter.cc:334
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
void set_gain(gain_t val, void *src)
Definition: route.cc:371
LIBARDOUR_API double slider_position_to_gain_with_max(double g, double max_gain=2.0)
Definition: utils.cc:762
void amp_stop_touch()
Definition: gain_meter.cc:736
void set_type(ARDOUR::MeterType)
Definition: level_meter.cc:472
virtual ~GainMeterBase()
Definition: gain_meter.cc:178
void set_fader_name(const char *name)
Definition: gain_meter.cc:583
void set_meter_type(MeterType t)
Definition: route.h:189
void set_gain(gain_t g, void *src)
Definition: amp.cc:374
Gtk::HBox hbox
Definition: gain_meter.h:232
gain_t gain() const
Definition: amp.h:71
void set_tweaks(Tweaks)
Definition: pixfader.cc:642
std::string _astyle_string(ARDOUR::AutoStyle, bool)
Definition: gain_meter.cc:824
uint32_t n_audio() const
Definition: chan_count.h:63
std::vector< ARDOUR::DataType > _types
Definition: gain_meter.h:236
tuple f
Definition: signals.py:35
Gtkmm2ext::FocusEntry gain_display
Definition: gain_meter.h:115
Definition: Beats.hpp:239
float gain_t
Definition: types.h:58
bool is_auditioner() const
Definition: route.h:110
PBD::Signal2< void, ChanCount, ChanCount > ConfigurationChanged
Definition: processor.h:113
boost::shared_ptr< PeakMeter > shared_peak_meter() const
Definition: route.h:198
GainMeter(ARDOUR::Session *, int)
Definition: gain_meter.cc:941
std::string astate_string(ARDOUR::AutoState)
Definition: gain_meter.cc:777
float update_meters()
Definition: level_meter.cc:127
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
#define GAIN_COEFF_ZERO
Definition: dB.h:26
#define invalidator(x)
Definition: gui_thread.h:40
virtual void setup_meters(int len=0)
Definition: gain_meter.cc:302
uint32_t n_midi() const
Definition: chan_count.h:66
AutoStyle
Definition: types.h:155
void reset_group_peak_display(ARDOUR::RouteGroup *)
Definition: gain_meter.cc:415
void color_handler(bool)
Definition: gain_meter.cc:909
static float accurate_coefficient_to_dB(float coeff)
Definition: dB.h:38
GainMeterBase(ARDOUR::Session *, bool horizontal, int, int)
Definition: gain_meter.cc:85
static UI * instance()
Definition: gtk_ui.h:119
sigc::signal< void, ARDOUR::Route * > ResetRoutePeakDisplays
void meter_type_changed(ARDOUR::MeterType)
Definition: gain_meter.cc:1187
gint meter_press(GdkEventButton *)
Definition: gain_meter.cc:625
void on_style_changed(const Glib::RefPtr< Gtk::Style > &)
Definition: gain_meter.cc:1104
uint32_t n_total() const
Definition: chan_count.h:69
void setup_meters(int len=0, int width=3, int thin=2)
Definition: level_meter.cc:237
#define _(Text)
Definition: i18n.h:11
LIBGTKMM2EXT_API void set_sensitive(std::vector< Glib::RefPtr< Gtk::Action > > &actions, bool)
gint gain_automation_style_button_event(GdkEventButton *)
Definition: gain_meter.cc:760
PBD::ScopedConnection _level_meter_connection
Definition: gain_meter.h:198
void effective_gain_display()
Definition: gain_meter.cc:545
boost::shared_ptr< ARDOUR::Amp > _amp
Definition: gain_meter.h:106
LIBGTKMM2EXT_API uint64_t Keyboard
Definition: debug.cc:23
void gain_automation_state_changed()
Definition: gain_meter.cc:849
Gtk::Alignment meter_alignment
Definition: gain_meter.h:235
PBD::Signal1< bool, GdkEventButton * > ButtonPress
Definition: level_meter.h:73
gint meter_release(GdkEventButton *)
Definition: gain_meter.cc:688
Gtk::DrawingArea meter_ticks2_area
Definition: gain_meter.h:120
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
static float minus_infinity(void)
Definition: fastlog.h:44
Gtk::DrawingArea meter_metric_area
Definition: gain_meter.h:118
void set_default_value(float)
Definition: pixfader.cc:635
std::string astyle_string(ARDOUR::AutoStyle)
Definition: gain_meter.cc:812
bool level_meter_button_press(GdkEventButton *)
Definition: gain_meter.cc:1121
void set_meter_point(ARDOUR::Route &, ARDOUR::MeterPoint)
Definition: gain_meter.cc:704
static double dB_coeff_step(double max_coeff)
Definition: dB.h:43
sigc::connection gain_watching
Definition: gain_meter.h:123
void set_meter_point(MeterPoint, bool force=false)
Definition: route.cc:3436
MeterType
Definition: types.h:182
framepos_t transport_frame() const
Definition: session.h:551
Definition: amp.h:29
Gtk::DrawingArea meter_ticks1_area
Definition: gain_meter.h:119
boost::shared_ptr< PBD::Controllable > get_controllable()
Definition: gain_meter.cc:1111
virtual void set_controls(boost::shared_ptr< ARDOUR::Route > route, boost::shared_ptr< ARDOUR::PeakMeter > meter, boost::shared_ptr< ARDOUR::Amp > amp)
Definition: gain_meter.cc:1009
void gain_activated()
Definition: gain_meter.cc:455
gint gain_automation_state_button_event(GdkEventButton *)
Definition: gain_meter.cc:742
gint meter_expose_metrics(GdkEventExpose *ev, ARDOUR::MeterType type, std::vector< ARDOUR::DataType > types, Gtk::DrawingArea *mma)
void set_meter_strip_name(const char *name)
Definition: gain_meter.cc:572
PBD::Signal0< void > active_changed
Definition: route.h:285
#define gui_context()
Definition: gui_thread.h:36
void foreach_route(T *obj, void(T::*func)(Route &), bool sort=true)
Definition: session_route.h:33
void setup_gain_adjustment()
Definition: gain_meter.cc:254
void meter_configuration_changed(ARDOUR::ChanCount)
Definition: gain_meter.cc:1127
void gain_changed()
Definition: gain_meter.cc:566
void route_active_changed()
Definition: gain_meter.cc:1179
Gtk::HBox meter_hbox
Definition: gain_meter.h:233
Gtk::Menu * meter_menu
Definition: gain_meter.h:170
static MeterPoint next_meter_point(MeterPoint mp)
Definition: gain_meter.cc:596
Gtk::Adjustment gain_adjustment
Definition: gain_meter.h:114
Gtk::Menu gain_astate_menu
Definition: gain_meter.h:128
PBD::Signal0< void > automation_style_changed
bool ignore_toggle
Definition: gain_meter.h:110
bool key_is_legal_for_numeric_entry(guint keyval)
Definition: utils.cc:718
sigc::signal< void > ResetAllPeakDisplays
T * get() const
Definition: shared_ptr.hpp:268
void set_type(ARDOUR::MeterType)
Definition: gain_meter.cc:362
Gtk::Alignment fader_alignment
Definition: gain_meter.h:234
float max_peak
Definition: gain_meter.h:155
Gtk::VBox * fader_vbox
Definition: gain_meter.h:231
void show_gain()
Definition: gain_meter.cc:498
PBD::Signal1< bool, GdkEventButton * > LevelMeterButtonPress
Definition: gain_meter.h:97
void set_tip(Gtk::Widget &w, const gchar *tip)
void call_slot(EventLoop::InvalidationRecord *, const boost::function< void()> &)
Definition: abstract_ui.cc:368
void reset_max()
Definition: meter.cc:208
bool active() const
Definition: route.h:95
ARDOUR::DataType _data_type
Definition: gain_meter.h:192
ChanCount input_streams() const
Definition: meter.h:72
LIBARDOUR_API double gain_to_slider_position_with_max(double g, double max_gain=2.0)
Definition: utils.cc:756
void hide_all_meters()
Definition: gain_meter.cc:296
const char * name
boost::shared_ptr< GainControl > gain_control()
Definition: amp.h:105
bool get_active()
Definition: cairo_widget.h:57
bool peak_button_release(GdkEventButton *)
Definition: gain_meter.cc:379
uint32_t get(DataType t) const
Definition: chan_count.h:59
void setup_meters(int len=0)
Definition: gain_meter.cc:340
void reset_peak_display()
Definition: gain_meter.cc:397
static void reset_cursor_to_default_state(Gtk::StateType, Gtk::Entry *widget)
Definition: gain_meter.cc:80
void set_active(bool)
Width
Definition: enums.h:25
RouteGroup * route_group() const
static UIConfiguration * config()
Definition: ardour_ui.h:188
void set_text(const std::string &)
MeterType meter_type() const
Definition: route.h:190
void redraw_metrics()
Definition: gain_meter.cc:932
bool gain_key_press(GdkEventKey *)
Definition: gain_meter.cc:368
void update_meters()
Definition: gain_meter.cc:890
sigc::signal< void > ColorsChanged
sigc::signal< void, ARDOUR::RouteGroup * > ResetGroupPeakDisplays
Definition: debug.h:30
void set_route_group_meter_point(ARDOUR::Route &, ARDOUR::MeterPoint)
Definition: gain_meter.cc:710
uint32_t ModifierMask
Definition: keyboard.h:53
void amp_start_touch()
Definition: gain_meter.cc:730
static float dB_to_coefficient(float dB)
Definition: dB.h:30
virtual void hide_all_meters()
Definition: gain_meter.cc:290
Gtkmm2ext::SliderController * gain_slider
Definition: gain_meter.h:113
#define S_(Text)
Definition: i18n.h:18
boost::shared_ptr< AutomationList > alist() const
PBD::ScopedConnectionList model_connections
Definition: gain_meter.h:108
bool gain_focused(GdkEventFocus *)
Definition: gain_meter.cc:444
virtual void set_session(ARDOUR::Session *)
PBD::Signal1< void, MeterType > TypeChanged
Definition: meter.h:82
void set_controllable(boost::shared_ptr< PBD::Controllable > c)
std::vector< sigc::connection > connections
Definition: gain_meter.h:107
static float ui_scale
Definition: ardour_ui.h:189
void meter_point_clicked()
Definition: gain_meter.cc:722
void on_theme_changed()
Definition: gain_meter.cc:927
void set_width(Width, int len=0)
Definition: gain_meter.cc:915
Definition: enums.h:27
MeterPoint
Definition: types.h:174
#define GAIN_COEFF_UNITY
Definition: dB.h:28
void reset_route_peak_display(ARDOUR::Route *)
Definition: gain_meter.cc:407
int get_gm_width()
Definition: gain_meter.cc:1055
sigc::signal< void > StopGesture
Definition: pixfader.h:41
sigc::connection rapid_connect(const sigc::slot< void > &slot)
Definition: timers.cc:183
std::string short_astate_string(ARDOUR::AutoState)
Definition: gain_meter.cc:783
Definition: enums.h:26
virtual void set_controls(boost::shared_ptr< ARDOUR::Route > route, boost::shared_ptr< ARDOUR::PeakMeter > meter, boost::shared_ptr< ARDOUR::Amp > amp)
Definition: gain_meter.cc:185
void hide_meters()
Definition: level_meter.cc:507
gint meter_metrics_expose(GdkEventExpose *)
Definition: gain_meter.cc:1074
ARDOUR::Session * _session
void foreach_route(Function f)
Definition: route_group.h:103
gint meter_ticks1_expose(GdkEventExpose *)
Definition: gain_meter.cc:1084
gint meter_expose_ticks(GdkEventExpose *ev, ARDOUR::MeterType type, std::vector< ARDOUR::DataType > types, Gtk::DrawingArea *mta)
virtual ChanCount output_streams() const
Definition: processor.h:89
PBD::Signal1< void, AutoState > automation_state_changed
boost::shared_ptr< ARDOUR::PeakMeter > _meter
Definition: gain_meter.h:105
sigc::signal< void > RedrawMetrics
AutoState
Definition: types.h:145