2 Copyright (C) 2012 Paul Davis
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.
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.
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.
20 #include <gdkmm/pixbuf.h>
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
25 #include "gtkmm2ext/bindable_button.h"
26 #include "gtkmm2ext/tearoff.h"
27 #include "gtkmm2ext/actions.h"
28 #include "gtkmm2ext/motionfeedback.h"
30 #include <gtkmm/menu.h>
31 #include <gtkmm/menuitem.h>
33 #include "ardour/monitor_processor.h"
34 #include "ardour/route.h"
36 #include "ardour_ui.h"
37 #include "gui_thread.h"
38 #include "monitor_section.h"
39 #include "public_editor.h"
41 #include "volume_controller.h"
46 using namespace ARDOUR;
47 using namespace ARDOUR_UI_UTILS;
49 using namespace Gtkmm2ext;
53 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
55 MonitorSection::MonitorSection (Session* s)
59 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
60 , *channel_table_scroller.get_vadjustment ())
63 , solo_boost_control (0)
64 , solo_cut_control (0)
67 , solo_boost_display (0)
68 , solo_cut_display (0)
69 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
70 , afl_button (_("AFL"), ArdourButton::led_default_elements)
71 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
72 , exclusive_solo_button (ArdourButton::led_default_elements)
73 , solo_mute_override_button (ArdourButton::led_default_elements)
74 , _inhibit_solo_model_update (false)
77 using namespace Menu_Helpers;
79 Glib::RefPtr<Action> act;
81 if (!monitor_actions) {
83 /* do some static stuff */
96 rude_solo_button.set_text (_("Soloing"));
97 rude_solo_button.set_name ("rude solo");
98 rude_solo_button.show ();
100 rude_iso_button.set_text (_("Isolated"));
101 rude_iso_button.set_name ("rude isolate");
102 rude_iso_button.show ();
104 rude_audition_button.set_text (_("Auditioning"));
105 rude_audition_button.set_name ("rude audition");
106 rude_audition_button.show ();
108 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
110 rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo), false);
111 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
113 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
114 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
116 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
117 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
119 solo_in_place_button.set_name ("monitor section solo model");
120 afl_button.set_name ("monitor section solo model");
121 pfl_button.set_name ("monitor section solo model");
123 solo_model_box.set_spacing (6);
124 solo_model_box.pack_start (solo_in_place_button, true, false);
125 solo_model_box.pack_start (afl_button, true, false);
126 solo_model_box.pack_start (pfl_button, true, false);
128 solo_in_place_button.show ();
131 solo_model_box.show ();
133 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
134 ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
136 solo_in_place_button.set_related_action (act);
139 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
140 ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
142 afl_button.set_related_action (act);
145 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
146 ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
148 pfl_button.set_related_action (act);
153 solo_boost_control = new ArdourKnob ();
154 solo_boost_control->set_name("monitor knob");
155 solo_boost_control->set_size_request(40,40);
156 ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
158 solo_boost_display = new ArdourDisplay ();
159 solo_boost_display->set_name("monitor section cut");
160 solo_boost_display->set_size_request(80,20);
161 solo_boost_display->add_controllable_preset("0dB", 0.0);
162 solo_boost_display->add_controllable_preset("3 dB", 3.0);
163 solo_boost_display->add_controllable_preset("6 dB", 6.0);
164 solo_boost_display->add_controllable_preset("10 dB", 10.0);
166 HBox* solo_packer = manage (new HBox);
167 solo_packer->set_spacing (6);
168 solo_packer->show ();
170 spin_label = manage (new Label (_("Solo Boost")));
171 spin_packer = manage (new VBox);
172 spin_packer->show ();
173 spin_packer->set_spacing (3);
174 spin_packer->pack_start (*spin_label, false, false);
175 spin_packer->pack_start (*solo_boost_control, false, false);
176 spin_packer->pack_start (*solo_boost_display, false, false);
178 solo_packer->pack_start (*spin_packer, true, false);
182 solo_cut_control = new ArdourKnob ();
183 solo_cut_control->set_name ("monitor knob");
184 solo_cut_control->set_size_request (40,40);
185 ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
187 solo_cut_display = new ArdourDisplay ();
188 solo_cut_display->set_name("monitor section cut");
189 solo_cut_display->set_size_request(80,20);
190 solo_cut_display->add_controllable_preset("0dB", 0.0);
191 solo_cut_display->add_controllable_preset("-6 dB", -6.0);
192 solo_cut_display->add_controllable_preset("-12 dB", -12.0);
193 solo_cut_display->add_controllable_preset("-20 dB", -20.0);
194 solo_cut_display->add_controllable_preset("OFF", -1200.0);
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);
204 solo_packer->pack_start (*spin_packer, true, false);
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"));
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);
222 HBox* dim_packer = manage (new HBox);
225 spin_label = manage (new Label (_("Dim")));
226 spin_packer = manage (new VBox);
227 spin_packer->show ();
228 spin_packer->set_spacing (3);
229 spin_packer->pack_start (*spin_label, false, false);
230 spin_packer->pack_start (*dim_control, false, false);
231 spin_packer->pack_start (*dim_display, false, false);
233 dim_packer->pack_start (*spin_packer, true, false);
235 exclusive_solo_button.set_text (_("Excl. Solo"));
236 exclusive_solo_button.set_name (X_("monitor solo exclusive"));
237 ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
239 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
241 exclusive_solo_button.set_related_action (act);
244 solo_mute_override_button.set_text (_("Solo » Mute"));
245 solo_mute_override_button.set_name (X_("monitor solo override"));
246 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 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
250 solo_mute_override_button.set_related_action (act);
253 HBox* solo_opt_box = manage (new HBox);
254 solo_opt_box->set_spacing (12);
255 solo_opt_box->set_homogeneous (true);
256 solo_opt_box->pack_start (exclusive_solo_button);
257 solo_opt_box->pack_start (solo_mute_override_button);
258 solo_opt_box->show ();
260 upper_packer.set_spacing (6);
262 Gtk::HBox* rude_box = manage (new HBox);
263 rude_box->pack_start (rude_solo_button, true, true);
264 rude_box->pack_start (rude_iso_button, true, true);
266 upper_packer.pack_start (*rude_box, false, false);
267 upper_packer.pack_start (rude_audition_button, false, false);
268 upper_packer.pack_start (solo_model_box, false, false, 12);
269 upper_packer.pack_start (*solo_opt_box, false, false);
270 upper_packer.pack_start (*solo_packer, false, false, 12);
272 cut_all_button.set_text (_("Mute"));
273 cut_all_button.set_name ("monitor section cut");
274 cut_all_button.set_name (X_("monitor section cut"));
275 cut_all_button.set_size_request (-1,50);
276 cut_all_button.show ();
278 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
280 cut_all_button.set_related_action (act);
283 dim_all_button.set_text (_("Dim"));
284 dim_all_button.set_name ("monitor section dim");
285 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
287 dim_all_button.set_related_action (act);
290 mono_button.set_text (_("Mono"));
291 mono_button.set_name ("monitor section mono");
292 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
294 mono_button.set_related_action (act);
297 HBox* bbox = manage (new HBox);
299 bbox->set_spacing (12);
300 bbox->pack_start (mono_button, true, true);
301 bbox->pack_start (dim_all_button, true, true);
303 lower_packer.set_spacing (12);
304 lower_packer.pack_start (*bbox, false, false);
305 lower_packer.pack_start (cut_all_button, false, false);
309 gain_control = new ArdourKnob ();
310 gain_control->set_name("monitor knob");
311 gain_control->set_size_request(80,80);
313 gain_display = new ArdourDisplay ();
314 gain_display->set_name("monitor section cut");
315 gain_display->set_size_request(40,20);
316 gain_display->add_controllable_preset("0dB", 0.0);
317 gain_display->add_controllable_preset("-3 dB", -3.0);
318 gain_display->add_controllable_preset("-6 dB", -6.0);
319 gain_display->add_controllable_preset("-12 dB", -12.0);
320 gain_display->add_controllable_preset("-20 dB", -20.0);
321 gain_display->add_controllable_preset("-30 dB", -30.0);
323 spin_label = manage (new Label (_("Monitor")));
324 spin_packer = manage (new VBox);
325 spin_packer->show ();
326 spin_packer->set_spacing (3);
327 spin_packer->pack_start (*spin_label, false, false);
328 spin_packer->pack_start (*gain_control, false, false);
329 spin_packer->pack_start (*gain_display, false, false);
331 lower_packer.pack_start (*spin_packer, true, true);
333 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
334 channel_table_scroller.set_size_request (-1, 150);
335 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
336 channel_table_scroller.show ();
337 channel_table_scroller.add (channel_table_viewport);
339 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
340 channel_size_group->add_widget (channel_table_header);
341 channel_size_group->add_widget (channel_table);
343 channel_table_header.resize (1, 5);
345 Label* l1 = manage (new Label (X_(" ")));
346 l1->set_name (X_("MonitorSectionLabel"));
347 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
349 l1 = manage (new Label (X_("Mute")));
350 l1->set_name (X_("MonitorSectionLabel"));
351 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
353 l1 = manage (new Label (X_("Dim")));
354 l1->set_name (X_("MonitorSectionLabel"));
355 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
357 l1 = manage (new Label (X_("Solo")));
358 l1->set_name (X_("MonitorSectionLabel"));
359 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
361 l1 = manage (new Label (X_("Inv")));
362 l1->set_name (X_("MonitorSectionLabel"));
363 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
365 channel_table_header.show ();
367 table_hpacker.pack_start (channel_table, true, true);
369 /* note that we don't pack the table_hpacker till later
372 vpacker.set_border_width (6);
373 vpacker.set_spacing (12);
374 vpacker.pack_start (upper_packer, false, false);
375 vpacker.pack_start (*dim_packer, false, false);
376 vpacker.pack_start (channel_table_header, false, false);
377 vpacker.pack_start (channel_table_packer, false, false);
378 vpacker.pack_start (lower_packer, false, false);
380 hpacker.pack_start (vpacker, true, true);
382 gain_control->show_all ();
383 gain_display->show_all ();
384 dim_control->show_all ();
385 dim_display->show_all();
386 solo_boost_control->show_all ();
387 solo_boost_display->show_all();
389 channel_table.show ();
391 upper_packer.show ();
392 lower_packer.show ();
397 assign_controllables ();
399 _tearoff = new TearOff (hpacker);
401 /* if torn off, make this a normal window */
402 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
403 _tearoff->tearoff_window().set_title (X_("Monitor"));
404 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
406 /* catch changes that affect us */
408 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
411 MonitorSection::~MonitorSection ()
413 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
417 _channel_buttons.clear ();
423 delete solo_boost_control;
424 delete solo_boost_display;
425 delete solo_cut_control;
426 delete solo_cut_display;
431 MonitorSection::set_session (Session* s)
433 AxisView::set_session (s);
437 _route = _session->monitor_out ();
440 /* session with monitor section */
441 _monitor = _route->monitor_control ();
442 assign_controllables ();
444 /* session with no monitor section */
449 if (channel_table_scroller.get_parent()) {
450 /* scroller is packed, so remove it */
451 channel_table_packer.remove (channel_table_scroller);
454 if (table_hpacker.get_parent () == &channel_table_packer) {
455 /* this occurs when the table hpacker is directly
456 packed, so remove it.
458 channel_table_packer.remove (table_hpacker);
459 } else if (table_hpacker.get_parent()) {
460 channel_table_viewport.remove ();
463 if (_monitor->output_streams().n_audio() > 7) {
464 /* put the table into a scrolled window, and then put
465 * that into the channel vpacker, after the table header
467 channel_table_viewport.add (table_hpacker);
468 channel_table_packer.pack_start (channel_table_scroller, true, true);
469 channel_table_viewport.show ();
470 channel_table_scroller.show ();
473 /* just put the channel table itself into the channel
474 * vpacker, after the table header
477 channel_table_packer.pack_start (table_hpacker, true, true);
478 channel_table_scroller.hide ();
481 table_hpacker.show ();
482 channel_table.show ();
489 control_connections.drop_connections ();
490 rude_iso_button.unset_active_state ();
491 rude_solo_button.unset_active_state ();
493 assign_controllables ();
497 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
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"));
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);
511 MonitorSection::populate_buttons ()
517 Glib::RefPtr<Action> act;
518 uint32_t nchans = _monitor->output_streams().n_audio();
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);
525 const uint32_t row_offset = 0;
527 for (uint32_t i = 0; i < nchans; ++i) {
540 snprintf (buf, sizeof (buf), "%d", i+1);
544 Label* label = manage (new Label (l));
545 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
547 ChannelButtonSet* cbs = new ChannelButtonSet;
549 _channel_buttons.push_back (cbs);
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);
556 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
557 act = ActionManager::get_action (X_("Monitor"), buf);
559 cbs->cut.set_related_action (act);
562 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
563 act = ActionManager::get_action (X_("Monitor"), buf);
565 cbs->dim.set_related_action (act);
568 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
569 act = ActionManager::get_action (X_("Monitor"), buf);
571 cbs->solo.set_related_action (act);
574 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
575 act = ActionManager::get_action (X_("Monitor"), buf);
577 cbs->invert.set_related_action (act);
581 channel_table.show_all ();
585 MonitorSection::toggle_exclusive_solo ()
591 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
593 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
594 Config->set_exclusive_solo (tact->get_active());
600 MonitorSection::toggle_mute_overrides_solo ()
606 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
608 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
609 Config->set_solo_mute_override (tact->get_active());
614 MonitorSection::dim_all ()
620 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
622 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
623 _monitor->set_dim_all (tact->get_active());
629 MonitorSection::cut_all ()
635 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
637 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
638 _monitor->set_cut_all (tact->get_active());
643 MonitorSection::mono ()
649 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
651 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
652 _monitor->set_mono (tact->get_active());
657 MonitorSection::cut_channel (uint32_t chn)
664 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
666 --chn; // 0-based in backend
668 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
670 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
671 _monitor->set_cut (chn, tact->get_active());
676 MonitorSection::dim_channel (uint32_t chn)
683 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
685 --chn; // 0-based in backend
687 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
689 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
690 _monitor->set_dim (chn, tact->get_active());
696 MonitorSection::solo_channel (uint32_t chn)
703 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
705 --chn; // 0-based in backend
707 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
709 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
710 _monitor->set_solo (chn, tact->get_active());
716 MonitorSection::invert_channel (uint32_t chn)
723 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
725 --chn; // 0-based in backend
727 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
729 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
730 _monitor->set_polarity (chn, tact->get_active());
735 MonitorSection::register_actions ()
739 Glib::RefPtr<Action> act;
741 monitor_actions = ActionGroup::create (X_("Monitor"));
742 ActionManager::add_action_group (monitor_actions);
744 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
745 sigc::mem_fun (*this, &MonitorSection::mono));
747 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
748 sigc::mem_fun (*this, &MonitorSection::cut_all));
750 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
751 sigc::mem_fun (*this, &MonitorSection::dim_all));
753 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
754 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
756 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
757 tact->set_active (Config->get_exclusive_solo());
759 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
760 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
762 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
763 tact->set_active (Config->get_solo_mute_override());
766 /* note the 1-based counting (for naming - backend uses 0-based) */
768 for (uint32_t chn = 1; chn <= 16; ++chn) {
770 action_name = string_compose (X_("monitor-cut-%1"), chn);
771 action_descr = string_compose (_("Cut monitor channel %1"), chn);
772 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
773 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
775 action_name = string_compose (X_("monitor-dim-%1"), chn);
776 action_descr = string_compose (_("Dim monitor channel %1"), chn);
777 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
778 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
780 action_name = string_compose (X_("monitor-solo-%1"), chn);
781 action_descr = string_compose (_("Solo monitor channel %1"), chn);
782 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
783 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
785 action_name = string_compose (X_("monitor-invert-%1"), chn);
786 action_descr = string_compose (_("Invert monitor channel %1"), chn);
787 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
788 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
793 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
794 RadioAction::Group solo_group;
796 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
797 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
798 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
799 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
800 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
801 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
803 ActionManager::add_action_group (solo_actions);
807 MonitorSection::solo_use_in_place ()
809 /* this is driven by a toggle on a radio group, and so is invoked twice,
810 once for the item that became inactive and once for the one that became
814 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
817 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
819 if (!ract->get_active ()) {
820 /* We are turning SiP off, which means that AFL or PFL will be turned on
821 shortly; don't update the solo model in the mean time, as if the currently
822 configured listen position is not the one that is about to be turned on,
823 things will go wrong.
825 _inhibit_solo_model_update = true;
827 Config->set_solo_control_is_listen_control (!ract->get_active());
828 _inhibit_solo_model_update = false;
834 MonitorSection::solo_use_afl ()
836 /* this is driven by a toggle on a radio group, and so is invoked twice,
837 once for the item that became inactive and once for the one that became
841 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
843 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
845 if (ract->get_active()) {
846 Config->set_solo_control_is_listen_control (true);
847 Config->set_listen_position (AfterFaderListen);
854 MonitorSection::solo_use_pfl ()
856 /* this is driven by a toggle on a radio group, and so is invoked twice,
857 once for the item that became inactive and once for the one that became
861 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
863 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
865 if (ract->get_active()) {
866 Config->set_solo_control_is_listen_control (true);
867 Config->set_listen_position (PreFaderListen);
874 MonitorSection::update_solo_model ()
876 if (_inhibit_solo_model_update) {
880 const char* action_name = 0;
881 Glib::RefPtr<Action> act;
883 if (Config->get_solo_control_is_listen_control()) {
884 switch (Config->get_listen_position()) {
885 case AfterFaderListen:
886 action_name = X_("solo-use-afl");
889 action_name = X_("solo-use-pfl");
893 action_name = X_("solo-use-in-place");
896 act = ActionManager::get_action (X_("Solo"), action_name);
899 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
901 /* because these are radio buttons, one of them will be
902 active no matter what. to trigger a change in the
903 action so that the view picks it up, toggle it.
905 if (ract->get_active()) {
906 ract->set_active (false);
908 ract->set_active (true);
915 MonitorSection::map_state ()
917 if (!_route || !_monitor) {
921 Glib::RefPtr<Action> act;
923 update_solo_model ();
925 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
927 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
929 tact->set_active (_monitor->cut_all());
933 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
935 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
937 tact->set_active (_monitor->dim_all());
941 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
943 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
945 tact->set_active (_monitor->mono());
949 uint32_t nchans = _monitor->output_streams().n_audio();
951 assert (nchans == _channel_buttons.size ());
953 for (uint32_t n = 0; n < nchans; ++n) {
955 char action_name[32];
957 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
958 act = ActionManager::get_action (X_("Monitor"), action_name);
960 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
962 tact->set_active (_monitor->cut (n));
966 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
967 act = ActionManager::get_action (X_("Monitor"), action_name);
969 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
971 tact->set_active (_monitor->dimmed (n));
975 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
976 act = ActionManager::get_action (X_("Monitor"), action_name);
978 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
980 tact->set_active (_monitor->soloed (n));
984 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
985 act = ActionManager::get_action (X_("Monitor"), action_name);
987 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
989 tact->set_active (_monitor->inverted (n));
996 MonitorSection::do_blink (bool onoff)
999 audition_blink (onoff);
1003 MonitorSection::audition_blink (bool onoff)
1005 if (_session == 0) {
1009 if (_session->is_auditioning()) {
1010 rude_audition_button.set_active (onoff);
1012 rude_audition_button.set_active (false);
1017 MonitorSection::solo_blink (bool onoff)
1019 if (_session == 0) {
1023 if (_session->soloing() || _session->listening()) {
1024 rude_solo_button.set_active (onoff);
1026 if (_session->soloing()) {
1027 if (_session->solo_isolated()) {
1028 rude_iso_button.set_active (false);
1033 rude_solo_button.set_active (false);
1034 rude_iso_button.set_active (false);
1039 MonitorSection::cancel_solo (GdkEventButton*)
1042 if (_session->soloing()) {
1043 _session->set_solo (_session->get_routes(), false);
1044 } else if (_session->listening()) {
1045 _session->set_listen (_session->get_routes(), false);
1053 MonitorSection::cancel_isolate (GdkEventButton*)
1056 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1057 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1064 MonitorSection::cancel_audition (GdkEventButton*)
1067 _session->cancel_audition();
1072 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1074 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1075 if (tact && tact->get_active() != value) { \
1076 tact->set_active(value); \
1081 MonitorSection::parameter_changed (std::string name)
1083 if (name == "solo-control-is-listen-control") {
1084 update_solo_model ();
1085 } else if (name == "listen-position") {
1086 update_solo_model ();
1087 } else if (name == "solo-mute-override") {
1088 SYNCHRONIZE_TOGGLE_ACTION(
1089 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1090 Config->get_solo_mute_override ())
1091 } else if (name == "exclusive-solo") {
1092 SYNCHRONIZE_TOGGLE_ACTION(
1093 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1094 Config->get_exclusive_solo ())
1099 MonitorSection::assign_controllables ()
1101 boost::shared_ptr<Controllable> none;
1103 if (!gain_control) {
1104 /* too early - GUI controls not set up yet */
1109 solo_cut_control->set_controllable (_session->solo_cut_control());
1110 solo_cut_display->set_controllable (_session->solo_cut_control());
1112 solo_cut_control->set_controllable (none);
1113 solo_cut_display->set_controllable (none);
1117 gain_control->set_controllable (_route->gain_control());
1118 gain_display->set_controllable (_route->gain_control());
1120 gain_control->set_controllable (none);
1125 cut_all_button.set_controllable (_monitor->cut_control());
1126 cut_all_button.watch ();
1127 dim_all_button.set_controllable (_monitor->dim_control());
1128 dim_all_button.watch ();
1129 mono_button.set_controllable (_monitor->mono_control());
1130 mono_button.watch ();
1132 dim_control->set_controllable (_monitor->dim_level_control ());
1133 dim_display->set_controllable (_monitor->dim_level_control ());
1134 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1135 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1139 cut_all_button.set_controllable (none);
1140 dim_all_button.set_controllable (none);
1141 mono_button.set_controllable (none);
1143 dim_control->set_controllable (none);
1144 dim_display->set_controllable (none);
1145 solo_boost_control->set_controllable (none);
1146 solo_boost_display->set_controllable (none);
1151 MonitorSection::state_id() const
1153 return "monitor-section";