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"
25 #include "pbd/stacktrace.h"
27 #include "gtkmm2ext/actions.h"
28 #include "gtkmm2ext/utils.h"
30 #include <gtkmm/menu.h>
31 #include <gtkmm/menuitem.h>
33 #include "widgets/tearoff.h"
34 #include "widgets/tooltips.h"
36 #include "ardour/amp.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/monitor_processor.h"
39 #include "ardour/port.h"
40 #include "ardour/route.h"
41 #include "ardour/solo_isolate_control.h"
42 #include "ardour/user_bundle.h"
43 #include "ardour/plugin_manager.h"
45 #include "ardour_ui.h"
46 #include "gui_thread.h"
48 #include "monitor_section.h"
49 #include "public_editor.h"
51 #include "ui_config.h"
56 using namespace ARDOUR;
57 using namespace ArdourWidgets;
58 using namespace ARDOUR_UI_UTILS;
60 using namespace Gtkmm2ext;
64 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
66 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
67 if (action && action->get_active() != value) { \
68 action->set_active(value); \
71 MonitorSection::MonitorSection ()
72 : RouteUI ((Session*) 0)
75 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
76 , *channel_table_scroller.get_vadjustment ())
79 , solo_boost_control (0)
80 , solo_cut_control (0)
83 , solo_boost_display (0)
84 , solo_cut_display (0)
85 , _output_selector (0)
86 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
87 , afl_button (_("AFL"), ArdourButton::led_default_elements)
88 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
89 , exclusive_solo_button (ArdourButton::led_default_elements)
90 , solo_mute_override_button (ArdourButton::led_default_elements)
91 , toggle_processorbox_button (ArdourButton::default_elements)
92 , _inhibit_solo_model_update (false)
94 , _ui_initialized (false)
96 /* note that although this a RouteUI, we never called ::set_route() so
97 * we do not need to worry about self-destructing when the Route (the
98 * monitor out) is destroyed.
101 using namespace Menu_Helpers;
103 Glib::RefPtr<Action> act;
107 set_data ("ardour-bindings", bindings);
109 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
111 _plugin_selector = new PluginSelector (PluginManager::instance());
112 insert_box = new ProcessorBox (0, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
113 insert_box->set_no_show_all ();
115 // TODO allow keyboard shortcuts in ProcessorBox
117 /* Rude Solo & Solo Isolated */
118 rude_solo_button.set_text (_("Soloing"));
119 rude_solo_button.set_name ("rude solo");
120 rude_solo_button.show ();
122 rude_iso_button.set_text (_("Isolated"));
123 rude_iso_button.set_name ("rude isolate");
124 rude_iso_button.show ();
126 rude_audition_button.set_text (_("Auditioning"));
127 rude_audition_button.set_name ("rude audition");
128 rude_audition_button.show ();
130 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
132 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
134 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
135 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
137 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
138 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
140 /* SIP, AFL, PFL radio */
142 solo_in_place_button.set_name ("monitor section solo model");
143 afl_button.set_name ("monitor section solo model");
144 pfl_button.set_name ("monitor section solo model");
146 solo_in_place_button.set_led_left (true);
147 afl_button.set_led_left (true);
148 pfl_button.set_led_left (true);
150 solo_in_place_button.show ();
154 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
155 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
157 solo_in_place_button.set_related_action (act);
160 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
161 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
163 afl_button.set_related_action (act);
166 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
167 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
169 pfl_button.set_related_action (act);
172 /* Solo option buttons */
173 exclusive_solo_button.set_text (_("Excl. Solo"));
174 exclusive_solo_button.set_name (X_("monitor section solo option"));
175 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
177 act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
179 exclusive_solo_button.set_related_action (act);
182 solo_mute_override_button.set_text (_("Solo ยป Mute"));
183 solo_mute_override_button.set_name (X_("monitor section solo option"));
184 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
186 solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
188 /* Processor Box hide/shos */
189 toggle_processorbox_button.set_text (_("Processors"));
190 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
191 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
193 proctoggle = ActionManager::get_toggle_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
194 toggle_processorbox_button.set_related_action (proctoggle);
197 Label* solo_boost_label;
198 Label* solo_cut_label;
201 /* Solo Boost Knob */
203 solo_boost_control = new ArdourKnob ();
204 solo_boost_control->set_name("monitor section knob");
205 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
206 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
208 solo_boost_display = new ArdourDisplay ();
209 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
210 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
211 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
212 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
213 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
215 solo_boost_label = manage (new Label (_("Solo Boost")));
219 solo_cut_control = new ArdourKnob ();
220 solo_cut_control->set_name ("monitor section knob");
221 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
222 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
224 solo_cut_display = new ArdourDisplay ();
225 solo_cut_display->set_name("monitor section dropdown"); // XXX
226 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
227 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
228 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
229 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
230 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
231 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
233 solo_cut_label = manage (new Label (_("SiP Cut")));
237 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
238 dim_control->set_name ("monitor section knob");
239 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
240 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
242 dim_display = new ArdourDisplay ();
243 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
244 dim_display->add_controllable_preset(_("0 dB"), 0.0);
245 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
246 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
247 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
248 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
250 dim_label = manage (new Label (_("Dim")));
253 cut_all_button.set_text (_("Mute"));
254 cut_all_button.set_name ("mute button");
255 cut_all_button.set_size_request (-1, PX_SCALE(30));
256 cut_all_button.show ();
258 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-cut-all"));
260 cut_all_button.set_related_action (act);
264 dim_all_button.set_text (_("Dim"));
265 dim_all_button.set_name ("monitor section dim");
266 dim_all_button.set_size_request (-1, PX_SCALE(25));
267 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-dim-all"));
269 dim_all_button.set_related_action (act);
273 mono_button.set_text (_("Mono"));
274 mono_button.set_name ("monitor section mono");
275 mono_button.set_size_request (-1, PX_SCALE(25));
276 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-mono"));
278 mono_button.set_related_action (act);
283 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
284 gain_control->set_name("monitor section knob");
285 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
287 gain_display = new ArdourDisplay ();
288 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
289 gain_display->add_controllable_preset(_("0 dB"), 0.0);
290 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
291 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
292 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
293 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
294 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
296 Label* output_label = manage (new Label (_("Output")));
297 output_label->set_name (X_("MonitorSectionLabel"));
299 output_button = new ArdourButton ();
300 output_button->set_text (_("Output"));
301 output_button->set_name (X_("monitor section cut")); // XXX
302 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
303 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
305 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
306 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
307 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
308 channel_table_scroller.show ();
309 channel_table_scroller.add (channel_table_viewport);
311 channel_size_group->add_widget (channel_table_header);
312 channel_table_header.resize (1, 5);
314 Label* l1 = manage (new Label (X_(" ")));
315 l1->set_name (X_("MonitorSectionLabel"));
316 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
318 l1 = manage (new Label (_("Mute")));
319 l1->set_name (X_("MonitorSectionLabel"));
320 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
322 l1 = manage (new Label (_("Dim")));
323 l1->set_name (X_("MonitorSectionLabel"));
324 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
326 l1 = manage (new Label (_("Solo")));
327 l1->set_name (X_("MonitorSectionLabel"));
328 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
330 l1 = manage (new Label (_("Inv")));
331 l1->set_name (X_("MonitorSectionLabel"));
332 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
334 channel_table_header.show ();
337 /****************************************************************************
338 * LAYOUT top to bottom
341 // solo, iso information
342 HBox* rude_box = manage (new HBox);
343 rude_box->set_spacing (PX_SCALE(4));
344 rude_box->set_homogeneous (true);
345 rude_box->pack_start (rude_solo_button, true, true);
346 rude_box->pack_start (rude_iso_button, true, true);
348 // solo options (right align)
349 HBox* tbx1 = manage (new HBox);
350 tbx1->pack_end (exclusive_solo_button, false, false);
352 HBox* tbx2 = manage (new HBox);
353 tbx2->pack_end (solo_mute_override_button, false, false);
355 HBox* tbx3 = manage (new HBox);
356 tbx3->pack_end (toggle_processorbox_button, false, false);
358 HBox* tbx0 = manage (new HBox); // space
360 // combined solo mode (Sip, AFL, PFL) & solo options
361 Table *solo_tbl = manage (new Table);
362 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
363 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
364 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
365 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
366 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
370 // boost, cut, dim volume control
371 Table *level_tbl = manage (new Table);
372 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
373 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
374 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
376 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
378 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
380 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
382 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
385 HBox* mono_dim_box = manage (new HBox);
386 mono_dim_box->set_spacing (PX_SCALE(4));
387 mono_dim_box->set_homogeneous (true);
388 mono_dim_box->pack_start (mono_button, true, true);
389 mono_dim_box->pack_end (dim_all_button, true, true);
392 Label* spin_label = manage (new Label (_("Monitor")));
393 VBox* spin_packer = manage (new VBox);
394 spin_packer->set_spacing (PX_SCALE(2));
395 spin_packer->pack_start (*spin_label, false, false);
396 spin_packer->pack_start (*gain_control, false, false);
397 spin_packer->pack_start (*gain_display, false, false);
399 master_packer.pack_start (*spin_packer, true, false);
401 // combined gain section (channels, mute, dim)
402 VBox* lower_packer = manage (new VBox);
403 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
404 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
405 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
406 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
408 // calc height of mixer scrollbar
409 int scrollbar_height = 0;
411 Gtk::Window window (WINDOW_TOPLEVEL);
412 HScrollbar scrollbar;
413 window.add (scrollbar);
414 scrollbar.set_name ("MixerWindow");
415 scrollbar.ensure_style();
416 Gtk::Requisition requisition(scrollbar.size_request ());
417 scrollbar_height = requisition.height;
420 // output port select
421 VBox* out_packer = manage (new VBox);
422 out_packer->set_spacing (PX_SCALE(2));
423 out_packer->pack_start (*output_label, false, false);
424 out_packer->pack_start (*output_button, false, false);
426 /****************************************************************************
429 vpacker.set_border_width (PX_SCALE(3));
430 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
431 vpacker.pack_start (rude_audition_button, false, false, 0);
432 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
433 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
434 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
435 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
436 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
437 vpacker.pack_end (*out_packer, false, false,
439 scrollbar_height - 2 /* no outer sample */
441 scrollbar_height + 2 /* sample borders */
445 hpacker.set_spacing (0);
446 hpacker.pack_start (vpacker, true, true);
450 gain_control->show_all ();
451 gain_display->show_all ();
452 dim_control->show_all ();
453 dim_display->show_all();
454 solo_boost_control->show_all ();
455 solo_boost_display->show_all();
457 mono_dim_box->show ();
458 spin_packer->show ();
459 master_packer.show ();
462 solo_tbl->show_all();
464 lower_packer->show ();
472 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
473 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
475 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
476 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
477 set_flags (CAN_FOCUS);
479 _tearoff = new TearOff (*this);
481 if (!UIConfiguration::instance().get_floating_monitor_section()) {
482 /* if torn off, make this a normal window
483 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
485 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
487 _tearoff->tearoff_window().set_title (X_("Monitor"));
488 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
490 update_output_display ();
491 update_processor_box ();
492 _ui_initialized = true;
494 /* catch changes that affect us */
495 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
496 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
498 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
501 MonitorSection::~MonitorSection ()
503 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
507 _channel_buttons.clear ();
508 route_connections.drop_connections ();
510 delete insert_box; insert_box = 0;
511 delete output_button; output_button = 0;
512 delete gain_control; gain_control = 0;
513 delete gain_display; gain_display = 0;
514 delete dim_control; dim_control = 0;
515 delete dim_display; dim_display = 0;
516 delete solo_boost_control; solo_boost_control = 0;
517 delete solo_boost_display; solo_boost_display = 0;
518 delete solo_cut_control; solo_cut_control = 0;
519 delete solo_cut_display; solo_cut_display = 0;
520 delete _tearoff; _tearoff = 0;
521 delete _output_selector; _output_selector = 0;
522 delete channel_table; channel_table = 0;
526 MonitorSection::enter_handler (GdkEventCrossing* ev)
533 MonitorSection::leave_handler (GdkEventCrossing* ev)
535 switch (ev->detail) {
536 case GDK_NOTIFY_INFERIOR:
542 /* cancel focus if we're not torn off. With X11 WM's that do
543 * focus-follows-mouse, focus will be taken from us anyway.
546 Widget* top = get_toplevel();
548 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
549 Window* win = dynamic_cast<Window*> (top);
550 gtk_window_set_focus (win->gobj(), 0);
557 MonitorSection::update_processor_box ()
559 bool show_processor_box = proctoggle->get_active ();
561 if (count_processors () > 0 && !show_processor_box) {
562 toggle_processorbox_button.set_name (X_("monitor section processors present"));
564 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
567 if (insert_box->is_visible() == show_processor_box) {
571 if (show_processor_box) {
572 if (master_packer.get_parent()) {
573 master_packer.get_parent()->remove (master_packer);
576 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
578 if (master_packer.get_parent()) {
579 master_packer.get_parent()->remove (master_packer);
582 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
587 MonitorSection::set_session (Session* s)
589 RouteUI::set_session (s);
590 _plugin_selector->set_session (_session);
591 insert_box->set_session (_session);
593 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
597 /* These are not actually dependent on the Session, but they
598 * need to be set after construction, not during, and
599 * this is as good a place as any.
602 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
603 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
605 _route = _session->monitor_out ();
608 /* session with monitor section */
609 _monitor = _route->monitor_control ();
610 assign_controllables ();
611 _route->output()->changed.connect (route_connections, invalidator (*this),
612 boost::bind (&MonitorSection::update_output_display, this),
614 insert_box->set_route (_route);
615 _route->processors_changed.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
616 _route->output()->PortCountChanged.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
617 _route->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
619 if (_ui_initialized) {
620 update_processor_box ();
623 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), true);
624 ActionManager::set_sensitive (global_monitor_actions, true);
625 ActionManager::set_sensitive (monitor_actions, true);
626 ActionManager::set_sensitive (solo_actions, true);
629 /* session with no monitor section */
630 route_connections.drop_connections();
633 delete _output_selector;
634 _output_selector = 0;
636 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), false);
637 ActionManager::set_sensitive (global_monitor_actions, false);
638 ActionManager::set_sensitive (monitor_actions, false);
639 ActionManager::set_sensitive (solo_actions, true);
640 /* this action needs to always be true in this, so that we can turn it back on */
641 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
653 unassign_controllables ();
656 ActionManager::set_sensitive (monitor_actions, false);
657 ActionManager::set_sensitive (solo_actions, false);
658 ActionManager::set_sensitive (global_monitor_actions, false);
663 MonitorSection::drop_route ()
665 route_connections.drop_connections();
668 unassign_controllables ();
669 rude_iso_button.unset_active_state ();
670 rude_solo_button.unset_active_state ();
671 delete _output_selector;
672 _output_selector = 0;
675 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
677 cut.set_name (X_("mute button"));
678 dim.set_name (X_("monitor section dim"));
679 solo.set_name (X_("solo button"));
680 invert.set_name (X_("invert button"));
682 cut.unset_flags (Gtk::CAN_FOCUS);
683 dim.unset_flags (Gtk::CAN_FOCUS);
684 solo.unset_flags (Gtk::CAN_FOCUS);
685 invert.unset_flags (Gtk::CAN_FOCUS);
689 MonitorSection::populate_buttons ()
696 channel_size_group->remove_widget (*channel_table);
697 delete channel_table;
700 channel_table = new Gtk::Table();
702 channel_table->set_col_spacings (6);
703 channel_table->set_row_spacings (6);
704 channel_table->set_homogeneous (true);
706 channel_size_group->add_widget (*channel_table);
707 channel_table->show ();
708 table_hpacker.pack_start (*channel_table, true, true);
710 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
713 _channel_buttons.clear ();
715 Glib::RefPtr<Action> act;
716 uint32_t nchans = _monitor->output_streams().n_audio();
718 channel_table->resize (nchans, 5);
720 const uint32_t row_offset = 0;
722 for (uint32_t i = 0; i < nchans; ++i) {
735 snprintf (buf, sizeof (buf), "%d", i+1);
739 Label* label = manage (new Label (l));
740 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
742 ChannelButtonSet* cbs = new ChannelButtonSet;
744 _channel_buttons.push_back (cbs);
746 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
747 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
748 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
749 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
751 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
752 act = ActionManager::get_action (X_("Monitor"), buf);
754 cbs->cut.set_related_action (act);
757 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
758 act = ActionManager::get_action (X_("Monitor"), buf);
760 cbs->dim.set_related_action (act);
763 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
764 act = ActionManager::get_action (X_("Monitor"), buf);
766 cbs->solo.set_related_action (act);
769 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
770 act = ActionManager::get_action (X_("Monitor"), buf);
772 cbs->invert.set_related_action (act);
776 channel_table->show_all ();
778 if (channel_table_scroller.get_parent()) {
779 /* scroller is packed, so remove it */
780 channel_table_packer.remove (channel_table_scroller);
783 if (table_hpacker.get_parent () == &channel_table_packer) {
784 /* this occurs when the table hpacker is directly
785 packed, so remove it.
787 channel_table_packer.remove (table_hpacker);
788 } else if (table_hpacker.get_parent()) {
789 channel_table_viewport.remove ();
793 /* put the table into a scrolled window, and then put
794 * that into the channel vpacker, after the table header
796 channel_table_viewport.add (table_hpacker);
797 channel_table_packer.pack_start (channel_table_scroller, true, true);
798 channel_table_viewport.show ();
799 channel_table_scroller.show ();
802 /* just put the channel table itself into the channel
803 * vpacker, after the table header
805 channel_table_packer.pack_start (table_hpacker, true, true);
806 channel_table_scroller.hide ();
808 table_hpacker.show ();
809 channel_table->show ();
813 MonitorSection::toggle_exclusive_solo ()
819 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
823 MonitorSection::toggle_mute_overrides_solo ()
829 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo");
830 Config->set_solo_mute_override (tact->get_active());
834 MonitorSection::dim_all ()
840 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
841 _monitor->set_dim_all (tact->get_active());
845 MonitorSection::cut_all ()
851 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
852 _monitor->set_cut_all (tact->get_active());
856 MonitorSection::mono ()
862 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
863 _monitor->set_mono (tact->get_active());
867 MonitorSection::cut_channel (uint32_t chn)
874 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
876 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
877 _monitor->set_cut (chn, tact->get_active());
881 MonitorSection::dim_channel (uint32_t chn)
888 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
890 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
891 _monitor->set_dim (chn, tact->get_active());
895 MonitorSection::solo_channel (uint32_t chn)
902 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
904 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
905 _monitor->set_solo (chn, tact->get_active());
910 MonitorSection::invert_channel (uint32_t chn)
917 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
919 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
920 _monitor->set_polarity (chn, tact->get_active());
924 MonitorSection::register_actions ()
928 Glib::RefPtr<Action> act;
930 /* ...will get sensitized if a mon-session is added */
932 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
933 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
936 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
938 /* these are global monitor actions that invoke MonitorSectioncode. Do
939 * not create local versions (i.e. as part of "monitor_actions")
940 * because then we can end up with two different bindings (one global,
941 * one local to the monitor section) for the same action.
944 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
946 ActionManager::register_toggle_action (global_monitor_actions, "monitor-mono", _("Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
947 ActionManager::register_toggle_action (global_monitor_actions, "monitor-cut-all", _("Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
948 ActionManager::register_toggle_action (global_monitor_actions, "monitor-dim-all", _("Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
950 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
951 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
954 for (uint32_t chn = 0; chn < 16; ++chn) {
956 action_name = string_compose (X_("monitor-cut-%1"), chn);
957 action_descr = string_compose (_("Cut monitor channel %1"), chn);
958 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
959 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
961 action_name = string_compose (X_("monitor-dim-%1"), chn);
962 action_descr = string_compose (_("Dim monitor channel %1"), chn);
963 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
964 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
966 action_name = string_compose (X_("monitor-solo-%1"), chn);
967 action_descr = string_compose (_("Solo monitor channel %1"), chn);
968 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
969 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
971 action_name = string_compose (X_("monitor-invert-%1"), chn);
972 action_descr = string_compose (_("Invert monitor channel %1"), chn);
973 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
974 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
978 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
979 RadioAction::Group solo_group;
981 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
982 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
983 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
984 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
985 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
986 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
988 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
989 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
990 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
991 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
995 MonitorSection::solo_use_in_place ()
997 /* this is driven by a toggle on a radio group, and so is invoked twice,
998 once for the item that became inactive and once for the one that became
1002 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-in-place"));
1003 if (!ract->get_active ()) {
1004 /* We are turning SiP off, which means that AFL or PFL will be turned on
1005 shortly; don't update the solo model in the mean time, as if the currently
1006 configured listen position is not the one that is about to be turned on,
1007 things will go wrong.
1009 _inhibit_solo_model_update = true;
1011 Config->set_solo_control_is_listen_control (!ract->get_active());
1012 _inhibit_solo_model_update = false;
1016 MonitorSection::solo_use_afl ()
1018 /* this is driven by a toggle on a radio group, and so is invoked twice,
1019 once for the item that became inactive and once for the one that became
1023 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-afl"));
1024 if (ract->get_active()) {
1025 Config->set_solo_control_is_listen_control (true);
1026 Config->set_listen_position (AfterFaderListen);
1031 MonitorSection::solo_use_pfl ()
1033 /* this is driven by a toggle on a radio group, and so is invoked twice,
1034 once for the item that became inactive and once for the one that became
1038 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-pfl"));
1039 if (ract->get_active()) {
1040 Config->set_solo_control_is_listen_control (true);
1041 Config->set_listen_position (PreFaderListen);
1046 MonitorSection::update_solo_model ()
1048 if (_inhibit_solo_model_update) {
1052 const char* action_name = 0;
1053 Glib::RefPtr<RadioAction> ract;
1055 if (Config->get_solo_control_is_listen_control()) {
1056 switch (Config->get_listen_position()) {
1057 case AfterFaderListen:
1058 action_name = X_("solo-use-afl");
1060 case PreFaderListen:
1061 action_name = X_("solo-use-pfl");
1065 action_name = X_("solo-use-in-place");
1068 ract = ActionManager::get_radio_action (X_("Solo"), action_name);
1070 /* because these are radio buttons, one of them will be
1071 active no matter what. to trigger a change in the
1072 action so that the view picks it up, toggle it.
1075 if (ract->get_active()) {
1076 ract->set_active (false);
1079 ract->set_active (true);
1083 MonitorSection::map_state ()
1085 if (!_route || !_monitor) {
1089 update_solo_model ();
1091 Glib::RefPtr<Action> act;
1092 Glib::RefPtr<ToggleAction> tact;
1094 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
1095 tact->set_active (_monitor->cut_all());
1097 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
1098 tact->set_active (_monitor->dim_all());
1100 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
1101 tact->set_active (_monitor->mono());
1103 uint32_t nchans = _monitor->output_streams().n_audio();
1105 assert (nchans == _channel_buttons.size ());
1107 for (uint32_t n = 0; n < nchans; ++n) {
1109 char action_name[32];
1111 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1112 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1113 tact->set_active (_monitor->cut (n));
1115 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1116 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1117 tact->set_active (_monitor->dimmed (n));
1119 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1120 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1121 tact->set_active (_monitor->soloed (n));
1123 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1124 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1125 tact->set_active (_monitor->inverted (n));
1130 MonitorSection::do_blink (bool onoff)
1132 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1137 audition_blink (onoff);
1141 MonitorSection::audition_blink (bool onoff)
1143 if (_session == 0) {
1147 if (_session->is_auditioning()) {
1148 rude_audition_button.set_active (onoff);
1150 rude_audition_button.set_active (false);
1155 MonitorSection::solo_blink (bool onoff)
1157 if (_session == 0) {
1161 if (_session->soloing() || _session->listening()) {
1162 rude_solo_button.set_active (onoff);
1164 if (_session->soloing()) {
1165 if (_session->solo_isolated()) {
1166 rude_iso_button.set_active (onoff);
1168 rude_iso_button.set_active (false);
1173 rude_solo_button.set_active (false);
1174 rude_iso_button.set_active (false);
1179 MonitorSection::cancel_isolate (GdkEventButton*)
1182 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1183 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1190 MonitorSection::cancel_audition (GdkEventButton*)
1193 _session->cancel_audition();
1199 MonitorSection::parameter_changed (std::string name)
1201 if (name == "solo-control-is-listen-control") {
1202 update_solo_model ();
1203 } else if (name == "listen-position") {
1204 update_solo_model ();
1205 } else if (name == "solo-mute-override") {
1206 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1207 } else if (name == "exclusive-solo") {
1208 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1213 MonitorSection::unassign_controllables ()
1215 boost::shared_ptr<Controllable> none;
1217 solo_cut_control->set_controllable (none);
1218 solo_cut_display->set_controllable (none);
1219 gain_control->set_controllable (none);
1220 gain_display->set_controllable (none);
1221 cut_all_button.set_controllable (none);
1222 dim_all_button.set_controllable (none);
1223 mono_button.set_controllable (none);
1224 dim_control->set_controllable (none);
1225 dim_display->set_controllable (none);
1226 solo_boost_control->set_controllable (none);
1227 solo_boost_display->set_controllable (none);
1231 MonitorSection::assign_controllables ()
1237 solo_cut_control->set_controllable (_session->solo_cut_control());
1238 solo_cut_display->set_controllable (_session->solo_cut_control());
1240 gain_control->set_controllable (_route->gain_control());
1241 gain_display->set_controllable (_route->gain_control());
1242 cut_all_button.set_controllable (_monitor->cut_control());
1243 cut_all_button.watch ();
1244 dim_all_button.set_controllable (_monitor->dim_control());
1245 dim_all_button.watch ();
1246 mono_button.set_controllable (_monitor->mono_control());
1247 mono_button.watch ();
1248 dim_control->set_controllable (_monitor->dim_level_control ());
1249 dim_display->set_controllable (_monitor->dim_level_control ());
1250 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1251 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1255 MonitorSection::state_id() const
1257 return "monitor-section";
1261 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1263 using namespace Menu_Helpers;
1265 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1269 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1270 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1274 if (i != output_menu_bundles.end()) {
1278 output_menu_bundles.push_back (b);
1280 MenuList& citems = output_menu.items();
1282 std::string n = b->name ();
1283 replace_all (n, "_", " ");
1285 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1289 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1292 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1294 if (std::find (current.begin(), current.end(), c) == current.end()) {
1295 _route->output()->connect_ports_to_bundle (c, true, this);
1297 _route->output()->disconnect_ports_from_bundle (c, this);
1302 MonitorSection::output_release (GdkEventButton *ev)
1304 switch (ev->button) {
1306 edit_output_configuration ();
1313 struct RouteCompareByName {
1314 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1315 return a->name().compare (b->name()) < 0;
1320 MonitorSection::output_press (GdkEventButton *ev)
1322 using namespace Menu_Helpers;
1324 MessageDialog msg (_("No session - no I/O changes are possible"));
1329 MenuList& citems = output_menu.items();
1330 switch (ev->button) {
1333 return false; //wait for the mouse-up to pop the dialog
1337 output_menu.set_name ("ArdourContextMenu");
1339 output_menu_bundles.clear ();
1341 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1343 citems.push_back (SeparatorElem());
1344 uint32_t const n_with_separator = citems.size ();
1346 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1348 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1350 /* give user bundles first chance at being in the menu */
1352 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1353 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1354 maybe_add_bundle_to_output_menu (*i, current);
1358 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1359 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1360 maybe_add_bundle_to_output_menu (*i, current);
1364 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1365 RouteList copy = *routes;
1366 copy.sort (RouteCompareByName ());
1367 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1368 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1371 if (citems.size() == n_with_separator) {
1372 /* no routes added; remove the separator */
1376 citems.push_back (SeparatorElem());
1377 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1379 output_menu.popup (1, ev->time);
1390 MonitorSection::update_output_display ()
1392 if (!_route || !_monitor || _session->deletion_in_progress()) {
1398 boost::shared_ptr<Port> port;
1399 vector<string> port_connections;
1401 uint32_t total_connection_count = 0;
1402 uint32_t io_connection_count = 0;
1403 uint32_t ardour_connection_count = 0;
1404 uint32_t system_connection_count = 0;
1405 uint32_t other_connection_count = 0;
1407 ostringstream label;
1409 bool have_label = false;
1410 bool each_io_has_one_connection = true;
1412 string connection_name;
1413 string ardour_track_name;
1414 string other_connection_type;
1415 string system_ports;
1418 ostringstream tooltip;
1419 char * tooltip_cstr;
1421 io_count = _route->n_outputs().n_total();
1422 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1425 for (io_index = 0; io_index < io_count; ++io_index) {
1427 port = _route->output()->nth (io_index);
1429 //ignore any port connections that don't match our DataType
1430 if (port->type() != DataType::AUDIO) {
1434 port_connections.clear ();
1435 port->get_connections(port_connections);
1436 io_connection_count = 0;
1438 if (!port_connections.empty()) {
1439 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1441 string& connection_name (*i);
1443 if (connection_name.find("system:") == 0) {
1444 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1447 if (io_connection_count == 0) {
1448 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1450 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1453 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1456 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1457 if (ardour_track_name.empty()) {
1458 // "ardour:Master/in 1" -> "ardour:Master/"
1459 string::size_type slash = connection_name.find("/");
1460 if (slash != string::npos) {
1461 ardour_track_name = connection_name.substr(0, slash + 1);
1465 if (connection_name.find(ardour_track_name) == 0) {
1466 ++ardour_connection_count;
1468 } else if (!pn.empty()) {
1469 if (system_ports.empty()) {
1472 system_ports += "/" + pn;
1474 if (connection_name.find("system:") == 0) {
1475 ++system_connection_count;
1477 } else if (connection_name.find("system:") == 0) {
1478 // "system:playback_123" -> "123"
1479 system_port = connection_name.substr(16);
1480 if (system_ports.empty()) {
1481 system_ports += system_port;
1483 system_ports += "/" + system_port;
1486 ++system_connection_count;
1488 if (other_connection_type.empty()) {
1489 // "jamin:in 1" -> "jamin:"
1490 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1493 if (connection_name.find(other_connection_type) == 0) {
1494 ++other_connection_count;
1498 ++total_connection_count;
1499 ++io_connection_count;
1503 if (io_connection_count != 1) {
1504 each_io_has_one_connection = false;
1508 if (total_connection_count == 0) {
1509 tooltip << endl << _("Disconnected");
1512 tooltip_cstr = new char[tooltip.str().size() + 1];
1513 strcpy(tooltip_cstr, tooltip.str().c_str());
1515 set_tooltip (output_button, tooltip_cstr, "");
1517 if (each_io_has_one_connection) {
1518 if (total_connection_count == ardour_connection_count) {
1519 // all connections are to the same track in ardour
1520 // "ardour:Master/" -> "Master"
1521 string::size_type slash = ardour_track_name.find("/");
1522 if (slash != string::npos) {
1523 label << ardour_track_name.substr(7, slash - 7);
1526 } else if (total_connection_count == system_connection_count) {
1527 // all connections are to system ports
1528 label << system_ports;
1530 } else if (total_connection_count == other_connection_count) {
1531 // all connections are to the same external program eg jamin
1532 // "jamin:" -> "jamin"
1533 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1539 if (total_connection_count == 0) {
1543 // Odd configuration
1544 label << "*" << total_connection_count << "*";
1548 output_button->set_text (label.str());
1552 MonitorSection::disconnect_output ()
1555 _route->output()->disconnect(this);
1560 MonitorSection::edit_output_configuration ()
1562 if (_output_selector == 0) {
1563 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1565 _output_selector->present ();
1569 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1574 boost::shared_ptr<Port> a = wa.lock ();
1575 boost::shared_ptr<Port> b = wb.lock ();
1576 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1577 update_output_display ();
1582 MonitorSection::load_bindings ()
1584 bindings = Bindings::get_bindings (X_("Monitor Section"));
1588 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1590 boost::shared_ptr<Processor> processor (p.lock ());
1591 if (!processor || !processor->display_to_user()) {
1594 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1601 MonitorSection::count_processors ()
1603 uint32_t processor_count = 0;
1605 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1607 return processor_count;
1611 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1613 update_processor_box ();
1617 MonitorSection::use_others_actions ()
1619 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1623 MonitorSection::toggle_use_monitor_section ()
1628 bool want_ms = ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active();
1629 bool have_ms = Config->get_use_monitor_bus ();
1631 if (want_ms == have_ms) {
1636 Config->set_use_monitor_bus (true);
1637 ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMonitorSection"))->set_active (true);
1639 Config->set_use_monitor_bus (false);