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"
40 #include "volume_controller.h"
45 using namespace ARDOUR;
46 using namespace ARDOUR_UI_UTILS;
48 using namespace Gtkmm2ext;
52 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
54 MonitorSection::MonitorSection (Session* s)
58 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
59 , *channel_table_scroller.get_vadjustment ())
62 , solo_boost_control (0)
63 , solo_cut_control (0)
66 , solo_boost_display (0)
67 , solo_cut_display (0)
68 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
69 , afl_button (_("AFL"), ArdourButton::led_default_elements)
70 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
71 , exclusive_solo_button (ArdourButton::led_default_elements)
72 , solo_mute_override_button (ArdourButton::led_default_elements)
73 , _inhibit_solo_model_update (false)
76 using namespace Menu_Helpers;
78 Glib::RefPtr<Action> act;
80 if (!monitor_actions) {
82 /* do some static stuff */
95 rude_solo_button.set_text (_("Soloing"));
96 rude_solo_button.set_name ("rude solo");
97 rude_solo_button.show ();
99 rude_iso_button.set_text (_("Isolated"));
100 rude_iso_button.set_name ("rude isolate");
101 rude_iso_button.show ();
103 rude_audition_button.set_text (_("Auditioning"));
104 rude_audition_button.set_name ("rude audition");
105 rude_audition_button.show ();
107 ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
109 rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo), false);
110 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
112 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
113 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
115 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
116 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
118 solo_in_place_button.set_name ("monitor section solo model");
119 afl_button.set_name ("monitor section solo model");
120 pfl_button.set_name ("monitor section solo model");
122 solo_model_box.set_spacing (6);
123 solo_model_box.pack_start (solo_in_place_button, true, false);
124 solo_model_box.pack_start (afl_button, true, false);
125 solo_model_box.pack_start (pfl_button, true, false);
127 solo_in_place_button.show ();
130 solo_model_box.show ();
132 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
133 ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
135 solo_in_place_button.set_related_action (act);
138 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
139 ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
141 afl_button.set_related_action (act);
144 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
145 ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
147 pfl_button.set_related_action (act);
152 solo_boost_control = new ArdourKnob ();
153 solo_boost_control->set_name("monitor knob");
154 solo_boost_control->set_size_request(40,40);
155 ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
157 solo_boost_display = new ArdourDisplay ();
158 solo_boost_display->set_name("monitor section cut");
159 solo_boost_display->set_size_request(80,20);
160 solo_boost_display->add_controllable_preset("0dB", 0.0);
161 solo_boost_display->add_controllable_preset("3 dB", 3.0);
162 solo_boost_display->add_controllable_preset("6 dB", 6.0);
163 solo_boost_display->add_controllable_preset("10 dB", 10.0);
165 HBox* solo_packer = manage (new HBox);
166 solo_packer->set_spacing (6);
167 solo_packer->show ();
169 spin_label = manage (new Label (_("Solo Boost")));
170 spin_packer = manage (new VBox);
171 spin_packer->show ();
172 spin_packer->set_spacing (3);
173 spin_packer->pack_start (*spin_label, false, false);
174 spin_packer->pack_start (*solo_boost_control, false, false);
175 spin_packer->pack_start (*solo_boost_display, false, false);
177 solo_packer->pack_start (*spin_packer, true, false);
181 solo_cut_control = new ArdourKnob ();
182 solo_cut_control->set_name ("monitor knob");
183 solo_cut_control->set_size_request (40,40);
184 ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
186 solo_cut_display = new ArdourDisplay ();
187 solo_cut_display->set_name("monitor section cut");
188 solo_cut_display->set_size_request(80,20);
189 solo_cut_display->add_controllable_preset("0dB", 0.0);
190 solo_cut_display->add_controllable_preset("-6 dB", -6.0);
191 solo_cut_display->add_controllable_preset("-12 dB", -12.0);
192 solo_cut_display->add_controllable_preset("-20 dB", -20.0);
193 solo_cut_display->add_controllable_preset("OFF", -1200.0);
195 spin_label = manage (new Label (_("SiP Cut")));
196 spin_packer = manage (new VBox);
197 spin_packer->show ();
198 spin_packer->set_spacing (3);
199 spin_packer->pack_start (*spin_label, false, false);
200 spin_packer->pack_start (*solo_cut_control, false, false);
201 spin_packer->pack_start (*solo_cut_display, false, false);
203 solo_packer->pack_start (*spin_packer, true, false);
207 dim_control = new ArdourKnob ();
208 dim_control->set_name ("monitor knob");
209 dim_control->set_size_request (40,40);
210 ARDOUR_UI::instance()->tooltips().set_tip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
212 dim_display = new ArdourDisplay ();
213 dim_display->set_name("monitor section cut");
214 dim_display->set_size_request(80,20);
215 dim_display->add_controllable_preset("0dB", 0.0);
216 dim_display->add_controllable_preset("-3 dB", -3.0);
217 dim_display->add_controllable_preset("-6 dB", -6.0);
218 dim_display->add_controllable_preset("-12 dB", -12.0);
219 dim_display->add_controllable_preset("-20 dB", -20.0);
221 HBox* dim_packer = manage (new HBox);
224 spin_label = manage (new Label (_("Dim")));
225 spin_packer = manage (new VBox);
226 spin_packer->show ();
227 spin_packer->set_spacing (3);
228 spin_packer->pack_start (*spin_label, false, false);
229 spin_packer->pack_start (*dim_control, false, false);
230 spin_packer->pack_start (*dim_display, false, false);
232 dim_packer->pack_start (*spin_packer, true, false);
234 exclusive_solo_button.set_text (_("Excl. Solo"));
235 exclusive_solo_button.set_name (X_("monitor solo exclusive"));
236 ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
238 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
240 exclusive_solo_button.set_related_action (act);
243 solo_mute_override_button.set_text (_("Solo » Mute"));
244 solo_mute_override_button.set_name (X_("monitor solo override"));
245 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)"));
247 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
249 solo_mute_override_button.set_related_action (act);
252 HBox* solo_opt_box = manage (new HBox);
253 solo_opt_box->set_spacing (12);
254 solo_opt_box->set_homogeneous (true);
255 solo_opt_box->pack_start (exclusive_solo_button);
256 solo_opt_box->pack_start (solo_mute_override_button);
257 solo_opt_box->show ();
259 upper_packer.set_spacing (6);
261 Gtk::HBox* rude_box = manage (new HBox);
262 rude_box->pack_start (rude_solo_button, true, true);
263 rude_box->pack_start (rude_iso_button, true, true);
265 upper_packer.pack_start (*rude_box, false, false);
266 upper_packer.pack_start (rude_audition_button, false, false);
267 upper_packer.pack_start (solo_model_box, false, false, 12);
268 upper_packer.pack_start (*solo_opt_box, false, false);
269 upper_packer.pack_start (*solo_packer, false, false, 12);
271 cut_all_button.set_text (_("Mute"));
272 cut_all_button.set_name ("monitor section cut");
273 cut_all_button.set_name (X_("monitor section cut"));
274 cut_all_button.set_size_request (-1,50);
275 cut_all_button.show ();
277 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
279 cut_all_button.set_related_action (act);
282 dim_all_button.set_text (_("Dim"));
283 dim_all_button.set_name ("monitor section dim");
284 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
286 dim_all_button.set_related_action (act);
289 mono_button.set_text (_("Mono"));
290 mono_button.set_name ("monitor section mono");
291 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
293 mono_button.set_related_action (act);
296 HBox* bbox = manage (new HBox);
298 bbox->set_spacing (12);
299 bbox->pack_start (mono_button, true, true);
300 bbox->pack_start (dim_all_button, true, true);
302 lower_packer.set_spacing (12);
303 lower_packer.pack_start (*bbox, false, false);
304 lower_packer.pack_start (cut_all_button, false, false);
308 gain_control = new ArdourKnob ();
309 gain_control->set_name("monitor knob");
310 gain_control->set_size_request(80,80);
312 gain_display = new ArdourDisplay ();
313 gain_display->set_name("monitor section cut");
314 gain_display->set_size_request(40,20);
315 gain_display->add_controllable_preset("0dB", 0.0);
316 gain_display->add_controllable_preset("-3 dB", -3.0);
317 gain_display->add_controllable_preset("-6 dB", -6.0);
318 gain_display->add_controllable_preset("-12 dB", -12.0);
319 gain_display->add_controllable_preset("-20 dB", -20.0);
320 gain_display->add_controllable_preset("-30 dB", -30.0);
322 spin_label = manage (new Label (_("Monitor")));
323 spin_packer = manage (new VBox);
324 spin_packer->show ();
325 spin_packer->set_spacing (3);
326 spin_packer->pack_start (*spin_label, false, false);
327 spin_packer->pack_start (*gain_control, false, false);
328 spin_packer->pack_start (*gain_display, false, false);
330 lower_packer.pack_start (*spin_packer, true, true);
332 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
333 channel_table_scroller.set_size_request (-1, 150);
334 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
335 channel_table_scroller.show ();
336 channel_table_scroller.add (channel_table_viewport);
338 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
339 channel_size_group->add_widget (channel_table_header);
340 channel_size_group->add_widget (channel_table);
342 channel_table_header.resize (1, 5);
344 Label* l1 = manage (new Label (X_(" ")));
345 l1->set_name (X_("MonitorSectionLabel"));
346 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);
352 l1 = manage (new Label (X_("Dim")));
353 l1->set_name (X_("MonitorSectionLabel"));
354 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
356 l1 = manage (new Label (X_("Solo")));
357 l1->set_name (X_("MonitorSectionLabel"));
358 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
360 l1 = manage (new Label (X_("Inv")));
361 l1->set_name (X_("MonitorSectionLabel"));
362 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
364 channel_table_header.show ();
366 table_hpacker.pack_start (channel_table, true, true);
368 /* note that we don't pack the table_hpacker till later
371 vpacker.set_border_width (6);
372 vpacker.set_spacing (12);
373 vpacker.pack_start (upper_packer, false, false);
374 vpacker.pack_start (*dim_packer, false, false);
375 vpacker.pack_start (channel_table_header, false, false);
376 vpacker.pack_start (channel_table_packer, false, false);
377 vpacker.pack_start (lower_packer, false, false);
379 hpacker.pack_start (vpacker, true, true);
381 gain_control->show_all ();
382 gain_display->show_all ();
383 dim_control->show_all ();
384 dim_display->show_all();
385 solo_boost_control->show_all ();
386 solo_boost_display->show_all();
388 channel_table.show ();
390 upper_packer.show ();
391 lower_packer.show ();
396 assign_controllables ();
398 _tearoff = new TearOff (hpacker);
400 /* if torn off, make this a normal window */
401 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
402 _tearoff->tearoff_window().set_title (X_("Monitor"));
403 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
405 /* catch changes that affect us */
407 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
410 MonitorSection::~MonitorSection ()
412 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
416 _channel_buttons.clear ();
422 delete solo_boost_control;
423 delete solo_boost_display;
424 delete solo_cut_control;
425 delete solo_cut_display;
430 MonitorSection::set_session (Session* s)
432 AxisView::set_session (s);
436 _route = _session->monitor_out ();
439 /* session with monitor section */
440 _monitor = _route->monitor_control ();
441 assign_controllables ();
443 /* session with no monitor section */
448 if (channel_table_scroller.get_parent()) {
449 /* scroller is packed, so remove it */
450 channel_table_packer.remove (channel_table_scroller);
453 if (table_hpacker.get_parent () == &channel_table_packer) {
454 /* this occurs when the table hpacker is directly
455 packed, so remove it.
457 channel_table_packer.remove (table_hpacker);
458 } else if (table_hpacker.get_parent()) {
459 channel_table_viewport.remove ();
462 if (_monitor->output_streams().n_audio() > 7) {
463 /* put the table into a scrolled window, and then put
464 * that into the channel vpacker, after the table header
466 channel_table_viewport.add (table_hpacker);
467 channel_table_packer.pack_start (channel_table_scroller, true, true);
468 channel_table_viewport.show ();
469 channel_table_scroller.show ();
472 /* just put the channel table itself into the channel
473 * vpacker, after the table header
476 channel_table_packer.pack_start (table_hpacker, true, true);
477 channel_table_scroller.hide ();
480 table_hpacker.show ();
481 channel_table.show ();
488 control_connections.drop_connections ();
489 rude_iso_button.unset_active_state ();
490 rude_solo_button.unset_active_state ();
492 assign_controllables ();
496 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
498 cut.set_name (X_("monitor section cut"));
499 dim.set_name (X_("monitor section dim"));
500 solo.set_name (X_("monitor section solo"));
501 invert.set_name (X_("monitor section invert"));
503 cut.unset_flags (Gtk::CAN_FOCUS);
504 dim.unset_flags (Gtk::CAN_FOCUS);
505 solo.unset_flags (Gtk::CAN_FOCUS);
506 invert.unset_flags (Gtk::CAN_FOCUS);
510 MonitorSection::populate_buttons ()
516 Glib::RefPtr<Action> act;
517 uint32_t nchans = _monitor->output_streams().n_audio();
519 channel_table.resize (nchans, 5);
520 channel_table.set_col_spacings (6);
521 channel_table.set_row_spacings (6);
522 channel_table.set_homogeneous (true);
524 const uint32_t row_offset = 0;
526 for (uint32_t i = 0; i < nchans; ++i) {
539 snprintf (buf, sizeof (buf), "%d", i+1);
543 Label* label = manage (new Label (l));
544 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
546 ChannelButtonSet* cbs = new ChannelButtonSet;
548 _channel_buttons.push_back (cbs);
550 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
551 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
552 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
553 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
555 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
556 act = ActionManager::get_action (X_("Monitor"), buf);
558 cbs->cut.set_related_action (act);
561 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
562 act = ActionManager::get_action (X_("Monitor"), buf);
564 cbs->dim.set_related_action (act);
567 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
568 act = ActionManager::get_action (X_("Monitor"), buf);
570 cbs->solo.set_related_action (act);
573 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
574 act = ActionManager::get_action (X_("Monitor"), buf);
576 cbs->invert.set_related_action (act);
580 channel_table.show_all ();
584 MonitorSection::toggle_exclusive_solo ()
590 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
592 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
593 Config->set_exclusive_solo (tact->get_active());
599 MonitorSection::toggle_mute_overrides_solo ()
605 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
607 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
608 Config->set_solo_mute_override (tact->get_active());
613 MonitorSection::dim_all ()
619 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
621 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
622 _monitor->set_dim_all (tact->get_active());
628 MonitorSection::cut_all ()
634 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
636 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
637 _monitor->set_cut_all (tact->get_active());
642 MonitorSection::mono ()
648 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
650 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
651 _monitor->set_mono (tact->get_active());
656 MonitorSection::cut_channel (uint32_t chn)
663 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
665 --chn; // 0-based in backend
667 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
669 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
670 _monitor->set_cut (chn, tact->get_active());
675 MonitorSection::dim_channel (uint32_t chn)
682 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
684 --chn; // 0-based in backend
686 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
688 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
689 _monitor->set_dim (chn, tact->get_active());
695 MonitorSection::solo_channel (uint32_t chn)
702 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
704 --chn; // 0-based in backend
706 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
708 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
709 _monitor->set_solo (chn, tact->get_active());
715 MonitorSection::invert_channel (uint32_t chn)
722 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
724 --chn; // 0-based in backend
726 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
728 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
729 _monitor->set_polarity (chn, tact->get_active());
734 MonitorSection::register_actions ()
738 Glib::RefPtr<Action> act;
740 monitor_actions = ActionGroup::create (X_("Monitor"));
741 ActionManager::add_action_group (monitor_actions);
743 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
744 sigc::mem_fun (*this, &MonitorSection::mono));
746 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
747 sigc::mem_fun (*this, &MonitorSection::cut_all));
749 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
750 sigc::mem_fun (*this, &MonitorSection::dim_all));
752 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
753 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
755 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
756 tact->set_active (Config->get_exclusive_solo());
758 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
759 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
761 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
762 tact->set_active (Config->get_solo_mute_override());
765 /* note the 1-based counting (for naming - backend uses 0-based) */
767 for (uint32_t chn = 1; chn <= 16; ++chn) {
769 action_name = string_compose (X_("monitor-cut-%1"), chn);
770 action_descr = string_compose (_("Cut monitor channel %1"), chn);
771 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
772 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
774 action_name = string_compose (X_("monitor-dim-%1"), chn);
775 action_descr = string_compose (_("Dim monitor channel %1"), chn);
776 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
777 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
779 action_name = string_compose (X_("monitor-solo-%1"), chn);
780 action_descr = string_compose (_("Solo monitor channel %1"), chn);
781 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
782 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
784 action_name = string_compose (X_("monitor-invert-%1"), chn);
785 action_descr = string_compose (_("Invert monitor channel %1"), chn);
786 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
787 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
792 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
793 RadioAction::Group solo_group;
795 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
796 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
797 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
798 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
799 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
800 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
802 ActionManager::add_action_group (solo_actions);
806 MonitorSection::solo_use_in_place ()
808 /* this is driven by a toggle on a radio group, and so is invoked twice,
809 once for the item that became inactive and once for the one that became
813 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
816 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
818 if (!ract->get_active ()) {
819 /* We are turning SiP off, which means that AFL or PFL will be turned on
820 shortly; don't update the solo model in the mean time, as if the currently
821 configured listen position is not the one that is about to be turned on,
822 things will go wrong.
824 _inhibit_solo_model_update = true;
826 Config->set_solo_control_is_listen_control (!ract->get_active());
827 _inhibit_solo_model_update = false;
833 MonitorSection::solo_use_afl ()
835 /* this is driven by a toggle on a radio group, and so is invoked twice,
836 once for the item that became inactive and once for the one that became
840 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
842 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
844 if (ract->get_active()) {
845 Config->set_solo_control_is_listen_control (true);
846 Config->set_listen_position (AfterFaderListen);
853 MonitorSection::solo_use_pfl ()
855 /* this is driven by a toggle on a radio group, and so is invoked twice,
856 once for the item that became inactive and once for the one that became
860 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
862 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
864 if (ract->get_active()) {
865 Config->set_solo_control_is_listen_control (true);
866 Config->set_listen_position (PreFaderListen);
873 MonitorSection::update_solo_model ()
875 if (_inhibit_solo_model_update) {
879 const char* action_name = 0;
880 Glib::RefPtr<Action> act;
882 if (Config->get_solo_control_is_listen_control()) {
883 switch (Config->get_listen_position()) {
884 case AfterFaderListen:
885 action_name = X_("solo-use-afl");
888 action_name = X_("solo-use-pfl");
892 action_name = X_("solo-use-in-place");
895 act = ActionManager::get_action (X_("Solo"), action_name);
898 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
900 /* because these are radio buttons, one of them will be
901 active no matter what. to trigger a change in the
902 action so that the view picks it up, toggle it.
904 if (ract->get_active()) {
905 ract->set_active (false);
907 ract->set_active (true);
914 MonitorSection::map_state ()
916 if (!_route || !_monitor) {
920 Glib::RefPtr<Action> act;
922 update_solo_model ();
924 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
926 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
928 tact->set_active (_monitor->cut_all());
932 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
934 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
936 tact->set_active (_monitor->dim_all());
940 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
942 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
944 tact->set_active (_monitor->mono());
948 uint32_t nchans = _monitor->output_streams().n_audio();
950 assert (nchans == _channel_buttons.size ());
952 for (uint32_t n = 0; n < nchans; ++n) {
954 char action_name[32];
956 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
957 act = ActionManager::get_action (X_("Monitor"), action_name);
959 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
961 tact->set_active (_monitor->cut (n));
965 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
966 act = ActionManager::get_action (X_("Monitor"), action_name);
968 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
970 tact->set_active (_monitor->dimmed (n));
974 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
975 act = ActionManager::get_action (X_("Monitor"), action_name);
977 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
979 tact->set_active (_monitor->soloed (n));
983 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
984 act = ActionManager::get_action (X_("Monitor"), action_name);
986 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
988 tact->set_active (_monitor->inverted (n));
995 MonitorSection::do_blink (bool onoff)
998 audition_blink (onoff);
1002 MonitorSection::audition_blink (bool onoff)
1004 if (_session == 0) {
1008 if (_session->is_auditioning()) {
1009 rude_audition_button.set_active (onoff);
1011 rude_audition_button.set_active (false);
1016 MonitorSection::solo_blink (bool onoff)
1018 if (_session == 0) {
1022 if (_session->soloing() || _session->listening()) {
1023 rude_solo_button.set_active (onoff);
1025 if (_session->soloing()) {
1026 if (_session->solo_isolated()) {
1027 rude_iso_button.set_active (false);
1032 rude_solo_button.set_active (false);
1033 rude_iso_button.set_active (false);
1038 MonitorSection::cancel_solo (GdkEventButton*)
1041 if (_session->soloing()) {
1042 _session->set_solo (_session->get_routes(), false);
1043 } else if (_session->listening()) {
1044 _session->set_listen (_session->get_routes(), false);
1052 MonitorSection::cancel_isolate (GdkEventButton*)
1055 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1056 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1063 MonitorSection::cancel_audition (GdkEventButton*)
1066 _session->cancel_audition();
1072 MonitorSection::parameter_changed (std::string name)
1074 if (name == "solo-control-is-listen-control") {
1075 update_solo_model ();
1076 } else if (name == "listen-position") {
1077 update_solo_model ();
1082 MonitorSection::assign_controllables ()
1084 boost::shared_ptr<Controllable> none;
1086 if (!gain_control) {
1087 /* too early - GUI controls not set up yet */
1092 solo_cut_control->set_controllable (_session->solo_cut_control());
1093 solo_cut_display->set_controllable (_session->solo_cut_control());
1095 solo_cut_control->set_controllable (none);
1096 solo_cut_display->set_controllable (none);
1100 gain_control->set_controllable (_route->gain_control());
1101 gain_display->set_controllable (_route->gain_control());
1103 gain_control->set_controllable (none);
1108 cut_all_button.set_controllable (_monitor->cut_control());
1109 cut_all_button.watch ();
1110 dim_all_button.set_controllable (_monitor->dim_control());
1111 dim_all_button.watch ();
1112 mono_button.set_controllable (_monitor->mono_control());
1113 mono_button.watch ();
1115 dim_control->set_controllable (_monitor->dim_level_control ());
1116 dim_display->set_controllable (_monitor->dim_level_control ());
1117 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1118 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1122 cut_all_button.set_controllable (none);
1123 dim_all_button.set_controllable (none);
1124 mono_button.set_controllable (none);
1126 dim_control->set_controllable (none);
1127 dim_display->set_controllable (none);
1128 solo_boost_control->set_controllable (none);
1129 solo_boost_display->set_controllable (none);
1134 MonitorSection::state_id() const
1136 return "monitor-section";