2 * Copyright (C) 2010-2019 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2011-2012 David Robillard <d@drobilla.net>
4 * Copyright (C) 2011 Carl Hetherington <carl@carlh.net>
5 * Copyright (C) 2014-2015 Tim Mayberry <mojofunk@gmail.com>
6 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
7 * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <gdkmm/pixbuf.h>
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/replace_all.h"
29 #include "pbd/stacktrace.h"
31 #include "gtkmm2ext/actions.h"
32 #include "gtkmm2ext/utils.h"
34 #include <gtkmm/menu.h>
35 #include <gtkmm/menuitem.h>
37 #include "widgets/tearoff.h"
38 #include "widgets/tooltips.h"
40 #include "ardour/amp.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/monitor_processor.h"
43 #include "ardour/port.h"
44 #include "ardour/route.h"
45 #include "ardour/solo_isolate_control.h"
46 #include "ardour/user_bundle.h"
47 #include "ardour/plugin_manager.h"
49 #include "ardour_ui.h"
50 #include "gui_thread.h"
52 #include "monitor_section.h"
53 #include "public_editor.h"
55 #include "ui_config.h"
60 using namespace ARDOUR;
61 using namespace ArdourWidgets;
62 using namespace ARDOUR_UI_UTILS;
64 using namespace Gtkmm2ext;
68 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
70 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
71 if (action && action->get_active() != value) { \
72 action->set_active(value); \
75 MonitorSection::MonitorSection ()
76 : RouteUI ((Session*) 0)
79 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
80 , *channel_table_scroller.get_vadjustment ())
83 , solo_boost_control (0)
84 , solo_cut_control (0)
87 , solo_boost_display (0)
88 , solo_cut_display (0)
89 , _output_selector (0)
90 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
91 , afl_button (_("AFL"), ArdourButton::led_default_elements)
92 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
93 , exclusive_solo_button (ArdourButton::led_default_elements)
94 , solo_mute_override_button (ArdourButton::led_default_elements)
95 , toggle_processorbox_button (ArdourButton::default_elements)
96 , _inhibit_solo_model_update (false)
98 , _ui_initialized (false)
100 /* note that although this a RouteUI, we never called ::set_route() so
101 * we do not need to worry about self-destructing when the Route (the
102 * monitor out) is destroyed.
105 using namespace Menu_Helpers;
107 Glib::RefPtr<Action> act;
111 set_data ("ardour-bindings", bindings);
113 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
115 insert_box = new ProcessorBox (0, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
116 insert_box->set_no_show_all ();
118 // TODO allow keyboard shortcuts in ProcessorBox
120 /* Rude Solo & Solo Isolated */
121 rude_solo_button.set_text (_("Soloing"));
122 rude_solo_button.set_name ("rude solo");
123 rude_solo_button.show ();
125 rude_iso_button.set_text (_("Isolated"));
126 rude_iso_button.set_name ("rude isolate");
127 rude_iso_button.show ();
129 rude_audition_button.set_text (_("Auditioning"));
130 rude_audition_button.set_name ("rude audition");
131 rude_audition_button.show ();
133 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
135 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
137 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
138 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
140 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
141 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
143 /* SIP, AFL, PFL radio */
145 solo_in_place_button.set_name ("monitor section solo model");
146 afl_button.set_name ("monitor section solo model");
147 pfl_button.set_name ("monitor section solo model");
149 solo_in_place_button.set_led_left (true);
150 afl_button.set_led_left (true);
151 pfl_button.set_led_left (true);
153 solo_in_place_button.show ();
157 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
158 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
160 solo_in_place_button.set_related_action (act);
163 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
164 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
166 afl_button.set_related_action (act);
169 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
170 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
172 pfl_button.set_related_action (act);
175 /* Solo option buttons */
176 exclusive_solo_button.set_text (_("Excl. Solo"));
177 exclusive_solo_button.set_name (X_("monitor section solo option"));
178 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
180 act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
182 exclusive_solo_button.set_related_action (act);
185 solo_mute_override_button.set_text (_("Solo ยป Mute"));
186 solo_mute_override_button.set_name (X_("monitor section solo option"));
187 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
189 solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
191 /* Processor Box hide/shos */
192 toggle_processorbox_button.set_text (_("Processors"));
193 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
194 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
196 proctoggle = ActionManager::get_toggle_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
197 toggle_processorbox_button.set_related_action (proctoggle);
200 Label* solo_boost_label;
201 Label* solo_cut_label;
204 /* Solo Boost Knob */
206 solo_boost_control = new ArdourKnob ();
207 solo_boost_control->set_name("monitor section knob");
208 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
209 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
211 solo_boost_display = new ArdourDisplay ();
212 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
213 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
214 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
215 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
216 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
218 solo_boost_label = manage (new Label (_("Solo Boost")));
222 solo_cut_control = new ArdourKnob ();
223 solo_cut_control->set_name ("monitor section knob");
224 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
225 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
227 solo_cut_display = new ArdourDisplay ();
228 solo_cut_display->set_name("monitor section dropdown"); // XXX
229 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
230 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
231 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
232 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
233 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
234 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
236 solo_cut_label = manage (new Label (_("SiP Cut")));
240 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
241 dim_control->set_name ("monitor section knob");
242 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
243 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
245 dim_display = new ArdourDisplay ();
246 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
247 dim_display->add_controllable_preset(_("0 dB"), 0.0);
248 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
249 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
250 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
251 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
253 dim_label = manage (new Label (_("Dim")));
256 cut_all_button.set_text (_("Mute"));
257 cut_all_button.set_name ("mute button");
258 cut_all_button.set_size_request (-1, PX_SCALE(30));
259 cut_all_button.show ();
261 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-cut-all"));
263 cut_all_button.set_related_action (act);
267 dim_all_button.set_text (_("Dim"));
268 dim_all_button.set_name ("monitor section dim");
269 dim_all_button.set_size_request (-1, PX_SCALE(25));
270 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-dim-all"));
272 dim_all_button.set_related_action (act);
276 mono_button.set_text (_("Mono"));
277 mono_button.set_name ("monitor section mono");
278 mono_button.set_size_request (-1, PX_SCALE(25));
279 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-mono"));
281 mono_button.set_related_action (act);
286 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
287 gain_control->set_name("monitor section knob");
288 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
290 gain_display = new ArdourDisplay ();
291 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
292 gain_display->add_controllable_preset(_("0 dB"), 0.0);
293 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
294 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
295 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
296 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
297 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
299 Label* output_label = manage (new Label (_("Output")));
300 output_label->set_name (X_("MonitorSectionLabel"));
302 output_button = new ArdourButton ();
303 output_button->set_text (_("Output"));
304 output_button->set_name (X_("monitor section cut")); // XXX
305 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
306 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
308 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
309 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
310 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
311 channel_table_scroller.show ();
312 channel_table_scroller.add (channel_table_viewport);
314 channel_size_group->add_widget (channel_table_header);
315 channel_table_header.resize (1, 5);
317 Label* l1 = manage (new Label (X_(" ")));
318 l1->set_name (X_("MonitorSectionLabel"));
319 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
321 l1 = manage (new Label (_("Mute")));
322 l1->set_name (X_("MonitorSectionLabel"));
323 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
325 l1 = manage (new Label (_("Dim")));
326 l1->set_name (X_("MonitorSectionLabel"));
327 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
329 l1 = manage (new Label (_("Solo")));
330 l1->set_name (X_("MonitorSectionLabel"));
331 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
333 l1 = manage (new Label (_("Inv")));
334 l1->set_name (X_("MonitorSectionLabel"));
335 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
337 channel_table_header.show ();
340 /****************************************************************************
341 * LAYOUT top to bottom
344 // solo, iso information
345 HBox* rude_box = manage (new HBox);
346 rude_box->set_spacing (PX_SCALE(4));
347 rude_box->set_homogeneous (true);
348 rude_box->pack_start (rude_solo_button, true, true);
349 rude_box->pack_start (rude_iso_button, true, true);
351 // solo options (right align)
352 HBox* tbx1 = manage (new HBox);
353 tbx1->pack_end (exclusive_solo_button, false, false);
355 HBox* tbx2 = manage (new HBox);
356 tbx2->pack_end (solo_mute_override_button, false, false);
358 HBox* tbx3 = manage (new HBox);
359 tbx3->pack_end (toggle_processorbox_button, false, false);
361 HBox* tbx0 = manage (new HBox); // space
363 // combined solo mode (Sip, AFL, PFL) & solo options
364 Table *solo_tbl = manage (new Table);
365 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
366 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
369 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
370 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
371 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
373 // boost, cut, dim volume control
374 Table *level_tbl = manage (new Table);
375 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
379 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
383 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
384 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
385 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
388 HBox* mono_dim_box = manage (new HBox);
389 mono_dim_box->set_spacing (PX_SCALE(4));
390 mono_dim_box->set_homogeneous (true);
391 mono_dim_box->pack_start (mono_button, true, true);
392 mono_dim_box->pack_end (dim_all_button, true, true);
395 Label* spin_label = manage (new Label (_("Monitor")));
396 VBox* spin_packer = manage (new VBox);
397 spin_packer->set_spacing (PX_SCALE(2));
398 spin_packer->pack_start (*spin_label, false, false);
399 spin_packer->pack_start (*gain_control, false, false);
400 spin_packer->pack_start (*gain_display, false, false);
402 master_packer.pack_start (*spin_packer, true, false);
404 // combined gain section (channels, mute, dim)
405 VBox* lower_packer = manage (new VBox);
406 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
407 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
408 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
409 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
411 // calc height of mixer scrollbar
412 int scrollbar_height = 0;
414 Gtk::Window window (WINDOW_TOPLEVEL);
415 HScrollbar scrollbar;
416 window.add (scrollbar);
417 scrollbar.set_name ("MixerWindow");
418 scrollbar.ensure_style();
419 Gtk::Requisition requisition(scrollbar.size_request ());
420 scrollbar_height = requisition.height;
423 // output port select
424 VBox* out_packer = manage (new VBox);
425 out_packer->set_spacing (PX_SCALE(2));
426 out_packer->pack_start (*output_label, false, false);
427 out_packer->pack_start (*output_button, false, false);
429 /****************************************************************************
432 vpacker.set_border_width (PX_SCALE(3));
433 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
434 vpacker.pack_start (rude_audition_button, false, false, 0);
435 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
436 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
437 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
438 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
439 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
440 vpacker.pack_end (*out_packer, false, false,
442 scrollbar_height /* no outer frame */
444 scrollbar_height + 2 /* frame borders */
448 hpacker.set_spacing (0);
449 hpacker.pack_start (vpacker, true, true);
453 gain_control->show_all ();
454 gain_display->show_all ();
455 dim_control->show_all ();
456 dim_display->show_all();
457 solo_boost_control->show_all ();
458 solo_boost_display->show_all();
460 mono_dim_box->show ();
461 spin_packer->show ();
462 master_packer.show ();
465 solo_tbl->show_all();
467 lower_packer->show ();
475 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
476 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
478 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
479 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
480 set_flags (CAN_FOCUS);
482 _tearoff = new TearOff (*this);
484 if (!UIConfiguration::instance().get_floating_monitor_section()) {
485 /* if torn off, make this a normal window
486 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
488 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
490 _tearoff->tearoff_window().set_title (X_("Monitor"));
491 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
493 update_output_display ();
494 update_processor_box ();
495 _ui_initialized = true;
497 /* catch changes that affect us */
498 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
499 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
501 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
504 MonitorSection::~MonitorSection ()
506 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
510 _channel_buttons.clear ();
511 route_connections.drop_connections ();
513 delete insert_box; insert_box = 0;
514 delete output_button; output_button = 0;
515 delete gain_control; gain_control = 0;
516 delete gain_display; gain_display = 0;
517 delete dim_control; dim_control = 0;
518 delete dim_display; dim_display = 0;
519 delete solo_boost_control; solo_boost_control = 0;
520 delete solo_boost_display; solo_boost_display = 0;
521 delete solo_cut_control; solo_cut_control = 0;
522 delete solo_cut_display; solo_cut_display = 0;
523 delete _tearoff; _tearoff = 0;
524 delete _output_selector; _output_selector = 0;
525 delete channel_table; channel_table = 0;
529 MonitorSection::enter_handler (GdkEventCrossing* ev)
536 MonitorSection::leave_handler (GdkEventCrossing* ev)
538 switch (ev->detail) {
539 case GDK_NOTIFY_INFERIOR:
545 /* cancel focus if we're not torn off. With X11 WM's that do
546 * focus-follows-mouse, focus will be taken from us anyway.
549 Widget* top = get_toplevel();
551 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
552 Window* win = dynamic_cast<Window*> (top);
553 gtk_window_set_focus (win->gobj(), 0);
560 MonitorSection::update_processor_box ()
562 bool show_processor_box = proctoggle->get_active ();
564 if (count_processors () > 0 && !show_processor_box) {
565 toggle_processorbox_button.set_name (X_("monitor section processors present"));
567 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
570 if (insert_box->is_visible() == show_processor_box) {
574 if (show_processor_box) {
575 if (master_packer.get_parent()) {
576 master_packer.get_parent()->remove (master_packer);
579 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
581 if (master_packer.get_parent()) {
582 master_packer.get_parent()->remove (master_packer);
585 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
590 MonitorSection::set_session (Session* s)
592 RouteUI::set_session (s);
593 insert_box->set_session (_session);
595 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
599 /* These are not actually dependent on the Session, but they
600 * need to be set after construction, not during, and
601 * this is as good a place as any.
604 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
605 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
607 _route = _session->monitor_out ();
610 /* session with monitor section */
611 _monitor = _route->monitor_control ();
612 assign_controllables ();
613 _route->output()->changed.connect (route_connections, invalidator (*this),
614 boost::bind (&MonitorSection::update_output_display, this),
616 insert_box->set_route (_route);
617 _route->processors_changed.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
618 _route->output()->PortCountChanged.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
619 _route->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
621 if (_ui_initialized) {
622 update_processor_box ();
625 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), true);
626 ActionManager::set_sensitive (global_monitor_actions, true);
627 ActionManager::set_sensitive (monitor_actions, true);
628 ActionManager::set_sensitive (solo_actions, true);
631 /* session with no monitor section */
632 route_connections.drop_connections();
635 delete _output_selector;
636 _output_selector = 0;
638 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), false);
639 ActionManager::set_sensitive (global_monitor_actions, false);
640 ActionManager::set_sensitive (monitor_actions, false);
641 ActionManager::set_sensitive (solo_actions, true);
642 /* this action needs to always be true in this, so that we can turn it back on */
643 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
655 unassign_controllables ();
658 ActionManager::set_sensitive (monitor_actions, false);
659 ActionManager::set_sensitive (solo_actions, false);
660 ActionManager::set_sensitive (global_monitor_actions, false);
665 MonitorSection::drop_route ()
667 route_connections.drop_connections();
670 unassign_controllables ();
671 rude_iso_button.unset_active_state ();
672 rude_solo_button.unset_active_state ();
673 delete _output_selector;
674 _output_selector = 0;
677 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
679 cut.set_name (X_("mute button"));
680 dim.set_name (X_("monitor section dim"));
681 solo.set_name (X_("solo button"));
682 invert.set_name (X_("invert button"));
684 cut.unset_flags (Gtk::CAN_FOCUS);
685 dim.unset_flags (Gtk::CAN_FOCUS);
686 solo.unset_flags (Gtk::CAN_FOCUS);
687 invert.unset_flags (Gtk::CAN_FOCUS);
691 MonitorSection::populate_buttons ()
698 channel_size_group->remove_widget (*channel_table);
699 delete channel_table;
702 channel_table = new Gtk::Table();
704 channel_table->set_col_spacings (6);
705 channel_table->set_row_spacings (6);
706 channel_table->set_homogeneous (true);
708 channel_size_group->add_widget (*channel_table);
709 channel_table->show ();
710 table_hpacker.pack_start (*channel_table, true, true);
712 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
715 _channel_buttons.clear ();
717 Glib::RefPtr<Action> act;
718 uint32_t nchans = _monitor->output_streams().n_audio();
720 channel_table->resize (nchans, 5);
722 const uint32_t row_offset = 0;
724 for (uint32_t i = 0; i < nchans; ++i) {
737 snprintf (buf, sizeof (buf), "%d", i+1);
741 Label* label = manage (new Label (l));
742 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
744 ChannelButtonSet* cbs = new ChannelButtonSet;
746 _channel_buttons.push_back (cbs);
748 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
749 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
750 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
751 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
753 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
754 act = ActionManager::get_action (X_("Monitor"), buf);
756 cbs->cut.set_related_action (act);
759 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
760 act = ActionManager::get_action (X_("Monitor"), buf);
762 cbs->dim.set_related_action (act);
765 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
766 act = ActionManager::get_action (X_("Monitor"), buf);
768 cbs->solo.set_related_action (act);
771 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
772 act = ActionManager::get_action (X_("Monitor"), buf);
774 cbs->invert.set_related_action (act);
778 channel_table->show_all ();
780 if (channel_table_scroller.get_parent()) {
781 /* scroller is packed, so remove it */
782 channel_table_packer.remove (channel_table_scroller);
785 if (table_hpacker.get_parent () == &channel_table_packer) {
786 /* this occurs when the table hpacker is directly
787 packed, so remove it.
789 channel_table_packer.remove (table_hpacker);
790 } else if (table_hpacker.get_parent()) {
791 channel_table_viewport.remove ();
795 /* put the table into a scrolled window, and then put
796 * that into the channel vpacker, after the table header
798 channel_table_viewport.add (table_hpacker);
799 channel_table_packer.pack_start (channel_table_scroller, true, true);
800 channel_table_viewport.show ();
801 channel_table_scroller.show ();
804 /* just put the channel table itself into the channel
805 * vpacker, after the table header
807 channel_table_packer.pack_start (table_hpacker, true, true);
808 channel_table_scroller.hide ();
810 table_hpacker.show ();
811 channel_table->show ();
815 MonitorSection::toggle_exclusive_solo ()
821 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
825 MonitorSection::toggle_mute_overrides_solo ()
831 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo");
832 Config->set_solo_mute_override (tact->get_active());
836 MonitorSection::dim_all ()
842 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
843 _monitor->set_dim_all (tact->get_active());
847 MonitorSection::cut_all ()
853 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
854 _monitor->set_cut_all (tact->get_active());
858 MonitorSection::mono ()
864 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
865 _monitor->set_mono (tact->get_active());
869 MonitorSection::cut_channel (uint32_t chn)
876 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
878 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
879 _monitor->set_cut (chn, tact->get_active());
883 MonitorSection::dim_channel (uint32_t chn)
890 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
892 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
893 _monitor->set_dim (chn, tact->get_active());
897 MonitorSection::solo_channel (uint32_t chn)
904 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
906 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
907 _monitor->set_solo (chn, tact->get_active());
912 MonitorSection::invert_channel (uint32_t chn)
919 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
921 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
922 _monitor->set_polarity (chn, tact->get_active());
926 MonitorSection::register_actions ()
930 Glib::RefPtr<Action> act;
932 /* ...will get sensitized if a mon-session is added */
934 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
935 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
938 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
940 /* these are global monitor actions that invoke MonitorSectioncode. Do
941 * not create local versions (i.e. as part of "monitor_actions")
942 * because then we can end up with two different bindings (one global,
943 * one local to the monitor section) for the same action.
946 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
948 ActionManager::register_toggle_action (global_monitor_actions, "monitor-mono", _("Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
949 ActionManager::register_toggle_action (global_monitor_actions, "monitor-cut-all", _("Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
950 ActionManager::register_toggle_action (global_monitor_actions, "monitor-dim-all", _("Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
952 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
953 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
956 for (uint32_t chn = 0; chn < 16; ++chn) {
958 action_name = string_compose (X_("monitor-cut-%1"), chn);
959 action_descr = string_compose (_("Cut monitor channel %1"), chn);
960 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
961 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
963 action_name = string_compose (X_("monitor-dim-%1"), chn);
964 action_descr = string_compose (_("Dim monitor channel %1"), chn);
965 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
966 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
968 action_name = string_compose (X_("monitor-solo-%1"), chn);
969 action_descr = string_compose (_("Solo monitor channel %1"), chn);
970 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
971 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
973 action_name = string_compose (X_("monitor-invert-%1"), chn);
974 action_descr = string_compose (_("Invert monitor channel %1"), chn);
975 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
976 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
980 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
981 RadioAction::Group solo_group;
983 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
984 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
985 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
986 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
987 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
988 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
990 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
991 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
992 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
993 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
997 MonitorSection::solo_use_in_place ()
999 /* this is driven by a toggle on a radio group, and so is invoked twice,
1000 once for the item that became inactive and once for the one that became
1004 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-in-place"));
1005 if (!ract->get_active ()) {
1006 /* We are turning SiP off, which means that AFL or PFL will be turned on
1007 shortly; don't update the solo model in the mean time, as if the currently
1008 configured listen position is not the one that is about to be turned on,
1009 things will go wrong.
1011 _inhibit_solo_model_update = true;
1013 Config->set_solo_control_is_listen_control (!ract->get_active());
1014 _inhibit_solo_model_update = false;
1018 MonitorSection::solo_use_afl ()
1020 /* this is driven by a toggle on a radio group, and so is invoked twice,
1021 once for the item that became inactive and once for the one that became
1025 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-afl"));
1026 if (ract->get_active()) {
1027 Config->set_solo_control_is_listen_control (true);
1028 Config->set_listen_position (AfterFaderListen);
1033 MonitorSection::solo_use_pfl ()
1035 /* this is driven by a toggle on a radio group, and so is invoked twice,
1036 once for the item that became inactive and once for the one that became
1040 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-pfl"));
1041 if (ract->get_active()) {
1042 Config->set_solo_control_is_listen_control (true);
1043 Config->set_listen_position (PreFaderListen);
1048 MonitorSection::update_solo_model ()
1050 if (_inhibit_solo_model_update) {
1054 const char* action_name = 0;
1055 Glib::RefPtr<RadioAction> ract;
1057 if (Config->get_solo_control_is_listen_control()) {
1058 switch (Config->get_listen_position()) {
1059 case AfterFaderListen:
1060 action_name = X_("solo-use-afl");
1062 case PreFaderListen:
1063 action_name = X_("solo-use-pfl");
1067 action_name = X_("solo-use-in-place");
1070 ract = ActionManager::get_radio_action (X_("Solo"), action_name);
1072 /* because these are radio buttons, one of them will be
1073 active no matter what. to trigger a change in the
1074 action so that the view picks it up, toggle it.
1077 if (ract->get_active()) {
1078 ract->set_active (false);
1081 ract->set_active (true);
1085 MonitorSection::map_state ()
1087 if (!_route || !_monitor) {
1091 update_solo_model ();
1093 Glib::RefPtr<Action> act;
1094 Glib::RefPtr<ToggleAction> tact;
1096 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
1097 tact->set_active (_monitor->cut_all());
1099 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
1100 tact->set_active (_monitor->dim_all());
1102 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
1103 tact->set_active (_monitor->mono());
1105 uint32_t nchans = _monitor->output_streams().n_audio();
1107 assert (nchans == _channel_buttons.size ());
1109 for (uint32_t n = 0; n < nchans; ++n) {
1111 char action_name[32];
1113 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1114 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1115 tact->set_active (_monitor->cut (n));
1117 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1118 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1119 tact->set_active (_monitor->dimmed (n));
1121 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1122 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1123 tact->set_active (_monitor->soloed (n));
1125 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1126 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1127 tact->set_active (_monitor->inverted (n));
1132 MonitorSection::do_blink (bool onoff)
1134 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1139 audition_blink (onoff);
1143 MonitorSection::audition_blink (bool onoff)
1145 if (_session == 0) {
1149 if (_session->is_auditioning()) {
1150 rude_audition_button.set_active (onoff);
1152 rude_audition_button.set_active (false);
1157 MonitorSection::solo_blink (bool onoff)
1159 if (_session == 0) {
1163 if (_session->soloing() || _session->listening()) {
1164 rude_solo_button.set_active (onoff);
1166 if (_session->soloing()) {
1167 if (_session->solo_isolated()) {
1168 rude_iso_button.set_active (onoff);
1170 rude_iso_button.set_active (false);
1175 rude_solo_button.set_active (false);
1176 rude_iso_button.set_active (false);
1181 MonitorSection::cancel_isolate (GdkEventButton*)
1184 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1185 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1192 MonitorSection::cancel_audition (GdkEventButton*)
1195 _session->cancel_audition();
1201 MonitorSection::parameter_changed (std::string name)
1203 if (name == "solo-control-is-listen-control") {
1204 update_solo_model ();
1205 } else if (name == "listen-position") {
1206 update_solo_model ();
1207 } else if (name == "solo-mute-override") {
1208 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1209 } else if (name == "exclusive-solo") {
1210 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1215 MonitorSection::unassign_controllables ()
1217 boost::shared_ptr<Controllable> none;
1219 solo_cut_control->set_controllable (none);
1220 solo_cut_display->set_controllable (none);
1221 gain_control->set_controllable (none);
1222 gain_display->set_controllable (none);
1223 cut_all_button.set_controllable (none);
1224 dim_all_button.set_controllable (none);
1225 mono_button.set_controllable (none);
1226 dim_control->set_controllable (none);
1227 dim_display->set_controllable (none);
1228 solo_boost_control->set_controllable (none);
1229 solo_boost_display->set_controllable (none);
1233 MonitorSection::assign_controllables ()
1239 solo_cut_control->set_controllable (_session->solo_cut_control());
1240 solo_cut_display->set_controllable (_session->solo_cut_control());
1242 gain_control->set_controllable (_route->gain_control());
1243 gain_display->set_controllable (_route->gain_control());
1244 cut_all_button.set_controllable (_monitor->cut_control());
1245 cut_all_button.watch ();
1246 dim_all_button.set_controllable (_monitor->dim_control());
1247 dim_all_button.watch ();
1248 mono_button.set_controllable (_monitor->mono_control());
1249 mono_button.watch ();
1250 dim_control->set_controllable (_monitor->dim_level_control ());
1251 dim_display->set_controllable (_monitor->dim_level_control ());
1252 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1253 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1257 MonitorSection::state_id() const
1259 return "monitor-section";
1263 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1265 using namespace Menu_Helpers;
1267 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1271 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1272 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1276 if (i != output_menu_bundles.end()) {
1280 output_menu_bundles.push_back (b);
1282 MenuList& citems = output_menu.items();
1284 std::string n = b->name ();
1285 replace_all (n, "_", " ");
1287 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1291 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1294 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1296 if (std::find (current.begin(), current.end(), c) == current.end()) {
1297 _route->output()->connect_ports_to_bundle (c, true, this);
1299 _route->output()->disconnect_ports_from_bundle (c, this);
1304 MonitorSection::output_release (GdkEventButton *ev)
1306 switch (ev->button) {
1308 edit_output_configuration ();
1315 struct RouteCompareByName {
1316 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1317 return a->name().compare (b->name()) < 0;
1322 MonitorSection::output_press (GdkEventButton *ev)
1324 using namespace Menu_Helpers;
1326 MessageDialog msg (_("No session - no I/O changes are possible"));
1331 MenuList& citems = output_menu.items();
1332 switch (ev->button) {
1335 return false; //wait for the mouse-up to pop the dialog
1339 output_menu.set_name ("ArdourContextMenu");
1341 output_menu_bundles.clear ();
1343 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1345 citems.push_back (SeparatorElem());
1346 uint32_t const n_with_separator = citems.size ();
1348 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1350 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1352 /* give user bundles first chance at being in the menu */
1354 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1355 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1356 maybe_add_bundle_to_output_menu (*i, current);
1360 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1361 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1362 maybe_add_bundle_to_output_menu (*i, current);
1366 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1367 RouteList copy = *routes;
1368 copy.sort (RouteCompareByName ());
1369 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1370 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1373 if (citems.size() == n_with_separator) {
1374 /* no routes added; remove the separator */
1378 citems.push_back (SeparatorElem());
1379 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1381 output_menu.popup (1, ev->time);
1392 MonitorSection::update_output_display ()
1394 if (!_route || !_monitor || _session->deletion_in_progress()) {
1400 boost::shared_ptr<Port> port;
1401 vector<string> port_connections;
1403 uint32_t total_connection_count = 0;
1404 uint32_t io_connection_count = 0;
1405 uint32_t ardour_connection_count = 0;
1406 uint32_t system_connection_count = 0;
1407 uint32_t other_connection_count = 0;
1409 ostringstream label;
1411 bool have_label = false;
1412 bool each_io_has_one_connection = true;
1414 string connection_name;
1415 string ardour_track_name;
1416 string other_connection_type;
1417 string system_ports;
1420 ostringstream tooltip;
1421 char * tooltip_cstr;
1423 io_count = _route->n_outputs().n_total();
1424 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1427 for (io_index = 0; io_index < io_count; ++io_index) {
1429 port = _route->output()->nth (io_index);
1431 //ignore any port connections that don't match our DataType
1432 if (port->type() != DataType::AUDIO) {
1436 port_connections.clear ();
1437 port->get_connections(port_connections);
1438 io_connection_count = 0;
1440 if (!port_connections.empty()) {
1441 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1443 string& connection_name (*i);
1445 if (connection_name.find("system:") == 0) {
1446 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1449 if (io_connection_count == 0) {
1450 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1452 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1455 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1458 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1459 if (ardour_track_name.empty()) {
1460 // "ardour:Master/in 1" -> "ardour:Master/"
1461 string::size_type slash = connection_name.find("/");
1462 if (slash != string::npos) {
1463 ardour_track_name = connection_name.substr(0, slash + 1);
1467 if (connection_name.find(ardour_track_name) == 0) {
1468 ++ardour_connection_count;
1470 } else if (!pn.empty()) {
1471 if (system_ports.empty()) {
1474 system_ports += "/" + pn;
1476 if (connection_name.find("system:") == 0) {
1477 ++system_connection_count;
1479 } else if (connection_name.find("system:") == 0) {
1480 // "system:playback_123" -> "123"
1481 system_port = connection_name.substr(16);
1482 if (system_ports.empty()) {
1483 system_ports += system_port;
1485 system_ports += "/" + system_port;
1488 ++system_connection_count;
1490 if (other_connection_type.empty()) {
1491 // "jamin:in 1" -> "jamin:"
1492 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1495 if (connection_name.find(other_connection_type) == 0) {
1496 ++other_connection_count;
1500 ++total_connection_count;
1501 ++io_connection_count;
1505 if (io_connection_count != 1) {
1506 each_io_has_one_connection = false;
1510 if (total_connection_count == 0) {
1511 tooltip << endl << _("Disconnected");
1514 tooltip_cstr = new char[tooltip.str().size() + 1];
1515 strcpy(tooltip_cstr, tooltip.str().c_str());
1517 set_tooltip (output_button, tooltip_cstr, "");
1519 if (each_io_has_one_connection) {
1520 if (total_connection_count == ardour_connection_count) {
1521 // all connections are to the same track in ardour
1522 // "ardour:Master/" -> "Master"
1523 string::size_type slash = ardour_track_name.find("/");
1524 if (slash != string::npos) {
1525 label << ardour_track_name.substr(7, slash - 7);
1528 } else if (total_connection_count == system_connection_count) {
1529 // all connections are to system ports
1530 label << system_ports;
1532 } else if (total_connection_count == other_connection_count) {
1533 // all connections are to the same external program eg jamin
1534 // "jamin:" -> "jamin"
1535 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1541 if (total_connection_count == 0) {
1545 // Odd configuration
1546 label << "*" << total_connection_count << "*";
1550 output_button->set_text (label.str());
1554 MonitorSection::disconnect_output ()
1557 _route->output()->disconnect(this);
1562 MonitorSection::edit_output_configuration ()
1564 if (_output_selector == 0) {
1565 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1567 _output_selector->present ();
1571 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1576 boost::shared_ptr<Port> a = wa.lock ();
1577 boost::shared_ptr<Port> b = wb.lock ();
1578 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1579 update_output_display ();
1584 MonitorSection::load_bindings ()
1586 bindings = Bindings::get_bindings (X_("Monitor Section"));
1590 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1592 boost::shared_ptr<Processor> processor (p.lock ());
1593 if (!processor || !processor->display_to_user()) {
1596 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1603 MonitorSection::count_processors ()
1605 uint32_t processor_count = 0;
1607 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1609 return processor_count;
1613 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1615 update_processor_box ();
1619 MonitorSection::plugin_selector ()
1621 return Mixer_UI::instance()->plugin_selector ();
1625 MonitorSection::use_others_actions ()
1627 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1631 MonitorSection::toggle_use_monitor_section ()
1636 bool want_ms = ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active();
1637 bool have_ms = Config->get_use_monitor_bus ();
1639 if (want_ms == have_ms) {
1644 Config->set_use_monitor_bus (true);
1645 ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMonitorSection"))->set_active (true);
1647 Config->set_use_monitor_bus (false);