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