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