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 "ardour/monitor_processor.h"
31 #include "ardour/route.h"
33 #include "ardour_ui.h"
34 #include "gui_thread.h"
35 #include "monitor_section.h"
36 #include "public_editor.h"
37 #include "volume_controller.h"
42 using namespace ARDOUR;
43 using namespace ARDOUR_UI_UTILS;
45 using namespace Gtkmm2ext;
49 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
50 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
51 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
53 MonitorSection::MonitorSection (Session* s)
57 , channel_table_viewport (*channel_table_scroller.get_hadjustment(),
58 *channel_table_scroller.get_vadjustment ())
61 , solo_boost_control (0)
62 , solo_cut_control (0)
63 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
64 , afl_button (_("AFL"), ArdourButton::led_default_elements)
65 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
66 , exclusive_solo_button (ArdourButton::led_default_elements)
67 , solo_mute_override_button (ArdourButton::led_default_elements)
68 , _inhibit_solo_model_update (false)
70 Glib::RefPtr<Action> act;
72 if (!monitor_actions) {
74 /* do some static stuff */
87 rude_solo_button.set_text (_("soloing"));
88 rude_solo_button.set_name ("rude solo");
89 rude_solo_button.show ();
91 rude_iso_button.set_text (_("isolated"));
92 rude_iso_button.set_name ("rude isolate");
93 rude_iso_button.show ();
95 rude_audition_button.set_text (_("auditioning"));
96 rude_audition_button.set_name ("rude audition");
97 rude_audition_button.show ();
99 ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
101 rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo));
102 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
104 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate));
105 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
107 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition));
108 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
110 solo_in_place_button.set_name ("monitor section solo model");
111 afl_button.set_name ("monitor section solo model");
112 pfl_button.set_name ("monitor section solo model");
114 solo_model_box.set_spacing (6);
115 solo_model_box.pack_start (solo_in_place_button, true, false);
116 solo_model_box.pack_start (afl_button, true, false);
117 solo_model_box.pack_start (pfl_button, true, false);
119 solo_in_place_button.show ();
122 solo_model_box.show ();
124 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
125 ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
127 solo_in_place_button.set_related_action (act);
130 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
131 ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
133 afl_button.set_related_action (act);
136 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
137 ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
139 pfl_button.set_related_action (act);
144 solo_boost_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.01, 0.1, true, 30, 30, true);
145 ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
147 HBox* solo_packer = manage (new HBox);
148 solo_packer->set_spacing (6);
149 solo_packer->show ();
151 spin_label = manage (new Label (_("Solo Boost")));
152 spin_packer = manage (new VBox);
153 spin_packer->show ();
154 spin_packer->set_spacing (6);
155 spin_packer->pack_start (*solo_boost_control, false, false);
156 spin_packer->pack_start (*spin_label, false, false);
158 solo_packer->pack_start (*spin_packer, true, false);
162 solo_cut_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.1, 0.5, true, 30, 30, true);
163 ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
165 spin_label = manage (new Label (_("SiP Cut")));
166 spin_packer = manage (new VBox);
167 spin_packer->show ();
168 spin_packer->set_spacing (6);
169 spin_packer->pack_start (*solo_cut_control, false, false);
170 spin_packer->pack_start (*spin_label, false, false);
172 solo_packer->pack_start (*spin_packer, true, false);
176 dim_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.01, 0.1, true, 30, 30, true);
177 ARDOUR_UI::instance()->tooltips().set_tip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
179 HBox* dim_packer = manage (new HBox);
182 spin_label = manage (new Label (_("Dim")));
183 spin_packer = manage (new VBox);
184 spin_packer->show ();
185 spin_packer->set_spacing (6);
186 spin_packer->pack_start (*dim_control, false, false);
187 spin_packer->pack_start (*spin_label, false, false);
189 dim_packer->pack_start (*spin_packer, true, false);
191 exclusive_solo_button.set_text (_("excl. solo"));
192 exclusive_solo_button.set_name (X_("monitor solo exclusive"));
193 ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
195 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
197 exclusive_solo_button.set_related_action (act);
200 solo_mute_override_button.set_text (_("solo ยป mute"));
201 solo_mute_override_button.set_name (X_("monitor solo override"));
202 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)"));
204 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
206 solo_mute_override_button.set_related_action (act);
209 HBox* solo_opt_box = manage (new HBox);
210 solo_opt_box->set_spacing (12);
211 solo_opt_box->set_homogeneous (true);
212 solo_opt_box->pack_start (exclusive_solo_button);
213 solo_opt_box->pack_start (solo_mute_override_button);
214 solo_opt_box->show ();
216 upper_packer.set_spacing (6);
218 Gtk::HBox* rude_box = manage (new HBox);
219 rude_box->pack_start (rude_solo_button, true, true);
220 rude_box->pack_start (rude_iso_button, true, true);
222 upper_packer.pack_start (*rude_box, false, false);
223 upper_packer.pack_start (rude_audition_button, false, false);
224 upper_packer.pack_start (solo_model_box, false, false, 12);
225 upper_packer.pack_start (*solo_opt_box, false, false);
226 upper_packer.pack_start (*solo_packer, false, false, 12);
228 cut_all_button.set_text (_("mute"));
229 cut_all_button.set_name ("monitor section cut");
230 cut_all_button.set_name (X_("monitor section cut"));
231 cut_all_button.set_size_request (-1,50);
232 cut_all_button.show ();
234 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
236 cut_all_button.set_related_action (act);
239 dim_all_button.set_text (_("dim"));
240 dim_all_button.set_name ("monitor section dim");
241 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
243 dim_all_button.set_related_action (act);
246 mono_button.set_text (_("mono"));
247 mono_button.set_name ("monitor section mono");
248 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
250 mono_button.set_related_action (act);
253 HBox* bbox = manage (new HBox);
255 bbox->set_spacing (12);
256 bbox->pack_start (mono_button, true, true);
257 bbox->pack_start (dim_all_button, true, true);
259 lower_packer.set_spacing (12);
260 lower_packer.pack_start (*bbox, false, false);
261 lower_packer.pack_start (cut_all_button, false, false);
265 gain_control = new VolumeController (big_knob_pixbuf, boost::shared_ptr<Controllable>(), 1.0, 0.01, 0.1, true, 80, 80, false);
267 spin_label = manage (new Label (_("Monitor")));
268 spin_packer = manage (new VBox);
269 spin_packer->show ();
270 spin_packer->set_spacing (6);
271 spin_packer->pack_start (*gain_control, false, false);
272 spin_packer->pack_start (*spin_label, false, false);
274 lower_packer.pack_start (*spin_packer, true, true);
276 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
277 channel_table_scroller.set_size_request (-1, 150);
278 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
279 channel_table_scroller.show ();
280 channel_table_scroller.add (channel_table_viewport);
282 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
283 channel_size_group->add_widget (channel_table_header);
284 channel_size_group->add_widget (channel_table);
286 channel_table_header.resize (1, 5);
287 Label* l1 = manage (new Label (X_("out")));
288 l1->set_name (X_("MonitorSectionLabel"));
289 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
290 l1 = manage (new Label (X_("mute")));
291 l1->set_name (X_("MonitorSectionLabel"));
292 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
293 l1 = manage (new Label (X_("dim")));
294 l1->set_name (X_("MonitorSectionLabel"));
295 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
296 l1 = manage (new Label (X_("solo")));
297 l1->set_name (X_("MonitorSectionLabel"));
298 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
299 l1 = manage (new Label (X_("inv")));
300 l1->set_name (X_("MonitorSectionLabel"));
301 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
302 channel_table_header.show ();
304 table_hpacker.pack_start (channel_table, true, true);
306 /* note that we don't pack the table_hpacker till later
309 vpacker.set_border_width (6);
310 vpacker.set_spacing (12);
311 vpacker.pack_start (upper_packer, false, false);
312 vpacker.pack_start (*dim_packer, false, false);
313 vpacker.pack_start (channel_table_header, false, false);
314 vpacker.pack_start (channel_table_packer, false, false);
315 vpacker.pack_start (lower_packer, false, false);
317 hpacker.pack_start (vpacker, true, true);
319 gain_control->show_all ();
320 dim_control->show_all ();
321 solo_boost_control->show_all ();
323 channel_table.show ();
325 upper_packer.show ();
326 lower_packer.show ();
331 assign_controllables ();
333 _tearoff = new TearOff (hpacker);
335 /* if torn off, make this a normal window */
336 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
337 _tearoff->tearoff_window().set_title (X_("Monitor"));
338 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
340 /* catch changes that affect us */
342 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
345 MonitorSection::~MonitorSection ()
347 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
351 _channel_buttons.clear ();
355 delete solo_boost_control;
360 MonitorSection::set_session (Session* s)
362 AxisView::set_session (s);
366 _route = _session->monitor_out ();
369 /* session with monitor section */
370 _monitor = _route->monitor_control ();
371 assign_controllables ();
373 /* session with no monitor section */
378 if (channel_table_scroller.get_parent()) {
379 /* scroller is packed, so remove it */
380 channel_table_packer.remove (channel_table_scroller);
383 if (table_hpacker.get_parent () == &channel_table_packer) {
384 /* this occurs when the table hpacker is directly
385 packed, so remove it.
387 channel_table_packer.remove (table_hpacker);
388 } else if (table_hpacker.get_parent()) {
389 channel_table_viewport.remove ();
392 if (_monitor->output_streams().n_audio() > 7) {
393 /* put the table into a scrolled window, and then put
394 * that into the channel vpacker, after the table header
396 channel_table_viewport.add (table_hpacker);
397 channel_table_packer.pack_start (channel_table_scroller, true, true);
398 channel_table_viewport.show ();
399 channel_table_scroller.show ();
402 /* just put the channel table itself into the channel
403 * vpacker, after the table header
406 channel_table_packer.pack_start (table_hpacker, true, true);
407 channel_table_scroller.hide ();
410 table_hpacker.show ();
411 channel_table.show ();
418 control_connections.drop_connections ();
419 rude_iso_button.unset_active_state ();
420 rude_solo_button.unset_active_state ();
422 assign_controllables ();
426 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
428 cut.set_diameter (3);
429 dim.set_diameter (3);
430 solo.set_diameter (3);
431 invert.set_diameter (3);
433 cut.set_name (X_("monitor section cut"));
434 dim.set_name (X_("monitor section dim"));
435 solo.set_name (X_("monitor section solo"));
436 invert.set_name (X_("monitor section invert"));
438 cut.unset_flags (Gtk::CAN_FOCUS);
439 dim.unset_flags (Gtk::CAN_FOCUS);
440 solo.unset_flags (Gtk::CAN_FOCUS);
441 invert.unset_flags (Gtk::CAN_FOCUS);
445 MonitorSection::populate_buttons ()
451 Glib::RefPtr<Action> act;
452 uint32_t nchans = _monitor->output_streams().n_audio();
454 channel_table.resize (nchans, 5);
455 channel_table.set_col_spacings (6);
456 channel_table.set_row_spacings (6);
457 channel_table.set_homogeneous (true);
459 const uint32_t row_offset = 0;
461 for (uint32_t i = 0; i < nchans; ++i) {
474 snprintf (buf, sizeof (buf), "%d", i+1);
478 Label* label = manage (new Label (l));
479 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
481 ChannelButtonSet* cbs = new ChannelButtonSet;
483 _channel_buttons.push_back (cbs);
485 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
486 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
487 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
488 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
490 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
491 act = ActionManager::get_action (X_("Monitor"), buf);
493 cbs->cut.set_related_action (act);
496 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
497 act = ActionManager::get_action (X_("Monitor"), buf);
499 cbs->dim.set_related_action (act);
502 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
503 act = ActionManager::get_action (X_("Monitor"), buf);
505 cbs->solo.set_related_action (act);
508 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
509 act = ActionManager::get_action (X_("Monitor"), buf);
511 cbs->invert.set_related_action (act);
515 channel_table.show_all ();
519 MonitorSection::toggle_exclusive_solo ()
525 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
527 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
528 Config->set_exclusive_solo (tact->get_active());
535 MonitorSection::toggle_mute_overrides_solo ()
541 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
543 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
544 Config->set_solo_mute_override (tact->get_active());
549 MonitorSection::dim_all ()
555 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
557 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
558 _monitor->set_dim_all (tact->get_active());
564 MonitorSection::cut_all ()
570 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
572 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
573 _monitor->set_cut_all (tact->get_active());
578 MonitorSection::mono ()
584 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
586 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
587 _monitor->set_mono (tact->get_active());
592 MonitorSection::cut_channel (uint32_t chn)
599 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
601 --chn; // 0-based in backend
603 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
605 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
606 _monitor->set_cut (chn, tact->get_active());
611 MonitorSection::dim_channel (uint32_t chn)
618 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
620 --chn; // 0-based in backend
622 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
624 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
625 _monitor->set_dim (chn, tact->get_active());
631 MonitorSection::solo_channel (uint32_t chn)
638 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
640 --chn; // 0-based in backend
642 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
644 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
645 _monitor->set_solo (chn, tact->get_active());
651 MonitorSection::invert_channel (uint32_t chn)
658 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
660 --chn; // 0-based in backend
662 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
664 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
665 _monitor->set_polarity (chn, tact->get_active());
670 MonitorSection::register_actions ()
674 Glib::RefPtr<Action> act;
676 monitor_actions = ActionGroup::create (X_("Monitor"));
677 ActionManager::add_action_group (monitor_actions);
679 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
680 sigc::mem_fun (*this, &MonitorSection::mono));
682 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
683 sigc::mem_fun (*this, &MonitorSection::cut_all));
685 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
686 sigc::mem_fun (*this, &MonitorSection::dim_all));
688 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
689 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
691 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
692 tact->set_active (Config->get_exclusive_solo());
694 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
695 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
697 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
698 tact->set_active (Config->get_solo_mute_override());
701 /* note the 1-based counting (for naming - backend uses 0-based) */
703 for (uint32_t chn = 1; chn <= 16; ++chn) {
705 action_name = string_compose (X_("monitor-cut-%1"), chn);
706 action_descr = string_compose (_("Cut monitor channel %1"), chn);
707 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
708 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
710 action_name = string_compose (X_("monitor-dim-%1"), chn);
711 action_descr = string_compose (_("Dim monitor channel %1"), chn);
712 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
713 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
715 action_name = string_compose (X_("monitor-solo-%1"), chn);
716 action_descr = string_compose (_("Solo monitor channel %1"), chn);
717 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
718 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
720 action_name = string_compose (X_("monitor-invert-%1"), chn);
721 action_descr = string_compose (_("Invert monitor channel %1"), chn);
722 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
723 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
728 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
729 RadioAction::Group solo_group;
731 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
732 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
733 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
734 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
735 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
736 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
738 ActionManager::add_action_group (solo_actions);
742 MonitorSection::solo_use_in_place ()
744 /* this is driven by a toggle on a radio group, and so is invoked twice,
745 once for the item that became inactive and once for the one that became
749 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
752 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
754 if (!ract->get_active ()) {
755 /* We are turning SiP off, which means that AFL or PFL will be turned on
756 shortly; don't update the solo model in the mean time, as if the currently
757 configured listen position is not the one that is about to be turned on,
758 things will go wrong.
760 _inhibit_solo_model_update = true;
762 Config->set_solo_control_is_listen_control (!ract->get_active());
763 _inhibit_solo_model_update = false;
769 MonitorSection::solo_use_afl ()
771 /* this is driven by a toggle on a radio group, and so is invoked twice,
772 once for the item that became inactive and once for the one that became
776 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
778 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
780 if (ract->get_active()) {
781 Config->set_solo_control_is_listen_control (true);
782 Config->set_listen_position (AfterFaderListen);
789 MonitorSection::solo_use_pfl ()
791 /* this is driven by a toggle on a radio group, and so is invoked twice,
792 once for the item that became inactive and once for the one that became
796 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
798 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
800 if (ract->get_active()) {
801 Config->set_solo_control_is_listen_control (true);
802 Config->set_listen_position (PreFaderListen);
809 MonitorSection::setup_knob_images ()
813 uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
815 snprintf (buf, 16, "#%x", (c >> 8));
816 MotionFeedback::set_lamp_color (buf);
817 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
821 error << "No usable large knob image" << endmsg;
822 throw failed_constructor ();
825 if (!big_knob_pixbuf) {
826 error << "No usable large knob image" << endmsg;
827 throw failed_constructor ();
832 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
836 error << "No usable small knob image" << endmsg;
837 throw failed_constructor ();
840 if (!little_knob_pixbuf) {
841 error << "No usable small knob image" << endmsg;
842 throw failed_constructor ();
848 MonitorSection::update_solo_model ()
850 if (_inhibit_solo_model_update) {
854 const char* action_name = 0;
855 Glib::RefPtr<Action> act;
857 if (Config->get_solo_control_is_listen_control()) {
858 switch (Config->get_listen_position()) {
859 case AfterFaderListen:
860 action_name = X_("solo-use-afl");
863 action_name = X_("solo-use-pfl");
867 action_name = X_("solo-use-in-place");
870 act = ActionManager::get_action (X_("Solo"), action_name);
873 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
875 /* because these are radio buttons, one of them will be
876 active no matter what. to trigger a change in the
877 action so that the view picks it up, toggle it.
879 if (ract->get_active()) {
880 ract->set_active (false);
882 ract->set_active (true);
889 MonitorSection::map_state ()
891 if (!_route || !_monitor) {
895 Glib::RefPtr<Action> act;
897 update_solo_model ();
899 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
901 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
903 tact->set_active (_monitor->cut_all());
907 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
909 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
911 tact->set_active (_monitor->dim_all());
915 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
917 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
919 tact->set_active (_monitor->mono());
923 uint32_t nchans = _monitor->output_streams().n_audio();
925 assert (nchans == _channel_buttons.size ());
927 for (uint32_t n = 0; n < nchans; ++n) {
929 char action_name[32];
931 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
932 act = ActionManager::get_action (X_("Monitor"), action_name);
934 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
936 tact->set_active (_monitor->cut (n));
940 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
941 act = ActionManager::get_action (X_("Monitor"), action_name);
943 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
945 tact->set_active (_monitor->dimmed (n));
949 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
950 act = ActionManager::get_action (X_("Monitor"), action_name);
952 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
954 tact->set_active (_monitor->soloed (n));
958 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
959 act = ActionManager::get_action (X_("Monitor"), action_name);
961 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
963 tact->set_active (_monitor->inverted (n));
970 MonitorSection::do_blink (bool onoff)
973 audition_blink (onoff);
977 MonitorSection::audition_blink (bool onoff)
983 if (_session->is_auditioning()) {
984 rude_audition_button.set_active (onoff);
986 rude_audition_button.set_active (false);
991 MonitorSection::solo_blink (bool onoff)
997 if (_session->soloing() || _session->listening()) {
998 rude_solo_button.set_active (onoff);
1000 if (_session->soloing()) {
1001 if (_session->solo_isolated()) {
1002 rude_iso_button.set_active (false);
1007 rude_solo_button.set_active (false);
1008 rude_iso_button.set_active (false);
1013 MonitorSection::cancel_solo (GdkEventButton*)
1016 if (_session->soloing()) {
1017 _session->set_solo (_session->get_routes(), false);
1018 } else if (_session->listening()) {
1019 _session->set_listen (_session->get_routes(), false);
1027 MonitorSection::cancel_isolate (GdkEventButton*)
1030 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1031 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1038 MonitorSection::cancel_audition (GdkEventButton*)
1041 _session->cancel_audition();
1047 MonitorSection::parameter_changed (std::string name)
1049 if (name == "solo-control-is-listen-control") {
1050 update_solo_model ();
1051 } else if (name == "listen-position") {
1052 update_solo_model ();
1057 MonitorSection::assign_controllables ()
1059 boost::shared_ptr<Controllable> none;
1061 if (!gain_control) {
1062 /* too early - GUI controls not set up yet */
1067 solo_cut_control->set_controllable (_session->solo_cut_control());
1069 solo_cut_control->set_controllable (none);
1073 gain_control->set_controllable (_route->gain_control());
1075 gain_control->set_controllable (none);
1080 cut_all_button.set_controllable (_monitor->cut_control());
1081 cut_all_button.watch ();
1082 dim_all_button.set_controllable (_monitor->dim_control());
1083 dim_all_button.watch ();
1084 mono_button.set_controllable (_monitor->mono_control());
1085 mono_button.watch ();
1087 dim_control->set_controllable (_monitor->dim_level_control ());
1088 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1092 cut_all_button.set_controllable (none);
1093 dim_all_button.set_controllable (none);
1094 mono_button.set_controllable (none);
1096 dim_control->set_controllable (none);
1097 solo_boost_control->set_controllable (none);
1102 MonitorSection::state_id() const
1104 return "monitor-section";