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"
24 #include "pbd/replace_all.h"
26 #include "gtkmm2ext/actions.h"
27 #include "gtkmm2ext/utils.h"
29 #include <gtkmm/menu.h>
30 #include <gtkmm/menuitem.h>
32 #include "widgets/tearoff.h"
33 #include "widgets/tooltips.h"
35 #include "ardour/amp.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/monitor_processor.h"
38 #include "ardour/port.h"
39 #include "ardour/route.h"
40 #include "ardour/solo_isolate_control.h"
41 #include "ardour/user_bundle.h"
42 #include "ardour/plugin_manager.h"
44 #include "ardour_ui.h"
45 #include "gui_thread.h"
47 #include "monitor_section.h"
48 #include "public_editor.h"
50 #include "ui_config.h"
55 using namespace ARDOUR;
56 using namespace ArdourWidgets;
57 using namespace ARDOUR_UI_UTILS;
59 using namespace Gtkmm2ext;
63 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
64 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
66 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
68 MonitorSection::MonitorSection (Session* s)
69 : SessionHandlePtr (s)
73 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
74 , *channel_table_scroller.get_vadjustment ())
77 , solo_boost_control (0)
78 , solo_cut_control (0)
81 , solo_boost_display (0)
82 , solo_cut_display (0)
83 , _output_selector (0)
84 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
85 , afl_button (_("AFL"), ArdourButton::led_default_elements)
86 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
87 , exclusive_solo_button (ArdourButton::led_default_elements)
88 , solo_mute_override_button (ArdourButton::led_default_elements)
89 , toggle_processorbox_button (ArdourButton::default_elements)
90 , _inhibit_solo_model_update (false)
92 , _ui_initialized (false)
95 using namespace Menu_Helpers;
97 Glib::RefPtr<Action> act;
99 if (!monitor_actions) {
104 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
106 set_data ("ardour-bindings", bindings);
108 _plugin_selector = new PluginSelector (PluginManager::instance());
109 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
110 insert_box->set_no_show_all ();
112 // TODO allow keyboard shortcuts in ProcessorBox
116 /* Rude Solo & Solo Isolated */
117 rude_solo_button.set_text (_("Soloing"));
118 rude_solo_button.set_name ("rude solo");
119 rude_solo_button.show ();
121 rude_iso_button.set_text (_("Isolated"));
122 rude_iso_button.set_name ("rude isolate");
123 rude_iso_button.show ();
125 rude_audition_button.set_text (_("Auditioning"));
126 rude_audition_button.set_name ("rude audition");
127 rude_audition_button.show ();
129 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
131 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
132 rude_solo_button.set_related_action (act);
133 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
135 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
136 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
138 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
139 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
141 /* SIP, AFL, PFL radio */
143 solo_in_place_button.set_name ("monitor section solo model");
144 afl_button.set_name ("monitor section solo model");
145 pfl_button.set_name ("monitor section solo model");
147 solo_in_place_button.set_led_left (true);
148 afl_button.set_led_left (true);
149 pfl_button.set_led_left (true);
151 solo_in_place_button.show ();
155 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
156 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
158 solo_in_place_button.set_related_action (act);
161 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
162 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
164 afl_button.set_related_action (act);
167 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
168 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
170 pfl_button.set_related_action (act);
173 /* Solo option buttons */
174 exclusive_solo_button.set_text (_("Excl. Solo"));
175 exclusive_solo_button.set_name (X_("monitor section solo option"));
176 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
178 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
180 exclusive_solo_button.set_related_action (act);
183 solo_mute_override_button.set_text (_("Solo ยป Mute"));
184 solo_mute_override_button.set_name (X_("monitor section solo option"));
185 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
187 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
189 solo_mute_override_button.set_related_action (act);
192 /* Processor Box hide/shos */
193 toggle_processorbox_button.set_text (_("Processors"));
194 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
195 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
197 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
198 toggle_processorbox_button.set_related_action (proctoggle);
201 Label* solo_boost_label;
202 Label* solo_cut_label;
205 /* Solo Boost Knob */
207 solo_boost_control = new ArdourKnob ();
208 solo_boost_control->set_name("monitor section knob");
209 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
210 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
212 solo_boost_display = new ArdourDisplay ();
213 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
214 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
215 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
216 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
217 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
219 solo_boost_label = manage (new Label (_("Solo Boost")));
223 solo_cut_control = new ArdourKnob ();
224 solo_cut_control->set_name ("monitor section knob");
225 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
226 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
228 solo_cut_display = new ArdourDisplay ();
229 solo_cut_display->set_name("monitor section dropdown"); // XXX
230 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
231 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
232 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
233 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
234 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
235 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
237 solo_cut_label = manage (new Label (_("SiP Cut")));
241 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
242 dim_control->set_name ("monitor section knob");
243 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
244 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
246 dim_display = new ArdourDisplay ();
247 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
248 dim_display->add_controllable_preset(_("0 dB"), 0.0);
249 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
250 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
251 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
252 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
254 dim_label = manage (new Label (_("Dim")));
257 cut_all_button.set_text (_("Mute"));
258 cut_all_button.set_name ("mute button");
259 cut_all_button.set_size_request (-1, PX_SCALE(30));
260 cut_all_button.show ();
262 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
264 cut_all_button.set_related_action (act);
268 dim_all_button.set_text (_("Dim"));
269 dim_all_button.set_name ("monitor section dim");
270 dim_all_button.set_size_request (-1, PX_SCALE(25));
271 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
273 dim_all_button.set_related_action (act);
277 mono_button.set_text (_("Mono"));
278 mono_button.set_name ("monitor section mono");
279 mono_button.set_size_request (-1, PX_SCALE(25));
280 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
282 mono_button.set_related_action (act);
287 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
288 gain_control->set_name("monitor section knob");
289 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
291 gain_display = new ArdourDisplay ();
292 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
293 gain_display->add_controllable_preset(_("0 dB"), 0.0);
294 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
295 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
296 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
297 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
298 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
300 Label* output_label = manage (new Label (_("Output")));
301 output_label->set_name (X_("MonitorSectionLabel"));
303 output_button = new ArdourButton ();
304 output_button->set_text (_("Output"));
305 output_button->set_name (X_("monitor section cut")); // XXX
306 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
307 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
309 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
310 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
311 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
312 channel_table_scroller.show ();
313 channel_table_scroller.add (channel_table_viewport);
315 channel_size_group->add_widget (channel_table_header);
316 channel_table_header.resize (1, 5);
318 Label* l1 = manage (new Label (X_(" ")));
319 l1->set_name (X_("MonitorSectionLabel"));
320 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
322 l1 = manage (new Label (_("Mute")));
323 l1->set_name (X_("MonitorSectionLabel"));
324 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
326 l1 = manage (new Label (_("Dim")));
327 l1->set_name (X_("MonitorSectionLabel"));
328 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
330 l1 = manage (new Label (_("Solo")));
331 l1->set_name (X_("MonitorSectionLabel"));
332 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
334 l1 = manage (new Label (_("Inv")));
335 l1->set_name (X_("MonitorSectionLabel"));
336 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
338 channel_table_header.show ();
341 /****************************************************************************
342 * LAYOUT top to bottom
345 // solo, iso information
346 HBox* rude_box = manage (new HBox);
347 rude_box->set_spacing (PX_SCALE(4));
348 rude_box->set_homogeneous (true);
349 rude_box->pack_start (rude_solo_button, true, true);
350 rude_box->pack_start (rude_iso_button, true, true);
352 // solo options (right align)
353 HBox* tbx1 = manage (new HBox);
354 tbx1->pack_end (exclusive_solo_button, false, false);
356 HBox* tbx2 = manage (new HBox);
357 tbx2->pack_end (solo_mute_override_button, false, false);
359 HBox* tbx3 = manage (new HBox);
360 tbx3->pack_end (toggle_processorbox_button, false, false);
362 HBox* tbx0 = manage (new HBox); // space
364 // combined solo mode (Sip, AFL, PFL) & solo options
365 Table *solo_tbl = manage (new Table);
366 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
369 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
370 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
371 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
372 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
374 // boost, cut, dim volume control
375 Table *level_tbl = manage (new Table);
376 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
378 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
380 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
382 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
384 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
385 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
386 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
389 HBox* mono_dim_box = manage (new HBox);
390 mono_dim_box->set_spacing (PX_SCALE(4));
391 mono_dim_box->set_homogeneous (true);
392 mono_dim_box->pack_start (mono_button, true, true);
393 mono_dim_box->pack_end (dim_all_button, true, true);
396 Label* spin_label = manage (new Label (_("Monitor")));
397 VBox* spin_packer = manage (new VBox);
398 spin_packer->set_spacing (PX_SCALE(2));
399 spin_packer->pack_start (*spin_label, false, false);
400 spin_packer->pack_start (*gain_control, false, false);
401 spin_packer->pack_start (*gain_display, false, false);
403 master_packer.pack_start (*spin_packer, true, false);
405 // combined gain section (channels, mute, dim)
406 VBox* lower_packer = manage (new VBox);
407 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
408 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
409 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
410 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
412 // calc height of mixer scrollbar
413 int scrollbar_height = 0;
415 Gtk::Window window (WINDOW_TOPLEVEL);
416 HScrollbar scrollbar;
417 window.add (scrollbar);
418 scrollbar.set_name ("MixerWindow");
419 scrollbar.ensure_style();
420 Gtk::Requisition requisition(scrollbar.size_request ());
421 scrollbar_height = requisition.height;
424 // output port select
425 VBox* out_packer = manage (new VBox);
426 out_packer->set_spacing (PX_SCALE(2));
427 out_packer->pack_start (*output_label, false, false);
428 out_packer->pack_start (*output_button, false, false);
430 /****************************************************************************
433 vpacker.set_border_width (PX_SCALE(3));
434 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
435 vpacker.pack_start (rude_audition_button, false, false, 0);
436 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
437 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
438 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
439 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
440 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
441 vpacker.pack_end (*out_packer, false, false,
443 scrollbar_height - 2 /* no outer sample */
445 scrollbar_height + 2 /* sample borders */
449 hpacker.set_spacing (0);
450 hpacker.pack_start (vpacker, true, true);
454 gain_control->show_all ();
455 gain_display->show_all ();
456 dim_control->show_all ();
457 dim_display->show_all();
458 solo_boost_control->show_all ();
459 solo_boost_display->show_all();
461 mono_dim_box->show ();
462 spin_packer->show ();
463 master_packer.show ();
466 solo_tbl->show_all();
468 lower_packer->show ();
475 assign_controllables ();
477 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
478 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
480 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
481 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
482 set_flags (CAN_FOCUS);
484 _tearoff = new TearOff (*this);
486 if (!UIConfiguration::instance().get_floating_monitor_section()) {
487 /* if torn off, make this a normal window
488 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
490 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
492 _tearoff->tearoff_window().set_title (X_("Monitor"));
493 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
495 update_output_display ();
496 update_processor_box ();
497 _ui_initialized = true;
499 /* catch changes that affect us */
500 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
501 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
503 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
506 MonitorSection::~MonitorSection ()
508 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
512 _channel_buttons.clear ();
513 output_changed_connections.drop_connections ();
515 delete insert_box; insert_box = 0;
516 delete output_button; output_button = 0;
517 delete gain_control; gain_control = 0;
518 delete gain_display; gain_display = 0;
519 delete dim_control; dim_control = 0;
520 delete dim_display; dim_display = 0;
521 delete solo_boost_control; solo_boost_control = 0;
522 delete solo_boost_display; solo_boost_display = 0;
523 delete solo_cut_control; solo_cut_control = 0;
524 delete solo_cut_display; solo_cut_display = 0;
525 delete _tearoff; _tearoff = 0;
526 delete _output_selector; _output_selector = 0;
527 delete channel_table; channel_table = 0;
531 MonitorSection::enter_handler (GdkEventCrossing* ev)
538 MonitorSection::leave_handler (GdkEventCrossing* ev)
540 switch (ev->detail) {
541 case GDK_NOTIFY_INFERIOR:
547 /* cancel focus if we're not torn off. With X11 WM's that do
548 * focus-follows-mouse, focus will be taken from us anyway.
551 Widget* top = get_toplevel();
553 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
554 Window* win = dynamic_cast<Window*> (top);
555 gtk_window_set_focus (win->gobj(), 0);
562 MonitorSection::update_processor_box ()
564 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
566 if (count_processors () > 0 && !show_processor_box) {
567 toggle_processorbox_button.set_name (X_("monitor section processors present"));
569 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
572 if (insert_box->is_visible() == show_processor_box) {
576 if (show_processor_box) {
577 if (master_packer.get_parent()) {
578 master_packer.get_parent()->remove (master_packer);
581 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
583 if (master_packer.get_parent()) {
584 master_packer.get_parent()->remove (master_packer);
587 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
592 MonitorSection::set_session (Session* s)
594 RouteUI::set_session (s);
595 _plugin_selector->set_session (_session);
599 _route = _session->monitor_out ();
602 /* session with monitor section */
603 _monitor = _route->monitor_control ();
604 assign_controllables ();
605 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
606 boost::bind (&MonitorSection::update_output_display, this),
608 insert_box->set_route (_route);
609 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
610 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
611 if (_ui_initialized) {
612 update_processor_box ();
615 /* session with no monitor section */
616 output_changed_connections.drop_connections();
619 delete _output_selector;
620 _output_selector = 0;
628 output_changed_connections.drop_connections();
631 control_connections.drop_connections ();
632 rude_iso_button.unset_active_state ();
633 rude_solo_button.unset_active_state ();
634 delete _output_selector;
635 _output_selector = 0;
637 assign_controllables ();
641 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
643 cut.set_name (X_("mute button"));
644 dim.set_name (X_("monitor section dim"));
645 solo.set_name (X_("solo button"));
646 invert.set_name (X_("invert button"));
648 cut.unset_flags (Gtk::CAN_FOCUS);
649 dim.unset_flags (Gtk::CAN_FOCUS);
650 solo.unset_flags (Gtk::CAN_FOCUS);
651 invert.unset_flags (Gtk::CAN_FOCUS);
655 MonitorSection::populate_buttons ()
662 channel_size_group->remove_widget (*channel_table);
663 delete channel_table;
666 channel_table = new Gtk::Table();
668 channel_table->set_col_spacings (6);
669 channel_table->set_row_spacings (6);
670 channel_table->set_homogeneous (true);
672 channel_size_group->add_widget (*channel_table);
673 channel_table->show ();
674 table_hpacker.pack_start (*channel_table, true, true);
676 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
679 _channel_buttons.clear ();
681 Glib::RefPtr<Action> act;
682 uint32_t nchans = _monitor->output_streams().n_audio();
684 channel_table->resize (nchans, 5);
686 const uint32_t row_offset = 0;
688 for (uint32_t i = 0; i < nchans; ++i) {
701 snprintf (buf, sizeof (buf), "%d", i+1);
705 Label* label = manage (new Label (l));
706 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
708 ChannelButtonSet* cbs = new ChannelButtonSet;
710 _channel_buttons.push_back (cbs);
712 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
713 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
714 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
715 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
717 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
718 act = ActionManager::get_action (X_("Monitor"), buf);
720 cbs->cut.set_related_action (act);
723 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
724 act = ActionManager::get_action (X_("Monitor"), buf);
726 cbs->dim.set_related_action (act);
729 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
730 act = ActionManager::get_action (X_("Monitor"), buf);
732 cbs->solo.set_related_action (act);
735 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
736 act = ActionManager::get_action (X_("Monitor"), buf);
738 cbs->invert.set_related_action (act);
742 channel_table->show_all ();
744 if (channel_table_scroller.get_parent()) {
745 /* scroller is packed, so remove it */
746 channel_table_packer.remove (channel_table_scroller);
749 if (table_hpacker.get_parent () == &channel_table_packer) {
750 /* this occurs when the table hpacker is directly
751 packed, so remove it.
753 channel_table_packer.remove (table_hpacker);
754 } else if (table_hpacker.get_parent()) {
755 channel_table_viewport.remove ();
759 /* put the table into a scrolled window, and then put
760 * that into the channel vpacker, after the table header
762 channel_table_viewport.add (table_hpacker);
763 channel_table_packer.pack_start (channel_table_scroller, true, true);
764 channel_table_viewport.show ();
765 channel_table_scroller.show ();
768 /* just put the channel table itself into the channel
769 * vpacker, after the table header
771 channel_table_packer.pack_start (table_hpacker, true, true);
772 channel_table_scroller.hide ();
774 table_hpacker.show ();
775 channel_table->show ();
779 MonitorSection::toggle_exclusive_solo ()
785 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
787 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
788 Config->set_exclusive_solo (tact->get_active());
794 MonitorSection::toggle_mute_overrides_solo ()
800 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
802 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
803 Config->set_solo_mute_override (tact->get_active());
808 MonitorSection::dim_all ()
814 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
816 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
817 _monitor->set_dim_all (tact->get_active());
823 MonitorSection::cut_all ()
829 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
831 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
832 _monitor->set_cut_all (tact->get_active());
837 MonitorSection::mono ()
843 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
845 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
846 _monitor->set_mono (tact->get_active());
851 MonitorSection::cut_channel (uint32_t chn)
858 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
860 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
862 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
863 _monitor->set_cut (chn, tact->get_active());
868 MonitorSection::dim_channel (uint32_t chn)
875 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
877 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
879 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
880 _monitor->set_dim (chn, tact->get_active());
886 MonitorSection::solo_channel (uint32_t chn)
893 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
895 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
897 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
898 _monitor->set_solo (chn, tact->get_active());
904 MonitorSection::invert_channel (uint32_t chn)
911 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
913 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
915 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
916 _monitor->set_polarity (chn, tact->get_active());
921 MonitorSection::register_actions ()
925 Glib::RefPtr<Action> act;
927 monitor_actions = ActionManager::create_action_group (X_("Monitor"));
929 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
930 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
932 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
933 tact->set_active (Config->get_exclusive_solo());
935 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
936 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
938 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
939 tact->set_active (Config->get_solo_mute_override());
941 for (uint32_t chn = 0; chn < 16; ++chn) {
943 action_name = string_compose (X_("monitor-cut-%1"), chn);
944 action_descr = string_compose (_("Cut monitor channel %1"), chn);
945 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
946 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
948 action_name = string_compose (X_("monitor-dim-%1"), chn);
949 action_descr = string_compose (_("Dim monitor channel %1"), chn);
950 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
951 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
953 action_name = string_compose (X_("monitor-solo-%1"), chn);
954 action_descr = string_compose (_("Solo monitor channel %1"), chn);
955 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
956 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
958 action_name = string_compose (X_("monitor-invert-%1"), chn);
959 action_descr = string_compose (_("Invert monitor channel %1"), chn);
960 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
961 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
966 Glib::RefPtr<ActionGroup> solo_actions = ActionManager::create_action_group (X_("Solo"));
967 RadioAction::Group solo_group;
969 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
970 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
971 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
972 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
973 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
974 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
976 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
977 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
982 MonitorSection::solo_use_in_place ()
984 /* this is driven by a toggle on a radio group, and so is invoked twice,
985 once for the item that became inactive and once for the one that became
989 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
992 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
994 if (!ract->get_active ()) {
995 /* We are turning SiP off, which means that AFL or PFL will be turned on
996 shortly; don't update the solo model in the mean time, as if the currently
997 configured listen position is not the one that is about to be turned on,
998 things will go wrong.
1000 _inhibit_solo_model_update = true;
1002 Config->set_solo_control_is_listen_control (!ract->get_active());
1003 _inhibit_solo_model_update = false;
1009 MonitorSection::solo_use_afl ()
1011 /* this is driven by a toggle on a radio group, and so is invoked twice,
1012 once for the item that became inactive and once for the one that became
1016 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1018 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1020 if (ract->get_active()) {
1021 Config->set_solo_control_is_listen_control (true);
1022 Config->set_listen_position (AfterFaderListen);
1029 MonitorSection::solo_use_pfl ()
1031 /* this is driven by a toggle on a radio group, and so is invoked twice,
1032 once for the item that became inactive and once for the one that became
1036 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1038 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1040 if (ract->get_active()) {
1041 Config->set_solo_control_is_listen_control (true);
1042 Config->set_listen_position (PreFaderListen);
1049 MonitorSection::update_solo_model ()
1051 if (_inhibit_solo_model_update) {
1055 const char* action_name = 0;
1056 Glib::RefPtr<Action> act;
1058 if (Config->get_solo_control_is_listen_control()) {
1059 switch (Config->get_listen_position()) {
1060 case AfterFaderListen:
1061 action_name = X_("solo-use-afl");
1063 case PreFaderListen:
1064 action_name = X_("solo-use-pfl");
1068 action_name = X_("solo-use-in-place");
1071 act = ActionManager::get_action (X_("Solo"), action_name);
1074 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1076 /* because these are radio buttons, one of them will be
1077 active no matter what. to trigger a change in the
1078 action so that the view picks it up, toggle it.
1080 if (ract->get_active()) {
1081 ract->set_active (false);
1083 ract->set_active (true);
1090 MonitorSection::map_state ()
1092 if (!_route || !_monitor) {
1096 update_solo_model ();
1098 Glib::RefPtr<Action> act;
1099 Glib::RefPtr<ToggleAction> tact;
1101 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1103 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1105 tact->set_active (_monitor->cut_all());
1109 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1111 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1113 tact->set_active (_monitor->dim_all());
1117 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1119 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1121 tact->set_active (_monitor->mono());
1125 uint32_t nchans = _monitor->output_streams().n_audio();
1127 assert (nchans == _channel_buttons.size ());
1129 for (uint32_t n = 0; n < nchans; ++n) {
1131 char action_name[32];
1133 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1134 act = ActionManager::get_action (X_("Monitor"), action_name);
1136 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1138 tact->set_active (_monitor->cut (n));
1142 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1143 act = ActionManager::get_action (X_("Monitor"), action_name);
1145 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1147 tact->set_active (_monitor->dimmed (n));
1151 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1152 act = ActionManager::get_action (X_("Monitor"), action_name);
1154 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1156 tact->set_active (_monitor->soloed (n));
1160 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1161 act = ActionManager::get_action (X_("Monitor"), action_name);
1163 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1165 tact->set_active (_monitor->inverted (n));
1172 MonitorSection::do_blink (bool onoff)
1174 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1179 audition_blink (onoff);
1183 MonitorSection::audition_blink (bool onoff)
1185 if (_session == 0) {
1189 if (_session->is_auditioning()) {
1190 rude_audition_button.set_active (onoff);
1192 rude_audition_button.set_active (false);
1197 MonitorSection::solo_blink (bool onoff)
1199 if (_session == 0) {
1203 if (_session->soloing() || _session->listening()) {
1204 rude_solo_button.set_active (onoff);
1206 if (_session->soloing()) {
1207 if (_session->solo_isolated()) {
1208 rude_iso_button.set_active (onoff);
1210 rude_iso_button.set_active (false);
1215 rude_solo_button.set_active (false);
1216 rude_iso_button.set_active (false);
1221 MonitorSection::cancel_isolate (GdkEventButton*)
1224 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1225 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1232 MonitorSection::cancel_audition (GdkEventButton*)
1235 _session->cancel_audition();
1240 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1242 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1243 if (tact && tact->get_active() != value) { \
1244 tact->set_active(value); \
1249 MonitorSection::parameter_changed (std::string name)
1251 if (name == "solo-control-is-listen-control") {
1252 update_solo_model ();
1253 } else if (name == "listen-position") {
1254 update_solo_model ();
1255 } else if (name == "solo-mute-override") {
1256 SYNCHRONIZE_TOGGLE_ACTION(
1257 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1258 Config->get_solo_mute_override ())
1259 } else if (name == "exclusive-solo") {
1260 SYNCHRONIZE_TOGGLE_ACTION(
1261 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1262 Config->get_exclusive_solo ())
1267 MonitorSection::assign_controllables ()
1269 boost::shared_ptr<Controllable> none;
1271 if (!gain_control) {
1272 /* too early - GUI controls not set up yet */
1277 solo_cut_control->set_controllable (_session->solo_cut_control());
1278 solo_cut_display->set_controllable (_session->solo_cut_control());
1280 solo_cut_control->set_controllable (none);
1281 solo_cut_display->set_controllable (none);
1285 gain_control->set_controllable (_route->gain_control());
1286 gain_display->set_controllable (_route->gain_control());
1288 gain_control->set_controllable (none);
1293 cut_all_button.set_controllable (_monitor->cut_control());
1294 cut_all_button.watch ();
1295 dim_all_button.set_controllable (_monitor->dim_control());
1296 dim_all_button.watch ();
1297 mono_button.set_controllable (_monitor->mono_control());
1298 mono_button.watch ();
1300 dim_control->set_controllable (_monitor->dim_level_control ());
1301 dim_display->set_controllable (_monitor->dim_level_control ());
1302 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1303 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1307 cut_all_button.set_controllable (none);
1308 dim_all_button.set_controllable (none);
1309 mono_button.set_controllable (none);
1311 dim_control->set_controllable (none);
1312 dim_display->set_controllable (none);
1313 solo_boost_control->set_controllable (none);
1314 solo_boost_display->set_controllable (none);
1319 MonitorSection::state_id() const
1321 return "monitor-section";
1325 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1327 using namespace Menu_Helpers;
1329 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1333 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1334 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1338 if (i != output_menu_bundles.end()) {
1342 output_menu_bundles.push_back (b);
1344 MenuList& citems = output_menu.items();
1346 std::string n = b->name ();
1347 replace_all (n, "_", " ");
1349 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1353 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1356 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1358 if (std::find (current.begin(), current.end(), c) == current.end()) {
1359 _route->output()->connect_ports_to_bundle (c, true, this);
1361 _route->output()->disconnect_ports_from_bundle (c, this);
1366 MonitorSection::output_release (GdkEventButton *ev)
1368 switch (ev->button) {
1370 edit_output_configuration ();
1377 struct RouteCompareByName {
1378 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1379 return a->name().compare (b->name()) < 0;
1384 MonitorSection::output_press (GdkEventButton *ev)
1386 using namespace Menu_Helpers;
1388 MessageDialog msg (_("No session - no I/O changes are possible"));
1393 MenuList& citems = output_menu.items();
1394 switch (ev->button) {
1397 return false; //wait for the mouse-up to pop the dialog
1401 output_menu.set_name ("ArdourContextMenu");
1403 output_menu_bundles.clear ();
1405 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1407 citems.push_back (SeparatorElem());
1408 uint32_t const n_with_separator = citems.size ();
1410 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1412 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1414 /* give user bundles first chance at being in the menu */
1416 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1417 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1418 maybe_add_bundle_to_output_menu (*i, current);
1422 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1423 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1424 maybe_add_bundle_to_output_menu (*i, current);
1428 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1429 RouteList copy = *routes;
1430 copy.sort (RouteCompareByName ());
1431 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1432 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1435 if (citems.size() == n_with_separator) {
1436 /* no routes added; remove the separator */
1440 citems.push_back (SeparatorElem());
1441 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1443 output_menu.popup (1, ev->time);
1454 MonitorSection::update_output_display ()
1456 if (!_route || !_monitor || _session->deletion_in_progress()) {
1462 boost::shared_ptr<Port> port;
1463 vector<string> port_connections;
1465 uint32_t total_connection_count = 0;
1466 uint32_t io_connection_count = 0;
1467 uint32_t ardour_connection_count = 0;
1468 uint32_t system_connection_count = 0;
1469 uint32_t other_connection_count = 0;
1471 ostringstream label;
1473 bool have_label = false;
1474 bool each_io_has_one_connection = true;
1476 string connection_name;
1477 string ardour_track_name;
1478 string other_connection_type;
1479 string system_ports;
1482 ostringstream tooltip;
1483 char * tooltip_cstr;
1485 io_count = _route->n_outputs().n_total();
1486 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1489 for (io_index = 0; io_index < io_count; ++io_index) {
1491 port = _route->output()->nth (io_index);
1493 //ignore any port connections that don't match our DataType
1494 if (port->type() != DataType::AUDIO) {
1498 port_connections.clear ();
1499 port->get_connections(port_connections);
1500 io_connection_count = 0;
1502 if (!port_connections.empty()) {
1503 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1505 string& connection_name (*i);
1507 if (connection_name.find("system:") == 0) {
1508 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1511 if (io_connection_count == 0) {
1512 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1514 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1517 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1520 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1521 if (ardour_track_name.empty()) {
1522 // "ardour:Master/in 1" -> "ardour:Master/"
1523 string::size_type slash = connection_name.find("/");
1524 if (slash != string::npos) {
1525 ardour_track_name = connection_name.substr(0, slash + 1);
1529 if (connection_name.find(ardour_track_name) == 0) {
1530 ++ardour_connection_count;
1532 } else if (!pn.empty()) {
1533 if (system_ports.empty()) {
1536 system_ports += "/" + pn;
1538 if (connection_name.find("system:") == 0) {
1539 ++system_connection_count;
1541 } else if (connection_name.find("system:") == 0) {
1542 // "system:playback_123" -> "123"
1543 system_port = connection_name.substr(16);
1544 if (system_ports.empty()) {
1545 system_ports += system_port;
1547 system_ports += "/" + system_port;
1550 ++system_connection_count;
1552 if (other_connection_type.empty()) {
1553 // "jamin:in 1" -> "jamin:"
1554 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1557 if (connection_name.find(other_connection_type) == 0) {
1558 ++other_connection_count;
1562 ++total_connection_count;
1563 ++io_connection_count;
1567 if (io_connection_count != 1) {
1568 each_io_has_one_connection = false;
1572 if (total_connection_count == 0) {
1573 tooltip << endl << _("Disconnected");
1576 tooltip_cstr = new char[tooltip.str().size() + 1];
1577 strcpy(tooltip_cstr, tooltip.str().c_str());
1579 set_tooltip (output_button, tooltip_cstr, "");
1581 if (each_io_has_one_connection) {
1582 if (total_connection_count == ardour_connection_count) {
1583 // all connections are to the same track in ardour
1584 // "ardour:Master/" -> "Master"
1585 string::size_type slash = ardour_track_name.find("/");
1586 if (slash != string::npos) {
1587 label << ardour_track_name.substr(7, slash - 7);
1590 } else if (total_connection_count == system_connection_count) {
1591 // all connections are to system ports
1592 label << system_ports;
1594 } else if (total_connection_count == other_connection_count) {
1595 // all connections are to the same external program eg jamin
1596 // "jamin:" -> "jamin"
1597 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1603 if (total_connection_count == 0) {
1607 // Odd configuration
1608 label << "*" << total_connection_count << "*";
1612 output_button->set_text (label.str());
1616 MonitorSection::disconnect_output ()
1619 _route->output()->disconnect(this);
1624 MonitorSection::edit_output_configuration ()
1626 if (_output_selector == 0) {
1627 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1629 _output_selector->present ();
1633 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1638 boost::shared_ptr<Port> a = wa.lock ();
1639 boost::shared_ptr<Port> b = wb.lock ();
1640 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1641 update_output_display ();
1646 MonitorSection::load_bindings ()
1648 bindings = Bindings::get_bindings (X_("Monitor Section"));
1652 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1654 boost::shared_ptr<Processor> processor (p.lock ());
1655 if (!processor || !processor->display_to_user()) {
1658 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1665 MonitorSection::count_processors ()
1667 uint32_t processor_count = 0;
1669 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1671 return processor_count;
1675 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1677 update_processor_box ();
1681 MonitorSection::action_proxy0 (enum MonitorActions action)
1683 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1697 case ToggleExclusiveSolo:
1698 ms->toggle_exclusive_solo ();
1700 case ToggleMuteOverridesSolo:
1701 ms->toggle_mute_overrides_solo ();
1703 case SoloUseInPlace:
1704 ms->solo_use_in_place ();
1707 ms->solo_use_afl ();
1710 ms->solo_use_pfl ();
1712 case ToggleMonitorProcessorBox:
1713 ms->update_processor_box ();
1719 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1721 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1727 ms->cut_channel (chn);
1730 ms->dim_channel (chn);
1733 ms->solo_channel (chn);
1736 ms->invert_channel (chn);