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