2 Copyright (C) 2012 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gdkmm/pixbuf.h>
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
25 #include "pbd/stacktrace.h"
27 #include "gtkmm2ext/actions.h"
28 #include "gtkmm2ext/utils.h"
30 #include <gtkmm/menu.h>
31 #include <gtkmm/menuitem.h>
33 #include "widgets/tearoff.h"
34 #include "widgets/tooltips.h"
36 #include "ardour/amp.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/monitor_processor.h"
39 #include "ardour/port.h"
40 #include "ardour/route.h"
41 #include "ardour/solo_isolate_control.h"
42 #include "ardour/user_bundle.h"
43 #include "ardour/plugin_manager.h"
45 #include "ardour_ui.h"
46 #include "gui_thread.h"
48 #include "monitor_section.h"
49 #include "public_editor.h"
51 #include "ui_config.h"
56 using namespace ARDOUR;
57 using namespace ArdourWidgets;
58 using namespace ARDOUR_UI_UTILS;
60 using namespace Gtkmm2ext;
64 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
66 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
67 if (action && action->get_active() != value) { \
68 action->set_active(value); \
71 MonitorSection::MonitorSection ()
72 : RouteUI ((Session*) 0)
75 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
76 , *channel_table_scroller.get_vadjustment ())
79 , solo_boost_control (0)
80 , solo_cut_control (0)
83 , solo_boost_display (0)
84 , solo_cut_display (0)
85 , _output_selector (0)
86 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
87 , afl_button (_("AFL"), ArdourButton::led_default_elements)
88 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
89 , exclusive_solo_button (ArdourButton::led_default_elements)
90 , solo_mute_override_button (ArdourButton::led_default_elements)
91 , toggle_processorbox_button (ArdourButton::default_elements)
92 , _inhibit_solo_model_update (false)
94 , _ui_initialized (false)
96 /* note that although this a RouteUI, we never called ::set_route() so
97 * we do not need to worry about self-destructing when the Route (the
98 * monitor out) is destroyed.
101 using namespace Menu_Helpers;
103 Glib::RefPtr<Action> act;
107 set_data ("ardour-bindings", bindings);
109 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
111 insert_box = new ProcessorBox (0, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
112 insert_box->set_no_show_all ();
114 // TODO allow keyboard shortcuts in ProcessorBox
116 /* Rude Solo & Solo Isolated */
117 rude_solo_button.set_text (_("Soloing"));
118 rude_solo_button.set_name ("rude solo");
119 rude_solo_button.show ();
121 rude_iso_button.set_text (_("Isolated"));
122 rude_iso_button.set_name ("rude isolate");
123 rude_iso_button.show ();
125 rude_audition_button.set_text (_("Auditioning"));
126 rude_audition_button.set_name ("rude audition");
127 rude_audition_button.show ();
129 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
131 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
133 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
134 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
136 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
137 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
139 /* SIP, AFL, PFL radio */
141 solo_in_place_button.set_name ("monitor section solo model");
142 afl_button.set_name ("monitor section solo model");
143 pfl_button.set_name ("monitor section solo model");
145 solo_in_place_button.set_led_left (true);
146 afl_button.set_led_left (true);
147 pfl_button.set_led_left (true);
149 solo_in_place_button.show ();
153 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
154 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
156 solo_in_place_button.set_related_action (act);
159 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
160 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
162 afl_button.set_related_action (act);
165 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
166 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
168 pfl_button.set_related_action (act);
171 /* Solo option buttons */
172 exclusive_solo_button.set_text (_("Excl. Solo"));
173 exclusive_solo_button.set_name (X_("monitor section solo option"));
174 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
176 act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
178 exclusive_solo_button.set_related_action (act);
181 solo_mute_override_button.set_text (_("Solo ยป Mute"));
182 solo_mute_override_button.set_name (X_("monitor section solo option"));
183 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
185 solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
187 /* Processor Box hide/shos */
188 toggle_processorbox_button.set_text (_("Processors"));
189 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
190 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
192 proctoggle = ActionManager::get_toggle_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
193 toggle_processorbox_button.set_related_action (proctoggle);
196 Label* solo_boost_label;
197 Label* solo_cut_label;
200 /* Solo Boost Knob */
202 solo_boost_control = new ArdourKnob ();
203 solo_boost_control->set_name("monitor section knob");
204 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
205 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
207 solo_boost_display = new ArdourDisplay ();
208 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
209 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
210 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
211 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
212 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
214 solo_boost_label = manage (new Label (_("Solo Boost")));
218 solo_cut_control = new ArdourKnob ();
219 solo_cut_control->set_name ("monitor section knob");
220 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
221 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
223 solo_cut_display = new ArdourDisplay ();
224 solo_cut_display->set_name("monitor section dropdown"); // XXX
225 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
226 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
227 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
228 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
229 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
230 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
232 solo_cut_label = manage (new Label (_("SiP Cut")));
236 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
237 dim_control->set_name ("monitor section knob");
238 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
239 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
241 dim_display = new ArdourDisplay ();
242 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
243 dim_display->add_controllable_preset(_("0 dB"), 0.0);
244 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
245 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
246 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
247 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
249 dim_label = manage (new Label (_("Dim")));
252 cut_all_button.set_text (_("Mute"));
253 cut_all_button.set_name ("mute button");
254 cut_all_button.set_size_request (-1, PX_SCALE(30));
255 cut_all_button.show ();
257 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-cut-all"));
259 cut_all_button.set_related_action (act);
263 dim_all_button.set_text (_("Dim"));
264 dim_all_button.set_name ("monitor section dim");
265 dim_all_button.set_size_request (-1, PX_SCALE(25));
266 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-dim-all"));
268 dim_all_button.set_related_action (act);
272 mono_button.set_text (_("Mono"));
273 mono_button.set_name ("monitor section mono");
274 mono_button.set_size_request (-1, PX_SCALE(25));
275 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-mono"));
277 mono_button.set_related_action (act);
282 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
283 gain_control->set_name("monitor section knob");
284 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
286 gain_display = new ArdourDisplay ();
287 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
288 gain_display->add_controllable_preset(_("0 dB"), 0.0);
289 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
290 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
291 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
292 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
293 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
295 Label* output_label = manage (new Label (_("Output")));
296 output_label->set_name (X_("MonitorSectionLabel"));
298 output_button = new ArdourButton ();
299 output_button->set_text (_("Output"));
300 output_button->set_name (X_("monitor section cut")); // XXX
301 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
302 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
304 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
305 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
306 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
307 channel_table_scroller.show ();
308 channel_table_scroller.add (channel_table_viewport);
310 channel_size_group->add_widget (channel_table_header);
311 channel_table_header.resize (1, 5);
313 Label* l1 = manage (new Label (X_(" ")));
314 l1->set_name (X_("MonitorSectionLabel"));
315 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
317 l1 = manage (new Label (_("Mute")));
318 l1->set_name (X_("MonitorSectionLabel"));
319 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
321 l1 = manage (new Label (_("Dim")));
322 l1->set_name (X_("MonitorSectionLabel"));
323 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
325 l1 = manage (new Label (_("Solo")));
326 l1->set_name (X_("MonitorSectionLabel"));
327 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
329 l1 = manage (new Label (_("Inv")));
330 l1->set_name (X_("MonitorSectionLabel"));
331 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
333 channel_table_header.show ();
336 /****************************************************************************
337 * LAYOUT top to bottom
340 // solo, iso information
341 HBox* rude_box = manage (new HBox);
342 rude_box->set_spacing (PX_SCALE(4));
343 rude_box->set_homogeneous (true);
344 rude_box->pack_start (rude_solo_button, true, true);
345 rude_box->pack_start (rude_iso_button, true, true);
347 // solo options (right align)
348 HBox* tbx1 = manage (new HBox);
349 tbx1->pack_end (exclusive_solo_button, false, false);
351 HBox* tbx2 = manage (new HBox);
352 tbx2->pack_end (solo_mute_override_button, false, false);
354 HBox* tbx3 = manage (new HBox);
355 tbx3->pack_end (toggle_processorbox_button, false, false);
357 HBox* tbx0 = manage (new HBox); // space
359 // combined solo mode (Sip, AFL, PFL) & solo options
360 Table *solo_tbl = manage (new Table);
361 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
362 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
363 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
364 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
365 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
366 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
369 // boost, cut, dim volume control
370 Table *level_tbl = manage (new Table);
371 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
372 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
373 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
375 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
379 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
384 HBox* mono_dim_box = manage (new HBox);
385 mono_dim_box->set_spacing (PX_SCALE(4));
386 mono_dim_box->set_homogeneous (true);
387 mono_dim_box->pack_start (mono_button, true, true);
388 mono_dim_box->pack_end (dim_all_button, true, true);
391 Label* spin_label = manage (new Label (_("Monitor")));
392 VBox* spin_packer = manage (new VBox);
393 spin_packer->set_spacing (PX_SCALE(2));
394 spin_packer->pack_start (*spin_label, false, false);
395 spin_packer->pack_start (*gain_control, false, false);
396 spin_packer->pack_start (*gain_display, false, false);
398 master_packer.pack_start (*spin_packer, true, false);
400 // combined gain section (channels, mute, dim)
401 VBox* lower_packer = manage (new VBox);
402 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
403 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
404 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
405 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
407 // calc height of mixer scrollbar
408 int scrollbar_height = 0;
410 Gtk::Window window (WINDOW_TOPLEVEL);
411 HScrollbar scrollbar;
412 window.add (scrollbar);
413 scrollbar.set_name ("MixerWindow");
414 scrollbar.ensure_style();
415 Gtk::Requisition requisition(scrollbar.size_request ());
416 scrollbar_height = requisition.height;
419 // output port select
420 VBox* out_packer = manage (new VBox);
421 out_packer->set_spacing (PX_SCALE(2));
422 out_packer->pack_start (*output_label, false, false);
423 out_packer->pack_start (*output_button, false, false);
425 /****************************************************************************
428 vpacker.set_border_width (PX_SCALE(3));
429 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
430 vpacker.pack_start (rude_audition_button, false, false, 0);
431 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
432 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
433 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
434 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
435 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
436 vpacker.pack_end (*out_packer, false, false,
438 scrollbar_height /* no outer frame */
440 scrollbar_height + 2 /* frame borders */
444 hpacker.set_spacing (0);
445 hpacker.pack_start (vpacker, true, true);
449 gain_control->show_all ();
450 gain_display->show_all ();
451 dim_control->show_all ();
452 dim_display->show_all();
453 solo_boost_control->show_all ();
454 solo_boost_display->show_all();
456 mono_dim_box->show ();
457 spin_packer->show ();
458 master_packer.show ();
461 solo_tbl->show_all();
463 lower_packer->show ();
471 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
472 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
474 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
475 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
476 set_flags (CAN_FOCUS);
478 _tearoff = new TearOff (*this);
480 if (!UIConfiguration::instance().get_floating_monitor_section()) {
481 /* if torn off, make this a normal window
482 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
484 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
486 _tearoff->tearoff_window().set_title (X_("Monitor"));
487 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
489 update_output_display ();
490 update_processor_box ();
491 _ui_initialized = true;
493 /* catch changes that affect us */
494 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
495 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
497 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
500 MonitorSection::~MonitorSection ()
502 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
506 _channel_buttons.clear ();
507 route_connections.drop_connections ();
509 delete insert_box; insert_box = 0;
510 delete output_button; output_button = 0;
511 delete gain_control; gain_control = 0;
512 delete gain_display; gain_display = 0;
513 delete dim_control; dim_control = 0;
514 delete dim_display; dim_display = 0;
515 delete solo_boost_control; solo_boost_control = 0;
516 delete solo_boost_display; solo_boost_display = 0;
517 delete solo_cut_control; solo_cut_control = 0;
518 delete solo_cut_display; solo_cut_display = 0;
519 delete _tearoff; _tearoff = 0;
520 delete _output_selector; _output_selector = 0;
521 delete channel_table; channel_table = 0;
525 MonitorSection::enter_handler (GdkEventCrossing* ev)
532 MonitorSection::leave_handler (GdkEventCrossing* ev)
534 switch (ev->detail) {
535 case GDK_NOTIFY_INFERIOR:
541 /* cancel focus if we're not torn off. With X11 WM's that do
542 * focus-follows-mouse, focus will be taken from us anyway.
545 Widget* top = get_toplevel();
547 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
548 Window* win = dynamic_cast<Window*> (top);
549 gtk_window_set_focus (win->gobj(), 0);
556 MonitorSection::update_processor_box ()
558 bool show_processor_box = proctoggle->get_active ();
560 if (count_processors () > 0 && !show_processor_box) {
561 toggle_processorbox_button.set_name (X_("monitor section processors present"));
563 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
566 if (insert_box->is_visible() == show_processor_box) {
570 if (show_processor_box) {
571 if (master_packer.get_parent()) {
572 master_packer.get_parent()->remove (master_packer);
575 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
577 if (master_packer.get_parent()) {
578 master_packer.get_parent()->remove (master_packer);
581 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
586 MonitorSection::set_session (Session* s)
588 RouteUI::set_session (s);
589 insert_box->set_session (_session);
591 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
595 /* These are not actually dependent on the Session, but they
596 * need to be set after construction, not during, and
597 * this is as good a place as any.
600 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
601 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
603 _route = _session->monitor_out ();
606 /* session with monitor section */
607 _monitor = _route->monitor_control ();
608 assign_controllables ();
609 _route->output()->changed.connect (route_connections, invalidator (*this),
610 boost::bind (&MonitorSection::update_output_display, this),
612 insert_box->set_route (_route);
613 _route->processors_changed.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
614 _route->output()->PortCountChanged.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
615 _route->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
617 if (_ui_initialized) {
618 update_processor_box ();
621 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), true);
622 ActionManager::set_sensitive (global_monitor_actions, true);
623 ActionManager::set_sensitive (monitor_actions, true);
624 ActionManager::set_sensitive (solo_actions, true);
627 /* session with no monitor section */
628 route_connections.drop_connections();
631 delete _output_selector;
632 _output_selector = 0;
634 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), false);
635 ActionManager::set_sensitive (global_monitor_actions, false);
636 ActionManager::set_sensitive (monitor_actions, false);
637 ActionManager::set_sensitive (solo_actions, true);
638 /* this action needs to always be true in this, so that we can turn it back on */
639 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
651 unassign_controllables ();
654 ActionManager::set_sensitive (monitor_actions, false);
655 ActionManager::set_sensitive (solo_actions, false);
656 ActionManager::set_sensitive (global_monitor_actions, false);
661 MonitorSection::drop_route ()
663 route_connections.drop_connections();
666 unassign_controllables ();
667 rude_iso_button.unset_active_state ();
668 rude_solo_button.unset_active_state ();
669 delete _output_selector;
670 _output_selector = 0;
673 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
675 cut.set_name (X_("mute button"));
676 dim.set_name (X_("monitor section dim"));
677 solo.set_name (X_("solo button"));
678 invert.set_name (X_("invert button"));
680 cut.unset_flags (Gtk::CAN_FOCUS);
681 dim.unset_flags (Gtk::CAN_FOCUS);
682 solo.unset_flags (Gtk::CAN_FOCUS);
683 invert.unset_flags (Gtk::CAN_FOCUS);
687 MonitorSection::populate_buttons ()
694 channel_size_group->remove_widget (*channel_table);
695 delete channel_table;
698 channel_table = new Gtk::Table();
700 channel_table->set_col_spacings (6);
701 channel_table->set_row_spacings (6);
702 channel_table->set_homogeneous (true);
704 channel_size_group->add_widget (*channel_table);
705 channel_table->show ();
706 table_hpacker.pack_start (*channel_table, true, true);
708 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
711 _channel_buttons.clear ();
713 Glib::RefPtr<Action> act;
714 uint32_t nchans = _monitor->output_streams().n_audio();
716 channel_table->resize (nchans, 5);
718 const uint32_t row_offset = 0;
720 for (uint32_t i = 0; i < nchans; ++i) {
733 snprintf (buf, sizeof (buf), "%d", i+1);
737 Label* label = manage (new Label (l));
738 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
740 ChannelButtonSet* cbs = new ChannelButtonSet;
742 _channel_buttons.push_back (cbs);
744 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
745 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
746 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
747 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
749 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
750 act = ActionManager::get_action (X_("Monitor"), buf);
752 cbs->cut.set_related_action (act);
755 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
756 act = ActionManager::get_action (X_("Monitor"), buf);
758 cbs->dim.set_related_action (act);
761 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
762 act = ActionManager::get_action (X_("Monitor"), buf);
764 cbs->solo.set_related_action (act);
767 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
768 act = ActionManager::get_action (X_("Monitor"), buf);
770 cbs->invert.set_related_action (act);
774 channel_table->show_all ();
776 if (channel_table_scroller.get_parent()) {
777 /* scroller is packed, so remove it */
778 channel_table_packer.remove (channel_table_scroller);
781 if (table_hpacker.get_parent () == &channel_table_packer) {
782 /* this occurs when the table hpacker is directly
783 packed, so remove it.
785 channel_table_packer.remove (table_hpacker);
786 } else if (table_hpacker.get_parent()) {
787 channel_table_viewport.remove ();
791 /* put the table into a scrolled window, and then put
792 * that into the channel vpacker, after the table header
794 channel_table_viewport.add (table_hpacker);
795 channel_table_packer.pack_start (channel_table_scroller, true, true);
796 channel_table_viewport.show ();
797 channel_table_scroller.show ();
800 /* just put the channel table itself into the channel
801 * vpacker, after the table header
803 channel_table_packer.pack_start (table_hpacker, true, true);
804 channel_table_scroller.hide ();
806 table_hpacker.show ();
807 channel_table->show ();
811 MonitorSection::toggle_exclusive_solo ()
817 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
821 MonitorSection::toggle_mute_overrides_solo ()
827 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo");
828 Config->set_solo_mute_override (tact->get_active());
832 MonitorSection::dim_all ()
838 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
839 _monitor->set_dim_all (tact->get_active());
843 MonitorSection::cut_all ()
849 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
850 _monitor->set_cut_all (tact->get_active());
854 MonitorSection::mono ()
860 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
861 _monitor->set_mono (tact->get_active());
865 MonitorSection::cut_channel (uint32_t chn)
872 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
874 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
875 _monitor->set_cut (chn, tact->get_active());
879 MonitorSection::dim_channel (uint32_t chn)
886 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
888 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
889 _monitor->set_dim (chn, tact->get_active());
893 MonitorSection::solo_channel (uint32_t chn)
900 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
902 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
903 _monitor->set_solo (chn, tact->get_active());
908 MonitorSection::invert_channel (uint32_t chn)
915 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
917 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
918 _monitor->set_polarity (chn, tact->get_active());
922 MonitorSection::register_actions ()
926 Glib::RefPtr<Action> act;
928 /* ...will get sensitized if a mon-session is added */
930 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
931 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
934 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
936 /* these are global monitor actions that invoke MonitorSectioncode. Do
937 * not create local versions (i.e. as part of "monitor_actions")
938 * because then we can end up with two different bindings (one global,
939 * one local to the monitor section) for the same action.
942 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
944 ActionManager::register_toggle_action (global_monitor_actions, "monitor-mono", _("Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
945 ActionManager::register_toggle_action (global_monitor_actions, "monitor-cut-all", _("Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
946 ActionManager::register_toggle_action (global_monitor_actions, "monitor-dim-all", _("Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
948 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
949 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
952 for (uint32_t chn = 0; chn < 16; ++chn) {
954 action_name = string_compose (X_("monitor-cut-%1"), chn);
955 action_descr = string_compose (_("Cut monitor channel %1"), chn);
956 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
957 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
959 action_name = string_compose (X_("monitor-dim-%1"), chn);
960 action_descr = string_compose (_("Dim monitor channel %1"), chn);
961 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
962 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
964 action_name = string_compose (X_("monitor-solo-%1"), chn);
965 action_descr = string_compose (_("Solo monitor channel %1"), chn);
966 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
967 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
969 action_name = string_compose (X_("monitor-invert-%1"), chn);
970 action_descr = string_compose (_("Invert monitor channel %1"), chn);
971 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
972 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
976 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
977 RadioAction::Group solo_group;
979 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
980 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
981 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
982 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
983 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
984 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
986 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
987 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
988 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
989 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
993 MonitorSection::solo_use_in_place ()
995 /* this is driven by a toggle on a radio group, and so is invoked twice,
996 once for the item that became inactive and once for the one that became
1000 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-in-place"));
1001 if (!ract->get_active ()) {
1002 /* We are turning SiP off, which means that AFL or PFL will be turned on
1003 shortly; don't update the solo model in the mean time, as if the currently
1004 configured listen position is not the one that is about to be turned on,
1005 things will go wrong.
1007 _inhibit_solo_model_update = true;
1009 Config->set_solo_control_is_listen_control (!ract->get_active());
1010 _inhibit_solo_model_update = false;
1014 MonitorSection::solo_use_afl ()
1016 /* this is driven by a toggle on a radio group, and so is invoked twice,
1017 once for the item that became inactive and once for the one that became
1021 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-afl"));
1022 if (ract->get_active()) {
1023 Config->set_solo_control_is_listen_control (true);
1024 Config->set_listen_position (AfterFaderListen);
1029 MonitorSection::solo_use_pfl ()
1031 /* this is driven by a toggle on a radio group, and so is invoked twice,
1032 once for the item that became inactive and once for the one that became
1036 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-pfl"));
1037 if (ract->get_active()) {
1038 Config->set_solo_control_is_listen_control (true);
1039 Config->set_listen_position (PreFaderListen);
1044 MonitorSection::update_solo_model ()
1046 if (_inhibit_solo_model_update) {
1050 const char* action_name = 0;
1051 Glib::RefPtr<RadioAction> ract;
1053 if (Config->get_solo_control_is_listen_control()) {
1054 switch (Config->get_listen_position()) {
1055 case AfterFaderListen:
1056 action_name = X_("solo-use-afl");
1058 case PreFaderListen:
1059 action_name = X_("solo-use-pfl");
1063 action_name = X_("solo-use-in-place");
1066 ract = ActionManager::get_radio_action (X_("Solo"), action_name);
1068 /* because these are radio buttons, one of them will be
1069 active no matter what. to trigger a change in the
1070 action so that the view picks it up, toggle it.
1073 if (ract->get_active()) {
1074 ract->set_active (false);
1077 ract->set_active (true);
1081 MonitorSection::map_state ()
1083 if (!_route || !_monitor) {
1087 update_solo_model ();
1089 Glib::RefPtr<Action> act;
1090 Glib::RefPtr<ToggleAction> tact;
1092 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
1093 tact->set_active (_monitor->cut_all());
1095 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
1096 tact->set_active (_monitor->dim_all());
1098 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
1099 tact->set_active (_monitor->mono());
1101 uint32_t nchans = _monitor->output_streams().n_audio();
1103 assert (nchans == _channel_buttons.size ());
1105 for (uint32_t n = 0; n < nchans; ++n) {
1107 char action_name[32];
1109 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1110 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1111 tact->set_active (_monitor->cut (n));
1113 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1114 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1115 tact->set_active (_monitor->dimmed (n));
1117 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1118 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1119 tact->set_active (_monitor->soloed (n));
1121 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1122 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1123 tact->set_active (_monitor->inverted (n));
1128 MonitorSection::do_blink (bool onoff)
1130 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1135 audition_blink (onoff);
1139 MonitorSection::audition_blink (bool onoff)
1141 if (_session == 0) {
1145 if (_session->is_auditioning()) {
1146 rude_audition_button.set_active (onoff);
1148 rude_audition_button.set_active (false);
1153 MonitorSection::solo_blink (bool onoff)
1155 if (_session == 0) {
1159 if (_session->soloing() || _session->listening()) {
1160 rude_solo_button.set_active (onoff);
1162 if (_session->soloing()) {
1163 if (_session->solo_isolated()) {
1164 rude_iso_button.set_active (onoff);
1166 rude_iso_button.set_active (false);
1171 rude_solo_button.set_active (false);
1172 rude_iso_button.set_active (false);
1177 MonitorSection::cancel_isolate (GdkEventButton*)
1180 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1181 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1188 MonitorSection::cancel_audition (GdkEventButton*)
1191 _session->cancel_audition();
1197 MonitorSection::parameter_changed (std::string name)
1199 if (name == "solo-control-is-listen-control") {
1200 update_solo_model ();
1201 } else if (name == "listen-position") {
1202 update_solo_model ();
1203 } else if (name == "solo-mute-override") {
1204 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1205 } else if (name == "exclusive-solo") {
1206 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1211 MonitorSection::unassign_controllables ()
1213 boost::shared_ptr<Controllable> none;
1215 solo_cut_control->set_controllable (none);
1216 solo_cut_display->set_controllable (none);
1217 gain_control->set_controllable (none);
1218 gain_display->set_controllable (none);
1219 cut_all_button.set_controllable (none);
1220 dim_all_button.set_controllable (none);
1221 mono_button.set_controllable (none);
1222 dim_control->set_controllable (none);
1223 dim_display->set_controllable (none);
1224 solo_boost_control->set_controllable (none);
1225 solo_boost_display->set_controllable (none);
1229 MonitorSection::assign_controllables ()
1235 solo_cut_control->set_controllable (_session->solo_cut_control());
1236 solo_cut_display->set_controllable (_session->solo_cut_control());
1238 gain_control->set_controllable (_route->gain_control());
1239 gain_display->set_controllable (_route->gain_control());
1240 cut_all_button.set_controllable (_monitor->cut_control());
1241 cut_all_button.watch ();
1242 dim_all_button.set_controllable (_monitor->dim_control());
1243 dim_all_button.watch ();
1244 mono_button.set_controllable (_monitor->mono_control());
1245 mono_button.watch ();
1246 dim_control->set_controllable (_monitor->dim_level_control ());
1247 dim_display->set_controllable (_monitor->dim_level_control ());
1248 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1249 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1253 MonitorSection::state_id() const
1255 return "monitor-section";
1259 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1261 using namespace Menu_Helpers;
1263 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1267 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1268 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1272 if (i != output_menu_bundles.end()) {
1276 output_menu_bundles.push_back (b);
1278 MenuList& citems = output_menu.items();
1280 std::string n = b->name ();
1281 replace_all (n, "_", " ");
1283 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1287 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1290 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1292 if (std::find (current.begin(), current.end(), c) == current.end()) {
1293 _route->output()->connect_ports_to_bundle (c, true, this);
1295 _route->output()->disconnect_ports_from_bundle (c, this);
1300 MonitorSection::output_release (GdkEventButton *ev)
1302 switch (ev->button) {
1304 edit_output_configuration ();
1311 struct RouteCompareByName {
1312 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1313 return a->name().compare (b->name()) < 0;
1318 MonitorSection::output_press (GdkEventButton *ev)
1320 using namespace Menu_Helpers;
1322 MessageDialog msg (_("No session - no I/O changes are possible"));
1327 MenuList& citems = output_menu.items();
1328 switch (ev->button) {
1331 return false; //wait for the mouse-up to pop the dialog
1335 output_menu.set_name ("ArdourContextMenu");
1337 output_menu_bundles.clear ();
1339 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1341 citems.push_back (SeparatorElem());
1342 uint32_t const n_with_separator = citems.size ();
1344 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1346 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1348 /* give user bundles first chance at being in the menu */
1350 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1351 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1352 maybe_add_bundle_to_output_menu (*i, current);
1356 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1357 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1358 maybe_add_bundle_to_output_menu (*i, current);
1362 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1363 RouteList copy = *routes;
1364 copy.sort (RouteCompareByName ());
1365 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1366 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1369 if (citems.size() == n_with_separator) {
1370 /* no routes added; remove the separator */
1374 citems.push_back (SeparatorElem());
1375 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1377 output_menu.popup (1, ev->time);
1388 MonitorSection::update_output_display ()
1390 if (!_route || !_monitor || _session->deletion_in_progress()) {
1396 boost::shared_ptr<Port> port;
1397 vector<string> port_connections;
1399 uint32_t total_connection_count = 0;
1400 uint32_t io_connection_count = 0;
1401 uint32_t ardour_connection_count = 0;
1402 uint32_t system_connection_count = 0;
1403 uint32_t other_connection_count = 0;
1405 ostringstream label;
1407 bool have_label = false;
1408 bool each_io_has_one_connection = true;
1410 string connection_name;
1411 string ardour_track_name;
1412 string other_connection_type;
1413 string system_ports;
1416 ostringstream tooltip;
1417 char * tooltip_cstr;
1419 io_count = _route->n_outputs().n_total();
1420 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1423 for (io_index = 0; io_index < io_count; ++io_index) {
1425 port = _route->output()->nth (io_index);
1427 //ignore any port connections that don't match our DataType
1428 if (port->type() != DataType::AUDIO) {
1432 port_connections.clear ();
1433 port->get_connections(port_connections);
1434 io_connection_count = 0;
1436 if (!port_connections.empty()) {
1437 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1439 string& connection_name (*i);
1441 if (connection_name.find("system:") == 0) {
1442 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1445 if (io_connection_count == 0) {
1446 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1448 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1451 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1454 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1455 if (ardour_track_name.empty()) {
1456 // "ardour:Master/in 1" -> "ardour:Master/"
1457 string::size_type slash = connection_name.find("/");
1458 if (slash != string::npos) {
1459 ardour_track_name = connection_name.substr(0, slash + 1);
1463 if (connection_name.find(ardour_track_name) == 0) {
1464 ++ardour_connection_count;
1466 } else if (!pn.empty()) {
1467 if (system_ports.empty()) {
1470 system_ports += "/" + pn;
1472 if (connection_name.find("system:") == 0) {
1473 ++system_connection_count;
1475 } else if (connection_name.find("system:") == 0) {
1476 // "system:playback_123" -> "123"
1477 system_port = connection_name.substr(16);
1478 if (system_ports.empty()) {
1479 system_ports += system_port;
1481 system_ports += "/" + system_port;
1484 ++system_connection_count;
1486 if (other_connection_type.empty()) {
1487 // "jamin:in 1" -> "jamin:"
1488 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1491 if (connection_name.find(other_connection_type) == 0) {
1492 ++other_connection_count;
1496 ++total_connection_count;
1497 ++io_connection_count;
1501 if (io_connection_count != 1) {
1502 each_io_has_one_connection = false;
1506 if (total_connection_count == 0) {
1507 tooltip << endl << _("Disconnected");
1510 tooltip_cstr = new char[tooltip.str().size() + 1];
1511 strcpy(tooltip_cstr, tooltip.str().c_str());
1513 set_tooltip (output_button, tooltip_cstr, "");
1515 if (each_io_has_one_connection) {
1516 if (total_connection_count == ardour_connection_count) {
1517 // all connections are to the same track in ardour
1518 // "ardour:Master/" -> "Master"
1519 string::size_type slash = ardour_track_name.find("/");
1520 if (slash != string::npos) {
1521 label << ardour_track_name.substr(7, slash - 7);
1524 } else if (total_connection_count == system_connection_count) {
1525 // all connections are to system ports
1526 label << system_ports;
1528 } else if (total_connection_count == other_connection_count) {
1529 // all connections are to the same external program eg jamin
1530 // "jamin:" -> "jamin"
1531 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1537 if (total_connection_count == 0) {
1541 // Odd configuration
1542 label << "*" << total_connection_count << "*";
1546 output_button->set_text (label.str());
1550 MonitorSection::disconnect_output ()
1553 _route->output()->disconnect(this);
1558 MonitorSection::edit_output_configuration ()
1560 if (_output_selector == 0) {
1561 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1563 _output_selector->present ();
1567 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1572 boost::shared_ptr<Port> a = wa.lock ();
1573 boost::shared_ptr<Port> b = wb.lock ();
1574 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1575 update_output_display ();
1580 MonitorSection::load_bindings ()
1582 bindings = Bindings::get_bindings (X_("Monitor Section"));
1586 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1588 boost::shared_ptr<Processor> processor (p.lock ());
1589 if (!processor || !processor->display_to_user()) {
1592 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1599 MonitorSection::count_processors ()
1601 uint32_t processor_count = 0;
1603 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1605 return processor_count;
1609 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1611 update_processor_box ();
1615 MonitorSection::plugin_selector ()
1617 return Mixer_UI::instance()->plugin_selector ();
1621 MonitorSection::use_others_actions ()
1623 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1627 MonitorSection::toggle_use_monitor_section ()
1632 bool want_ms = ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active();
1633 bool have_ms = Config->get_use_monitor_bus ();
1635 if (want_ms == have_ms) {
1640 Config->set_use_monitor_bus (true);
1641 ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMonitorSection"))->set_active (true);
1643 Config->set_use_monitor_bus (false);