2 Copyright (C) 2002 Paul Davis
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.
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.
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.
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"
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"
37 #include "gain_meter.h"
39 #include "gui_thread.h"
41 #include "public_editor.h"
43 #include "meter_patterns.h"
46 #include "ui_config.h"
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"
57 using namespace ARDOUR;
58 using namespace ARDOUR_UI_UTILS;
60 using namespace Gtkmm2ext;
63 using Gtkmm2ext::Keyboard;
64 using namespace ArdourMeter;
67 reset_cursor_to_default (Gtk::Entry* widget)
69 Glib::RefPtr<Gdk::Window> win = widget->get_text_window ();
71 /* C++ doesn't provide a pointer argument version of this
72 (i.e. you cannot set to NULL to get the default/parent
75 gdk_window_set_cursor (win->gobj(), 0);
80 reset_cursor_to_default_state (Gtk::StateType, Gtk::Entry* widget)
82 reset_cursor_to_default (widget);
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
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)
95 using namespace Menu_Helpers;
99 ignore_toggle = false;
101 next_release_selects = false;
104 fader_length = rint (fader_length * UIConfiguration::instance().get_ui_scale());
105 fader_girth = rint (fader_girth * UIConfiguration::instance().get_ui_scale());
108 gain_slider = manage (new HSliderController (&gain_adjustment, boost::shared_ptr<PBD::Controllable>(), fader_length, fader_girth));
110 gain_slider = manage (new VSliderController (&gain_adjustment, boost::shared_ptr<PBD::Controllable>(), fader_length, fader_girth));
113 level_meter = new LevelMeterHBox(_session);
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);
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");
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);
131 peak_display.set_name ("MixerStripPeakDisplay");
132 set_size_request_to_display_given_text (peak_display, "-80.g", 2, 6); /* note the descender */
133 max_peak = minus_infinity();
134 peak_display.set_text (_("-inf"));
135 peak_display.set_alignment(0.5);
137 /* stuff related to the fact that the peak display is not, in
138 fact, supposed to be a text entry.
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);
146 gain_automation_style_button.set_name ("mixer strip button");
147 gain_automation_state_button.set_name ("mixer strip button");
149 set_tooltip (gain_automation_state_button, _("Fader automation mode"));
150 set_tooltip (gain_automation_style_button, _("Fader automation type"));
152 gain_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
153 gain_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
155 gain_automation_state_button.set_size_request(15, 15);
156 gain_automation_style_button.set_size_request(15, 15);
158 gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
159 gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
161 gain_astate_menu.set_name ("ArdourContextMenu");
162 gain_astyle_menu.set_name ("ArdourContextMenu");
164 gain_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &GainMeterBase::fader_moved));
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);
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));
173 UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &GainMeterBase::on_theme_changed));
174 UIConfiguration::instance().ColorsChanged.connect (sigc::bind(sigc::mem_fun (*this, &GainMeterBase::color_handler), false));
175 UIConfiguration::instance().DPIReset.connect (sigc::bind(sigc::mem_fun (*this, &GainMeterBase::color_handler), true));
178 GainMeterBase::~GainMeterBase ()
185 GainMeterBase::set_controls (boost::shared_ptr<Route> r,
186 boost::shared_ptr<PeakMeter> pm,
187 boost::shared_ptr<Amp> amp,
188 boost::shared_ptr<GainControl> control)
190 connections.clear ();
191 model_connections.drop_connections ();
193 /* no meter and no control? nothing to do ... */
195 if (!pm && !control) {
196 level_meter->set_meter (0);
197 gain_slider->set_controllable (boost::shared_ptr<PBD::Controllable>());
210 level_meter->set_meter (pm.get());
211 gain_slider->set_controllable (_control);
214 amp->ConfigurationChanged.connect (
215 model_connections, invalidator (*this), boost::bind (&GainMeterBase::setup_gain_adjustment, this), gui_context ()
219 setup_gain_adjustment ();
221 if (!_route || !_route->is_auditioner()) {
223 using namespace Menu_Helpers;
225 gain_astate_menu.items().clear ();
227 gain_astate_menu.items().push_back (MenuElem (S_("Automation|Manual"),
228 sigc::bind (sigc::mem_fun (*(amp.get()), &Automatable::set_parameter_automation_state),
229 Evoral::Parameter(GainAutomation), (AutoState) ARDOUR::Off)));
230 gain_astate_menu.items().push_back (MenuElem (_("Play"),
231 sigc::bind (sigc::mem_fun (*(amp.get()), &Automatable::set_parameter_automation_state),
232 Evoral::Parameter(GainAutomation), (AutoState) Play)));
233 gain_astate_menu.items().push_back (MenuElem (_("Write"),
234 sigc::bind (sigc::mem_fun (*(amp.get()), &Automatable::set_parameter_automation_state),
235 Evoral::Parameter(GainAutomation), (AutoState) Write)));
236 gain_astate_menu.items().push_back (MenuElem (_("Touch"),
237 sigc::bind (sigc::mem_fun (*(amp.get()), &Automatable::set_parameter_automation_state),
238 Evoral::Parameter(GainAutomation), (AutoState) Touch)));
240 connections.push_back (gain_automation_style_button.signal_button_press_event().connect (sigc::mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false));
241 connections.push_back (gain_automation_state_button.signal_button_press_event().connect (sigc::mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false));
243 _control->alist()->automation_state_changed.connect (model_connections, invalidator (*this), boost::bind (&GainMeter::gain_automation_state_changed, this), gui_context());
244 _control->alist()->automation_style_changed.connect (model_connections, invalidator (*this), boost::bind (&GainMeter::gain_automation_style_changed, this), gui_context());
246 gain_automation_state_changed ();
249 _control->Changed.connect (model_connections, invalidator (*this), boost::bind (&GainMeterBase::gain_changed, this), gui_context());
253 update_gain_sensitive ();
257 GainMeterBase::setup_gain_adjustment ()
263 if (_previous_amp_output_streams == _amp->output_streams ()) {
267 ignore_toggle = true;
269 if (_amp->output_streams().n_midi() <= _amp->output_streams().n_audio()) {
270 _data_type = DataType::AUDIO;
271 gain_adjustment.set_lower (GAIN_COEFF_ZERO);
272 gain_adjustment.set_upper (GAIN_COEFF_UNITY);
273 gain_adjustment.set_step_increment (dB_coeff_step(Config->get_max_gain()) / 10.0);
274 gain_adjustment.set_page_increment (dB_coeff_step(Config->get_max_gain()));
275 gain_slider->set_default_value (gain_to_slider_position (GAIN_COEFF_UNITY));
277 _data_type = DataType::MIDI;
278 gain_adjustment.set_lower (0.0);
279 gain_adjustment.set_upper (2.0);
280 gain_adjustment.set_step_increment (1.0/128.0);
281 gain_adjustment.set_page_increment (10.0/128.0);
282 gain_slider->set_default_value (1.0);
285 ignore_toggle = false;
287 effective_gain_display ();
289 _previous_amp_output_streams = _amp->output_streams ();
293 GainMeterBase::hide_all_meters ()
295 level_meter->hide_meters();
299 GainMeter::hide_all_meters ()
301 GainMeterBase::hide_all_meters ();
305 GainMeterBase::setup_meters (int len)
308 uint32_t meter_channels = 0;
310 meter_channels = _meter->input_streams().n_total();
312 meter_channels = _route->shared_peak_meter()->input_streams().n_total();
317 //meter_ticks1_area.show();
318 //meter_ticks2_area.show();
319 meter_metric_area.show();
320 if (meter_channels == 1) {
325 if (meter_channels > 1) {
328 //meter_ticks1_area.hide();
329 //meter_ticks2_area.hide();
330 meter_metric_area.hide();
333 level_meter->setup_meters(len, meter_width);
337 GainMeterBase::set_type (MeterType t)
339 level_meter->set_type(t);
343 GainMeter::setup_meters (int len)
348 uint32_t meter_channels = 0;
350 meter_channels = _meter->input_streams().n_total();
352 meter_channels = _route->shared_peak_meter()->input_streams().n_total();
354 hbox.set_homogeneous(meter_channels < 7 ? true : false);
358 hbox.set_homogeneous(false);
361 GainMeterBase::setup_meters (len);
365 GainMeter::set_type (MeterType t)
367 GainMeterBase::set_type (t);
371 GainMeterBase::gain_key_press (GdkEventKey* ev)
373 if (key_is_legal_for_numeric_entry (ev->keyval)) {
374 /* drop through to normal handling */
377 /* illegal key for gain entry */
382 GainMeterBase::peak_button_release (GdkEventButton* ev)
384 /* reset peak label */
386 if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) {
387 ResetAllPeakDisplays ();
388 } else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
390 ResetGroupPeakDisplays (_route->route_group());
393 ResetRoutePeakDisplays (_route.get());
400 GainMeterBase::reset_peak_display ()
403 level_meter->clear_meters();
404 max_peak = -INFINITY;
405 peak_display.set_text (_("-inf"));
406 peak_display.set_name ("MixerStripPeakDisplay");
410 GainMeterBase::reset_route_peak_display (Route* route)
412 if (_route && _route.get() == route) {
413 reset_peak_display ();
418 GainMeterBase::reset_group_peak_display (RouteGroup* group)
420 if (_route && group == _route->route_group()) {
421 reset_peak_display ();
426 GainMeterBase::popup_meter_menu (GdkEventButton *ev)
428 using namespace Menu_Helpers;
430 if (meter_menu == 0) {
431 meter_menu = new Gtk::Menu;
432 MenuList& items = meter_menu->items();
434 items.push_back (MenuElem ("-inf .. +0dBFS"));
435 items.push_back (MenuElem ("-10dB .. +0dBFS"));
436 items.push_back (MenuElem ("-4 .. +0dBFS"));
437 items.push_back (SeparatorElem());
438 items.push_back (MenuElem ("-inf .. -2dBFS"));
439 items.push_back (MenuElem ("-10dB .. -2dBFS"));
440 items.push_back (MenuElem ("-4 .. -2dBFS"));
443 meter_menu->popup (1, ev->time);
447 GainMeterBase::gain_focused (GdkEventFocus* ev)
450 gain_display.select_region (0, -1);
452 gain_display.select_region (0, 0);
458 GainMeterBase::gain_activated ()
463 // Switch to user's preferred locale so that
464 // if they use different LC_NUMERIC conventions,
465 // we will honor them.
468 if (sscanf (gain_display.get_text().c_str(), "%f", &f) != 1) {
473 /* clamp to displayable values */
474 if (_data_type == DataType::AUDIO) {
476 _control->set_value (dB_to_coefficient(f), Controllable::NoGroup);
478 f = min (fabs (f), 2.0f);
479 _control->set_value (f, Controllable::NoGroup);
482 if (gain_display.has_focus()) {
483 Gtk::Widget* w = gain_display.get_toplevel();
485 Gtk::Window* win = dynamic_cast<Gtk::Window*> (w);
487 /* sigh. gtkmm doesn't wrap get_default_widget() */
490 GtkWidget* f = gtk_window_get_default_widget (win->gobj());
492 gtk_widget_grab_focus (f);
501 GainMeterBase::show_gain ()
505 float v = gain_adjustment.get_value();
507 switch (_data_type) {
508 case DataType::AUDIO:
510 strcpy (buf, _("-inf"));
512 snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (slider_position_to_gain_with_max (v, Config->get_max_gain())));
516 snprintf (buf, sizeof (buf), "%.1f", v);
520 gain_display.set_text (buf);
524 GainMeterBase::fader_moved ()
526 if (!ignore_toggle) {
529 const gain_t master_gain = _control->get_master_gain ();
531 /* convert from adjustment range (0..1) to gain coefficient */
533 if (_data_type == DataType::AUDIO) {
535 if (_control->slaved ()) {
537 /* fader has been moved. The initial position of the fader
538 reflects any master gain (see ::gain_changed() below). So
539 when we reset the actual gain value, we have to remove the
540 influence of the master gain (if any).
542 but ... the fader is non-linear. a given number of dB will have a
543 relatively small effect on fader position far from the 0dB
544 position, and a larger effect near to it.
546 so... we take the current gain value, and compute where the
547 fader was BEFORE it was moved. Then we compute how the
548 position delta that the master gain caused.
550 once we have that value, we subtract it from the current
551 fader position, which gives us the current fader position as
552 if there was no master.
555 const gain_t current_value = _control->get_value (); /* current value */
556 const float position_delta_caused_by_master = gain_to_slider_position_with_max (current_value * master_gain, Config->get_max_gain()) -
557 gain_to_slider_position_with_max (current_value, Config->get_max_gain());
559 /* this is "where would the fader be now if the master
560 wan't changing things?"
563 const float adjusted_position = min (gain_adjustment.get_upper(), max (gain_adjustment.get_lower(), gain_adjustment.get_value() - position_delta_caused_by_master));
565 value = slider_position_to_gain_with_max (adjusted_position, Config->get_max_gain());
569 value = slider_position_to_gain_with_max (gain_adjustment.get_value(), Config->get_max_gain());
573 value = gain_adjustment.get_value();
576 if (_route && _control == _route->gain_control()) {
577 _route->set_gain (value, Controllable::UseGroup);
579 _control->set_value (value, Controllable::NoGroup);
587 GainMeterBase::effective_gain_display ()
589 gain_t fader_position = 0;
591 switch (_data_type) {
592 case DataType::AUDIO:
593 /* the position of the fader should reflect any master gain,
594 * not just the control's own inherent value
596 fader_position = gain_to_slider_position_with_max (_control->get_value() * _control->get_master_gain(), Config->get_max_gain());
599 fader_position = _control->get_value ();
603 if (gain_adjustment.get_value() != fader_position) {
604 ignore_toggle = true;
605 gain_adjustment.set_value (fader_position);
606 ignore_toggle = false;
611 GainMeterBase::gain_changed ()
613 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&GainMeterBase::effective_gain_display, this));
617 GainMeterBase::set_meter_strip_name (const char * name)
620 meter_metric_area.set_name (name);
621 sprintf(tmp, "Mark%sLeft", name);
622 meter_ticks1_area.set_name (tmp);
623 sprintf(tmp, "Mark%sRight", name);
624 meter_ticks2_area.set_name (tmp);
628 GainMeterBase::set_fader_name (const char * name)
630 gain_slider->set_name (name);
634 GainMeterBase::update_gain_sensitive ()
636 bool x = !(_control->alist()->automation_state() & Play);
637 static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive (x);
641 next_meter_point (MeterPoint mp)
645 return MeterPreFader;
649 return MeterPostFader;
665 abort(); /*NOTREACHED*/
670 GainMeterBase::meter_press(GdkEventButton* ev)
672 wait_for_release = false;
678 if (!ignore_toggle) {
680 if (Keyboard::is_context_menu_event (ev)) {
682 // no menu at this time.
686 if (Keyboard::is_button2_event(ev)) {
688 // Primary-button2 click is the midi binding click
689 // button2-click is "momentary"
691 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
692 wait_for_release = true;
693 old_meter_point = _route->meter_point ();
697 if (_route && (ev->button == 1 || Keyboard::is_button2_event (ev))) {
699 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
701 /* Primary+Tertiary-click applies change to all routes */
703 _session->foreach_route (this, &GainMeterBase::set_meter_point, next_meter_point (_route->meter_point()));
706 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
708 /* Primary-click: solo mix group.
709 NOTE: Primary-button2 is MIDI learn.
712 if (ev->button == 1) {
713 set_route_group_meter_point (*_route, next_meter_point (_route->meter_point()));
718 /* click: change just this route */
722 _route->set_meter_point (next_meter_point (_route->meter_point()));
733 GainMeterBase::meter_release(GdkEventButton*)
735 if (!ignore_toggle) {
736 if (wait_for_release) {
737 wait_for_release = false;
740 set_meter_point (*_route, old_meter_point);
749 GainMeterBase::set_meter_point (Route& route, MeterPoint mp)
751 route.set_meter_point (mp);
755 GainMeterBase::set_route_group_meter_point (Route& route, MeterPoint mp)
757 RouteGroup* route_group;
759 if ((route_group = route.route_group ()) != 0) {
760 route_group->foreach_route (boost::bind (&Route::set_meter_point, _1, mp, false));
762 route.set_meter_point (mp);
767 GainMeterBase::meter_point_clicked ()
775 GainMeterBase::amp_start_touch ()
777 _control->start_touch (_control->session().transport_frame());
781 GainMeterBase::amp_stop_touch ()
783 _control->stop_touch (false, _control->session().transport_frame());
787 GainMeterBase::gain_automation_state_button_event (GdkEventButton *ev)
789 if (ev->type == GDK_BUTTON_RELEASE) {
793 switch (ev->button) {
795 gain_astate_menu.popup (1, ev->time);
805 GainMeterBase::gain_automation_style_button_event (GdkEventButton *ev)
807 if (ev->type == GDK_BUTTON_RELEASE) {
811 switch (ev->button) {
813 gain_astyle_menu.popup (1, ev->time);
822 GainMeterBase::astate_string (AutoState state)
824 return _astate_string (state, false);
828 GainMeterBase::short_astate_string (AutoState state)
830 return _astate_string (state, true);
834 GainMeterBase::_astate_string (AutoState state, bool shrt)
840 sstr = (shrt ? "M" : _("M"));
843 sstr = (shrt ? "P" : _("P"));
846 sstr = (shrt ? "T" : _("T"));
849 sstr = (shrt ? "W" : _("W"));
857 GainMeterBase::astyle_string (AutoStyle style)
859 return _astyle_string (style, false);
863 GainMeterBase::short_astyle_string (AutoStyle style)
865 return _astyle_string (style, true);
869 GainMeterBase::_astyle_string (AutoStyle style, bool shrt)
874 /* XXX it might different in different languages */
876 return (shrt ? _("Abs") : _("Abs"));
881 GainMeterBase::gain_automation_style_changed ()
885 gain_automation_style_button.set_text (astyle_string(_control->alist()->automation_style()));
888 gain_automation_style_button.set_text (short_astyle_string(_control->alist()->automation_style()));
894 GainMeterBase::gain_automation_state_changed ()
896 ENSURE_GUI_THREAD (*this, &GainMeterBase::gain_automation_state_changed);
900 gain_automation_state_button.set_text (astate_string(_control->alist()->automation_state()));
903 gain_automation_state_button.set_text (short_astate_string(_control->alist()->automation_state()));
907 const bool automation_watch_required = (_control->alist()->automation_state() != ARDOUR::Off);
909 if (gain_automation_state_button.get_active() != automation_watch_required) {
910 ignore_toggle = true;
911 gain_automation_state_button.set_active (automation_watch_required);
912 ignore_toggle = false;
915 update_gain_sensitive ();
917 gain_watching.disconnect();
919 if (automation_watch_required) {
920 /* start watching automation so that things move */
921 gain_watching = Timers::rapid_connect (sigc::mem_fun (*this, &GainMeterBase::effective_gain_display));
923 /* update once to get the correct value shown as we re-enter off/manual mode */
924 effective_gain_display();
929 GainMeterBase::meter_channels() const
931 if (_meter) { return _meter->input_streams(); }
932 else { return ChanCount(); }
935 GainMeterBase::update_meters()
938 float mpeak = level_meter->update_meters();
940 if (mpeak > max_peak) {
942 if (mpeak <= -200.0f) {
943 peak_display.set_text (_("-inf"));
945 snprintf (buf, sizeof(buf), "%.1f", mpeak);
946 peak_display.set_text (buf);
949 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
950 peak_display.set_name ("MixerStripPeakDisplayPeak");
954 void GainMeterBase::color_handler(bool /*dpi*/)
960 GainMeterBase::set_width (Width w, int len)
964 if (_width == Wide && _route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
967 level_meter->setup_meters(len, meter_width);
972 GainMeterBase::on_theme_changed()
977 GainMeterBase::redraw_metrics()
979 meter_metric_area.queue_draw ();
980 meter_ticks1_area.queue_draw ();
981 meter_ticks2_area.queue_draw ();
984 #define PX_SCALE(pxmin, dflt) rint(std::max((double)pxmin, (double)dflt * UIConfiguration::instance().get_ui_scale()))
986 GainMeter::GainMeter (Session* s, int fader_length)
987 : GainMeterBase (s, false, fader_length, 24)
988 , gain_display_box(true, 0)
991 if (gain_display.get_parent()) {
992 gain_display.get_parent()->remove (gain_display);
994 gain_display_box.pack_start (gain_display, true, true);
996 if (peak_display.get_parent()) {
997 peak_display.get_parent()->remove (gain_display);
999 gain_display_box.pack_start (peak_display, true, true);
1001 meter_metric_area.set_name ("AudioTrackMetrics");
1002 meter_metric_area.set_size_request(PX_SCALE(24, 24), -1);
1004 gain_automation_style_button.set_name ("mixer strip button");
1005 gain_automation_state_button.set_name ("mixer strip button");
1007 set_tooltip (gain_automation_state_button, _("Fader automation mode"));
1008 set_tooltip (gain_automation_style_button, _("Fader automation type"));
1010 gain_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
1011 gain_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
1013 gain_automation_state_button.set_size_request (PX_SCALE(12, 15), PX_SCALE(12, 15));
1014 gain_automation_style_button.set_size_request (PX_SCALE(12, 15), PX_SCALE(12, 15));
1016 fader_vbox = manage (new Gtk::VBox());
1017 fader_vbox->set_spacing (0);
1018 fader_vbox->pack_start (*gain_slider, true, true);
1020 fader_alignment.set (0.5, 0.5, 0.0, 1.0);
1021 fader_alignment.add (*fader_vbox);
1023 hbox.pack_start (fader_alignment, true, true);
1025 set_spacing (PX_SCALE(2, 2));
1027 pack_start (gain_display_box, Gtk::PACK_SHRINK);
1028 pack_start (hbox, true, true);
1030 meter_alignment.set (0.5, 0.5, 0.0, 1.0);
1031 meter_alignment.add (*level_meter);
1033 meter_metric_area.signal_expose_event().connect (
1034 sigc::mem_fun(*this, &GainMeter::meter_metrics_expose));
1036 meter_ticks1_area.set_size_request (PX_SCALE(3, 3), -1);
1037 meter_ticks2_area.set_size_request (PX_SCALE(3, 3), -1);
1039 meter_ticks1_area.signal_expose_event().connect (
1040 sigc::mem_fun(*this, &GainMeter::meter_ticks1_expose));
1041 meter_ticks2_area.signal_expose_event().connect (
1042 sigc::mem_fun(*this, &GainMeter::meter_ticks2_expose));
1044 meter_hbox.pack_start (meter_ticks1_area, false, false);
1045 meter_hbox.pack_start (meter_alignment, false, false);
1046 meter_hbox.pack_start (meter_ticks2_area, false, false);
1047 meter_hbox.pack_start (meter_metric_area, false, false);
1051 GainMeter::~GainMeter () { }
1054 GainMeter::set_controls (boost::shared_ptr<Route> r,
1055 boost::shared_ptr<PeakMeter> meter,
1056 boost::shared_ptr<Amp> amp,
1057 boost::shared_ptr<GainControl> control)
1059 if (meter_hbox.get_parent()) {
1060 hbox.remove (meter_hbox);
1063 // if (gain_automation_state_button.get_parent()) {
1064 // fader_vbox->remove (gain_automation_state_button);
1067 GainMeterBase::set_controls (r, meter, amp, control);
1070 _meter->ConfigurationChanged.connect (
1071 model_connections, invalidator (*this), boost::bind (&GainMeter::meter_configuration_changed, this, _1), gui_context()
1073 _meter->TypeChanged.connect (
1074 model_connections, invalidator (*this), boost::bind (&GainMeter::meter_type_changed, this, _1), gui_context()
1077 meter_configuration_changed (_meter->input_streams ());
1082 _route->active_changed.connect (model_connections, invalidator (*this), boost::bind (&GainMeter::route_active_changed, this), gui_context ());
1086 if we have a non-hidden route (ie. we're not the click or the auditioner),
1087 pack some route-dependent stuff.
1090 hbox.pack_start (meter_hbox, true, true);
1092 // if (r && !r->is_auditioner()) {
1093 // fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
1101 GainMeter::get_gm_width ()
1103 Gtk::Requisition sz;
1106 meter_metric_area.size_request (sz);
1108 level_meter->size_request (sz);
1111 fader_alignment.size_request (sz);
1113 return max(sz.width * 2, min_w * 2) + 6;
1115 return sz.width + min_w + 6;
1120 GainMeter::meter_metrics_expose (GdkEventExpose *ev)
1123 if (_types.empty()) { _types.push_back(DataType::AUDIO); }
1124 return meter_expose_metrics(ev, MeterPeak, _types, &meter_metric_area);
1126 return meter_expose_metrics(ev, _route->meter_type(), _types, &meter_metric_area);
1130 GainMeter::meter_ticks1_expose (GdkEventExpose *ev)
1133 if (_types.empty()) { _types.push_back(DataType::AUDIO); }
1134 return meter_expose_ticks(ev, MeterPeak, _types, &meter_ticks1_area);
1136 return meter_expose_ticks(ev, _route->meter_type(), _types, &meter_ticks1_area);
1140 GainMeter::meter_ticks2_expose (GdkEventExpose *ev)
1143 if (_types.empty()) { _types.push_back(DataType::AUDIO); }
1144 return meter_expose_ticks(ev, MeterPeak, _types, &meter_ticks2_area);
1146 return meter_expose_ticks(ev, _route->meter_type(), _types, &meter_ticks2_area);
1150 GainMeter::on_style_changed (const Glib::RefPtr<Gtk::Style>&)
1152 gain_display.queue_draw();
1153 peak_display.queue_draw();
1156 boost::shared_ptr<PBD::Controllable>
1157 GainMeterBase::get_controllable()
1162 return boost::shared_ptr<PBD::Controllable>();
1167 GainMeterBase::level_meter_button_press (GdkEventButton* ev)
1169 return static_cast<bool>(LevelMeterButtonPress (ev)); /* EMIT SIGNAL */
1173 GainMeter::meter_configuration_changed (ChanCount c)
1178 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1179 if (c.get (*i) > 0) {
1180 _types.push_back (*i);
1186 && boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
1187 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0
1189 if (_route->active()) {
1190 set_meter_strip_name ("AudioBusMetrics");
1192 set_meter_strip_name ("AudioBusMetricsInactive");
1196 (type == (1 << DataType::MIDI))
1197 || (_route && boost::dynamic_pointer_cast<MidiTrack>(_route))
1199 if (!_route || _route->active()) {
1200 set_meter_strip_name ("MidiTrackMetrics");
1202 set_meter_strip_name ("MidiTrackMetricsInactive");
1205 else if (type == (1 << DataType::AUDIO)) {
1206 if (!_route || _route->active()) {
1207 set_meter_strip_name ("AudioTrackMetrics");
1209 set_meter_strip_name ("AudioTrackMetricsInactive");
1212 if (!_route || _route->active()) {
1213 set_meter_strip_name ("AudioMidiTrackMetrics");
1215 set_meter_strip_name ("AudioMidiTrackMetricsInactive");
1220 meter_clear_pattern_cache(4);
1221 on_style_changed(Glib::RefPtr<Gtk::Style>());
1225 GainMeter::route_active_changed ()
1228 meter_configuration_changed (_meter->input_streams ());
1233 GainMeter::meter_type_changed (MeterType t)
1235 _route->set_meter_type(t);