bd12ad306b7e5d6e6be471c1f299bbf438de42f1
[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 #include "gtkmm2ext/motionfeedback.h"
10
11 #include "ardour/dB.h"
12 #include "ardour/monitor_processor.h"
13 #include "ardour/route.h"
14 #include "ardour/utils.h"
15
16 #include "ardour_ui.h"
17 #include "gui_thread.h"
18 #include "monitor_section.h"
19 #include "public_editor.h"
20 #include "volume_controller.h"
21 #include "utils.h"
22
23 #include "i18n.h"
24
25 using namespace ARDOUR;
26 using namespace Gtk;
27 using namespace Gtkmm2ext;
28 using namespace PBD;
29 using namespace std;
30
31 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
32 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
33 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
34
35 MonitorSection::MonitorSection (Session* s)
36         : AxisView (s)
37         , RouteUI (s)
38         , _tearoff (0)
39         , gain_control (0)
40         , dim_control (0)
41         , solo_boost_control (0)
42         , solo_cut_control (0)
43         , solo_in_place_button (solo_model_group, _("SiP"))
44         , afl_button (solo_model_group, _("AFL"))
45         , pfl_button (solo_model_group, _("PFL"))
46         , cut_all_button (ArdourButton::led_default_elements)
47         , dim_all_button (ArdourButton::led_default_elements)
48         , mono_button (ArdourButton::led_default_elements)
49         , exclusive_solo_button (ArdourButton::led_default_elements)
50         , solo_mute_override_button (ArdourButton::led_default_elements)
51 {
52         Glib::RefPtr<Action> act;
53
54         if (!monitor_actions) {
55
56                 /* do some static stuff */
57
58                 register_actions ();
59
60         }
61
62         set_session (s);
63
64         VBox* spin_packer;
65         Label* spin_label;
66
67         /* Rude Solo */
68
69         rude_solo_button.set_text (_("soloing"));
70         rude_solo_button.set_name ("rude solo");
71         rude_solo_button.show ();
72
73         rude_iso_button.set_text (_("isolated"));
74         rude_iso_button.set_name ("rude isolate");
75         rude_iso_button.show ();
76
77         rude_audition_button.set_text (_("auditioning"));
78         rude_audition_button.set_name ("rude audition");
79         rude_audition_button.show ();
80
81         ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
82
83         rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo));
84         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
85
86         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate));
87         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
88
89         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition));
90         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
91
92         solo_model_box.set_spacing (6);
93         solo_model_box.pack_start (solo_in_place_button, true, false);
94         solo_model_box.pack_start (afl_button, true, false);
95         solo_model_box.pack_start (pfl_button, true, false);
96
97         solo_in_place_button.show ();
98         afl_button.show ();
99         pfl_button.show ();
100         solo_model_box.show ();
101
102         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
103         ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
104         if (act) {
105                 act->connect_proxy (solo_in_place_button);
106         }
107
108         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
109         ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
110         if (act) {
111                 act->connect_proxy (afl_button);
112         }
113
114         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
115         ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
116         if (act) {
117                 act->connect_proxy (pfl_button);
118         }
119
120         /* Solo Boost */
121
122         solo_boost_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.01, 0.1, true, 30, 30, true);
123         ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
124
125         HBox* solo_packer = manage (new HBox);
126         solo_packer->set_spacing (6);
127         solo_packer->show ();
128
129         spin_label = manage (new Label (_("Solo Boost")));
130         spin_packer = manage (new VBox);
131         spin_packer->show ();
132         spin_packer->set_spacing (6);
133         spin_packer->pack_start (*solo_boost_control, false, false);
134         spin_packer->pack_start (*spin_label, false, false);
135
136         solo_packer->pack_start (*spin_packer, true, false);
137
138         /* Solo (SiP) cut */
139
140         solo_cut_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.1, 0.5, true, 30, 30, true);
141         ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
142
143         spin_label = manage (new Label (_("SiP Cut")));
144         spin_packer = manage (new VBox);
145         spin_packer->show ();
146         spin_packer->set_spacing (6);
147         spin_packer->pack_start (*solo_cut_control, false, false);
148         spin_packer->pack_start (*spin_label, false, false);
149
150         solo_packer->pack_start (*spin_packer, true, false);
151
152         /* Dim */
153
154         dim_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.01, 0.1, true, 30, 30, true);
155         ARDOUR_UI::instance()->tooltips().set_tip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
156
157         HBox* dim_packer = manage (new HBox);
158         dim_packer->show ();
159
160         spin_label = manage (new Label (_("Dim")));
161         spin_packer = manage (new VBox);
162         spin_packer->show ();
163         spin_packer->set_spacing (6);
164         spin_packer->pack_start (*dim_control, false, false);
165         spin_packer->pack_start (*spin_label, false, false);
166
167         dim_packer->pack_start (*spin_packer, true, false);
168
169         exclusive_solo_button.set_text (_("excl. solo"));
170         exclusive_solo_button.set_name (X_("monitor solo exclusive"));
171         ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
172
173         act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
174         if (act) {
175                 exclusive_solo_button.set_related_action (act);
176         }
177
178         solo_mute_override_button.set_text (_("solo ยป mute"));
179         solo_mute_override_button.set_name (X_("monitor solo override"));
180         ARDOUR_UI::instance()->set_tip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
181
182         act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
183         if (act) {
184                 solo_mute_override_button.set_related_action (act);
185         }
186
187         HBox* solo_opt_box = manage (new HBox);
188         solo_opt_box->set_spacing (12);
189         solo_opt_box->set_homogeneous (true);
190         solo_opt_box->pack_start (exclusive_solo_button);
191         solo_opt_box->pack_start (solo_mute_override_button);
192         solo_opt_box->show ();
193
194         upper_packer.set_spacing (6);
195
196         Gtk::HBox* rude_box = manage (new HBox);
197         rude_box->pack_start (rude_solo_button, true, true);
198         rude_box->pack_start (rude_iso_button, true, true);
199
200         upper_packer.pack_start (*rude_box, false, false);
201         upper_packer.pack_start (rude_audition_button, false, false);
202         upper_packer.pack_start (solo_model_box, false, false, 12);
203         upper_packer.pack_start (*solo_opt_box, false, false);
204         upper_packer.pack_start (*solo_packer, false, false, 12);
205
206         cut_all_button.set_text (_("mute"));
207         cut_all_button.set_name ("monitor section cut");
208         cut_all_button.set_name (X_("monitor section cut"));
209         cut_all_button.set_size_request (-1,50);
210         cut_all_button.show ();
211
212         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
213         if (act) {
214                 cut_all_button.set_related_action (act);
215         }
216
217         dim_all_button.set_text (_("dim"));
218         dim_all_button.set_name ("monitor section dim");
219         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
220         if (act) {
221                 dim_all_button.set_related_action (act);
222         }
223
224         mono_button.set_text (_("mono"));
225         mono_button.set_name ("monitor section mono");
226         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
227         if (act) {
228                 mono_button.set_related_action (act);
229         }
230
231         HBox* bbox = manage (new HBox);
232
233         bbox->set_spacing (12);
234         bbox->pack_start (mono_button, true, true);
235         bbox->pack_start (dim_all_button, true, true);
236
237         lower_packer.set_spacing (12);
238         lower_packer.pack_start (*bbox, false, false);
239         lower_packer.pack_start (cut_all_button, false, false);
240
241         /* Gain */
242
243         gain_control = new VolumeController (big_knob_pixbuf, boost::shared_ptr<Controllable>(), 1.0, 0.01, 0.1, true, 80, 80, false);
244
245         spin_label = manage (new Label (_("Monitor")));
246         spin_packer = manage (new VBox);
247         spin_packer->show ();
248         spin_packer->set_spacing (6);
249         spin_packer->pack_start (*gain_control, false, false);
250         spin_packer->pack_start (*spin_label, false, false);
251
252         lower_packer.pack_start (*spin_packer, true, true);
253
254         channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
255         channel_table_scroller.set_size_request (-1, 150);
256         channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
257         channel_table_scroller.show ();
258         
259         channel_size_group  = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
260         channel_size_group->add_widget (channel_table_header);
261         channel_size_group->add_widget (channel_table);
262
263         channel_table_header.resize (1, 5);
264         Label* l1 = manage (new Label (X_("out")));
265         l1->set_name (X_("MonitorSectionLabel"));
266         channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
267         l1 = manage (new Label (X_("cut")));
268         l1->set_name (X_("MonitorSectionLabel"));
269         channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
270         l1 = manage (new Label (X_("dim")));
271         l1->set_name (X_("MonitorSectionLabel"));
272         channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
273         l1 = manage (new Label (X_("solo")));
274         l1->set_name (X_("MonitorSectionLabel"));
275         channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
276         l1 = manage (new Label (X_("inv")));
277         l1->set_name (X_("MonitorSectionLabel"));
278         channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
279         channel_table_header.show ();
280
281         table_hpacker.pack_start (channel_table, true, true);
282
283         /* note that we don't pack the table_hpacker till later
284          */
285
286         vpacker.set_border_width (6);
287         vpacker.set_spacing (12);
288         vpacker.pack_start (upper_packer, false, false);
289         vpacker.pack_start (*dim_packer, false, false);
290         vpacker.pack_start (channel_table_header, false, false);
291         vpacker.pack_start (channel_table_packer, false, false);
292         vpacker.pack_start (lower_packer, false, false);
293
294         hpacker.pack_start (vpacker, true, true);
295
296         gain_control->show_all ();
297         dim_control->show_all ();
298         solo_boost_control->show_all ();
299
300         channel_table.show ();
301         hpacker.show ();
302         upper_packer.show ();
303         lower_packer.show ();
304         vpacker.show ();
305
306         populate_buttons ();
307         map_state ();
308         assign_controllables ();
309
310         _tearoff = new TearOff (hpacker);
311
312         /* if torn off, make this a normal window */
313         _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
314         _tearoff->tearoff_window().set_title (X_("Monitor"));
315         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
316
317         /* catch changes that affect us */
318
319         Config->ParameterChanged.connect (config_connection, invalidator (*this), ui_bind (&MonitorSection::parameter_changed, this, _1), gui_context());
320 }
321
322 MonitorSection::~MonitorSection ()
323 {
324         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
325                 delete *i;
326         }
327
328         _channel_buttons.clear ();
329
330         delete gain_control;
331         delete dim_control;
332         delete solo_boost_control;
333         delete _tearoff;
334 }
335
336 void
337 MonitorSection::set_session (Session* s)
338 {
339         AxisView::set_session (s);
340
341         if (_session) {
342
343                 _route = _session->monitor_out ();
344
345                 if (_route) {
346                         /* session with monitor section */
347                         _monitor = _route->monitor_control ();
348                         assign_controllables ();
349                 } else {
350                         /* session with no monitor section */
351                         _monitor.reset ();
352                         _route.reset ();
353                 }
354
355                 if (channel_table_scroller.get_parent()) {
356                         /* scroller is packed, so remove it */
357                         channel_table_packer.remove (channel_table_scroller);
358                         /* remove the table_hpacker from the scroller */
359                         channel_table_scroller.remove ();
360                 } 
361
362                 if (table_hpacker.get_parent ()) {
363                         /* this occurs when the table hpacker is directly
364                            packed, so remove it.
365                         */
366                         channel_table_packer.remove (table_hpacker);
367                 }
368                 
369                 if (_monitor->output_streams().n_audio() > 7) {
370                         /* put the table into a scrolled window, and then put
371                          * that into the channel vpacker, after the table header
372                          */
373                         channel_table_scroller.add (table_hpacker);
374                         channel_table_packer.pack_start (channel_table_scroller, true, true);
375                         channel_table_scroller.show ();
376
377                 } else {
378                         /* just put the channel table itself into the channel
379                          * vpacker, after the table header
380                          */
381                          
382                         channel_table_packer.pack_start (table_hpacker, true, true);
383                         channel_table_scroller.hide ();
384                 }
385
386                 table_hpacker.show ();
387                 channel_table.show ();
388
389         } else {
390                 /* no session */
391
392                 _monitor.reset ();
393                 _route.reset ();
394                 control_connections.drop_connections ();
395                 rude_iso_button.unset_active_state ();
396                 rude_solo_button.unset_active_state ();
397
398                 assign_controllables ();
399         }
400 }
401
402 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
403         : cut (ArdourButton::just_led_default_elements)
404         , dim (ArdourButton::just_led_default_elements)
405         , solo (ArdourButton::just_led_default_elements)
406         , invert (ArdourButton::just_led_default_elements)
407 {
408         cut.set_diameter (3);
409         dim.set_diameter (3);
410         solo.set_diameter (3);
411         invert.set_diameter (3);
412
413         cut.set_name (X_("monitor section cut"));
414         dim.set_name (X_("monitor section dim"));
415         solo.set_name (X_("monitor section solo"));
416         invert.set_name (X_("monitor section invert"));
417
418         cut.unset_flags (Gtk::CAN_FOCUS);
419         dim.unset_flags (Gtk::CAN_FOCUS);
420         solo.unset_flags (Gtk::CAN_FOCUS);
421         invert.unset_flags (Gtk::CAN_FOCUS);
422 }
423
424 void
425 MonitorSection::populate_buttons ()
426 {
427         if (!_monitor) {
428                 return;
429         }
430
431         Glib::RefPtr<Action> act;
432         uint32_t nchans = _monitor->output_streams().n_audio();
433
434         channel_table.resize (nchans, 5);
435         channel_table.set_col_spacings (6);
436         channel_table.set_row_spacings (6);
437         channel_table.set_homogeneous (true);
438
439         const uint32_t row_offset = 0;
440
441         for (uint32_t i = 0; i < nchans; ++i) {
442
443                 string l;
444                 char buf[64];
445
446                 if (nchans == 2) {
447                         if (i == 0) {
448                                 l = "L";
449                         } else {
450                                 l = "R";
451                         }
452                 } else {
453                         char buf[32];
454                         snprintf (buf, sizeof (buf), "%d", i+1);
455                         l = buf;
456                 }
457
458                 Label* label = manage (new Label (l));
459                 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
460
461                 ChannelButtonSet* cbs = new ChannelButtonSet;
462
463                 _channel_buttons.push_back (cbs);
464
465                 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
466                 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
467                 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
468                 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
469
470                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
471                 act = ActionManager::get_action (X_("Monitor"), buf);
472                 if (act) {
473                         cbs->cut.set_related_action (act);
474                 }
475
476                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
477                 act = ActionManager::get_action (X_("Monitor"), buf);
478                 if (act) {
479                         cbs->dim.set_related_action (act);
480                 }
481
482                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
483                 act = ActionManager::get_action (X_("Monitor"), buf);
484                 if (act) {
485                         cbs->solo.set_related_action (act);
486                 }
487
488                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
489                 act = ActionManager::get_action (X_("Monitor"), buf);
490                 if (act) {
491                         cbs->invert.set_related_action (act);
492                 }
493         }
494
495         channel_table.show_all ();
496 }
497
498 void
499 MonitorSection::set_button_names ()
500 {
501         rec_enable_button_label.set_text ("rec");
502         mute_button_label.set_text ("rec");
503         solo_button_label.set_text ("rec");
504 }
505
506 void
507 MonitorSection::toggle_exclusive_solo ()
508 {
509         if (!_monitor) {
510                 return;
511         }
512
513         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
514         if (act) {
515                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
516                 Config->set_exclusive_solo (tact->get_active());
517         }
518
519 }
520
521
522 void
523 MonitorSection::toggle_mute_overrides_solo ()
524 {
525         if (!_monitor) {
526                 return;
527         }
528
529         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
530         if (act) {
531                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
532                 Config->set_solo_mute_override (tact->get_active());
533         }
534 }
535
536 void
537 MonitorSection::dim_all ()
538 {
539         if (!_monitor) {
540                 return;
541         }
542
543         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
544         if (act) {
545                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
546                 _monitor->set_dim_all (tact->get_active());
547         }
548
549 }
550
551 void
552 MonitorSection::cut_all ()
553 {
554         if (!_monitor) {
555                 return;
556         }
557
558         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
559         if (act) {
560                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
561                 _monitor->set_cut_all (tact->get_active());
562         }
563 }
564
565 void
566 MonitorSection::mono ()
567 {
568         if (!_monitor) {
569                 return;
570         }
571
572         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
573         if (act) {
574                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
575                 _monitor->set_mono (tact->get_active());
576         }
577 }
578
579 void
580 MonitorSection::cut_channel (uint32_t chn)
581 {
582         if (!_monitor) {
583                 return;
584         }
585
586         char buf[64];
587         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
588
589         --chn; // 0-based in backend
590
591         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
592         if (act) {
593                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
594                 _monitor->set_cut (chn, tact->get_active());
595         }
596 }
597
598 void
599 MonitorSection::dim_channel (uint32_t chn)
600 {
601         if (!_monitor) {
602                 return;
603         }
604
605         char buf[64];
606         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
607
608         --chn; // 0-based in backend
609
610         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
611         if (act) {
612                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
613                 _monitor->set_dim (chn, tact->get_active());
614         }
615
616 }
617
618 void
619 MonitorSection::solo_channel (uint32_t chn)
620 {
621         if (!_monitor) {
622                 return;
623         }
624
625         char buf[64];
626         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
627
628         --chn; // 0-based in backend
629
630         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
631         if (act) {
632                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
633                 _monitor->set_solo (chn, tact->get_active());
634         }
635
636 }
637
638 void
639 MonitorSection::invert_channel (uint32_t chn)
640 {
641         if (!_monitor) {
642                 return;
643         }
644
645         char buf[64];
646         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
647
648         --chn; // 0-based in backend
649
650         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
651         if (act) {
652                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
653                 _monitor->set_polarity (chn, tact->get_active());
654         }
655 }
656
657 void
658 MonitorSection::register_actions ()
659 {
660         string action_name;
661         string action_descr;
662         Glib::RefPtr<Action> act;
663
664         monitor_actions = ActionGroup::create (X_("Monitor"));
665         ActionManager::add_action_group (monitor_actions);
666
667         ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", "Switch monitor to mono",
668                                                sigc::mem_fun (*this, &MonitorSection::mono));
669
670         ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", "Cut monitor",
671                                                sigc::mem_fun (*this, &MonitorSection::cut_all));
672
673         ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", "Dim monitor",
674                                                sigc::mem_fun (*this, &MonitorSection::dim_all));
675
676         act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", "Toggle exclusive solo mode",
677                                                sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
678
679         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
680         tact->set_active (Config->get_exclusive_solo());
681
682         act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", "Toggle mute overrides solo mode",
683                                                      sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
684
685         tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
686         tact->set_active (Config->get_solo_mute_override());
687
688
689         /* note the 1-based counting (for naming - backend uses 0-based) */
690
691         for (uint32_t chn = 1; chn <= 16; ++chn) {
692
693                 action_name = string_compose (X_("monitor-cut-%1"), chn);
694                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
695                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
696                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
697
698                 action_name = string_compose (X_("monitor-dim-%1"), chn);
699                 action_descr = string_compose (_("Dim monitor channel %1"), chn+1);
700                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
701                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
702
703                 action_name = string_compose (X_("monitor-solo-%1"), chn);
704                 action_descr = string_compose (_("Solo monitor channel %1"), chn+1);
705                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
706                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
707
708                 action_name = string_compose (X_("monitor-invert-%1"), chn);
709                 action_descr = string_compose (_("Invert monitor channel %1"), chn+1);
710                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
711                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
712
713         }
714
715
716         Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
717         RadioAction::Group solo_group;
718
719         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", "In-place solo",
720                                               sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
721         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", "After Fade Listen (AFL) solo",
722                                               sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
723         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", "Pre Fade Listen (PFL) solo",
724                                               sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
725
726         ActionManager::add_action_group (solo_actions);
727 }
728
729 void
730 MonitorSection::solo_use_in_place ()
731 {
732         /* this is driven by a toggle on a radio group, and so is invoked twice,
733            once for the item that became inactive and once for the one that became
734            active.
735         */
736
737         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
738
739         if (act) {
740                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
741                 if (ract) {
742                         Config->set_solo_control_is_listen_control (!ract->get_active());
743                 }
744         }
745 }
746
747 void
748 MonitorSection::solo_use_afl ()
749 {
750         /* this is driven by a toggle on a radio group, and so is invoked twice,
751            once for the item that became inactive and once for the one that became
752            active.
753         */
754
755         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
756         if (act) {
757                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
758                 if (ract) {
759                         if (ract->get_active()) {
760                                 Config->set_listen_position (AfterFaderListen);
761                                 Config->set_solo_control_is_listen_control (true);
762                         }
763                 }
764         }
765 }
766
767 void
768 MonitorSection::solo_use_pfl ()
769 {
770         /* this is driven by a toggle on a radio group, and so is invoked twice,
771            once for the item that became inactive and once for the one that became
772            active.
773         */
774
775         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
776         if (act) {
777                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
778                 if (ract) {
779                         if (ract->get_active()) {
780                                 Config->set_listen_position (PreFaderListen);
781                                 Config->set_solo_control_is_listen_control (true);
782                         }
783                 }
784         }
785 }
786
787 void
788 MonitorSection::setup_knob_images ()
789 {
790         
791         try {
792                 uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
793                 char buf[16];
794                 snprintf (buf, 16, "#%x", (c >> 8));
795                 MotionFeedback::set_lamp_color (buf);
796                 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
797
798         }  catch (...) {
799
800                 error << "No usable large knob image" << endmsg;
801                 throw failed_constructor ();
802         }
803
804         if (!big_knob_pixbuf) {
805                 error << "No usable large knob image" << endmsg;
806                 throw failed_constructor ();
807         }
808
809         try {
810
811                 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
812
813         }  catch (...) {
814
815                 error << "No usable small knob image" << endmsg;
816                 throw failed_constructor ();
817         }
818
819         if (!little_knob_pixbuf) {
820                 error << "No usable small knob image" << endmsg;
821                 throw failed_constructor ();
822         }
823
824 }
825
826 void
827 MonitorSection::update_solo_model ()
828 {
829         const char* action_name = 0;
830         Glib::RefPtr<Action> act;
831
832         if (Config->get_solo_control_is_listen_control()) {
833                 switch (Config->get_listen_position()) {
834                 case AfterFaderListen:
835                         action_name = X_("solo-use-afl");
836                         break;
837                 case PreFaderListen:
838                         action_name = X_("solo-use-pfl");
839                         break;
840                 }
841         } else {
842                 action_name = X_("solo-use-in-place");
843         }
844
845         act = ActionManager::get_action (X_("Solo"), action_name);
846         if (act) {
847                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
848                 if (ract) {
849                         ract->set_active (true);
850                 }
851         }
852 }
853
854 void
855 MonitorSection::map_state ()
856 {
857         if (!_route || !_monitor) {
858                 return;
859         }
860
861         Glib::RefPtr<Action> act;
862
863         update_solo_model ();
864
865         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
866         if (act) {
867                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
868                 if (tact) {
869                         tact->set_active (_monitor->cut_all());
870                 }
871         }
872
873         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
874         if (act) {
875                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
876                 if (tact) {
877                         tact->set_active (_monitor->dim_all());
878                 }
879         }
880
881         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
882         if (act) {
883                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
884                 if (tact) {
885                         tact->set_active (_monitor->mono());
886                 }
887         }
888
889         uint32_t nchans = _monitor->output_streams().n_audio();
890
891         assert (nchans == _channel_buttons.size ());
892
893         for (uint32_t n = 0; n < nchans; ++n) {
894
895                 char action_name[32];
896
897                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n+1);
898                 act = ActionManager::get_action (X_("Monitor"), action_name);
899                 if (act) {
900                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
901                         if (tact) {
902                                 tact->set_active (_monitor->cut (n));
903                         }
904                 }
905
906                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n+1);
907                 act = ActionManager::get_action (X_("Monitor"), action_name);
908                 if (act) {
909                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
910                         if (tact) {
911                                 tact->set_active (_monitor->dimmed (n));
912                         }
913                 }
914
915                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n+1);
916                 act = ActionManager::get_action (X_("Monitor"), action_name);
917                 if (act) {
918                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
919                         if (tact) {
920                                 tact->set_active (_monitor->soloed (n));
921                         }
922                 }
923
924                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n+1);
925                 act = ActionManager::get_action (X_("Monitor"), action_name);
926                 if (act) {
927                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
928                         if (tact) {
929                                 tact->set_active (_monitor->inverted (n));
930                         }
931                 }
932         }
933 }
934
935 void
936 MonitorSection::do_blink (bool onoff)
937 {
938         solo_blink (onoff);
939         audition_blink (onoff);
940 }
941
942 void
943 MonitorSection::audition_blink (bool onoff)
944 {
945         if (_session == 0) {
946                 return;
947         }
948
949         if (_session->is_auditioning()) {
950                 if (onoff) {
951                         rude_audition_button.set_active_state (Gtkmm2ext::Active);
952                 } else {
953                         rude_audition_button.unset_active_state ();
954                 }
955         } else {
956                 rude_audition_button.unset_active_state ();
957         }
958 }
959
960 void
961 MonitorSection::solo_blink (bool onoff)
962 {
963         if (_session == 0) {
964                 return;
965         }
966
967         if (_session->soloing() || _session->listening()) {
968                 if (onoff) {
969                         rude_solo_button.set_active_state (Gtkmm2ext::Active);
970                 } else {
971                         rude_solo_button.unset_active_state ();
972                 }
973
974                 if (_session->soloing()) {
975                         if (_session->solo_isolated()) {
976                                 rude_iso_button.set_active_state (Gtkmm2ext::Active);
977                         }
978                 }
979
980         } else {
981                 // rude_solo_button.set_active (false);
982                 rude_solo_button.unset_active_state ();
983                 rude_iso_button.unset_active_state ();
984         }
985 }
986
987 bool
988 MonitorSection::cancel_solo (GdkEventButton*)
989 {
990         if (_session) {
991                 if (_session->soloing()) {
992                         _session->set_solo (_session->get_routes(), false);
993                 } else if (_session->listening()) {
994                         _session->set_listen (_session->get_routes(), false);
995                 }
996         }
997
998         return true;
999 }
1000
1001 bool
1002 MonitorSection::cancel_isolate (GdkEventButton*)
1003 {
1004         if (_session) {
1005                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1006                 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1007         }
1008
1009         return true;
1010 }
1011
1012 bool
1013 MonitorSection::cancel_audition (GdkEventButton*)
1014 {
1015         if (_session) {
1016                 _session->cancel_audition();
1017         }
1018         return true;
1019 }
1020
1021 void
1022 MonitorSection::parameter_changed (std::string name)
1023 {
1024         if (name == "solo-control-is-listen-control" ||
1025             name == "listen-position") {
1026                 update_solo_model ();
1027         }
1028 }
1029
1030 void
1031 MonitorSection::assign_controllables ()
1032 {
1033         boost::shared_ptr<Controllable> none;
1034
1035         if (!gain_control) {
1036                 /* too early - GUI controls not set up yet */
1037                 return;
1038         }
1039
1040         if (_session) {
1041                 solo_cut_control->set_controllable (_session->solo_cut_control());
1042         } else {
1043                 solo_cut_control->set_controllable (none);
1044         }
1045
1046         if (_route) {
1047                 gain_control->set_controllable (_route->gain_control());
1048         } else {
1049                 gain_control->set_controllable (none);
1050         }
1051
1052         if (_monitor) {
1053
1054                 cut_all_button.set_controllable (_monitor->cut_control());
1055                 cut_all_button.watch ();
1056                 dim_all_button.set_controllable (_monitor->dim_control());
1057                 dim_all_button.watch ();
1058                 mono_button.set_controllable (_monitor->mono_control());
1059                 mono_button.watch ();
1060
1061                 dim_control->set_controllable (_monitor->dim_level_control ());
1062                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1063
1064         } else {
1065
1066                 cut_all_button.set_controllable (none);
1067                 dim_all_button.set_controllable (none);
1068                 mono_button.set_controllable (none);
1069
1070                 dim_control->set_controllable (none);
1071                 solo_boost_control->set_controllable (none);
1072         }
1073 }
1074
1075 string
1076 MonitorSection::state_id() const
1077 {
1078         return "monitor-section";
1079 }