2 Copyright (C) 2012 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gdkmm/pixbuf.h>
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
26 #include "gtkmm2ext/actions.h"
27 #include "gtkmm2ext/utils.h"
29 #include <gtkmm/menu.h>
30 #include <gtkmm/menuitem.h>
32 #include "widgets/tearoff.h"
33 #include "widgets/tooltips.h"
35 #include "ardour/amp.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/monitor_processor.h"
38 #include "ardour/port.h"
39 #include "ardour/route.h"
40 #include "ardour/solo_isolate_control.h"
41 #include "ardour/user_bundle.h"
42 #include "ardour/plugin_manager.h"
44 #include "ardour_ui.h"
45 #include "gui_thread.h"
47 #include "monitor_section.h"
48 #include "public_editor.h"
50 #include "ui_config.h"
55 using namespace ARDOUR;
56 using namespace ArdourWidgets;
57 using namespace ARDOUR_UI_UTILS;
59 using namespace Gtkmm2ext;
63 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
65 MonitorSection::MonitorSection ()
66 : RouteUI ((Session*) 0)
69 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
70 , *channel_table_scroller.get_vadjustment ())
73 , solo_boost_control (0)
74 , solo_cut_control (0)
77 , solo_boost_display (0)
78 , solo_cut_display (0)
79 , _output_selector (0)
80 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
81 , afl_button (_("AFL"), ArdourButton::led_default_elements)
82 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
83 , exclusive_solo_button (ArdourButton::led_default_elements)
84 , solo_mute_override_button (ArdourButton::led_default_elements)
85 , toggle_processorbox_button (ArdourButton::default_elements)
86 , _inhibit_solo_model_update (false)
88 , _ui_initialized (false)
90 /* note that although this a RouteUI, we never called ::set_route() so
91 * we do not need to worry about self-destructing when the Route (the
92 * monitor out) is destroyed.
95 using namespace Menu_Helpers;
97 Glib::RefPtr<Action> act;
101 set_data ("ardour-bindings", bindings);
103 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
105 _plugin_selector = new PluginSelector (PluginManager::instance());
106 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
107 insert_box->set_no_show_all ();
109 // TODO allow keyboard shortcuts in ProcessorBox
111 /* Rude Solo & Solo Isolated */
112 rude_solo_button.set_text (_("Soloing"));
113 rude_solo_button.set_name ("rude solo");
114 rude_solo_button.show ();
116 rude_iso_button.set_text (_("Isolated"));
117 rude_iso_button.set_name ("rude isolate");
118 rude_iso_button.show ();
120 rude_audition_button.set_text (_("Auditioning"));
121 rude_audition_button.set_name ("rude audition");
122 rude_audition_button.show ();
124 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
126 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
128 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
129 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
131 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
132 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
134 /* SIP, AFL, PFL radio */
136 solo_in_place_button.set_name ("monitor section solo model");
137 afl_button.set_name ("monitor section solo model");
138 pfl_button.set_name ("monitor section solo model");
140 solo_in_place_button.set_led_left (true);
141 afl_button.set_led_left (true);
142 pfl_button.set_led_left (true);
144 solo_in_place_button.show ();
148 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
149 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
151 solo_in_place_button.set_related_action (act);
154 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
155 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
157 afl_button.set_related_action (act);
160 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
161 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
163 pfl_button.set_related_action (act);
166 /* Solo option buttons */
167 exclusive_solo_button.set_text (_("Excl. Solo"));
168 exclusive_solo_button.set_name (X_("monitor section solo option"));
169 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
171 act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
173 exclusive_solo_button.set_related_action (act);
176 solo_mute_override_button.set_text (_("Solo ยป Mute"));
177 solo_mute_override_button.set_name (X_("monitor section solo option"));
178 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
180 solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
182 /* Processor Box hide/shos */
183 toggle_processorbox_button.set_text (_("Processors"));
184 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
185 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
187 proctoggle = ActionManager::get_toggle_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
188 toggle_processorbox_button.set_related_action (proctoggle);
191 Label* solo_boost_label;
192 Label* solo_cut_label;
195 /* Solo Boost Knob */
197 solo_boost_control = new ArdourKnob ();
198 solo_boost_control->set_name("monitor section knob");
199 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
200 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
202 solo_boost_display = new ArdourDisplay ();
203 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
204 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
205 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
206 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
207 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
209 solo_boost_label = manage (new Label (_("Solo Boost")));
213 solo_cut_control = new ArdourKnob ();
214 solo_cut_control->set_name ("monitor section knob");
215 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
216 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
218 solo_cut_display = new ArdourDisplay ();
219 solo_cut_display->set_name("monitor section dropdown"); // XXX
220 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
221 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
222 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
223 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
224 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
225 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
227 solo_cut_label = manage (new Label (_("SiP Cut")));
231 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
232 dim_control->set_name ("monitor section knob");
233 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
234 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
236 dim_display = new ArdourDisplay ();
237 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
238 dim_display->add_controllable_preset(_("0 dB"), 0.0);
239 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
240 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
241 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
242 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
244 dim_label = manage (new Label (_("Dim")));
247 cut_all_button.set_text (_("Mute"));
248 cut_all_button.set_name ("mute button");
249 cut_all_button.set_size_request (-1, PX_SCALE(30));
250 cut_all_button.show ();
252 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
254 cut_all_button.set_related_action (act);
258 dim_all_button.set_text (_("Dim"));
259 dim_all_button.set_name ("monitor section dim");
260 dim_all_button.set_size_request (-1, PX_SCALE(25));
261 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
263 dim_all_button.set_related_action (act);
267 mono_button.set_text (_("Mono"));
268 mono_button.set_name ("monitor section mono");
269 mono_button.set_size_request (-1, PX_SCALE(25));
270 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
272 mono_button.set_related_action (act);
277 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
278 gain_control->set_name("monitor section knob");
279 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
281 gain_display = new ArdourDisplay ();
282 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
283 gain_display->add_controllable_preset(_("0 dB"), 0.0);
284 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
285 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
286 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
287 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
288 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
290 Label* output_label = manage (new Label (_("Output")));
291 output_label->set_name (X_("MonitorSectionLabel"));
293 output_button = new ArdourButton ();
294 output_button->set_text (_("Output"));
295 output_button->set_name (X_("monitor section cut")); // XXX
296 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
297 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
299 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
300 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
301 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
302 channel_table_scroller.show ();
303 channel_table_scroller.add (channel_table_viewport);
305 channel_size_group->add_widget (channel_table_header);
306 channel_table_header.resize (1, 5);
308 Label* l1 = manage (new Label (X_(" ")));
309 l1->set_name (X_("MonitorSectionLabel"));
310 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
312 l1 = manage (new Label (_("Mute")));
313 l1->set_name (X_("MonitorSectionLabel"));
314 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
316 l1 = manage (new Label (_("Dim")));
317 l1->set_name (X_("MonitorSectionLabel"));
318 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
320 l1 = manage (new Label (_("Solo")));
321 l1->set_name (X_("MonitorSectionLabel"));
322 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
324 l1 = manage (new Label (_("Inv")));
325 l1->set_name (X_("MonitorSectionLabel"));
326 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
328 channel_table_header.show ();
331 /****************************************************************************
332 * LAYOUT top to bottom
335 // solo, iso information
336 HBox* rude_box = manage (new HBox);
337 rude_box->set_spacing (PX_SCALE(4));
338 rude_box->set_homogeneous (true);
339 rude_box->pack_start (rude_solo_button, true, true);
340 rude_box->pack_start (rude_iso_button, true, true);
342 // solo options (right align)
343 HBox* tbx1 = manage (new HBox);
344 tbx1->pack_end (exclusive_solo_button, false, false);
346 HBox* tbx2 = manage (new HBox);
347 tbx2->pack_end (solo_mute_override_button, false, false);
349 HBox* tbx3 = manage (new HBox);
350 tbx3->pack_end (toggle_processorbox_button, false, false);
352 HBox* tbx0 = manage (new HBox); // space
354 // combined solo mode (Sip, AFL, PFL) & solo options
355 Table *solo_tbl = manage (new Table);
356 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
357 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
358 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
359 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
360 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
361 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
362 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
364 // boost, cut, dim volume control
365 Table *level_tbl = manage (new Table);
366 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
367 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
368 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
370 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
371 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
372 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
374 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
375 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
379 HBox* mono_dim_box = manage (new HBox);
380 mono_dim_box->set_spacing (PX_SCALE(4));
381 mono_dim_box->set_homogeneous (true);
382 mono_dim_box->pack_start (mono_button, true, true);
383 mono_dim_box->pack_end (dim_all_button, true, true);
386 Label* spin_label = manage (new Label (_("Monitor")));
387 VBox* spin_packer = manage (new VBox);
388 spin_packer->set_spacing (PX_SCALE(2));
389 spin_packer->pack_start (*spin_label, false, false);
390 spin_packer->pack_start (*gain_control, false, false);
391 spin_packer->pack_start (*gain_display, false, false);
393 master_packer.pack_start (*spin_packer, true, false);
395 // combined gain section (channels, mute, dim)
396 VBox* lower_packer = manage (new VBox);
397 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
398 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
399 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
400 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
402 // calc height of mixer scrollbar
403 int scrollbar_height = 0;
405 Gtk::Window window (WINDOW_TOPLEVEL);
406 HScrollbar scrollbar;
407 window.add (scrollbar);
408 scrollbar.set_name ("MixerWindow");
409 scrollbar.ensure_style();
410 Gtk::Requisition requisition(scrollbar.size_request ());
411 scrollbar_height = requisition.height;
414 // output port select
415 VBox* out_packer = manage (new VBox);
416 out_packer->set_spacing (PX_SCALE(2));
417 out_packer->pack_start (*output_label, false, false);
418 out_packer->pack_start (*output_button, false, false);
420 /****************************************************************************
423 vpacker.set_border_width (PX_SCALE(3));
424 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
425 vpacker.pack_start (rude_audition_button, false, false, 0);
426 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
427 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
428 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
429 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
430 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
431 vpacker.pack_end (*out_packer, false, false,
433 scrollbar_height - 2 /* no outer sample */
435 scrollbar_height + 2 /* sample borders */
439 hpacker.set_spacing (0);
440 hpacker.pack_start (vpacker, true, true);
444 gain_control->show_all ();
445 gain_display->show_all ();
446 dim_control->show_all ();
447 dim_display->show_all();
448 solo_boost_control->show_all ();
449 solo_boost_display->show_all();
451 mono_dim_box->show ();
452 spin_packer->show ();
453 master_packer.show ();
456 solo_tbl->show_all();
458 lower_packer->show ();
465 assign_controllables ();
467 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
468 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
470 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
471 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
472 set_flags (CAN_FOCUS);
474 _tearoff = new TearOff (*this);
476 if (!UIConfiguration::instance().get_floating_monitor_section()) {
477 /* if torn off, make this a normal window
478 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
480 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
482 _tearoff->tearoff_window().set_title (X_("Monitor"));
483 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
485 update_output_display ();
486 update_processor_box ();
487 _ui_initialized = true;
489 /* catch changes that affect us */
490 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
491 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
493 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
496 MonitorSection::~MonitorSection ()
498 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
502 _channel_buttons.clear ();
503 output_changed_connections.drop_connections ();
505 delete insert_box; insert_box = 0;
506 delete output_button; output_button = 0;
507 delete gain_control; gain_control = 0;
508 delete gain_display; gain_display = 0;
509 delete dim_control; dim_control = 0;
510 delete dim_display; dim_display = 0;
511 delete solo_boost_control; solo_boost_control = 0;
512 delete solo_boost_display; solo_boost_display = 0;
513 delete solo_cut_control; solo_cut_control = 0;
514 delete solo_cut_display; solo_cut_display = 0;
515 delete _tearoff; _tearoff = 0;
516 delete _output_selector; _output_selector = 0;
517 delete channel_table; channel_table = 0;
521 MonitorSection::enter_handler (GdkEventCrossing* ev)
528 MonitorSection::leave_handler (GdkEventCrossing* ev)
530 switch (ev->detail) {
531 case GDK_NOTIFY_INFERIOR:
537 /* cancel focus if we're not torn off. With X11 WM's that do
538 * focus-follows-mouse, focus will be taken from us anyway.
541 Widget* top = get_toplevel();
543 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
544 Window* win = dynamic_cast<Window*> (top);
545 gtk_window_set_focus (win->gobj(), 0);
552 MonitorSection::update_processor_box ()
554 bool show_processor_box = proctoggle->get_active ();
556 if (count_processors () > 0 && !show_processor_box) {
557 toggle_processorbox_button.set_name (X_("monitor section processors present"));
559 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
562 if (insert_box->is_visible() == show_processor_box) {
566 if (show_processor_box) {
567 if (master_packer.get_parent()) {
568 master_packer.get_parent()->remove (master_packer);
571 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
573 if (master_packer.get_parent()) {
574 master_packer.get_parent()->remove (master_packer);
577 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
582 MonitorSection::set_session (Session* s)
584 RouteUI::set_session (s);
585 _plugin_selector->set_session (_session);
589 /* These are not actually dependent on the Session, but they
590 * need to be set after construction, not during, and
591 * this is as good a place as any.
594 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
595 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
597 _route = _session->monitor_out ();
600 /* session with monitor section */
601 _monitor = _route->monitor_control ();
602 assign_controllables ();
603 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
604 boost::bind (&MonitorSection::update_output_display, this),
606 insert_box->set_route (_route);
607 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
608 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
609 _route->DropReferences.connect (*this, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
611 if (_ui_initialized) {
612 update_processor_box ();
615 ActionManager::set_sensitive (monitor_actions, true);
616 ActionManager::set_sensitive (solo_actions, true);
619 /* session with no monitor section */
620 output_changed_connections.drop_connections();
623 delete _output_selector;
624 _output_selector = 0;
626 ActionManager::set_sensitive (monitor_actions, false);
627 /* this action needs to always be true in this * scenaro, so that we can turn it back on*/
628 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
629 ActionManager::set_sensitive (solo_actions, true);
632 /* make sure the state of this action reflects reality */
633 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_active (_route != 0);
643 assign_controllables ();
645 ActionManager::set_sensitive (monitor_actions, false);
646 ActionManager::set_sensitive (solo_actions, false);
651 MonitorSection::drop_route ()
653 output_changed_connections.drop_connections();
656 control_connections.drop_connections ();
657 rude_iso_button.unset_active_state ();
658 rude_solo_button.unset_active_state ();
659 delete _output_selector;
660 _output_selector = 0;
663 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
665 cut.set_name (X_("mute button"));
666 dim.set_name (X_("monitor section dim"));
667 solo.set_name (X_("solo button"));
668 invert.set_name (X_("invert button"));
670 cut.unset_flags (Gtk::CAN_FOCUS);
671 dim.unset_flags (Gtk::CAN_FOCUS);
672 solo.unset_flags (Gtk::CAN_FOCUS);
673 invert.unset_flags (Gtk::CAN_FOCUS);
677 MonitorSection::populate_buttons ()
684 channel_size_group->remove_widget (*channel_table);
685 delete channel_table;
688 channel_table = new Gtk::Table();
690 channel_table->set_col_spacings (6);
691 channel_table->set_row_spacings (6);
692 channel_table->set_homogeneous (true);
694 channel_size_group->add_widget (*channel_table);
695 channel_table->show ();
696 table_hpacker.pack_start (*channel_table, true, true);
698 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
701 _channel_buttons.clear ();
703 Glib::RefPtr<Action> act;
704 uint32_t nchans = _monitor->output_streams().n_audio();
706 channel_table->resize (nchans, 5);
708 const uint32_t row_offset = 0;
710 for (uint32_t i = 0; i < nchans; ++i) {
723 snprintf (buf, sizeof (buf), "%d", i+1);
727 Label* label = manage (new Label (l));
728 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
730 ChannelButtonSet* cbs = new ChannelButtonSet;
732 _channel_buttons.push_back (cbs);
734 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
735 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
736 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
737 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
739 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
740 act = ActionManager::get_action (X_("Monitor"), buf);
742 cbs->cut.set_related_action (act);
745 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
746 act = ActionManager::get_action (X_("Monitor"), buf);
748 cbs->dim.set_related_action (act);
751 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
752 act = ActionManager::get_action (X_("Monitor"), buf);
754 cbs->solo.set_related_action (act);
757 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
758 act = ActionManager::get_action (X_("Monitor"), buf);
760 cbs->invert.set_related_action (act);
764 channel_table->show_all ();
766 if (channel_table_scroller.get_parent()) {
767 /* scroller is packed, so remove it */
768 channel_table_packer.remove (channel_table_scroller);
771 if (table_hpacker.get_parent () == &channel_table_packer) {
772 /* this occurs when the table hpacker is directly
773 packed, so remove it.
775 channel_table_packer.remove (table_hpacker);
776 } else if (table_hpacker.get_parent()) {
777 channel_table_viewport.remove ();
781 /* put the table into a scrolled window, and then put
782 * that into the channel vpacker, after the table header
784 channel_table_viewport.add (table_hpacker);
785 channel_table_packer.pack_start (channel_table_scroller, true, true);
786 channel_table_viewport.show ();
787 channel_table_scroller.show ();
790 /* just put the channel table itself into the channel
791 * vpacker, after the table header
793 channel_table_packer.pack_start (table_hpacker, true, true);
794 channel_table_scroller.hide ();
796 table_hpacker.show ();
797 channel_table->show ();
801 MonitorSection::toggle_exclusive_solo ()
807 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
811 MonitorSection::toggle_mute_overrides_solo ()
817 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo");
818 Config->set_solo_mute_override (tact->get_active());
822 MonitorSection::dim_all ()
828 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
829 _monitor->set_dim_all (tact->get_active());
833 MonitorSection::cut_all ()
839 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
840 _monitor->set_cut_all (tact->get_active());
844 MonitorSection::mono ()
850 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
851 _monitor->set_mono (tact->get_active());
855 MonitorSection::cut_channel (uint32_t chn)
862 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
864 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
865 _monitor->set_cut (chn, tact->get_active());
869 MonitorSection::dim_channel (uint32_t chn)
876 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
878 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
879 _monitor->set_dim (chn, tact->get_active());
883 MonitorSection::solo_channel (uint32_t chn)
890 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
892 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
893 _monitor->set_solo (chn, tact->get_active());
898 MonitorSection::invert_channel (uint32_t chn)
905 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
907 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
908 _monitor->set_polarity (chn, tact->get_active());
912 MonitorSection::register_actions ()
916 Glib::RefPtr<Action> act;
918 /* ...will get sensitized if a mon-session is added */
920 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
921 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
923 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
924 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", _("Monitor Section: Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
925 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", _("Monitor Section: Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
926 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", _("Monitor Section: Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
928 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
929 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
932 for (uint32_t chn = 0; chn < 16; ++chn) {
934 action_name = string_compose (X_("monitor-cut-%1"), chn);
935 action_descr = string_compose (_("Cut monitor channel %1"), chn);
936 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
937 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
939 action_name = string_compose (X_("monitor-dim-%1"), chn);
940 action_descr = string_compose (_("Dim monitor channel %1"), chn);
941 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
942 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
944 action_name = string_compose (X_("monitor-solo-%1"), chn);
945 action_descr = string_compose (_("Solo monitor channel %1"), chn);
946 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
947 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
949 action_name = string_compose (X_("monitor-invert-%1"), chn);
950 action_descr = string_compose (_("Invert monitor channel %1"), chn);
951 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
952 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
956 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
957 RadioAction::Group solo_group;
959 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
960 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
961 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
962 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
963 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
964 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
966 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
967 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
968 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
969 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
973 MonitorSection::solo_use_in_place ()
975 /* this is driven by a toggle on a radio group, and so is invoked twice,
976 once for the item that became inactive and once for the one that became
980 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-in-place"));
981 if (!ract->get_active ()) {
982 /* We are turning SiP off, which means that AFL or PFL will be turned on
983 shortly; don't update the solo model in the mean time, as if the currently
984 configured listen position is not the one that is about to be turned on,
985 things will go wrong.
987 _inhibit_solo_model_update = true;
989 Config->set_solo_control_is_listen_control (!ract->get_active());
990 _inhibit_solo_model_update = false;
994 MonitorSection::solo_use_afl ()
996 /* this is driven by a toggle on a radio group, and so is invoked twice,
997 once for the item that became inactive and once for the one that became
1001 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-afl"));
1002 if (ract->get_active()) {
1003 Config->set_solo_control_is_listen_control (true);
1004 Config->set_listen_position (AfterFaderListen);
1009 MonitorSection::solo_use_pfl ()
1011 /* this is driven by a toggle on a radio group, and so is invoked twice,
1012 once for the item that became inactive and once for the one that became
1016 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-pfl"));
1017 if (ract->get_active()) {
1018 Config->set_solo_control_is_listen_control (true);
1019 Config->set_listen_position (PreFaderListen);
1024 MonitorSection::update_solo_model ()
1026 if (_inhibit_solo_model_update) {
1030 const char* action_name = 0;
1031 Glib::RefPtr<RadioAction> ract;
1033 if (Config->get_solo_control_is_listen_control()) {
1034 switch (Config->get_listen_position()) {
1035 case AfterFaderListen:
1036 action_name = X_("solo-use-afl");
1038 case PreFaderListen:
1039 action_name = X_("solo-use-pfl");
1043 action_name = X_("solo-use-in-place");
1046 ract = ActionManager::get_radio_action (X_("Solo"), action_name);
1048 /* because these are radio buttons, one of them will be
1049 active no matter what. to trigger a change in the
1050 action so that the view picks it up, toggle it.
1053 if (ract->get_active()) {
1054 ract->set_active (false);
1057 ract->set_active (true);
1061 MonitorSection::map_state ()
1063 if (!_route || !_monitor) {
1067 update_solo_model ();
1069 Glib::RefPtr<Action> act;
1070 Glib::RefPtr<ToggleAction> tact;
1072 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
1073 tact->set_active (_monitor->cut_all());
1075 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
1076 tact->set_active (_monitor->dim_all());
1078 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
1079 tact->set_active (_monitor->mono());
1081 uint32_t nchans = _monitor->output_streams().n_audio();
1083 assert (nchans == _channel_buttons.size ());
1085 for (uint32_t n = 0; n < nchans; ++n) {
1087 char action_name[32];
1089 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1090 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1091 tact->set_active (_monitor->cut (n));
1093 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1094 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1095 tact->set_active (_monitor->dimmed (n));
1097 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1098 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1099 tact->set_active (_monitor->soloed (n));
1101 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1102 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1103 tact->set_active (_monitor->inverted (n));
1108 MonitorSection::do_blink (bool onoff)
1110 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1115 audition_blink (onoff);
1119 MonitorSection::audition_blink (bool onoff)
1121 if (_session == 0) {
1125 if (_session->is_auditioning()) {
1126 rude_audition_button.set_active (onoff);
1128 rude_audition_button.set_active (false);
1133 MonitorSection::solo_blink (bool onoff)
1135 if (_session == 0) {
1139 if (_session->soloing() || _session->listening()) {
1140 rude_solo_button.set_active (onoff);
1142 if (_session->soloing()) {
1143 if (_session->solo_isolated()) {
1144 rude_iso_button.set_active (onoff);
1146 rude_iso_button.set_active (false);
1151 rude_solo_button.set_active (false);
1152 rude_iso_button.set_active (false);
1157 MonitorSection::cancel_isolate (GdkEventButton*)
1160 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1161 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1168 MonitorSection::cancel_audition (GdkEventButton*)
1171 _session->cancel_audition();
1176 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1177 if (action && action->get_active() != value) { \
1178 action->set_active(value); \
1182 MonitorSection::parameter_changed (std::string name)
1184 if (name == "solo-control-is-listen-control") {
1185 update_solo_model ();
1186 } else if (name == "listen-position") {
1187 update_solo_model ();
1188 } else if (name == "solo-mute-override") {
1189 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1190 } else if (name == "exclusive-solo") {
1191 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1192 } else if (name == "use-monitor-bus") {
1193 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), Config->get_use_monitor_bus ());
1198 MonitorSection::assign_controllables ()
1200 boost::shared_ptr<Controllable> none;
1202 if (!gain_control) {
1203 /* too early - GUI controls not set up yet */
1208 solo_cut_control->set_controllable (_session->solo_cut_control());
1209 solo_cut_display->set_controllable (_session->solo_cut_control());
1211 solo_cut_control->set_controllable (none);
1212 solo_cut_display->set_controllable (none);
1216 gain_control->set_controllable (_route->gain_control());
1217 gain_display->set_controllable (_route->gain_control());
1219 gain_control->set_controllable (none);
1224 cut_all_button.set_controllable (_monitor->cut_control());
1225 cut_all_button.watch ();
1226 dim_all_button.set_controllable (_monitor->dim_control());
1227 dim_all_button.watch ();
1228 mono_button.set_controllable (_monitor->mono_control());
1229 mono_button.watch ();
1231 dim_control->set_controllable (_monitor->dim_level_control ());
1232 dim_display->set_controllable (_monitor->dim_level_control ());
1233 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1234 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1238 cut_all_button.set_controllable (none);
1239 dim_all_button.set_controllable (none);
1240 mono_button.set_controllable (none);
1242 dim_control->set_controllable (none);
1243 dim_display->set_controllable (none);
1244 solo_boost_control->set_controllable (none);
1245 solo_boost_display->set_controllable (none);
1250 MonitorSection::state_id() const
1252 return "monitor-section";
1256 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1258 using namespace Menu_Helpers;
1260 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1264 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1265 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1269 if (i != output_menu_bundles.end()) {
1273 output_menu_bundles.push_back (b);
1275 MenuList& citems = output_menu.items();
1277 std::string n = b->name ();
1278 replace_all (n, "_", " ");
1280 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1284 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1287 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1289 if (std::find (current.begin(), current.end(), c) == current.end()) {
1290 _route->output()->connect_ports_to_bundle (c, true, this);
1292 _route->output()->disconnect_ports_from_bundle (c, this);
1297 MonitorSection::output_release (GdkEventButton *ev)
1299 switch (ev->button) {
1301 edit_output_configuration ();
1308 struct RouteCompareByName {
1309 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1310 return a->name().compare (b->name()) < 0;
1315 MonitorSection::output_press (GdkEventButton *ev)
1317 using namespace Menu_Helpers;
1319 MessageDialog msg (_("No session - no I/O changes are possible"));
1324 MenuList& citems = output_menu.items();
1325 switch (ev->button) {
1328 return false; //wait for the mouse-up to pop the dialog
1332 output_menu.set_name ("ArdourContextMenu");
1334 output_menu_bundles.clear ();
1336 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1338 citems.push_back (SeparatorElem());
1339 uint32_t const n_with_separator = citems.size ();
1341 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1343 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1345 /* give user bundles first chance at being in the menu */
1347 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1348 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1349 maybe_add_bundle_to_output_menu (*i, current);
1353 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1354 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1355 maybe_add_bundle_to_output_menu (*i, current);
1359 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1360 RouteList copy = *routes;
1361 copy.sort (RouteCompareByName ());
1362 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1363 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1366 if (citems.size() == n_with_separator) {
1367 /* no routes added; remove the separator */
1371 citems.push_back (SeparatorElem());
1372 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1374 output_menu.popup (1, ev->time);
1385 MonitorSection::update_output_display ()
1387 if (!_route || !_monitor || _session->deletion_in_progress()) {
1393 boost::shared_ptr<Port> port;
1394 vector<string> port_connections;
1396 uint32_t total_connection_count = 0;
1397 uint32_t io_connection_count = 0;
1398 uint32_t ardour_connection_count = 0;
1399 uint32_t system_connection_count = 0;
1400 uint32_t other_connection_count = 0;
1402 ostringstream label;
1404 bool have_label = false;
1405 bool each_io_has_one_connection = true;
1407 string connection_name;
1408 string ardour_track_name;
1409 string other_connection_type;
1410 string system_ports;
1413 ostringstream tooltip;
1414 char * tooltip_cstr;
1416 io_count = _route->n_outputs().n_total();
1417 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1420 for (io_index = 0; io_index < io_count; ++io_index) {
1422 port = _route->output()->nth (io_index);
1424 //ignore any port connections that don't match our DataType
1425 if (port->type() != DataType::AUDIO) {
1429 port_connections.clear ();
1430 port->get_connections(port_connections);
1431 io_connection_count = 0;
1433 if (!port_connections.empty()) {
1434 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1436 string& connection_name (*i);
1438 if (connection_name.find("system:") == 0) {
1439 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1442 if (io_connection_count == 0) {
1443 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1445 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1448 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1451 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1452 if (ardour_track_name.empty()) {
1453 // "ardour:Master/in 1" -> "ardour:Master/"
1454 string::size_type slash = connection_name.find("/");
1455 if (slash != string::npos) {
1456 ardour_track_name = connection_name.substr(0, slash + 1);
1460 if (connection_name.find(ardour_track_name) == 0) {
1461 ++ardour_connection_count;
1463 } else if (!pn.empty()) {
1464 if (system_ports.empty()) {
1467 system_ports += "/" + pn;
1469 if (connection_name.find("system:") == 0) {
1470 ++system_connection_count;
1472 } else if (connection_name.find("system:") == 0) {
1473 // "system:playback_123" -> "123"
1474 system_port = connection_name.substr(16);
1475 if (system_ports.empty()) {
1476 system_ports += system_port;
1478 system_ports += "/" + system_port;
1481 ++system_connection_count;
1483 if (other_connection_type.empty()) {
1484 // "jamin:in 1" -> "jamin:"
1485 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1488 if (connection_name.find(other_connection_type) == 0) {
1489 ++other_connection_count;
1493 ++total_connection_count;
1494 ++io_connection_count;
1498 if (io_connection_count != 1) {
1499 each_io_has_one_connection = false;
1503 if (total_connection_count == 0) {
1504 tooltip << endl << _("Disconnected");
1507 tooltip_cstr = new char[tooltip.str().size() + 1];
1508 strcpy(tooltip_cstr, tooltip.str().c_str());
1510 set_tooltip (output_button, tooltip_cstr, "");
1512 if (each_io_has_one_connection) {
1513 if (total_connection_count == ardour_connection_count) {
1514 // all connections are to the same track in ardour
1515 // "ardour:Master/" -> "Master"
1516 string::size_type slash = ardour_track_name.find("/");
1517 if (slash != string::npos) {
1518 label << ardour_track_name.substr(7, slash - 7);
1521 } else if (total_connection_count == system_connection_count) {
1522 // all connections are to system ports
1523 label << system_ports;
1525 } else if (total_connection_count == other_connection_count) {
1526 // all connections are to the same external program eg jamin
1527 // "jamin:" -> "jamin"
1528 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1534 if (total_connection_count == 0) {
1538 // Odd configuration
1539 label << "*" << total_connection_count << "*";
1543 output_button->set_text (label.str());
1547 MonitorSection::disconnect_output ()
1550 _route->output()->disconnect(this);
1555 MonitorSection::edit_output_configuration ()
1557 if (_output_selector == 0) {
1558 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1560 _output_selector->present ();
1564 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1569 boost::shared_ptr<Port> a = wa.lock ();
1570 boost::shared_ptr<Port> b = wb.lock ();
1571 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1572 update_output_display ();
1577 MonitorSection::load_bindings ()
1579 bindings = Bindings::get_bindings (X_("Monitor Section"));
1583 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1585 boost::shared_ptr<Processor> processor (p.lock ());
1586 if (!processor || !processor->display_to_user()) {
1589 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1596 MonitorSection::count_processors ()
1598 uint32_t processor_count = 0;
1600 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1602 return processor_count;
1606 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1608 update_processor_box ();
1612 MonitorSection::use_others_actions ()
1614 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1618 MonitorSection::toggle_use_monitor_section ()
1624 Config->set_use_monitor_bus (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active());