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