480786eb2c3317a0917b7e2a08ecffa89c33b060
[ardour.git] / gtk2_ardour / monitor_section.cc
1 #include <gdkmm/pixbuf.h>
2
3 #include "pbd/compose.h"
4 #include "pbd/error.h"
5
6 #include "gtkmm2ext/bindable_button.h"
7 #include "gtkmm2ext/tearoff.h"
8 #include "gtkmm2ext/actions.h"
9
10 #include "ardour/dB.h"
11 #include "ardour/monitor_processor.h"
12 #include "ardour/route.h"
13 #include "ardour/utils.h"
14
15 #include "ardour_ui.h"
16 #include "monitor_section.h"
17 #include "public_editor.h"
18 #include "utils.h"
19 #include "volume_controller.h"
20
21 #include "i18n.h"
22
23 using namespace ARDOUR;
24 using namespace Gtk;
25 using namespace Gtkmm2ext;
26 using namespace PBD;
27 using namespace std;
28
29 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
30 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
31 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
32
33 MonitorSection::MonitorSection (Session* s)
34         : AxisView (s)
35         , RouteUI (s)
36         , main_table (2, 3)
37         , meter (s)
38         , _tearoff (0)
39         , gain_adjustment (1.0, 0.0, 1.0, 0.01, 0.1)
40         , gain_control (0)
41         , dim_adjustment (0.2, 0.0, 1.0, 0.01, 0.1) 
42         , dim_control (0)
43         , solo_boost_adjustment (1.0, 1.0, 2.0, 0.01, 0.1) 
44         , solo_boost_control (0)
45         , solo_in_place_button (solo_model_group, _("SiP"))
46         , afl_button (solo_model_group, _("AFL"))
47         , pfl_button (solo_model_group, _("PFL"))
48         , cut_all_button (_("MUTE"))
49         , dim_all_button (_("dim"))
50         , mono_button (_("mono"))
51         , rude_solo_button (_("soloing"))
52
53 {
54         Glib::RefPtr<Action> act;
55
56         if (!monitor_actions) {
57
58                 /* do some static stuff */
59
60                 register_actions ();
61
62         }
63         
64         set_session (s);
65         
66         VBox* sub_knob_packer = manage (new VBox);
67         sub_knob_packer->set_spacing (12);
68
69         VBox* spin_packer;
70         Label* spin_label;
71
72         gain_control = new VolumeController (big_knob_pixbuf, &gain_adjustment, true);
73         gain_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::gain_value_changed));
74         gain_control->spinner().signal_output().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::nonlinear_gain_printer), 
75                                                                      &gain_control->spinner()));
76
77         spin_label = manage (new Label (_("Gain (dB)")));
78         spin_packer = manage (new VBox);
79         spin_packer->show ();
80         spin_packer->set_spacing (6);
81         spin_packer->pack_start (*gain_control, false, false);
82         spin_packer->pack_start (*spin_label, false, false);
83
84         sub_knob_packer->pack_start (*spin_packer, false, false);
85                 
86         dim_control = new VolumeController (little_knob_pixbuf, &dim_adjustment, true, 30, 30);
87         dim_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::dim_level_changed));
88         dim_control->spinner().signal_output().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::linear_gain_printer), 
89                                                                     &dim_control->spinner()));
90
91         HBox* dim_packer = manage (new HBox);
92         dim_packer->show ();
93
94         spin_label = manage (new Label (_("Dim Cut (dB)")));
95         spin_packer = manage (new VBox);
96         spin_packer->show ();
97         spin_packer->set_spacing (6);
98         spin_packer->pack_start (*dim_control, false, false);
99         spin_packer->pack_start (*spin_label, false, false); 
100
101         dim_packer->set_spacing (12);
102         dim_packer->pack_start (*spin_packer, false, false);
103
104         VBox* keep_dim_under_vertical_size_control = manage (new VBox);
105         keep_dim_under_vertical_size_control->pack_start (dim_all_button, true, false);
106         keep_dim_under_vertical_size_control->show ();
107         dim_all_button.set_size_request (40,40);
108         dim_all_button.show ();
109
110         dim_packer->pack_start (*keep_dim_under_vertical_size_control, false, false);
111         sub_knob_packer->pack_start (*dim_packer, false, true);
112
113         solo_boost_control = new VolumeController (little_knob_pixbuf, &solo_boost_adjustment, true, 30, 30);
114         solo_boost_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::solo_boost_changed));
115         solo_boost_control->spinner().signal_output().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::linear_gain_printer),
116                                                                            &solo_boost_control->spinner()));
117
118         HBox* solo_packer = manage (new HBox);
119         solo_packer->show ();
120
121         spin_label = manage (new Label (_("Solo Boost (dB)")));
122         spin_packer = manage (new VBox);
123         spin_packer->show ();
124         spin_packer->set_spacing (6);
125         spin_packer->pack_start (*solo_boost_control, false, false);
126         spin_packer->pack_start (*spin_label, false, false); 
127
128         VBox* keep_rude_solo_under_vertical_size_control = manage (new VBox);
129         keep_rude_solo_under_vertical_size_control->show ();
130         keep_rude_solo_under_vertical_size_control->pack_start (rude_solo_button, true, false);
131
132         solo_packer->set_spacing (12);
133         solo_packer->pack_start (*spin_packer, false, false);
134         solo_packer->pack_start (*keep_rude_solo_under_vertical_size_control, true, false);
135
136         rude_solo_button.set_name ("TransportSoloAlert");
137         rude_solo_button.show ();
138
139         ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::solo_blink));
140         rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo));
141         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
142
143         sub_knob_packer->pack_start (*solo_packer, false, true);
144
145         knob_packer.pack_start (*sub_knob_packer, false, true);
146
147         sub_knob_packer->show ();
148         knob_packer.show ();
149         gain_control->show_all ();
150         dim_control->show_all ();
151         solo_boost_control->show_all ();
152
153         meter.set_meter (&_route->peak_meter());
154         meter.setup_meters (300, 5);
155         
156         table_knob_packer.pack_start (main_table, true, true);
157         table_knob_packer.pack_start (knob_packer, false, false);
158
159         table_knob_packer.show ();
160
161         solo_model_box.set_spacing (6);
162         solo_model_box.pack_start (solo_in_place_button, false, false);
163         solo_model_box.pack_start (afl_button, false, false);
164         solo_model_box.pack_start (pfl_button, false, false);
165
166         solo_in_place_button.show ();
167         afl_button.show ();
168         pfl_button.show ();
169         solo_model_box.show ();
170
171         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
172         if (act) {
173                 act->connect_proxy (solo_in_place_button);
174         } 
175
176         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
177         if (act) {
178                 act->connect_proxy (afl_button);
179         } 
180
181         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
182         if (act) {
183                 act->connect_proxy (pfl_button);
184         } 
185
186         upper_packer.pack_start (solo_model_box, false, false);
187
188         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
189         if (act) {
190                 act->connect_proxy (cut_all_button);
191         } 
192
193         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
194         if (act) {
195                 act->connect_proxy (dim_all_button);
196         } 
197
198         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
199         if (act) {
200                 act->connect_proxy (mono_button);
201         } 
202
203         cut_all_button.set_size_request (50,50);
204         cut_all_button.show ();
205
206         lower_packer.set_spacing (12);
207         lower_packer.pack_start (mono_button, false, false);
208         lower_packer.pack_start (cut_all_button, false, false);
209
210         vpacker.set_border_width (12);
211         vpacker.set_spacing (12);
212         vpacker.pack_start (upper_packer, false, false);
213         vpacker.pack_start (table_knob_packer, false, false);
214         vpacker.pack_start (lower_packer, false, false);
215
216         VBox* keep_meter_under_control = manage (new VBox);
217         keep_meter_under_control->pack_start (meter, false, false);
218         keep_meter_under_control->show ();
219
220         hpacker.set_border_width (12);
221         hpacker.set_spacing (12);
222         hpacker.pack_start (*keep_meter_under_control, false, false);
223         hpacker.pack_start (vpacker, true, true);
224
225         main_table.show ();
226         hpacker.show ();
227         upper_packer.show ();
228         lower_packer.show ();
229         vpacker.show ();
230         meter.show_all ();
231
232         populate_buttons ();
233         map_state ();
234
235         _tearoff = new TearOff (hpacker);
236
237         /* if torn off, make this a normal window */
238         _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
239         _tearoff->tearoff_window().set_title (X_("Monitor"));
240         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
241 }
242
243 MonitorSection::~MonitorSection ()
244 {
245         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
246                 delete *i;
247         }
248
249         _channel_buttons.clear ();
250
251         delete gain_control;
252         delete dim_control;
253         delete solo_boost_control;
254         delete _tearoff;
255 }
256
257 void
258 MonitorSection::set_session (Session* s)
259 {
260         AxisView::set_session (s);
261
262         if (_session) {
263
264                 _route = _session->control_out ();
265
266                 if (_route) {
267                         /* session with control outs */
268                         _monitor = _route->monitor_control ();
269                         meter.set_meter (&_route->peak_meter());
270                 } else { 
271                         /* session with no control outs */
272                         _monitor.reset ();
273                         _route.reset ();
274                         meter.set_meter (0);
275                 }
276                         
277         } else {
278                 /* no session */
279                 _monitor.reset ();
280                 _route.reset ();
281                 meter.set_meter (0);
282         }
283
284         /* both might be null */
285 }
286
287 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
288         : cut (X_(""))
289         , dim (X_(""))
290         , solo (X_(""))
291         , invert (X_(""))
292 {
293         cut.set_name (X_("MixerMuteButton"));
294         dim.set_name (X_("MixerMuteButton"));
295         solo.set_name (X_("MixerSoloButton"));
296
297         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (cut.gobj()), false);
298         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (dim.gobj()), false);
299         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (invert.gobj()), false);
300         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (solo.gobj()), false);
301 }
302
303 void
304 MonitorSection::populate_buttons ()
305 {
306         if (!_monitor) {
307                 return;
308         }
309
310         Glib::RefPtr<Action> act;
311         uint32_t nchans = _monitor->output_streams().n_audio();
312         
313         main_table.resize (nchans+1, 5);
314         main_table.set_col_spacings (6);
315         main_table.set_row_spacings (6);
316         main_table.set_homogeneous (true);
317
318         Label* l1 = manage (new Label (X_("out")));
319         main_table.attach (*l1, 0, 1, 0, 1, SHRINK|FILL, SHRINK|FILL);
320         l1 = manage (new Label (X_("cut")));
321         main_table.attach (*l1, 1, 2, 0, 1, SHRINK|FILL, SHRINK|FILL);
322         l1 = manage (new Label (X_("dim")));
323         main_table.attach (*l1, 2, 3, 0, 1, SHRINK|FILL, SHRINK|FILL);
324         l1 = manage (new Label (X_("solo")));
325         main_table.attach (*l1, 3, 4, 0, 1, SHRINK|FILL, SHRINK|FILL);
326         l1 = manage (new Label (X_("inv")));
327         main_table.attach (*l1, 4, 5, 0, 1, SHRINK|FILL, SHRINK|FILL);
328
329         const uint32_t row_offset = 1;
330
331         for (uint32_t i = 0; i < nchans; ++i) {
332                 
333                 string l;
334                 char buf[64];
335
336                 if (nchans == 2) {
337                         if (i == 0) {
338                                 l = "L";
339                         } else {
340                                 l = "R";
341                         }
342                 } else {
343                         char buf[32];
344                         snprintf (buf, sizeof (buf), "%d", i+1);
345                         l = buf;
346                 }
347
348                 Label* label = manage (new Label (l));
349                 main_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
350
351                 ChannelButtonSet* cbs = new ChannelButtonSet;
352
353                 _channel_buttons.push_back (cbs);
354
355                 main_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
356                 main_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL); 
357                 main_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
358                 main_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
359                
360                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
361                 act = ActionManager::get_action (X_("Monitor"), buf);
362                 if (act) {
363                         act->connect_proxy (cbs->cut);
364                 } 
365
366                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
367                 act = ActionManager::get_action (X_("Monitor"), buf);
368                 if (act) {
369                         act->connect_proxy (cbs->dim);
370                 }
371
372                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
373                 act = ActionManager::get_action (X_("Monitor"), buf);
374                 if (act) {
375                         act->connect_proxy (cbs->solo);
376                 }
377
378                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
379                 act = ActionManager::get_action (X_("Monitor"), buf);
380                 if (act) {
381                         act->connect_proxy (cbs->invert);
382                 }
383         }
384
385         main_table.show_all ();
386 }
387
388 void 
389 MonitorSection::set_button_names ()
390 {
391         rec_enable_button_label.set_text ("rec");
392         mute_button_label.set_text ("rec");
393         solo_button_label.set_text ("rec");
394 }
395
396 Widget&
397 MonitorSection::pack_widget () const
398 {
399         return *_tearoff;
400 }
401
402 void
403 MonitorSection::dim_all ()
404 {
405         if (!_monitor) {
406                 return;
407         }
408
409         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
410         if (act) {
411                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
412                 _monitor->set_dim_all (tact->get_active());
413         }
414
415 }
416
417 void
418 MonitorSection::cut_all ()
419 {
420         if (!_monitor) {
421                 return;
422         }
423
424         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
425         if (act) {
426                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
427                 _monitor->set_cut_all (tact->get_active());
428         }
429 }
430
431 void
432 MonitorSection::mono ()
433 {
434         if (!_monitor) {
435                 return;
436         }
437
438         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
439         if (act) {
440                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
441                 _monitor->set_mono (tact->get_active());
442         }
443 }
444
445 void
446 MonitorSection::cut_channel (uint32_t chn)
447 {
448         if (!_monitor) {
449                 return;
450         }
451
452         char buf[64];
453         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
454
455         --chn; // 0-based in backend
456
457         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
458         if (act) {
459                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
460                 _monitor->set_cut (chn, tact->get_active());
461         }
462 }
463
464 void
465 MonitorSection::dim_channel (uint32_t chn)
466 {
467         if (!_monitor) {
468                 return;
469         }
470
471         char buf[64];
472         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
473
474         --chn; // 0-based in backend
475
476         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
477         if (act) {
478                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
479                 _monitor->set_dim (chn, tact->get_active());
480         }
481
482 }
483
484 void
485 MonitorSection::solo_channel (uint32_t chn)
486 {
487         if (!_monitor) {
488                 return;
489         }
490
491         char buf[64];
492         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
493
494         --chn; // 0-based in backend
495
496         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
497         if (act) {
498                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
499                 _monitor->set_solo (chn, tact->get_active());
500         }
501
502 }
503
504 void
505 MonitorSection::invert_channel (uint32_t chn)
506 {
507         if (!_monitor) {
508                 return;
509         }
510
511         char buf[64];
512         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
513
514         --chn; // 0-based in backend
515
516         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
517         if (act) {
518                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
519                 _monitor->set_polarity (chn, tact->get_active());
520         } 
521 }
522
523 void
524 MonitorSection::register_actions ()
525 {
526         string action_name;
527         string action_descr;
528
529         monitor_actions = ActionGroup::create (X_("Monitor"));
530         ActionManager::add_action_group (monitor_actions);
531
532         ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", 
533                                                sigc::mem_fun (*this, &MonitorSection::mono));
534
535         ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", 
536                                                sigc::mem_fun (*this, &MonitorSection::cut_all));
537
538         ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", 
539                                                sigc::mem_fun (*this, &MonitorSection::dim_all));
540
541         /* note the 1-based counting (for naming - backend uses 0-based) */
542
543         for (uint32_t chn = 1; chn <= 16; ++chn) {
544
545                 /* for the time being, do not use the action description because it always
546                    shows up in the buttons, which is undesirable.
547                 */
548
549                 action_name = string_compose (X_("monitor-cut-%1"), chn);
550                 action_descr = string_compose (_("Cut Monitor Chn %1"), chn);
551                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", 
552                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
553
554                 action_name = string_compose (X_("monitor-dim-%1"), chn);
555                 action_descr = string_compose (_("Dim Monitor Chn %1"), chn+1);
556                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", 
557                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
558
559                 action_name = string_compose (X_("monitor-solo-%1"), chn);
560                 action_descr = string_compose (_("Solo Monitor Chn %1"), chn);
561                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", 
562                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
563
564                 action_name = string_compose (X_("monitor-invert-%1"), chn);
565                 action_descr = string_compose (_("Invert Monitor Chn %1"), chn);
566                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", 
567                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
568
569         }
570
571
572         Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
573         RadioAction::Group solo_group;
574
575         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "",
576                                               sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
577         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "",
578                                               sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
579         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "",
580                                               sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
581
582         ActionManager::add_action_group (solo_actions);
583 }
584
585 void
586 MonitorSection::solo_use_in_place ()
587 {
588         /* this is driven by a toggle on a radio group, and so is invoked twice,
589            once for the item that became inactive and once for the one that became
590            active.
591         */
592
593         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
594
595         if (act) {
596                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
597                 if (ract) {
598                         Config->set_solo_control_is_listen_control (!ract->get_active());
599                 }
600         }
601 }
602
603 void
604 MonitorSection::solo_use_afl ()
605 {
606         /* this is driven by a toggle on a radio group, and so is invoked twice,
607            once for the item that became inactive and once for the one that became
608            active.
609         */
610         
611         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
612         if (act) {
613                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
614                 if (ract) {
615                         if (ract->get_active()) {
616                                 Config->set_listen_position (AfterFaderListen);
617                                 Config->set_solo_control_is_listen_control (true);
618                         }
619                 }
620         }
621 }
622
623 void
624 MonitorSection::solo_use_pfl ()
625 {
626         /* this is driven by a toggle on a radio group, and so is invoked twice,
627            once for the item that became inactive and once for the one that became
628            active.
629         */
630
631         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
632         if (act) {
633                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
634                 if (ract) {
635                         if (ract->get_active()) {
636                                 Config->set_listen_position (PreFaderListen);
637                                 Config->set_solo_control_is_listen_control (true);
638                         }
639                 }
640         }
641 }
642
643 void
644 MonitorSection::fast_update ()
645 {
646         meter.update_meters ();
647 }
648
649 void
650 MonitorSection::setup_knob_images ()
651 {
652         try {
653                 
654                 big_knob_pixbuf = ::get_icon ("knob");
655                 
656         }  catch (...) {
657                 
658                 error << "No knob image found (or not loadable) at "
659                       << " .... "
660                       << endmsg;
661                 throw failed_constructor ();
662         }
663         
664         try {
665                 
666                 little_knob_pixbuf = ::get_icon ("littleknob");
667                 
668         }  catch (...) {
669                 
670                 error << "No knob image found (or not loadable) at "
671                       << " .... "
672                       << endmsg;
673                 throw failed_constructor ();
674         }
675 }
676
677 void
678 MonitorSection::gain_value_changed ()
679 {
680         if (_route) {
681                 _route->set_gain (slider_position_to_gain (gain_adjustment.get_value()), this);
682         }
683 }
684
685 void
686 MonitorSection::dim_level_changed ()
687 {
688         if (_monitor) {
689                 _monitor->set_dim_level (dim_adjustment.get_value());
690         }
691 }
692
693 void
694 MonitorSection::solo_boost_changed ()
695 {
696         if (_monitor) {
697                 _monitor->set_solo_boost_level (solo_boost_adjustment.get_value());
698         }
699 }
700
701 bool
702 MonitorSection::nonlinear_gain_printer (SpinButton* button)
703 {
704         double val = button->get_adjustment()->get_value();
705         char buf[16];
706         snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (slider_position_to_gain (val)));
707         button->set_text (buf);
708         return true;
709 }
710
711 bool
712 MonitorSection::linear_gain_printer (SpinButton* button)
713 {
714         double val = button->get_adjustment()->get_value();
715         char buf[16];
716         snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (val));
717         button->set_text (buf);
718         return true;
719 }
720
721 void
722 MonitorSection::map_state ()
723 {
724         if (!_route || !_monitor) {
725                 return;
726         }
727
728         gain_control->get_adjustment()->set_value (gain_to_slider_position (_route->gain_control()->get_value()));
729         dim_control->get_adjustment()->set_value (_monitor->dim_level());
730         solo_boost_control->get_adjustment()->set_value (_monitor->solo_boost_level());
731
732         const char *action_name;
733
734         if (Config->get_solo_control_is_listen_control()) {
735                 switch (Config->get_listen_position()) {
736                 case AfterFaderListen:
737                         action_name = X_("solo-use-afl");
738                         break;
739                 case PreFaderListen:
740                         action_name = X_("solo-use-afl");
741                         break;
742                 }
743         } else {
744                 action_name = X_("solo-use-in-place");
745         }
746         
747         Glib::RefPtr<Action> act;
748         
749         act = ActionManager::get_action (X_("Solo"), action_name);
750         if (act) {
751                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
752                 if (ract) {
753                         ract->set_active (true);
754                 }
755         }
756
757         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
758         if (act) {
759                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
760                 if (tact) {
761                         cerr << "Set monitor cut all action to " << _monitor->cut_all () << endl;
762                         tact->set_active (_monitor->cut_all());
763                 } else {
764                         cerr << " no global cut action\n";
765                 }
766         } else {
767                 cerr << " no global cut action2\n";
768         }
769
770         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
771         if (act) {
772                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
773                 if (tact) {
774                         tact->set_active (_monitor->dim_all());
775                 }
776         }
777         
778         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
779         if (act) {
780                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
781                 if (tact) {
782                         tact->set_active (_monitor->mono());
783                 }
784         }
785
786         uint32_t nchans = _monitor->output_streams().n_audio();
787
788         assert (nchans == _channel_buttons.size ());
789
790         for (uint32_t n = 0; n < nchans; ++n) {
791
792                 char action_name[32];
793
794                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n+1);
795                 act = ActionManager::get_action (X_("Monitor"), action_name);
796                 if (act) {
797                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
798                         if (tact) {
799                                 tact->set_active (_monitor->cut (n));
800                         }
801                 }
802
803                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n+1);
804                 act = ActionManager::get_action (X_("Monitor"), action_name);
805                 if (act) {
806                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
807                         if (tact) {
808                                 tact->set_active (_monitor->dimmed (n));
809                         }
810                 }
811
812                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n+1);
813                 act = ActionManager::get_action (X_("Monitor"), action_name);
814                 if (act) {
815                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
816                         if (tact) {
817                                 tact->set_active (_monitor->soloed (n));
818                         }
819                 }
820
821                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n+1);
822                 act = ActionManager::get_action (X_("Monitor"), action_name);
823                 if (act) {
824                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
825                         if (tact) {
826                                 tact->set_active (_monitor->inverted (n));
827                         }
828                 }
829         }
830 }
831
832 void
833 MonitorSection::solo_blink (bool onoff)
834 {
835         if (_session == 0) {
836                 return;
837         }
838
839         if (_session->soloing() || _session->listening()) {
840                 if (onoff) {
841                         rude_solo_button.set_state (STATE_ACTIVE);
842                 } else {
843                         rude_solo_button.set_state (STATE_NORMAL);
844                 }
845         } else {
846                 rude_solo_button.set_active (false);
847                 rude_solo_button.set_state (STATE_NORMAL);
848         }
849 }
850
851 bool
852 MonitorSection::cancel_solo (GdkEventButton* ev)
853 {
854         if (_session && _session->soloing()) {
855                 _session->set_solo (_session->get_routes(), false);
856         }
857
858         return true;
859 }