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