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