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);
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_diameter (3);
501 dim.set_diameter (3);
502 solo.set_diameter (3);
503 invert.set_diameter (3);
505 cut.set_name (X_("monitor section cut"));
506 dim.set_name (X_("monitor section dim"));
507 solo.set_name (X_("monitor section solo"));
508 invert.set_name (X_("monitor section invert"));
510 cut.unset_flags (Gtk::CAN_FOCUS);
511 dim.unset_flags (Gtk::CAN_FOCUS);
512 solo.unset_flags (Gtk::CAN_FOCUS);
513 invert.unset_flags (Gtk::CAN_FOCUS);
517 MonitorSection::populate_buttons ()
523 Glib::RefPtr<Action> act;
524 uint32_t nchans = _monitor->output_streams().n_audio();
526 channel_table.resize (nchans, 5);
527 channel_table.set_col_spacings (6);
528 channel_table.set_row_spacings (6);
529 channel_table.set_homogeneous (true);
531 const uint32_t row_offset = 0;
533 for (uint32_t i = 0; i < nchans; ++i) {
546 snprintf (buf, sizeof (buf), "%d", i+1);
550 Label* label = manage (new Label (l));
551 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
553 ChannelButtonSet* cbs = new ChannelButtonSet;
555 _channel_buttons.push_back (cbs);
557 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
558 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
559 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
560 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
562 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
563 act = ActionManager::get_action (X_("Monitor"), buf);
565 cbs->cut.set_related_action (act);
568 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
569 act = ActionManager::get_action (X_("Monitor"), buf);
571 cbs->dim.set_related_action (act);
574 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
575 act = ActionManager::get_action (X_("Monitor"), buf);
577 cbs->solo.set_related_action (act);
580 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
581 act = ActionManager::get_action (X_("Monitor"), buf);
583 cbs->invert.set_related_action (act);
587 channel_table.show_all ();
591 MonitorSection::toggle_exclusive_solo ()
597 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
599 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
600 Config->set_exclusive_solo (tact->get_active());
607 MonitorSection::toggle_mute_overrides_solo ()
613 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
615 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
616 Config->set_solo_mute_override (tact->get_active());
621 MonitorSection::dim_all ()
627 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
629 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
630 _monitor->set_dim_all (tact->get_active());
636 MonitorSection::cut_all ()
642 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
644 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
645 _monitor->set_cut_all (tact->get_active());
650 MonitorSection::mono ()
656 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
658 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
659 _monitor->set_mono (tact->get_active());
664 MonitorSection::cut_channel (uint32_t chn)
671 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
673 --chn; // 0-based in backend
675 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
677 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
678 _monitor->set_cut (chn, tact->get_active());
683 MonitorSection::dim_channel (uint32_t chn)
690 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
692 --chn; // 0-based in backend
694 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
696 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
697 _monitor->set_dim (chn, tact->get_active());
703 MonitorSection::solo_channel (uint32_t chn)
710 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
712 --chn; // 0-based in backend
714 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
716 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
717 _monitor->set_solo (chn, tact->get_active());
723 MonitorSection::invert_channel (uint32_t chn)
730 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
732 --chn; // 0-based in backend
734 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
736 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
737 _monitor->set_polarity (chn, tact->get_active());
742 MonitorSection::register_actions ()
746 Glib::RefPtr<Action> act;
748 monitor_actions = ActionGroup::create (X_("Monitor"));
749 ActionManager::add_action_group (monitor_actions);
751 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
752 sigc::mem_fun (*this, &MonitorSection::mono));
754 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
755 sigc::mem_fun (*this, &MonitorSection::cut_all));
757 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
758 sigc::mem_fun (*this, &MonitorSection::dim_all));
760 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
761 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
763 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
764 tact->set_active (Config->get_exclusive_solo());
766 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
767 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
769 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
770 tact->set_active (Config->get_solo_mute_override());
773 /* note the 1-based counting (for naming - backend uses 0-based) */
775 for (uint32_t chn = 1; chn <= 16; ++chn) {
777 action_name = string_compose (X_("monitor-cut-%1"), chn);
778 action_descr = string_compose (_("Cut 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::cut_channel), chn));
782 action_name = string_compose (X_("monitor-dim-%1"), chn);
783 action_descr = string_compose (_("Dim 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::dim_channel), chn));
787 action_name = string_compose (X_("monitor-solo-%1"), chn);
788 action_descr = string_compose (_("Solo 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::solo_channel), chn));
792 action_name = string_compose (X_("monitor-invert-%1"), chn);
793 action_descr = string_compose (_("Invert monitor channel %1"), chn);
794 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
795 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
800 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
801 RadioAction::Group solo_group;
803 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
804 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
805 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
806 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
807 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
808 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
810 ActionManager::add_action_group (solo_actions);
814 MonitorSection::solo_use_in_place ()
816 /* this is driven by a toggle on a radio group, and so is invoked twice,
817 once for the item that became inactive and once for the one that became
821 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
824 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
826 if (!ract->get_active ()) {
827 /* We are turning SiP off, which means that AFL or PFL will be turned on
828 shortly; don't update the solo model in the mean time, as if the currently
829 configured listen position is not the one that is about to be turned on,
830 things will go wrong.
832 _inhibit_solo_model_update = true;
834 Config->set_solo_control_is_listen_control (!ract->get_active());
835 _inhibit_solo_model_update = false;
841 MonitorSection::solo_use_afl ()
843 /* this is driven by a toggle on a radio group, and so is invoked twice,
844 once for the item that became inactive and once for the one that became
848 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
850 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
852 if (ract->get_active()) {
853 Config->set_solo_control_is_listen_control (true);
854 Config->set_listen_position (AfterFaderListen);
861 MonitorSection::solo_use_pfl ()
863 /* this is driven by a toggle on a radio group, and so is invoked twice,
864 once for the item that became inactive and once for the one that became
868 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
870 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
872 if (ract->get_active()) {
873 Config->set_solo_control_is_listen_control (true);
874 Config->set_listen_position (PreFaderListen);
881 MonitorSection::setup_knob_images ()
885 uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
887 snprintf (buf, 16, "#%x", (c >> 8));
888 MotionFeedback::set_lamp_color (buf);
889 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
893 error << "No usable large knob image" << endmsg;
894 throw failed_constructor ();
897 if (!big_knob_pixbuf) {
898 error << "No usable large knob image" << endmsg;
899 throw failed_constructor ();
904 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
908 error << "No usable small knob image" << endmsg;
909 throw failed_constructor ();
912 if (!little_knob_pixbuf) {
913 error << "No usable small knob image" << endmsg;
914 throw failed_constructor ();
920 MonitorSection::update_solo_model ()
922 if (_inhibit_solo_model_update) {
926 const char* action_name = 0;
927 Glib::RefPtr<Action> act;
929 if (Config->get_solo_control_is_listen_control()) {
930 switch (Config->get_listen_position()) {
931 case AfterFaderListen:
932 action_name = X_("solo-use-afl");
935 action_name = X_("solo-use-pfl");
939 action_name = X_("solo-use-in-place");
942 act = ActionManager::get_action (X_("Solo"), action_name);
945 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
947 /* because these are radio buttons, one of them will be
948 active no matter what. to trigger a change in the
949 action so that the view picks it up, toggle it.
951 if (ract->get_active()) {
952 ract->set_active (false);
954 ract->set_active (true);
961 MonitorSection::map_state ()
963 if (!_route || !_monitor) {
967 Glib::RefPtr<Action> act;
969 update_solo_model ();
971 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
973 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
975 tact->set_active (_monitor->cut_all());
979 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
981 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
983 tact->set_active (_monitor->dim_all());
987 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
989 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
991 tact->set_active (_monitor->mono());
995 uint32_t nchans = _monitor->output_streams().n_audio();
997 assert (nchans == _channel_buttons.size ());
999 for (uint32_t n = 0; n < nchans; ++n) {
1001 char action_name[32];
1003 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1004 act = ActionManager::get_action (X_("Monitor"), action_name);
1006 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1008 tact->set_active (_monitor->cut (n));
1012 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1013 act = ActionManager::get_action (X_("Monitor"), action_name);
1015 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1017 tact->set_active (_monitor->dimmed (n));
1021 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1022 act = ActionManager::get_action (X_("Monitor"), action_name);
1024 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1026 tact->set_active (_monitor->soloed (n));
1030 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1031 act = ActionManager::get_action (X_("Monitor"), action_name);
1033 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1035 tact->set_active (_monitor->inverted (n));
1042 MonitorSection::do_blink (bool onoff)
1045 audition_blink (onoff);
1049 MonitorSection::audition_blink (bool onoff)
1051 if (_session == 0) {
1055 if (_session->is_auditioning()) {
1056 rude_audition_button.set_active (onoff);
1058 rude_audition_button.set_active (false);
1063 MonitorSection::solo_blink (bool onoff)
1065 if (_session == 0) {
1069 if (_session->soloing() || _session->listening()) {
1070 rude_solo_button.set_active (onoff);
1072 if (_session->soloing()) {
1073 if (_session->solo_isolated()) {
1074 rude_iso_button.set_active (false);
1079 rude_solo_button.set_active (false);
1080 rude_iso_button.set_active (false);
1085 MonitorSection::cancel_solo (GdkEventButton*)
1088 if (_session->soloing()) {
1089 _session->set_solo (_session->get_routes(), false);
1090 } else if (_session->listening()) {
1091 _session->set_listen (_session->get_routes(), false);
1099 MonitorSection::cancel_isolate (GdkEventButton*)
1102 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1103 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1110 MonitorSection::cancel_audition (GdkEventButton*)
1113 _session->cancel_audition();
1119 MonitorSection::parameter_changed (std::string name)
1121 if (name == "solo-control-is-listen-control") {
1122 update_solo_model ();
1123 } else if (name == "listen-position") {
1124 update_solo_model ();
1129 MonitorSection::assign_controllables ()
1131 boost::shared_ptr<Controllable> none;
1133 if (!gain_control) {
1134 /* too early - GUI controls not set up yet */
1139 solo_cut_control->set_controllable (_session->solo_cut_control());
1140 solo_cut_display->set_controllable (_session->solo_cut_control());
1142 solo_cut_control->set_controllable (none);
1143 solo_cut_display->set_controllable (none);
1147 gain_control->set_controllable (_route->gain_control());
1148 gain_display->set_controllable (_route->gain_control());
1150 gain_control->set_controllable (none);
1155 cut_all_button.set_controllable (_monitor->cut_control());
1156 cut_all_button.watch ();
1157 dim_all_button.set_controllable (_monitor->dim_control());
1158 dim_all_button.watch ();
1159 mono_button.set_controllable (_monitor->mono_control());
1160 mono_button.watch ();
1162 dim_control->set_controllable (_monitor->dim_level_control ());
1163 dim_display->set_controllable (_monitor->dim_level_control ());
1164 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1165 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1169 cut_all_button.set_controllable (none);
1170 dim_all_button.set_controllable (none);
1171 mono_button.set_controllable (none);
1173 dim_control->set_controllable (none);
1174 dim_display->set_controllable (none);
1175 solo_boost_control->set_controllable (none);
1176 solo_boost_display->set_controllable (none);
1181 MonitorSection::state_id() const
1183 return "monitor-section";