1 #include <gdkmm/pixbuf.h>
3 #include "pbd/compose.h"
6 #include "gtkmm2ext/bindable_button.h"
7 #include "gtkmm2ext/tearoff.h"
8 #include "gtkmm2ext/actions.h"
9 #include "gtkmm2ext/motionfeedback.h"
11 #include "ardour/dB.h"
12 #include "ardour/monitor_processor.h"
13 #include "ardour/route.h"
14 #include "ardour/utils.h"
16 #include "ardour_ui.h"
17 #include "gui_thread.h"
18 #include "monitor_section.h"
19 #include "public_editor.h"
20 #include "volume_controller.h"
25 using namespace ARDOUR;
27 using namespace Gtkmm2ext;
31 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
32 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
33 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
35 MonitorSection::MonitorSection (Session* s)
41 , solo_boost_control (0)
42 , solo_cut_control (0)
43 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
44 , afl_button (_("AFL"), ArdourButton::led_default_elements)
45 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
46 , exclusive_solo_button (ArdourButton::led_default_elements)
47 , solo_mute_override_button (ArdourButton::led_default_elements)
48 , _inhibit_solo_model_update (false)
50 Glib::RefPtr<Action> act;
52 if (!monitor_actions) {
54 /* do some static stuff */
67 rude_solo_button.set_text (_("soloing"));
68 rude_solo_button.set_name ("rude solo");
69 rude_solo_button.show ();
71 rude_iso_button.set_text (_("isolated"));
72 rude_iso_button.set_name ("rude isolate");
73 rude_iso_button.show ();
75 rude_audition_button.set_text (_("auditioning"));
76 rude_audition_button.set_name ("rude audition");
77 rude_audition_button.show ();
79 ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
81 rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo));
82 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
84 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate));
85 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
87 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition));
88 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
90 solo_in_place_button.set_name ("monitor section solo model");
91 afl_button.set_name ("monitor section solo model");
92 pfl_button.set_name ("monitor section solo model");
94 solo_model_box.set_spacing (6);
95 solo_model_box.pack_start (solo_in_place_button, true, false);
96 solo_model_box.pack_start (afl_button, true, false);
97 solo_model_box.pack_start (pfl_button, true, false);
99 solo_in_place_button.show ();
102 solo_model_box.show ();
104 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
105 ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
107 solo_in_place_button.set_related_action (act);
110 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
111 ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
113 afl_button.set_related_action (act);
116 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
117 ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
119 pfl_button.set_related_action (act);
124 solo_boost_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.01, 0.1, true, 30, 30, true);
125 ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
127 HBox* solo_packer = manage (new HBox);
128 solo_packer->set_spacing (6);
129 solo_packer->show ();
131 spin_label = manage (new Label (_("Solo Boost")));
132 spin_packer = manage (new VBox);
133 spin_packer->show ();
134 spin_packer->set_spacing (6);
135 spin_packer->pack_start (*solo_boost_control, false, false);
136 spin_packer->pack_start (*spin_label, false, false);
138 solo_packer->pack_start (*spin_packer, true, false);
142 solo_cut_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.1, 0.5, true, 30, 30, true);
143 ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
145 spin_label = manage (new Label (_("SiP Cut")));
146 spin_packer = manage (new VBox);
147 spin_packer->show ();
148 spin_packer->set_spacing (6);
149 spin_packer->pack_start (*solo_cut_control, false, false);
150 spin_packer->pack_start (*spin_label, false, false);
152 solo_packer->pack_start (*spin_packer, true, false);
156 dim_control = new VolumeController (little_knob_pixbuf, boost::shared_ptr<Controllable>(), 0.0, 0.01, 0.1, true, 30, 30, true);
157 ARDOUR_UI::instance()->tooltips().set_tip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
159 HBox* dim_packer = manage (new HBox);
162 spin_label = manage (new Label (_("Dim")));
163 spin_packer = manage (new VBox);
164 spin_packer->show ();
165 spin_packer->set_spacing (6);
166 spin_packer->pack_start (*dim_control, false, false);
167 spin_packer->pack_start (*spin_label, false, false);
169 dim_packer->pack_start (*spin_packer, true, false);
171 exclusive_solo_button.set_text (_("excl. solo"));
172 exclusive_solo_button.set_name (X_("monitor solo exclusive"));
173 ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
175 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
177 exclusive_solo_button.set_related_action (act);
180 solo_mute_override_button.set_text (_("solo ยป mute"));
181 solo_mute_override_button.set_name (X_("monitor solo override"));
182 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)"));
184 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
186 solo_mute_override_button.set_related_action (act);
189 HBox* solo_opt_box = manage (new HBox);
190 solo_opt_box->set_spacing (12);
191 solo_opt_box->set_homogeneous (true);
192 solo_opt_box->pack_start (exclusive_solo_button);
193 solo_opt_box->pack_start (solo_mute_override_button);
194 solo_opt_box->show ();
196 upper_packer.set_spacing (6);
198 Gtk::HBox* rude_box = manage (new HBox);
199 rude_box->pack_start (rude_solo_button, true, true);
200 rude_box->pack_start (rude_iso_button, true, true);
202 upper_packer.pack_start (*rude_box, false, false);
203 upper_packer.pack_start (rude_audition_button, false, false);
204 upper_packer.pack_start (solo_model_box, false, false, 12);
205 upper_packer.pack_start (*solo_opt_box, false, false);
206 upper_packer.pack_start (*solo_packer, false, false, 12);
208 cut_all_button.set_text (_("mute"));
209 cut_all_button.set_name ("monitor section cut");
210 cut_all_button.set_name (X_("monitor section cut"));
211 cut_all_button.set_size_request (-1,50);
212 cut_all_button.show ();
214 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
216 cut_all_button.set_related_action (act);
219 dim_all_button.set_text (_("dim"));
220 dim_all_button.set_name ("monitor section dim");
221 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
223 dim_all_button.set_related_action (act);
226 mono_button.set_text (_("mono"));
227 mono_button.set_name ("monitor section mono");
228 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
230 mono_button.set_related_action (act);
233 HBox* bbox = manage (new HBox);
235 bbox->set_spacing (12);
236 bbox->pack_start (mono_button, true, true);
237 bbox->pack_start (dim_all_button, true, true);
239 lower_packer.set_spacing (12);
240 lower_packer.pack_start (*bbox, false, false);
241 lower_packer.pack_start (cut_all_button, false, false);
245 gain_control = new VolumeController (big_knob_pixbuf, boost::shared_ptr<Controllable>(), 1.0, 0.01, 0.1, true, 80, 80, false);
247 spin_label = manage (new Label (_("Monitor")));
248 spin_packer = manage (new VBox);
249 spin_packer->show ();
250 spin_packer->set_spacing (6);
251 spin_packer->pack_start (*gain_control, false, false);
252 spin_packer->pack_start (*spin_label, false, false);
254 lower_packer.pack_start (*spin_packer, true, true);
256 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
257 channel_table_scroller.set_size_request (-1, 150);
258 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
259 channel_table_scroller.show ();
261 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
262 channel_size_group->add_widget (channel_table_header);
263 channel_size_group->add_widget (channel_table);
265 channel_table_header.resize (1, 5);
266 Label* l1 = manage (new Label (X_("out")));
267 l1->set_name (X_("MonitorSectionLabel"));
268 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
269 l1 = manage (new Label (X_("mute")));
270 l1->set_name (X_("MonitorSectionLabel"));
271 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
272 l1 = manage (new Label (X_("dim")));
273 l1->set_name (X_("MonitorSectionLabel"));
274 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
275 l1 = manage (new Label (X_("solo")));
276 l1->set_name (X_("MonitorSectionLabel"));
277 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
278 l1 = manage (new Label (X_("inv")));
279 l1->set_name (X_("MonitorSectionLabel"));
280 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
281 channel_table_header.show ();
283 table_hpacker.pack_start (channel_table, true, true);
285 /* note that we don't pack the table_hpacker till later
288 vpacker.set_border_width (6);
289 vpacker.set_spacing (12);
290 vpacker.pack_start (upper_packer, false, false);
291 vpacker.pack_start (*dim_packer, false, false);
292 vpacker.pack_start (channel_table_header, false, false);
293 vpacker.pack_start (channel_table_packer, false, false);
294 vpacker.pack_start (lower_packer, false, false);
296 hpacker.pack_start (vpacker, true, true);
298 gain_control->show_all ();
299 dim_control->show_all ();
300 solo_boost_control->show_all ();
302 channel_table.show ();
304 upper_packer.show ();
305 lower_packer.show ();
310 assign_controllables ();
312 _tearoff = new TearOff (hpacker);
314 /* if torn off, make this a normal window */
315 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
316 _tearoff->tearoff_window().set_title (X_("Monitor"));
317 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
319 /* catch changes that affect us */
321 Config->ParameterChanged.connect (config_connection, invalidator (*this), ui_bind (&MonitorSection::parameter_changed, this, _1), gui_context());
324 MonitorSection::~MonitorSection ()
326 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
330 _channel_buttons.clear ();
334 delete solo_boost_control;
339 MonitorSection::set_session (Session* s)
341 AxisView::set_session (s);
345 _route = _session->monitor_out ();
348 /* session with monitor section */
349 _monitor = _route->monitor_control ();
350 assign_controllables ();
352 /* session with no monitor section */
357 if (channel_table_scroller.get_parent()) {
358 /* scroller is packed, so remove it */
359 channel_table_packer.remove (channel_table_scroller);
360 /* remove the table_hpacker from the scroller */
361 channel_table_scroller.remove ();
364 if (table_hpacker.get_parent ()) {
365 /* this occurs when the table hpacker is directly
366 packed, so remove it.
368 channel_table_packer.remove (table_hpacker);
371 if (_monitor->output_streams().n_audio() > 7) {
372 /* put the table into a scrolled window, and then put
373 * that into the channel vpacker, after the table header
375 channel_table_scroller.add (table_hpacker);
376 channel_table_packer.pack_start (channel_table_scroller, true, true);
377 channel_table_scroller.show ();
380 /* just put the channel table itself into the channel
381 * vpacker, after the table header
384 channel_table_packer.pack_start (table_hpacker, true, true);
385 channel_table_scroller.hide ();
388 table_hpacker.show ();
389 channel_table.show ();
396 control_connections.drop_connections ();
397 rude_iso_button.unset_active_state ();
398 rude_solo_button.unset_active_state ();
400 assign_controllables ();
404 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
406 cut.set_diameter (3);
407 dim.set_diameter (3);
408 solo.set_diameter (3);
409 invert.set_diameter (3);
411 cut.set_name (X_("monitor section cut"));
412 dim.set_name (X_("monitor section dim"));
413 solo.set_name (X_("monitor section solo"));
414 invert.set_name (X_("monitor section invert"));
416 cut.unset_flags (Gtk::CAN_FOCUS);
417 dim.unset_flags (Gtk::CAN_FOCUS);
418 solo.unset_flags (Gtk::CAN_FOCUS);
419 invert.unset_flags (Gtk::CAN_FOCUS);
423 MonitorSection::populate_buttons ()
429 Glib::RefPtr<Action> act;
430 uint32_t nchans = _monitor->output_streams().n_audio();
432 channel_table.resize (nchans, 5);
433 channel_table.set_col_spacings (6);
434 channel_table.set_row_spacings (6);
435 channel_table.set_homogeneous (true);
437 const uint32_t row_offset = 0;
439 for (uint32_t i = 0; i < nchans; ++i) {
452 snprintf (buf, sizeof (buf), "%d", i+1);
456 Label* label = manage (new Label (l));
457 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
459 ChannelButtonSet* cbs = new ChannelButtonSet;
461 _channel_buttons.push_back (cbs);
463 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
464 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
465 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
466 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
468 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
469 act = ActionManager::get_action (X_("Monitor"), buf);
471 cbs->cut.set_related_action (act);
474 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
475 act = ActionManager::get_action (X_("Monitor"), buf);
477 cbs->dim.set_related_action (act);
480 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
481 act = ActionManager::get_action (X_("Monitor"), buf);
483 cbs->solo.set_related_action (act);
486 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
487 act = ActionManager::get_action (X_("Monitor"), buf);
489 cbs->invert.set_related_action (act);
493 channel_table.show_all ();
497 MonitorSection::toggle_exclusive_solo ()
503 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
505 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
506 Config->set_exclusive_solo (tact->get_active());
513 MonitorSection::toggle_mute_overrides_solo ()
519 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
521 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
522 Config->set_solo_mute_override (tact->get_active());
527 MonitorSection::dim_all ()
533 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
535 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
536 _monitor->set_dim_all (tact->get_active());
542 MonitorSection::cut_all ()
548 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
550 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
551 _monitor->set_cut_all (tact->get_active());
556 MonitorSection::mono ()
562 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
564 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
565 _monitor->set_mono (tact->get_active());
570 MonitorSection::cut_channel (uint32_t chn)
577 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
579 --chn; // 0-based in backend
581 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
583 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
584 _monitor->set_cut (chn, tact->get_active());
589 MonitorSection::dim_channel (uint32_t chn)
596 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
598 --chn; // 0-based in backend
600 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
602 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
603 _monitor->set_dim (chn, tact->get_active());
609 MonitorSection::solo_channel (uint32_t chn)
616 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
618 --chn; // 0-based in backend
620 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
622 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
623 _monitor->set_solo (chn, tact->get_active());
629 MonitorSection::invert_channel (uint32_t chn)
636 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
638 --chn; // 0-based in backend
640 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
642 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
643 _monitor->set_polarity (chn, tact->get_active());
648 MonitorSection::register_actions ()
652 Glib::RefPtr<Action> act;
654 monitor_actions = ActionGroup::create (X_("Monitor"));
655 ActionManager::add_action_group (monitor_actions);
657 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", "Switch monitor to mono",
658 sigc::mem_fun (*this, &MonitorSection::mono));
660 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", "Cut monitor",
661 sigc::mem_fun (*this, &MonitorSection::cut_all));
663 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", "Dim monitor",
664 sigc::mem_fun (*this, &MonitorSection::dim_all));
666 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", "Toggle exclusive solo mode",
667 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
669 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
670 tact->set_active (Config->get_exclusive_solo());
672 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", "Toggle mute overrides solo mode",
673 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
675 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
676 tact->set_active (Config->get_solo_mute_override());
679 /* note the 1-based counting (for naming - backend uses 0-based) */
681 for (uint32_t chn = 1; chn <= 16; ++chn) {
683 action_name = string_compose (X_("monitor-cut-%1"), chn);
684 action_descr = string_compose (_("Cut monitor channel %1"), chn);
685 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
686 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
688 action_name = string_compose (X_("monitor-dim-%1"), chn);
689 action_descr = string_compose (_("Dim monitor channel %1"), chn+1);
690 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
691 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
693 action_name = string_compose (X_("monitor-solo-%1"), chn);
694 action_descr = string_compose (_("Solo monitor channel %1"), chn+1);
695 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
696 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
698 action_name = string_compose (X_("monitor-invert-%1"), chn);
699 action_descr = string_compose (_("Invert monitor channel %1"), chn+1);
700 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
701 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
706 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
707 RadioAction::Group solo_group;
709 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", "In-place solo",
710 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
711 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", "After Fade Listen (AFL) solo",
712 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
713 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", "Pre Fade Listen (PFL) solo",
714 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
716 ActionManager::add_action_group (solo_actions);
720 MonitorSection::solo_use_in_place ()
722 /* this is driven by a toggle on a radio group, and so is invoked twice,
723 once for the item that became inactive and once for the one that became
727 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
730 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
732 if (!ract->get_active ()) {
733 /* We are turning SiP off, which means that AFL or PFL will be turned on
734 shortly; don't update the solo model in the mean time, as if the currently
735 configured listen position is not the one that is about to be turned on,
736 things will go wrong.
738 _inhibit_solo_model_update = true;
740 Config->set_solo_control_is_listen_control (!ract->get_active());
741 _inhibit_solo_model_update = false;
747 MonitorSection::solo_use_afl ()
749 /* this is driven by a toggle on a radio group, and so is invoked twice,
750 once for the item that became inactive and once for the one that became
754 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
756 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
758 if (ract->get_active()) {
759 Config->set_solo_control_is_listen_control (true);
760 Config->set_listen_position (AfterFaderListen);
767 MonitorSection::solo_use_pfl ()
769 /* this is driven by a toggle on a radio group, and so is invoked twice,
770 once for the item that became inactive and once for the one that became
774 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
776 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
778 if (ract->get_active()) {
779 Config->set_solo_control_is_listen_control (true);
780 Config->set_listen_position (PreFaderListen);
787 MonitorSection::setup_knob_images ()
791 uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
793 snprintf (buf, 16, "#%x", (c >> 8));
794 MotionFeedback::set_lamp_color (buf);
795 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
799 error << "No usable large knob image" << endmsg;
800 throw failed_constructor ();
803 if (!big_knob_pixbuf) {
804 error << "No usable large knob image" << endmsg;
805 throw failed_constructor ();
810 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
814 error << "No usable small knob image" << endmsg;
815 throw failed_constructor ();
818 if (!little_knob_pixbuf) {
819 error << "No usable small knob image" << endmsg;
820 throw failed_constructor ();
826 MonitorSection::update_solo_model ()
828 if (_inhibit_solo_model_update) {
832 const char* action_name = 0;
833 Glib::RefPtr<Action> act;
835 if (Config->get_solo_control_is_listen_control()) {
836 switch (Config->get_listen_position()) {
837 case AfterFaderListen:
838 action_name = X_("solo-use-afl");
841 action_name = X_("solo-use-pfl");
845 action_name = X_("solo-use-in-place");
848 act = ActionManager::get_action (X_("Solo"), action_name);
851 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
853 /* because these are radio buttons, one of them will be
854 active no matter what. to trigger a change in the
855 action so that the view picks it up, toggle it.
857 if (ract->get_active()) {
858 ract->set_active (false);
860 ract->set_active (true);
867 MonitorSection::map_state ()
869 if (!_route || !_monitor) {
873 Glib::RefPtr<Action> act;
875 update_solo_model ();
877 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
879 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
881 tact->set_active (_monitor->cut_all());
885 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
887 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
889 tact->set_active (_monitor->dim_all());
893 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
895 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
897 tact->set_active (_monitor->mono());
901 uint32_t nchans = _monitor->output_streams().n_audio();
903 assert (nchans == _channel_buttons.size ());
905 for (uint32_t n = 0; n < nchans; ++n) {
907 char action_name[32];
909 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n+1);
910 act = ActionManager::get_action (X_("Monitor"), action_name);
912 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
914 tact->set_active (_monitor->cut (n));
918 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n+1);
919 act = ActionManager::get_action (X_("Monitor"), action_name);
921 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
923 tact->set_active (_monitor->dimmed (n));
927 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n+1);
928 act = ActionManager::get_action (X_("Monitor"), action_name);
930 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
932 tact->set_active (_monitor->soloed (n));
936 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n+1);
937 act = ActionManager::get_action (X_("Monitor"), action_name);
939 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
941 tact->set_active (_monitor->inverted (n));
948 MonitorSection::do_blink (bool onoff)
951 audition_blink (onoff);
955 MonitorSection::audition_blink (bool onoff)
961 if (_session->is_auditioning()) {
962 rude_audition_button.set_active (onoff);
964 rude_audition_button.set_active (false);
969 MonitorSection::solo_blink (bool onoff)
975 if (_session->soloing() || _session->listening()) {
976 rude_solo_button.set_active (onoff);
978 if (_session->soloing()) {
979 if (_session->solo_isolated()) {
980 rude_iso_button.set_active (false);
985 rude_solo_button.set_active (false);
986 rude_iso_button.set_active (false);
991 MonitorSection::cancel_solo (GdkEventButton*)
994 if (_session->soloing()) {
995 _session->set_solo (_session->get_routes(), false);
996 } else if (_session->listening()) {
997 _session->set_listen (_session->get_routes(), false);
1005 MonitorSection::cancel_isolate (GdkEventButton*)
1008 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1009 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1016 MonitorSection::cancel_audition (GdkEventButton*)
1019 _session->cancel_audition();
1025 MonitorSection::parameter_changed (std::string name)
1027 if (name == "solo-control-is-listen-control") {
1028 update_solo_model ();
1029 } else if (name == "listen-position") {
1030 update_solo_model ();
1035 MonitorSection::assign_controllables ()
1037 boost::shared_ptr<Controllable> none;
1039 if (!gain_control) {
1040 /* too early - GUI controls not set up yet */
1045 solo_cut_control->set_controllable (_session->solo_cut_control());
1047 solo_cut_control->set_controllable (none);
1051 gain_control->set_controllable (_route->gain_control());
1053 gain_control->set_controllable (none);
1058 cut_all_button.set_controllable (_monitor->cut_control());
1059 cut_all_button.watch ();
1060 dim_all_button.set_controllable (_monitor->dim_control());
1061 dim_all_button.watch ();
1062 mono_button.set_controllable (_monitor->mono_control());
1063 mono_button.watch ();
1065 dim_control->set_controllable (_monitor->dim_level_control ());
1066 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1070 cut_all_button.set_controllable (none);
1071 dim_all_button.set_controllable (none);
1072 mono_button.set_controllable (none);
1074 dim_control->set_controllable (none);
1075 solo_boost_control->set_controllable (none);
1080 MonitorSection::state_id() const
1082 return "monitor-section";