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 (0, 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);
586 insert_box->set_session (_session);
590 /* These are not actually dependent on the Session, but they
591 * need to be set after construction, not during, and
592 * this is as good a place as any.
595 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
596 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
598 _route = _session->monitor_out ();
601 /* session with monitor section */
602 _monitor = _route->monitor_control ();
603 assign_controllables ();
604 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
605 boost::bind (&MonitorSection::update_output_display, this),
607 insert_box->set_route (_route);
608 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
609 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
610 _route->DropReferences.connect (*this, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
612 if (_ui_initialized) {
613 update_processor_box ();
616 ActionManager::set_sensitive (monitor_actions, true);
617 ActionManager::set_sensitive (solo_actions, true);
620 /* session with no monitor section */
621 output_changed_connections.drop_connections();
624 delete _output_selector;
625 _output_selector = 0;
627 ActionManager::set_sensitive (monitor_actions, false);
628 /* this action needs to always be true in this * scenaro, so that we can turn it back on*/
629 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
630 ActionManager::set_sensitive (solo_actions, true);
633 /* make sure the state of this action reflects reality */
634 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_active (_route != 0);
644 assign_controllables ();
646 ActionManager::set_sensitive (monitor_actions, false);
647 ActionManager::set_sensitive (solo_actions, false);
652 MonitorSection::drop_route ()
654 output_changed_connections.drop_connections();
657 control_connections.drop_connections ();
658 rude_iso_button.unset_active_state ();
659 rude_solo_button.unset_active_state ();
660 delete _output_selector;
661 _output_selector = 0;
664 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
666 cut.set_name (X_("mute button"));
667 dim.set_name (X_("monitor section dim"));
668 solo.set_name (X_("solo button"));
669 invert.set_name (X_("invert button"));
671 cut.unset_flags (Gtk::CAN_FOCUS);
672 dim.unset_flags (Gtk::CAN_FOCUS);
673 solo.unset_flags (Gtk::CAN_FOCUS);
674 invert.unset_flags (Gtk::CAN_FOCUS);
678 MonitorSection::populate_buttons ()
685 channel_size_group->remove_widget (*channel_table);
686 delete channel_table;
689 channel_table = new Gtk::Table();
691 channel_table->set_col_spacings (6);
692 channel_table->set_row_spacings (6);
693 channel_table->set_homogeneous (true);
695 channel_size_group->add_widget (*channel_table);
696 channel_table->show ();
697 table_hpacker.pack_start (*channel_table, true, true);
699 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
702 _channel_buttons.clear ();
704 Glib::RefPtr<Action> act;
705 uint32_t nchans = _monitor->output_streams().n_audio();
707 channel_table->resize (nchans, 5);
709 const uint32_t row_offset = 0;
711 for (uint32_t i = 0; i < nchans; ++i) {
724 snprintf (buf, sizeof (buf), "%d", i+1);
728 Label* label = manage (new Label (l));
729 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
731 ChannelButtonSet* cbs = new ChannelButtonSet;
733 _channel_buttons.push_back (cbs);
735 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
736 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
737 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
738 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
740 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
741 act = ActionManager::get_action (X_("Monitor"), buf);
743 cbs->cut.set_related_action (act);
746 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
747 act = ActionManager::get_action (X_("Monitor"), buf);
749 cbs->dim.set_related_action (act);
752 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
753 act = ActionManager::get_action (X_("Monitor"), buf);
755 cbs->solo.set_related_action (act);
758 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
759 act = ActionManager::get_action (X_("Monitor"), buf);
761 cbs->invert.set_related_action (act);
765 channel_table->show_all ();
767 if (channel_table_scroller.get_parent()) {
768 /* scroller is packed, so remove it */
769 channel_table_packer.remove (channel_table_scroller);
772 if (table_hpacker.get_parent () == &channel_table_packer) {
773 /* this occurs when the table hpacker is directly
774 packed, so remove it.
776 channel_table_packer.remove (table_hpacker);
777 } else if (table_hpacker.get_parent()) {
778 channel_table_viewport.remove ();
782 /* put the table into a scrolled window, and then put
783 * that into the channel vpacker, after the table header
785 channel_table_viewport.add (table_hpacker);
786 channel_table_packer.pack_start (channel_table_scroller, true, true);
787 channel_table_viewport.show ();
788 channel_table_scroller.show ();
791 /* just put the channel table itself into the channel
792 * vpacker, after the table header
794 channel_table_packer.pack_start (table_hpacker, true, true);
795 channel_table_scroller.hide ();
797 table_hpacker.show ();
798 channel_table->show ();
802 MonitorSection::toggle_exclusive_solo ()
808 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
812 MonitorSection::toggle_mute_overrides_solo ()
818 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo");
819 Config->set_solo_mute_override (tact->get_active());
823 MonitorSection::dim_all ()
829 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
830 _monitor->set_dim_all (tact->get_active());
834 MonitorSection::cut_all ()
840 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
841 _monitor->set_cut_all (tact->get_active());
845 MonitorSection::mono ()
851 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
852 _monitor->set_mono (tact->get_active());
856 MonitorSection::cut_channel (uint32_t chn)
863 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
865 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
866 _monitor->set_cut (chn, tact->get_active());
870 MonitorSection::dim_channel (uint32_t chn)
877 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
879 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
880 _monitor->set_dim (chn, tact->get_active());
884 MonitorSection::solo_channel (uint32_t chn)
891 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
893 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
894 _monitor->set_solo (chn, tact->get_active());
899 MonitorSection::invert_channel (uint32_t chn)
906 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
908 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
909 _monitor->set_polarity (chn, tact->get_active());
913 MonitorSection::register_actions ()
917 Glib::RefPtr<Action> act;
919 /* ...will get sensitized if a mon-session is added */
921 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
922 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
924 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
925 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", _("Monitor Section: Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
926 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", _("Monitor Section: Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
927 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", _("Monitor Section: Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
929 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
930 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
933 for (uint32_t chn = 0; chn < 16; ++chn) {
935 action_name = string_compose (X_("monitor-cut-%1"), chn);
936 action_descr = string_compose (_("Cut monitor channel %1"), chn);
937 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
938 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
940 action_name = string_compose (X_("monitor-dim-%1"), chn);
941 action_descr = string_compose (_("Dim monitor channel %1"), chn);
942 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
943 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
945 action_name = string_compose (X_("monitor-solo-%1"), chn);
946 action_descr = string_compose (_("Solo monitor channel %1"), chn);
947 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
948 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
950 action_name = string_compose (X_("monitor-invert-%1"), chn);
951 action_descr = string_compose (_("Invert monitor channel %1"), chn);
952 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
953 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
957 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
958 RadioAction::Group solo_group;
960 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
961 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
962 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
963 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
964 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
965 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
967 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
968 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
969 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
970 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
974 MonitorSection::solo_use_in_place ()
976 /* this is driven by a toggle on a radio group, and so is invoked twice,
977 once for the item that became inactive and once for the one that became
981 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-in-place"));
982 if (!ract->get_active ()) {
983 /* We are turning SiP off, which means that AFL or PFL will be turned on
984 shortly; don't update the solo model in the mean time, as if the currently
985 configured listen position is not the one that is about to be turned on,
986 things will go wrong.
988 _inhibit_solo_model_update = true;
990 Config->set_solo_control_is_listen_control (!ract->get_active());
991 _inhibit_solo_model_update = false;
995 MonitorSection::solo_use_afl ()
997 /* this is driven by a toggle on a radio group, and so is invoked twice,
998 once for the item that became inactive and once for the one that became
1002 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-afl"));
1003 if (ract->get_active()) {
1004 Config->set_solo_control_is_listen_control (true);
1005 Config->set_listen_position (AfterFaderListen);
1010 MonitorSection::solo_use_pfl ()
1012 /* this is driven by a toggle on a radio group, and so is invoked twice,
1013 once for the item that became inactive and once for the one that became
1017 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-pfl"));
1018 if (ract->get_active()) {
1019 Config->set_solo_control_is_listen_control (true);
1020 Config->set_listen_position (PreFaderListen);
1025 MonitorSection::update_solo_model ()
1027 if (_inhibit_solo_model_update) {
1031 const char* action_name = 0;
1032 Glib::RefPtr<RadioAction> ract;
1034 if (Config->get_solo_control_is_listen_control()) {
1035 switch (Config->get_listen_position()) {
1036 case AfterFaderListen:
1037 action_name = X_("solo-use-afl");
1039 case PreFaderListen:
1040 action_name = X_("solo-use-pfl");
1044 action_name = X_("solo-use-in-place");
1047 ract = ActionManager::get_radio_action (X_("Solo"), action_name);
1049 /* because these are radio buttons, one of them will be
1050 active no matter what. to trigger a change in the
1051 action so that the view picks it up, toggle it.
1054 if (ract->get_active()) {
1055 ract->set_active (false);
1058 ract->set_active (true);
1062 MonitorSection::map_state ()
1064 if (!_route || !_monitor) {
1068 update_solo_model ();
1070 Glib::RefPtr<Action> act;
1071 Glib::RefPtr<ToggleAction> tact;
1073 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
1074 tact->set_active (_monitor->cut_all());
1076 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
1077 tact->set_active (_monitor->dim_all());
1079 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
1080 tact->set_active (_monitor->mono());
1082 uint32_t nchans = _monitor->output_streams().n_audio();
1084 assert (nchans == _channel_buttons.size ());
1086 for (uint32_t n = 0; n < nchans; ++n) {
1088 char action_name[32];
1090 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1091 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1092 tact->set_active (_monitor->cut (n));
1094 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1095 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1096 tact->set_active (_monitor->dimmed (n));
1098 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1099 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1100 tact->set_active (_monitor->soloed (n));
1102 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1103 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1104 tact->set_active (_monitor->inverted (n));
1109 MonitorSection::do_blink (bool onoff)
1111 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1116 audition_blink (onoff);
1120 MonitorSection::audition_blink (bool onoff)
1122 if (_session == 0) {
1126 if (_session->is_auditioning()) {
1127 rude_audition_button.set_active (onoff);
1129 rude_audition_button.set_active (false);
1134 MonitorSection::solo_blink (bool onoff)
1136 if (_session == 0) {
1140 if (_session->soloing() || _session->listening()) {
1141 rude_solo_button.set_active (onoff);
1143 if (_session->soloing()) {
1144 if (_session->solo_isolated()) {
1145 rude_iso_button.set_active (onoff);
1147 rude_iso_button.set_active (false);
1152 rude_solo_button.set_active (false);
1153 rude_iso_button.set_active (false);
1158 MonitorSection::cancel_isolate (GdkEventButton*)
1161 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1162 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1169 MonitorSection::cancel_audition (GdkEventButton*)
1172 _session->cancel_audition();
1177 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1178 if (action && action->get_active() != value) { \
1179 action->set_active(value); \
1183 MonitorSection::parameter_changed (std::string name)
1185 if (name == "solo-control-is-listen-control") {
1186 update_solo_model ();
1187 } else if (name == "listen-position") {
1188 update_solo_model ();
1189 } else if (name == "solo-mute-override") {
1190 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1191 } else if (name == "exclusive-solo") {
1192 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1193 } else if (name == "use-monitor-bus") {
1194 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), Config->get_use_monitor_bus ());
1199 MonitorSection::assign_controllables ()
1201 boost::shared_ptr<Controllable> none;
1203 if (!gain_control) {
1204 /* too early - GUI controls not set up yet */
1209 solo_cut_control->set_controllable (_session->solo_cut_control());
1210 solo_cut_display->set_controllable (_session->solo_cut_control());
1212 solo_cut_control->set_controllable (none);
1213 solo_cut_display->set_controllable (none);
1217 gain_control->set_controllable (_route->gain_control());
1218 gain_display->set_controllable (_route->gain_control());
1220 gain_control->set_controllable (none);
1225 cut_all_button.set_controllable (_monitor->cut_control());
1226 cut_all_button.watch ();
1227 dim_all_button.set_controllable (_monitor->dim_control());
1228 dim_all_button.watch ();
1229 mono_button.set_controllable (_monitor->mono_control());
1230 mono_button.watch ();
1232 dim_control->set_controllable (_monitor->dim_level_control ());
1233 dim_display->set_controllable (_monitor->dim_level_control ());
1234 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1235 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1239 cut_all_button.set_controllable (none);
1240 dim_all_button.set_controllable (none);
1241 mono_button.set_controllable (none);
1243 dim_control->set_controllable (none);
1244 dim_display->set_controllable (none);
1245 solo_boost_control->set_controllable (none);
1246 solo_boost_display->set_controllable (none);
1251 MonitorSection::state_id() const
1253 return "monitor-section";
1257 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1259 using namespace Menu_Helpers;
1261 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1265 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1266 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1270 if (i != output_menu_bundles.end()) {
1274 output_menu_bundles.push_back (b);
1276 MenuList& citems = output_menu.items();
1278 std::string n = b->name ();
1279 replace_all (n, "_", " ");
1281 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1285 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1288 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1290 if (std::find (current.begin(), current.end(), c) == current.end()) {
1291 _route->output()->connect_ports_to_bundle (c, true, this);
1293 _route->output()->disconnect_ports_from_bundle (c, this);
1298 MonitorSection::output_release (GdkEventButton *ev)
1300 switch (ev->button) {
1302 edit_output_configuration ();
1309 struct RouteCompareByName {
1310 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1311 return a->name().compare (b->name()) < 0;
1316 MonitorSection::output_press (GdkEventButton *ev)
1318 using namespace Menu_Helpers;
1320 MessageDialog msg (_("No session - no I/O changes are possible"));
1325 MenuList& citems = output_menu.items();
1326 switch (ev->button) {
1329 return false; //wait for the mouse-up to pop the dialog
1333 output_menu.set_name ("ArdourContextMenu");
1335 output_menu_bundles.clear ();
1337 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1339 citems.push_back (SeparatorElem());
1340 uint32_t const n_with_separator = citems.size ();
1342 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1344 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1346 /* give user bundles first chance at being in the menu */
1348 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1349 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1350 maybe_add_bundle_to_output_menu (*i, current);
1354 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1355 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1356 maybe_add_bundle_to_output_menu (*i, current);
1360 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1361 RouteList copy = *routes;
1362 copy.sort (RouteCompareByName ());
1363 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1364 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1367 if (citems.size() == n_with_separator) {
1368 /* no routes added; remove the separator */
1372 citems.push_back (SeparatorElem());
1373 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1375 output_menu.popup (1, ev->time);
1386 MonitorSection::update_output_display ()
1388 if (!_route || !_monitor || _session->deletion_in_progress()) {
1394 boost::shared_ptr<Port> port;
1395 vector<string> port_connections;
1397 uint32_t total_connection_count = 0;
1398 uint32_t io_connection_count = 0;
1399 uint32_t ardour_connection_count = 0;
1400 uint32_t system_connection_count = 0;
1401 uint32_t other_connection_count = 0;
1403 ostringstream label;
1405 bool have_label = false;
1406 bool each_io_has_one_connection = true;
1408 string connection_name;
1409 string ardour_track_name;
1410 string other_connection_type;
1411 string system_ports;
1414 ostringstream tooltip;
1415 char * tooltip_cstr;
1417 io_count = _route->n_outputs().n_total();
1418 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1421 for (io_index = 0; io_index < io_count; ++io_index) {
1423 port = _route->output()->nth (io_index);
1425 //ignore any port connections that don't match our DataType
1426 if (port->type() != DataType::AUDIO) {
1430 port_connections.clear ();
1431 port->get_connections(port_connections);
1432 io_connection_count = 0;
1434 if (!port_connections.empty()) {
1435 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1437 string& connection_name (*i);
1439 if (connection_name.find("system:") == 0) {
1440 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1443 if (io_connection_count == 0) {
1444 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1446 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1449 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1452 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1453 if (ardour_track_name.empty()) {
1454 // "ardour:Master/in 1" -> "ardour:Master/"
1455 string::size_type slash = connection_name.find("/");
1456 if (slash != string::npos) {
1457 ardour_track_name = connection_name.substr(0, slash + 1);
1461 if (connection_name.find(ardour_track_name) == 0) {
1462 ++ardour_connection_count;
1464 } else if (!pn.empty()) {
1465 if (system_ports.empty()) {
1468 system_ports += "/" + pn;
1470 if (connection_name.find("system:") == 0) {
1471 ++system_connection_count;
1473 } else if (connection_name.find("system:") == 0) {
1474 // "system:playback_123" -> "123"
1475 system_port = connection_name.substr(16);
1476 if (system_ports.empty()) {
1477 system_ports += system_port;
1479 system_ports += "/" + system_port;
1482 ++system_connection_count;
1484 if (other_connection_type.empty()) {
1485 // "jamin:in 1" -> "jamin:"
1486 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1489 if (connection_name.find(other_connection_type) == 0) {
1490 ++other_connection_count;
1494 ++total_connection_count;
1495 ++io_connection_count;
1499 if (io_connection_count != 1) {
1500 each_io_has_one_connection = false;
1504 if (total_connection_count == 0) {
1505 tooltip << endl << _("Disconnected");
1508 tooltip_cstr = new char[tooltip.str().size() + 1];
1509 strcpy(tooltip_cstr, tooltip.str().c_str());
1511 set_tooltip (output_button, tooltip_cstr, "");
1513 if (each_io_has_one_connection) {
1514 if (total_connection_count == ardour_connection_count) {
1515 // all connections are to the same track in ardour
1516 // "ardour:Master/" -> "Master"
1517 string::size_type slash = ardour_track_name.find("/");
1518 if (slash != string::npos) {
1519 label << ardour_track_name.substr(7, slash - 7);
1522 } else if (total_connection_count == system_connection_count) {
1523 // all connections are to system ports
1524 label << system_ports;
1526 } else if (total_connection_count == other_connection_count) {
1527 // all connections are to the same external program eg jamin
1528 // "jamin:" -> "jamin"
1529 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1535 if (total_connection_count == 0) {
1539 // Odd configuration
1540 label << "*" << total_connection_count << "*";
1544 output_button->set_text (label.str());
1548 MonitorSection::disconnect_output ()
1551 _route->output()->disconnect(this);
1556 MonitorSection::edit_output_configuration ()
1558 if (_output_selector == 0) {
1559 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1561 _output_selector->present ();
1565 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1570 boost::shared_ptr<Port> a = wa.lock ();
1571 boost::shared_ptr<Port> b = wb.lock ();
1572 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1573 update_output_display ();
1578 MonitorSection::load_bindings ()
1580 bindings = Bindings::get_bindings (X_("Monitor Section"));
1584 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1586 boost::shared_ptr<Processor> processor (p.lock ());
1587 if (!processor || !processor->display_to_user()) {
1590 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1597 MonitorSection::count_processors ()
1599 uint32_t processor_count = 0;
1601 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1603 return processor_count;
1607 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1609 update_processor_box ();
1613 MonitorSection::use_others_actions ()
1615 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1619 MonitorSection::toggle_use_monitor_section ()
1625 Config->set_use_monitor_bus (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active());