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;
53 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
54 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
56 MonitorSection::MonitorSection (Session* s)
60 , channel_table_viewport (*channel_table_scroller.get_hadjustment(),
61 *channel_table_scroller.get_vadjustment ())
64 , solo_boost_control (0)
65 , solo_cut_control (0)
68 , solo_boost_display (0)
69 , solo_cut_display (0)
70 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
71 , afl_button (_("AFL"), ArdourButton::led_default_elements)
72 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
73 , exclusive_solo_button (ArdourButton::led_default_elements)
74 , solo_mute_override_button (ArdourButton::led_default_elements)
75 , _inhibit_solo_model_update (false)
78 using namespace Menu_Helpers;
80 Glib::RefPtr<Action> act;
82 if (!monitor_actions) {
84 /* do some static stuff */
97 rude_solo_button.set_text (_("soloing"));
98 rude_solo_button.set_name ("rude solo");
99 rude_solo_button.show ();
101 rude_iso_button.set_text (_("isolated"));
102 rude_iso_button.set_name ("rude isolate");
103 rude_iso_button.show ();
105 rude_audition_button.set_text (_("auditioning"));
106 rude_audition_button.set_name ("rude audition");
107 rude_audition_button.show ();
109 ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
111 rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo));
112 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
114 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate));
115 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
117 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition));
118 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
120 solo_in_place_button.set_name ("monitor section solo model");
121 afl_button.set_name ("monitor section solo model");
122 pfl_button.set_name ("monitor section solo model");
124 solo_model_box.set_spacing (6);
125 solo_model_box.pack_start (solo_in_place_button, true, false);
126 solo_model_box.pack_start (afl_button, true, false);
127 solo_model_box.pack_start (pfl_button, true, false);
129 solo_in_place_button.show ();
132 solo_model_box.show ();
134 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
135 ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
137 solo_in_place_button.set_related_action (act);
140 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
141 ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
143 afl_button.set_related_action (act);
146 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
147 ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
149 pfl_button.set_related_action (act);
154 solo_boost_control = new ArdourKnob ();
155 solo_boost_control->set_name("monitor knob");
156 solo_boost_control->set_size_request(40,40);
157 ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
159 solo_boost_display = new ArdourDisplay ();
160 solo_boost_display->set_name("monitor section cut");
161 solo_boost_display->set_size_request(80,20);
162 solo_boost_display->add_controllable_preset("0dB", 0.0);
163 solo_boost_display->add_controllable_preset("3 dB", 3.0);
164 solo_boost_display->add_controllable_preset("6 dB", 6.0);
165 solo_boost_display->add_controllable_preset("10 dB", 10.0);
167 HBox* solo_packer = manage (new HBox);
168 solo_packer->set_spacing (6);
169 solo_packer->show ();
171 spin_label = manage (new Label (_("Solo Boost")));
172 spin_packer = manage (new VBox);
173 spin_packer->show ();
174 spin_packer->set_spacing (3);
175 spin_packer->pack_start (*spin_label, false, false);
176 spin_packer->pack_start (*solo_boost_control, false, false);
177 spin_packer->pack_start (*solo_boost_display, false, false);
179 solo_packer->pack_start (*spin_packer, true, false);
183 solo_cut_control = new ArdourKnob ();
184 solo_cut_control->set_name ("monitor knob");
185 solo_cut_control->set_size_request (40,40);
186 ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
188 solo_cut_display = new ArdourDisplay ();
189 solo_cut_display->set_name("monitor section cut");
190 solo_cut_display->set_size_request(80,20);
191 solo_cut_display->add_controllable_preset("0dB", 0.0);
192 solo_cut_display->add_controllable_preset("-6 dB", -6.0);
193 solo_cut_display->add_controllable_preset("-12 dB", -12.0);
194 solo_cut_display->add_controllable_preset("-20 dB", -20.0);
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);
221 dim_display->add_controllable_preset("-30 dB", -30.0);
223 HBox* dim_packer = manage (new HBox);
226 spin_label = manage (new Label (_("Dim")));
227 spin_packer = manage (new VBox);
228 spin_packer->show ();
229 spin_packer->set_spacing (3);
230 spin_packer->pack_start (*spin_label, false, false);
231 spin_packer->pack_start (*dim_control, false, false);
232 spin_packer->pack_start (*dim_display, false, false);
234 dim_packer->pack_start (*spin_packer, true, false);
236 exclusive_solo_button.set_text (_("excl. solo"));
237 exclusive_solo_button.set_name (X_("monitor solo exclusive"));
238 ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
240 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
242 exclusive_solo_button.set_related_action (act);
245 solo_mute_override_button.set_text (_("solo » mute"));
246 solo_mute_override_button.set_name (X_("monitor solo override"));
247 ARDOUR_UI::instance()->set_tip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
249 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
251 solo_mute_override_button.set_related_action (act);
254 HBox* solo_opt_box = manage (new HBox);
255 solo_opt_box->set_spacing (12);
256 solo_opt_box->set_homogeneous (true);
257 solo_opt_box->pack_start (exclusive_solo_button);
258 solo_opt_box->pack_start (solo_mute_override_button);
259 solo_opt_box->show ();
261 upper_packer.set_spacing (6);
263 Gtk::HBox* rude_box = manage (new HBox);
264 rude_box->pack_start (rude_solo_button, true, true);
265 rude_box->pack_start (rude_iso_button, true, true);
267 upper_packer.pack_start (*rude_box, false, false);
268 upper_packer.pack_start (rude_audition_button, false, false);
269 upper_packer.pack_start (solo_model_box, false, false, 12);
270 upper_packer.pack_start (*solo_opt_box, false, false);
271 upper_packer.pack_start (*solo_packer, false, false, 12);
273 cut_all_button.set_text (_("mute"));
274 cut_all_button.set_name ("monitor section cut");
275 cut_all_button.set_name (X_("monitor section cut"));
276 cut_all_button.set_size_request (-1,50);
277 cut_all_button.show ();
279 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
281 cut_all_button.set_related_action (act);
284 dim_all_button.set_text (_("dim"));
285 dim_all_button.set_name ("monitor section dim");
286 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
288 dim_all_button.set_related_action (act);
291 mono_button.set_text (_("mono"));
292 mono_button.set_name ("monitor section mono");
293 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
295 mono_button.set_related_action (act);
298 HBox* bbox = manage (new HBox);
300 bbox->set_spacing (12);
301 bbox->pack_start (mono_button, true, true);
302 bbox->pack_start (dim_all_button, true, true);
304 lower_packer.set_spacing (12);
305 lower_packer.pack_start (*bbox, false, false);
306 lower_packer.pack_start (cut_all_button, false, false);
310 gain_control = new ArdourKnob ();
311 gain_control->set_name("monitor knob");
312 gain_control->set_size_request(80,80);
314 gain_display = new ArdourDisplay ();
315 gain_display->set_name("monitor section cut");
316 gain_display->set_size_request(40,20);
317 gain_display->add_controllable_preset("0dB", 0.0);
318 gain_display->add_controllable_preset("-3 dB", -3.0);
319 gain_display->add_controllable_preset("-6 dB", -6.0);
320 gain_display->add_controllable_preset("-12 dB", -12.0);
321 gain_display->add_controllable_preset("-20 dB", -20.0);
322 gain_display->add_controllable_preset("-30 dB", -30.0);
324 spin_label = manage (new Label (_("Monitor")));
325 spin_packer = manage (new VBox);
326 spin_packer->show ();
327 spin_packer->set_spacing (3);
328 spin_packer->pack_start (*spin_label, false, false);
329 spin_packer->pack_start (*gain_control, false, false);
330 spin_packer->pack_start (*gain_display, false, false);
332 lower_packer.pack_start (*spin_packer, true, true);
334 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
335 channel_table_scroller.set_size_request (-1, 150);
336 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
337 channel_table_scroller.show ();
338 channel_table_scroller.add (channel_table_viewport);
340 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
341 channel_size_group->add_widget (channel_table_header);
342 channel_size_group->add_widget (channel_table);
344 channel_table_header.resize (1, 5);
345 Label* l1 = manage (new Label (X_("out")));
346 l1->set_name (X_("MonitorSectionLabel"));
347 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
348 l1 = manage (new Label (X_("mute")));
349 l1->set_name (X_("MonitorSectionLabel"));
350 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
351 l1 = manage (new Label (X_("dim")));
352 l1->set_name (X_("MonitorSectionLabel"));
353 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
354 l1 = manage (new Label (X_("solo")));
355 l1->set_name (X_("MonitorSectionLabel"));
356 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
357 l1 = manage (new Label (X_("inv")));
358 l1->set_name (X_("MonitorSectionLabel"));
359 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
360 channel_table_header.show ();
362 table_hpacker.pack_start (channel_table, true, true);
364 /* note that we don't pack the table_hpacker till later
367 vpacker.set_border_width (6);
368 vpacker.set_spacing (12);
369 vpacker.pack_start (upper_packer, false, false);
370 vpacker.pack_start (*dim_packer, false, false);
371 vpacker.pack_start (channel_table_header, false, false);
372 vpacker.pack_start (channel_table_packer, false, false);
373 vpacker.pack_start (lower_packer, false, false);
375 hpacker.pack_start (vpacker, true, true);
377 gain_control->show_all ();
378 gain_display->show_all ();
379 dim_control->show_all ();
380 dim_display->show_all();
381 solo_boost_control->show_all ();
382 solo_boost_display->show_all();
384 channel_table.show ();
386 upper_packer.show ();
387 lower_packer.show ();
392 assign_controllables ();
394 _tearoff = new TearOff (hpacker);
396 /* if torn off, make this a normal window */
397 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
398 _tearoff->tearoff_window().set_title (X_("Monitor"));
399 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
401 /* catch changes that affect us */
403 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
406 MonitorSection::~MonitorSection ()
408 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
412 _channel_buttons.clear ();
418 delete solo_boost_control;
419 delete solo_boost_display;
420 delete solo_cut_control;
421 delete solo_cut_display;
426 MonitorSection::set_session (Session* s)
428 AxisView::set_session (s);
432 _route = _session->monitor_out ();
435 /* session with monitor section */
436 _monitor = _route->monitor_control ();
437 assign_controllables ();
439 /* session with no monitor section */
444 if (channel_table_scroller.get_parent()) {
445 /* scroller is packed, so remove it */
446 channel_table_packer.remove (channel_table_scroller);
449 if (table_hpacker.get_parent () == &channel_table_packer) {
450 /* this occurs when the table hpacker is directly
451 packed, so remove it.
453 channel_table_packer.remove (table_hpacker);
454 } else if (table_hpacker.get_parent()) {
455 channel_table_viewport.remove ();
458 if (_monitor->output_streams().n_audio() > 7) {
459 /* put the table into a scrolled window, and then put
460 * that into the channel vpacker, after the table header
462 channel_table_viewport.add (table_hpacker);
463 channel_table_packer.pack_start (channel_table_scroller, true, true);
464 channel_table_viewport.show ();
465 channel_table_scroller.show ();
468 /* just put the channel table itself into the channel
469 * vpacker, after the table header
472 channel_table_packer.pack_start (table_hpacker, true, true);
473 channel_table_scroller.hide ();
476 table_hpacker.show ();
477 channel_table.show ();
484 control_connections.drop_connections ();
485 rude_iso_button.unset_active_state ();
486 rude_solo_button.unset_active_state ();
488 assign_controllables ();
492 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
494 cut.set_diameter (3);
495 dim.set_diameter (3);
496 solo.set_diameter (3);
497 invert.set_diameter (3);
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());
601 MonitorSection::toggle_mute_overrides_solo ()
607 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
609 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
610 Config->set_solo_mute_override (tact->get_active());
615 MonitorSection::dim_all ()
621 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
623 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
624 _monitor->set_dim_all (tact->get_active());
630 MonitorSection::cut_all ()
636 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
638 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
639 _monitor->set_cut_all (tact->get_active());
644 MonitorSection::mono ()
650 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
652 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
653 _monitor->set_mono (tact->get_active());
658 MonitorSection::cut_channel (uint32_t chn)
665 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
667 --chn; // 0-based in backend
669 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
671 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
672 _monitor->set_cut (chn, tact->get_active());
677 MonitorSection::dim_channel (uint32_t chn)
684 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
686 --chn; // 0-based in backend
688 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
690 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
691 _monitor->set_dim (chn, tact->get_active());
697 MonitorSection::solo_channel (uint32_t chn)
704 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
706 --chn; // 0-based in backend
708 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
710 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
711 _monitor->set_solo (chn, tact->get_active());
717 MonitorSection::invert_channel (uint32_t chn)
724 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
726 --chn; // 0-based in backend
728 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
730 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
731 _monitor->set_polarity (chn, tact->get_active());
736 MonitorSection::register_actions ()
740 Glib::RefPtr<Action> act;
742 monitor_actions = ActionGroup::create (X_("Monitor"));
743 ActionManager::add_action_group (monitor_actions);
745 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
746 sigc::mem_fun (*this, &MonitorSection::mono));
748 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
749 sigc::mem_fun (*this, &MonitorSection::cut_all));
751 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
752 sigc::mem_fun (*this, &MonitorSection::dim_all));
754 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
755 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
757 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
758 tact->set_active (Config->get_exclusive_solo());
760 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
761 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
763 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
764 tact->set_active (Config->get_solo_mute_override());
767 /* note the 1-based counting (for naming - backend uses 0-based) */
769 for (uint32_t chn = 1; chn <= 16; ++chn) {
771 action_name = string_compose (X_("monitor-cut-%1"), chn);
772 action_descr = string_compose (_("Cut monitor channel %1"), chn);
773 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
774 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
776 action_name = string_compose (X_("monitor-dim-%1"), chn);
777 action_descr = string_compose (_("Dim monitor channel %1"), chn);
778 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
779 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
781 action_name = string_compose (X_("monitor-solo-%1"), chn);
782 action_descr = string_compose (_("Solo monitor channel %1"), chn);
783 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
784 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
786 action_name = string_compose (X_("monitor-invert-%1"), chn);
787 action_descr = string_compose (_("Invert monitor channel %1"), chn);
788 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
789 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
794 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
795 RadioAction::Group solo_group;
797 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
798 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
799 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
800 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
801 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
802 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
804 ActionManager::add_action_group (solo_actions);
808 MonitorSection::solo_use_in_place ()
810 /* this is driven by a toggle on a radio group, and so is invoked twice,
811 once for the item that became inactive and once for the one that became
815 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
818 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
820 if (!ract->get_active ()) {
821 /* We are turning SiP off, which means that AFL or PFL will be turned on
822 shortly; don't update the solo model in the mean time, as if the currently
823 configured listen position is not the one that is about to be turned on,
824 things will go wrong.
826 _inhibit_solo_model_update = true;
828 Config->set_solo_control_is_listen_control (!ract->get_active());
829 _inhibit_solo_model_update = false;
835 MonitorSection::solo_use_afl ()
837 /* this is driven by a toggle on a radio group, and so is invoked twice,
838 once for the item that became inactive and once for the one that became
842 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
844 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
846 if (ract->get_active()) {
847 Config->set_solo_control_is_listen_control (true);
848 Config->set_listen_position (AfterFaderListen);
855 MonitorSection::solo_use_pfl ()
857 /* this is driven by a toggle on a radio group, and so is invoked twice,
858 once for the item that became inactive and once for the one that became
862 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
864 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
866 if (ract->get_active()) {
867 Config->set_solo_control_is_listen_control (true);
868 Config->set_listen_position (PreFaderListen);
875 MonitorSection::setup_knob_images ()
879 uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
881 snprintf (buf, 16, "#%x", (c >> 8));
882 MotionFeedback::set_lamp_color (buf);
883 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
887 error << "No usable large knob image" << endmsg;
888 throw failed_constructor ();
891 if (!big_knob_pixbuf) {
892 error << "No usable large knob image" << endmsg;
893 throw failed_constructor ();
898 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
902 error << "No usable small knob image" << endmsg;
903 throw failed_constructor ();
906 if (!little_knob_pixbuf) {
907 error << "No usable small knob image" << endmsg;
908 throw failed_constructor ();
914 MonitorSection::update_solo_model ()
916 if (_inhibit_solo_model_update) {
920 const char* action_name = 0;
921 Glib::RefPtr<Action> act;
923 if (Config->get_solo_control_is_listen_control()) {
924 switch (Config->get_listen_position()) {
925 case AfterFaderListen:
926 action_name = X_("solo-use-afl");
929 action_name = X_("solo-use-pfl");
933 action_name = X_("solo-use-in-place");
936 act = ActionManager::get_action (X_("Solo"), action_name);
939 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
941 /* because these are radio buttons, one of them will be
942 active no matter what. to trigger a change in the
943 action so that the view picks it up, toggle it.
945 if (ract->get_active()) {
946 ract->set_active (false);
948 ract->set_active (true);
955 MonitorSection::map_state ()
957 if (!_route || !_monitor) {
961 Glib::RefPtr<Action> act;
963 update_solo_model ();
965 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
967 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
969 tact->set_active (_monitor->cut_all());
973 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
975 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
977 tact->set_active (_monitor->dim_all());
981 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
983 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
985 tact->set_active (_monitor->mono());
989 uint32_t nchans = _monitor->output_streams().n_audio();
991 assert (nchans == _channel_buttons.size ());
993 for (uint32_t n = 0; n < nchans; ++n) {
995 char action_name[32];
997 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
998 act = ActionManager::get_action (X_("Monitor"), action_name);
1000 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1002 tact->set_active (_monitor->cut (n));
1006 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1007 act = ActionManager::get_action (X_("Monitor"), action_name);
1009 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1011 tact->set_active (_monitor->dimmed (n));
1015 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1016 act = ActionManager::get_action (X_("Monitor"), action_name);
1018 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1020 tact->set_active (_monitor->soloed (n));
1024 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1025 act = ActionManager::get_action (X_("Monitor"), action_name);
1027 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1029 tact->set_active (_monitor->inverted (n));
1036 MonitorSection::do_blink (bool onoff)
1039 audition_blink (onoff);
1043 MonitorSection::audition_blink (bool onoff)
1045 if (_session == 0) {
1049 if (_session->is_auditioning()) {
1050 rude_audition_button.set_active (onoff);
1052 rude_audition_button.set_active (false);
1057 MonitorSection::solo_blink (bool onoff)
1059 if (_session == 0) {
1063 if (_session->soloing() || _session->listening()) {
1064 rude_solo_button.set_active (onoff);
1066 if (_session->soloing()) {
1067 if (_session->solo_isolated()) {
1068 rude_iso_button.set_active (false);
1073 rude_solo_button.set_active (false);
1074 rude_iso_button.set_active (false);
1079 MonitorSection::cancel_solo (GdkEventButton*)
1082 if (_session->soloing()) {
1083 _session->set_solo (_session->get_routes(), false);
1084 } else if (_session->listening()) {
1085 _session->set_listen (_session->get_routes(), false);
1093 MonitorSection::cancel_isolate (GdkEventButton*)
1096 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1097 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1104 MonitorSection::cancel_audition (GdkEventButton*)
1107 _session->cancel_audition();
1113 MonitorSection::parameter_changed (std::string name)
1115 if (name == "solo-control-is-listen-control") {
1116 update_solo_model ();
1117 } else if (name == "listen-position") {
1118 update_solo_model ();
1123 MonitorSection::assign_controllables ()
1125 boost::shared_ptr<Controllable> none;
1127 if (!gain_control) {
1128 /* too early - GUI controls not set up yet */
1133 solo_cut_control->set_controllable (_session->solo_cut_control());
1134 solo_cut_display->set_controllable (_session->solo_cut_control());
1136 solo_cut_control->set_controllable (none);
1137 solo_cut_display->set_controllable (none);
1141 gain_control->set_controllable (_route->gain_control());
1142 gain_display->set_controllable (_route->gain_control());
1144 gain_control->set_controllable (none);
1149 cut_all_button.set_controllable (_monitor->cut_control());
1150 cut_all_button.watch ();
1151 dim_all_button.set_controllable (_monitor->dim_control());
1152 dim_all_button.watch ();
1153 mono_button.set_controllable (_monitor->mono_control());
1154 mono_button.watch ();
1156 dim_control->set_controllable (_monitor->dim_level_control ());
1157 dim_display->set_controllable (_monitor->dim_level_control ());
1158 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1159 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1163 cut_all_button.set_controllable (none);
1164 dim_all_button.set_controllable (none);
1165 mono_button.set_controllable (none);
1167 dim_control->set_controllable (none);
1168 dim_display->set_controllable (none);
1169 solo_boost_control->set_controllable (none);
1170 solo_boost_display->set_controllable (none);
1175 MonitorSection::state_id() const
1177 return "monitor-section";