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), false);
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), false);
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), false);
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);
195 solo_cut_display->add_controllable_preset("OFF", -1200.0);
197 spin_label = manage (new Label (_("SiP Cut")));
198 spin_packer = manage (new VBox);
199 spin_packer->show ();
200 spin_packer->set_spacing (3);
201 spin_packer->pack_start (*spin_label, false, false);
202 spin_packer->pack_start (*solo_cut_control, false, false);
203 spin_packer->pack_start (*solo_cut_display, false, false);
205 solo_packer->pack_start (*spin_packer, true, false);
209 dim_control = new ArdourKnob ();
210 dim_control->set_name ("monitor knob");
211 dim_control->set_size_request (40,40);
212 ARDOUR_UI::instance()->tooltips().set_tip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
214 dim_display = new ArdourDisplay ();
215 dim_display->set_name("monitor section cut");
216 dim_display->set_size_request(80,20);
217 dim_display->add_controllable_preset("0dB", 0.0);
218 dim_display->add_controllable_preset("-3 dB", -3.0);
219 dim_display->add_controllable_preset("-6 dB", -6.0);
220 dim_display->add_controllable_preset("-12 dB", -12.0);
221 dim_display->add_controllable_preset("-20 dB", -20.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);
346 Label* l1 = manage (new Label (X_(" ")));
347 l1->set_name (X_("MonitorSectionLabel"));
348 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
350 l1 = manage (new Label (X_("Mute")));
351 l1->set_name (X_("MonitorSectionLabel"));
352 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
354 l1 = manage (new Label (X_("Dim")));
355 l1->set_name (X_("MonitorSectionLabel"));
356 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
358 l1 = manage (new Label (X_("Solo")));
359 l1->set_name (X_("MonitorSectionLabel"));
360 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
362 l1 = manage (new Label (X_("Inv")));
363 l1->set_name (X_("MonitorSectionLabel"));
364 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
366 channel_table_header.show ();
368 table_hpacker.pack_start (channel_table, true, true);
370 /* note that we don't pack the table_hpacker till later
373 vpacker.set_border_width (6);
374 vpacker.set_spacing (12);
375 vpacker.pack_start (upper_packer, false, false);
376 vpacker.pack_start (*dim_packer, false, false);
377 vpacker.pack_start (channel_table_header, false, false);
378 vpacker.pack_start (channel_table_packer, false, false);
379 vpacker.pack_start (lower_packer, false, false);
381 hpacker.pack_start (vpacker, true, true);
383 gain_control->show_all ();
384 gain_display->show_all ();
385 dim_control->show_all ();
386 dim_display->show_all();
387 solo_boost_control->show_all ();
388 solo_boost_display->show_all();
390 channel_table.show ();
392 upper_packer.show ();
393 lower_packer.show ();
398 assign_controllables ();
400 _tearoff = new TearOff (hpacker);
402 /* if torn off, make this a normal window */
403 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
404 _tearoff->tearoff_window().set_title (X_("Monitor"));
405 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
407 /* catch changes that affect us */
409 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
412 MonitorSection::~MonitorSection ()
414 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
418 _channel_buttons.clear ();
424 delete solo_boost_control;
425 delete solo_boost_display;
426 delete solo_cut_control;
427 delete solo_cut_display;
432 MonitorSection::set_session (Session* s)
434 AxisView::set_session (s);
438 _route = _session->monitor_out ();
441 /* session with monitor section */
442 _monitor = _route->monitor_control ();
443 assign_controllables ();
445 /* session with no monitor section */
450 if (channel_table_scroller.get_parent()) {
451 /* scroller is packed, so remove it */
452 channel_table_packer.remove (channel_table_scroller);
455 if (table_hpacker.get_parent () == &channel_table_packer) {
456 /* this occurs when the table hpacker is directly
457 packed, so remove it.
459 channel_table_packer.remove (table_hpacker);
460 } else if (table_hpacker.get_parent()) {
461 channel_table_viewport.remove ();
464 if (_monitor->output_streams().n_audio() > 7) {
465 /* put the table into a scrolled window, and then put
466 * that into the channel vpacker, after the table header
468 channel_table_viewport.add (table_hpacker);
469 channel_table_packer.pack_start (channel_table_scroller, true, true);
470 channel_table_viewport.show ();
471 channel_table_scroller.show ();
474 /* just put the channel table itself into the channel
475 * vpacker, after the table header
478 channel_table_packer.pack_start (table_hpacker, true, true);
479 channel_table_scroller.hide ();
482 table_hpacker.show ();
483 channel_table.show ();
490 control_connections.drop_connections ();
491 rude_iso_button.unset_active_state ();
492 rude_solo_button.unset_active_state ();
494 assign_controllables ();
498 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
500 cut.set_name (X_("monitor section cut"));
501 dim.set_name (X_("monitor section dim"));
502 solo.set_name (X_("monitor section solo"));
503 invert.set_name (X_("monitor section invert"));
505 cut.unset_flags (Gtk::CAN_FOCUS);
506 dim.unset_flags (Gtk::CAN_FOCUS);
507 solo.unset_flags (Gtk::CAN_FOCUS);
508 invert.unset_flags (Gtk::CAN_FOCUS);
512 MonitorSection::populate_buttons ()
518 Glib::RefPtr<Action> act;
519 uint32_t nchans = _monitor->output_streams().n_audio();
521 channel_table.resize (nchans, 5);
522 channel_table.set_col_spacings (6);
523 channel_table.set_row_spacings (6);
524 channel_table.set_homogeneous (true);
526 const uint32_t row_offset = 0;
528 for (uint32_t i = 0; i < nchans; ++i) {
541 snprintf (buf, sizeof (buf), "%d", i+1);
545 Label* label = manage (new Label (l));
546 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
548 ChannelButtonSet* cbs = new ChannelButtonSet;
550 _channel_buttons.push_back (cbs);
552 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
553 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
554 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
555 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
557 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
558 act = ActionManager::get_action (X_("Monitor"), buf);
560 cbs->cut.set_related_action (act);
563 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
564 act = ActionManager::get_action (X_("Monitor"), buf);
566 cbs->dim.set_related_action (act);
569 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
570 act = ActionManager::get_action (X_("Monitor"), buf);
572 cbs->solo.set_related_action (act);
575 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
576 act = ActionManager::get_action (X_("Monitor"), buf);
578 cbs->invert.set_related_action (act);
582 channel_table.show_all ();
586 MonitorSection::toggle_exclusive_solo ()
592 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
594 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
595 Config->set_exclusive_solo (tact->get_active());
602 MonitorSection::toggle_mute_overrides_solo ()
608 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
610 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
611 Config->set_solo_mute_override (tact->get_active());
616 MonitorSection::dim_all ()
622 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
624 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
625 _monitor->set_dim_all (tact->get_active());
631 MonitorSection::cut_all ()
637 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
639 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
640 _monitor->set_cut_all (tact->get_active());
645 MonitorSection::mono ()
651 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
653 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
654 _monitor->set_mono (tact->get_active());
659 MonitorSection::cut_channel (uint32_t chn)
666 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
668 --chn; // 0-based in backend
670 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
672 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
673 _monitor->set_cut (chn, tact->get_active());
678 MonitorSection::dim_channel (uint32_t chn)
685 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
687 --chn; // 0-based in backend
689 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
691 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
692 _monitor->set_dim (chn, tact->get_active());
698 MonitorSection::solo_channel (uint32_t chn)
705 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
707 --chn; // 0-based in backend
709 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
711 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
712 _monitor->set_solo (chn, tact->get_active());
718 MonitorSection::invert_channel (uint32_t chn)
725 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
727 --chn; // 0-based in backend
729 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
731 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
732 _monitor->set_polarity (chn, tact->get_active());
737 MonitorSection::register_actions ()
741 Glib::RefPtr<Action> act;
743 monitor_actions = ActionGroup::create (X_("Monitor"));
744 ActionManager::add_action_group (monitor_actions);
746 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
747 sigc::mem_fun (*this, &MonitorSection::mono));
749 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
750 sigc::mem_fun (*this, &MonitorSection::cut_all));
752 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
753 sigc::mem_fun (*this, &MonitorSection::dim_all));
755 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
756 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
758 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
759 tact->set_active (Config->get_exclusive_solo());
761 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
762 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
764 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
765 tact->set_active (Config->get_solo_mute_override());
768 /* note the 1-based counting (for naming - backend uses 0-based) */
770 for (uint32_t chn = 1; chn <= 16; ++chn) {
772 action_name = string_compose (X_("monitor-cut-%1"), chn);
773 action_descr = string_compose (_("Cut monitor channel %1"), chn);
774 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
775 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
777 action_name = string_compose (X_("monitor-dim-%1"), chn);
778 action_descr = string_compose (_("Dim monitor channel %1"), chn);
779 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
780 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
782 action_name = string_compose (X_("monitor-solo-%1"), chn);
783 action_descr = string_compose (_("Solo monitor channel %1"), chn);
784 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
785 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
787 action_name = string_compose (X_("monitor-invert-%1"), chn);
788 action_descr = string_compose (_("Invert monitor channel %1"), chn);
789 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
790 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
795 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
796 RadioAction::Group solo_group;
798 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
799 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
800 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
801 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
802 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
803 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
805 ActionManager::add_action_group (solo_actions);
809 MonitorSection::solo_use_in_place ()
811 /* this is driven by a toggle on a radio group, and so is invoked twice,
812 once for the item that became inactive and once for the one that became
816 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
819 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
821 if (!ract->get_active ()) {
822 /* We are turning SiP off, which means that AFL or PFL will be turned on
823 shortly; don't update the solo model in the mean time, as if the currently
824 configured listen position is not the one that is about to be turned on,
825 things will go wrong.
827 _inhibit_solo_model_update = true;
829 Config->set_solo_control_is_listen_control (!ract->get_active());
830 _inhibit_solo_model_update = false;
836 MonitorSection::solo_use_afl ()
838 /* this is driven by a toggle on a radio group, and so is invoked twice,
839 once for the item that became inactive and once for the one that became
843 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
845 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
847 if (ract->get_active()) {
848 Config->set_solo_control_is_listen_control (true);
849 Config->set_listen_position (AfterFaderListen);
856 MonitorSection::solo_use_pfl ()
858 /* this is driven by a toggle on a radio group, and so is invoked twice,
859 once for the item that became inactive and once for the one that became
863 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
865 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
867 if (ract->get_active()) {
868 Config->set_solo_control_is_listen_control (true);
869 Config->set_listen_position (PreFaderListen);
876 MonitorSection::setup_knob_images ()
880 uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
882 snprintf (buf, 16, "#%x", (c >> 8));
883 MotionFeedback::set_lamp_color (buf);
884 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
888 error << "No usable large knob image" << endmsg;
889 throw failed_constructor ();
892 if (!big_knob_pixbuf) {
893 error << "No usable large knob image" << endmsg;
894 throw failed_constructor ();
899 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
903 error << "No usable small knob image" << endmsg;
904 throw failed_constructor ();
907 if (!little_knob_pixbuf) {
908 error << "No usable small knob image" << endmsg;
909 throw failed_constructor ();
915 MonitorSection::update_solo_model ()
917 if (_inhibit_solo_model_update) {
921 const char* action_name = 0;
922 Glib::RefPtr<Action> act;
924 if (Config->get_solo_control_is_listen_control()) {
925 switch (Config->get_listen_position()) {
926 case AfterFaderListen:
927 action_name = X_("solo-use-afl");
930 action_name = X_("solo-use-pfl");
934 action_name = X_("solo-use-in-place");
937 act = ActionManager::get_action (X_("Solo"), action_name);
940 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
942 /* because these are radio buttons, one of them will be
943 active no matter what. to trigger a change in the
944 action so that the view picks it up, toggle it.
946 if (ract->get_active()) {
947 ract->set_active (false);
949 ract->set_active (true);
956 MonitorSection::map_state ()
958 if (!_route || !_monitor) {
962 Glib::RefPtr<Action> act;
964 update_solo_model ();
966 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
968 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
970 tact->set_active (_monitor->cut_all());
974 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
976 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
978 tact->set_active (_monitor->dim_all());
982 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
984 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
986 tact->set_active (_monitor->mono());
990 uint32_t nchans = _monitor->output_streams().n_audio();
992 assert (nchans == _channel_buttons.size ());
994 for (uint32_t n = 0; n < nchans; ++n) {
996 char action_name[32];
998 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
999 act = ActionManager::get_action (X_("Monitor"), action_name);
1001 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1003 tact->set_active (_monitor->cut (n));
1007 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1008 act = ActionManager::get_action (X_("Monitor"), action_name);
1010 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1012 tact->set_active (_monitor->dimmed (n));
1016 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1017 act = ActionManager::get_action (X_("Monitor"), action_name);
1019 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1021 tact->set_active (_monitor->soloed (n));
1025 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1026 act = ActionManager::get_action (X_("Monitor"), action_name);
1028 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1030 tact->set_active (_monitor->inverted (n));
1037 MonitorSection::do_blink (bool onoff)
1040 audition_blink (onoff);
1044 MonitorSection::audition_blink (bool onoff)
1046 if (_session == 0) {
1050 if (_session->is_auditioning()) {
1051 rude_audition_button.set_active (onoff);
1053 rude_audition_button.set_active (false);
1058 MonitorSection::solo_blink (bool onoff)
1060 if (_session == 0) {
1064 if (_session->soloing() || _session->listening()) {
1065 rude_solo_button.set_active (onoff);
1067 if (_session->soloing()) {
1068 if (_session->solo_isolated()) {
1069 rude_iso_button.set_active (false);
1074 rude_solo_button.set_active (false);
1075 rude_iso_button.set_active (false);
1080 MonitorSection::cancel_solo (GdkEventButton*)
1083 if (_session->soloing()) {
1084 _session->set_solo (_session->get_routes(), false);
1085 } else if (_session->listening()) {
1086 _session->set_listen (_session->get_routes(), false);
1094 MonitorSection::cancel_isolate (GdkEventButton*)
1097 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1098 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1105 MonitorSection::cancel_audition (GdkEventButton*)
1108 _session->cancel_audition();
1114 MonitorSection::parameter_changed (std::string name)
1116 if (name == "solo-control-is-listen-control") {
1117 update_solo_model ();
1118 } else if (name == "listen-position") {
1119 update_solo_model ();
1124 MonitorSection::assign_controllables ()
1126 boost::shared_ptr<Controllable> none;
1128 if (!gain_control) {
1129 /* too early - GUI controls not set up yet */
1134 solo_cut_control->set_controllable (_session->solo_cut_control());
1135 solo_cut_display->set_controllable (_session->solo_cut_control());
1137 solo_cut_control->set_controllable (none);
1138 solo_cut_display->set_controllable (none);
1142 gain_control->set_controllable (_route->gain_control());
1143 gain_display->set_controllable (_route->gain_control());
1145 gain_control->set_controllable (none);
1150 cut_all_button.set_controllable (_monitor->cut_control());
1151 cut_all_button.watch ();
1152 dim_all_button.set_controllable (_monitor->dim_control());
1153 dim_all_button.watch ();
1154 mono_button.set_controllable (_monitor->mono_control());
1155 mono_button.watch ();
1157 dim_control->set_controllable (_monitor->dim_level_control ());
1158 dim_display->set_controllable (_monitor->dim_level_control ());
1159 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1160 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1164 cut_all_button.set_controllable (none);
1165 dim_all_button.set_controllable (none);
1166 mono_button.set_controllable (none);
1168 dim_control->set_controllable (none);
1169 dim_display->set_controllable (none);
1170 solo_boost_control->set_controllable (none);
1171 solo_boost_display->set_controllable (none);
1176 MonitorSection::state_id() const
1178 return "monitor-section";