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 (Session* s)
66 : SessionHandlePtr (s)
70 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
71 , *channel_table_scroller.get_vadjustment ())
74 , solo_boost_control (0)
75 , solo_cut_control (0)
78 , solo_boost_display (0)
79 , solo_cut_display (0)
80 , _output_selector (0)
81 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
82 , afl_button (_("AFL"), ArdourButton::led_default_elements)
83 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
84 , exclusive_solo_button (ArdourButton::led_default_elements)
85 , solo_mute_override_button (ArdourButton::led_default_elements)
86 , toggle_processorbox_button (ArdourButton::default_elements)
87 , _inhibit_solo_model_update (false)
89 , _ui_initialized (false)
92 using namespace Menu_Helpers;
94 Glib::RefPtr<Action> act;
98 set_data ("ardour-bindings", bindings);
99 bindings->associate ();
101 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
103 _plugin_selector = new PluginSelector (PluginManager::instance());
104 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
105 insert_box->set_no_show_all ();
107 // 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 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
127 rude_solo_button.set_related_action (act);
128 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
130 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
131 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
133 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
134 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
136 /* SIP, AFL, PFL radio */
138 solo_in_place_button.set_name ("monitor section solo model");
139 afl_button.set_name ("monitor section solo model");
140 pfl_button.set_name ("monitor section solo model");
142 solo_in_place_button.set_led_left (true);
143 afl_button.set_led_left (true);
144 pfl_button.set_led_left (true);
146 solo_in_place_button.show ();
150 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
151 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
153 solo_in_place_button.set_related_action (act);
156 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
157 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
159 afl_button.set_related_action (act);
162 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
163 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
165 pfl_button.set_related_action (act);
168 /* Solo option buttons */
169 exclusive_solo_button.set_text (_("Excl. Solo"));
170 exclusive_solo_button.set_name (X_("monitor section solo option"));
171 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
173 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
175 exclusive_solo_button.set_related_action (act);
178 solo_mute_override_button.set_text (_("Solo ยป Mute"));
179 solo_mute_override_button.set_name (X_("monitor section solo option"));
180 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
182 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
184 solo_mute_override_button.set_related_action (act);
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_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"), 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"), 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"), 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 - 2 /* no outer sample */
440 scrollbar_height + 2 /* sample 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 ();
470 assign_controllables ();
472 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
473 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
475 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
476 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
477 set_flags (CAN_FOCUS);
479 _tearoff = new TearOff (*this);
481 if (!UIConfiguration::instance().get_floating_monitor_section()) {
482 /* if torn off, make this a normal window
483 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
485 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
487 _tearoff->tearoff_window().set_title (X_("Monitor"));
488 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
490 update_output_display ();
491 update_processor_box ();
492 _ui_initialized = true;
494 /* catch changes that affect us */
495 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
496 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
498 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
501 MonitorSection::~MonitorSection ()
503 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
507 _channel_buttons.clear ();
508 output_changed_connections.drop_connections ();
510 delete insert_box; insert_box = 0;
511 delete output_button; output_button = 0;
512 delete gain_control; gain_control = 0;
513 delete gain_display; gain_display = 0;
514 delete dim_control; dim_control = 0;
515 delete dim_display; dim_display = 0;
516 delete solo_boost_control; solo_boost_control = 0;
517 delete solo_boost_display; solo_boost_display = 0;
518 delete solo_cut_control; solo_cut_control = 0;
519 delete solo_cut_display; solo_cut_display = 0;
520 delete _tearoff; _tearoff = 0;
521 delete _output_selector; _output_selector = 0;
522 delete channel_table; channel_table = 0;
526 MonitorSection::enter_handler (GdkEventCrossing* ev)
533 MonitorSection::leave_handler (GdkEventCrossing* ev)
535 switch (ev->detail) {
536 case GDK_NOTIFY_INFERIOR:
542 /* cancel focus if we're not torn off. With X11 WM's that do
543 * focus-follows-mouse, focus will be taken from us anyway.
546 Widget* top = get_toplevel();
548 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
549 Window* win = dynamic_cast<Window*> (top);
550 gtk_window_set_focus (win->gobj(), 0);
557 MonitorSection::update_processor_box ()
559 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
561 if (count_processors () > 0 && !show_processor_box) {
562 toggle_processorbox_button.set_name (X_("monitor section processors present"));
564 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
567 if (insert_box->is_visible() == show_processor_box) {
571 if (show_processor_box) {
572 if (master_packer.get_parent()) {
573 master_packer.get_parent()->remove (master_packer);
576 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
578 if (master_packer.get_parent()) {
579 master_packer.get_parent()->remove (master_packer);
582 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
587 MonitorSection::set_session (Session* s)
589 RouteUI::set_session (s);
590 _plugin_selector->set_session (_session);
594 _route = _session->monitor_out ();
597 /* session with monitor section */
598 _monitor = _route->monitor_control ();
599 assign_controllables ();
600 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
601 boost::bind (&MonitorSection::update_output_display, this),
603 insert_box->set_route (_route);
604 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
605 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
606 if (_ui_initialized) {
607 update_processor_box ();
610 /* session with no monitor section */
611 output_changed_connections.drop_connections();
614 delete _output_selector;
615 _output_selector = 0;
620 /* some actions may have been left in the wrong state from a
621 * previous monitor route that was then deleted
623 ActionManager::set_sensitive (monitor_actions, true);
624 ActionManager::set_sensitive (solo_actions, true);
629 output_changed_connections.drop_connections();
632 control_connections.drop_connections ();
633 rude_iso_button.unset_active_state ();
634 rude_solo_button.unset_active_state ();
635 delete _output_selector;
636 _output_selector = 0;
638 assign_controllables ();
642 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
644 cut.set_name (X_("mute button"));
645 dim.set_name (X_("monitor section dim"));
646 solo.set_name (X_("solo button"));
647 invert.set_name (X_("invert button"));
649 cut.unset_flags (Gtk::CAN_FOCUS);
650 dim.unset_flags (Gtk::CAN_FOCUS);
651 solo.unset_flags (Gtk::CAN_FOCUS);
652 invert.unset_flags (Gtk::CAN_FOCUS);
656 MonitorSection::populate_buttons ()
663 channel_size_group->remove_widget (*channel_table);
664 delete channel_table;
667 channel_table = new Gtk::Table();
669 channel_table->set_col_spacings (6);
670 channel_table->set_row_spacings (6);
671 channel_table->set_homogeneous (true);
673 channel_size_group->add_widget (*channel_table);
674 channel_table->show ();
675 table_hpacker.pack_start (*channel_table, true, true);
677 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
680 _channel_buttons.clear ();
682 Glib::RefPtr<Action> act;
683 uint32_t nchans = _monitor->output_streams().n_audio();
685 channel_table->resize (nchans, 5);
687 const uint32_t row_offset = 0;
689 for (uint32_t i = 0; i < nchans; ++i) {
702 snprintf (buf, sizeof (buf), "%d", i+1);
706 Label* label = manage (new Label (l));
707 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
709 ChannelButtonSet* cbs = new ChannelButtonSet;
711 _channel_buttons.push_back (cbs);
713 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
714 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
715 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
716 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
718 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
719 act = ActionManager::get_action (X_("Monitor"), buf);
721 cbs->cut.set_related_action (act);
724 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
725 act = ActionManager::get_action (X_("Monitor"), buf);
727 cbs->dim.set_related_action (act);
730 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
731 act = ActionManager::get_action (X_("Monitor"), buf);
733 cbs->solo.set_related_action (act);
736 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
737 act = ActionManager::get_action (X_("Monitor"), buf);
739 cbs->invert.set_related_action (act);
743 channel_table->show_all ();
745 if (channel_table_scroller.get_parent()) {
746 /* scroller is packed, so remove it */
747 channel_table_packer.remove (channel_table_scroller);
750 if (table_hpacker.get_parent () == &channel_table_packer) {
751 /* this occurs when the table hpacker is directly
752 packed, so remove it.
754 channel_table_packer.remove (table_hpacker);
755 } else if (table_hpacker.get_parent()) {
756 channel_table_viewport.remove ();
760 /* put the table into a scrolled window, and then put
761 * that into the channel vpacker, after the table header
763 channel_table_viewport.add (table_hpacker);
764 channel_table_packer.pack_start (channel_table_scroller, true, true);
765 channel_table_viewport.show ();
766 channel_table_scroller.show ();
769 /* just put the channel table itself into the channel
770 * vpacker, after the table header
772 channel_table_packer.pack_start (table_hpacker, true, true);
773 channel_table_scroller.hide ();
775 table_hpacker.show ();
776 channel_table->show ();
780 MonitorSection::toggle_exclusive_solo ()
786 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
788 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
789 Config->set_exclusive_solo (tact->get_active());
795 MonitorSection::toggle_mute_overrides_solo ()
801 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
803 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
804 Config->set_solo_mute_override (tact->get_active());
809 MonitorSection::dim_all ()
815 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
817 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
818 _monitor->set_dim_all (tact->get_active());
824 MonitorSection::cut_all ()
830 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
832 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
833 _monitor->set_cut_all (tact->get_active());
838 MonitorSection::mono ()
844 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
846 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
847 _monitor->set_mono (tact->get_active());
852 MonitorSection::cut_channel (uint32_t chn)
859 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
861 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
863 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
864 _monitor->set_cut (chn, tact->get_active());
869 MonitorSection::dim_channel (uint32_t chn)
876 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
878 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
880 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
881 _monitor->set_dim (chn, tact->get_active());
887 MonitorSection::solo_channel (uint32_t chn)
894 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
896 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
898 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
899 _monitor->set_solo (chn, tact->get_active());
905 MonitorSection::invert_channel (uint32_t chn)
912 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
914 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
916 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
917 _monitor->set_polarity (chn, tact->get_active());
922 MonitorSection::register_actions ()
926 Glib::RefPtr<Action> act;
928 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
930 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
931 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
933 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
934 tact->set_active (Config->get_exclusive_solo());
936 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
937 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
939 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
940 tact->set_active (Config->get_solo_mute_override());
942 for (uint32_t chn = 0; chn < 16; ++chn) {
944 action_name = string_compose (X_("monitor-cut-%1"), chn);
945 action_descr = string_compose (_("Cut monitor channel %1"), chn);
946 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
947 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
949 action_name = string_compose (X_("monitor-dim-%1"), chn);
950 action_descr = string_compose (_("Dim monitor channel %1"), chn);
951 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
952 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
954 action_name = string_compose (X_("monitor-solo-%1"), chn);
955 action_descr = string_compose (_("Solo monitor channel %1"), chn);
956 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
957 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
959 action_name = string_compose (X_("monitor-invert-%1"), chn);
960 action_descr = string_compose (_("Invert monitor channel %1"), chn);
961 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
962 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
966 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
967 RadioAction::Group solo_group;
969 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
970 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
971 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
972 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
973 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
974 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
976 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
977 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
982 MonitorSection::solo_use_in_place ()
984 /* this is driven by a toggle on a radio group, and so is invoked twice,
985 once for the item that became inactive and once for the one that became
989 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
992 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
994 if (!ract->get_active ()) {
995 /* We are turning SiP off, which means that AFL or PFL will be turned on
996 shortly; don't update the solo model in the mean time, as if the currently
997 configured listen position is not the one that is about to be turned on,
998 things will go wrong.
1000 _inhibit_solo_model_update = true;
1002 Config->set_solo_control_is_listen_control (!ract->get_active());
1003 _inhibit_solo_model_update = false;
1009 MonitorSection::solo_use_afl ()
1011 /* this is driven by a toggle on a radio group, and so is invoked twice,
1012 once for the item that became inactive and once for the one that became
1016 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1018 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1020 if (ract->get_active()) {
1021 Config->set_solo_control_is_listen_control (true);
1022 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<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1038 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1040 if (ract->get_active()) {
1041 Config->set_solo_control_is_listen_control (true);
1042 Config->set_listen_position (PreFaderListen);
1049 MonitorSection::update_solo_model ()
1051 if (_inhibit_solo_model_update) {
1055 const char* action_name = 0;
1056 Glib::RefPtr<Action> act;
1058 if (Config->get_solo_control_is_listen_control()) {
1059 switch (Config->get_listen_position()) {
1060 case AfterFaderListen:
1061 action_name = X_("solo-use-afl");
1063 case PreFaderListen:
1064 action_name = X_("solo-use-pfl");
1068 action_name = X_("solo-use-in-place");
1071 act = ActionManager::get_action (X_("Solo"), action_name);
1074 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1076 /* because these are radio buttons, one of them will be
1077 active no matter what. to trigger a change in the
1078 action so that the view picks it up, toggle it.
1080 if (ract->get_active()) {
1081 ract->set_active (false);
1083 ract->set_active (true);
1090 MonitorSection::map_state ()
1092 if (!_route || !_monitor) {
1096 update_solo_model ();
1098 Glib::RefPtr<Action> act;
1099 Glib::RefPtr<ToggleAction> tact;
1101 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1103 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1105 tact->set_active (_monitor->cut_all());
1109 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1111 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1113 tact->set_active (_monitor->dim_all());
1117 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1119 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1121 tact->set_active (_monitor->mono());
1125 uint32_t nchans = _monitor->output_streams().n_audio();
1127 assert (nchans == _channel_buttons.size ());
1129 for (uint32_t n = 0; n < nchans; ++n) {
1131 char action_name[32];
1133 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1134 act = ActionManager::get_action (X_("Monitor"), action_name);
1136 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1138 tact->set_active (_monitor->cut (n));
1142 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1143 act = ActionManager::get_action (X_("Monitor"), action_name);
1145 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1147 tact->set_active (_monitor->dimmed (n));
1151 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1152 act = ActionManager::get_action (X_("Monitor"), action_name);
1154 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1156 tact->set_active (_monitor->soloed (n));
1160 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1161 act = ActionManager::get_action (X_("Monitor"), action_name);
1163 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1165 tact->set_active (_monitor->inverted (n));
1172 MonitorSection::do_blink (bool onoff)
1174 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1179 audition_blink (onoff);
1183 MonitorSection::audition_blink (bool onoff)
1185 if (_session == 0) {
1189 if (_session->is_auditioning()) {
1190 rude_audition_button.set_active (onoff);
1192 rude_audition_button.set_active (false);
1197 MonitorSection::solo_blink (bool onoff)
1199 if (_session == 0) {
1203 if (_session->soloing() || _session->listening()) {
1204 rude_solo_button.set_active (onoff);
1206 if (_session->soloing()) {
1207 if (_session->solo_isolated()) {
1208 rude_iso_button.set_active (onoff);
1210 rude_iso_button.set_active (false);
1215 rude_solo_button.set_active (false);
1216 rude_iso_button.set_active (false);
1221 MonitorSection::cancel_isolate (GdkEventButton*)
1224 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1225 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1232 MonitorSection::cancel_audition (GdkEventButton*)
1235 _session->cancel_audition();
1240 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1242 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1243 if (tact && tact->get_active() != value) { \
1244 tact->set_active(value); \
1249 MonitorSection::parameter_changed (std::string name)
1251 if (name == "solo-control-is-listen-control") {
1252 update_solo_model ();
1253 } else if (name == "listen-position") {
1254 update_solo_model ();
1255 } else if (name == "solo-mute-override") {
1256 SYNCHRONIZE_TOGGLE_ACTION(
1257 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1258 Config->get_solo_mute_override ())
1259 } else if (name == "exclusive-solo") {
1260 SYNCHRONIZE_TOGGLE_ACTION(
1261 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1262 Config->get_exclusive_solo ())
1267 MonitorSection::assign_controllables ()
1269 boost::shared_ptr<Controllable> none;
1271 if (!gain_control) {
1272 /* too early - GUI controls not set up yet */
1277 solo_cut_control->set_controllable (_session->solo_cut_control());
1278 solo_cut_display->set_controllable (_session->solo_cut_control());
1280 solo_cut_control->set_controllable (none);
1281 solo_cut_display->set_controllable (none);
1285 gain_control->set_controllable (_route->gain_control());
1286 gain_display->set_controllable (_route->gain_control());
1288 gain_control->set_controllable (none);
1293 cut_all_button.set_controllable (_monitor->cut_control());
1294 cut_all_button.watch ();
1295 dim_all_button.set_controllable (_monitor->dim_control());
1296 dim_all_button.watch ();
1297 mono_button.set_controllable (_monitor->mono_control());
1298 mono_button.watch ();
1300 dim_control->set_controllable (_monitor->dim_level_control ());
1301 dim_display->set_controllable (_monitor->dim_level_control ());
1302 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1303 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1307 cut_all_button.set_controllable (none);
1308 dim_all_button.set_controllable (none);
1309 mono_button.set_controllable (none);
1311 dim_control->set_controllable (none);
1312 dim_display->set_controllable (none);
1313 solo_boost_control->set_controllable (none);
1314 solo_boost_display->set_controllable (none);
1319 MonitorSection::state_id() const
1321 return "monitor-section";
1325 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1327 using namespace Menu_Helpers;
1329 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1333 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1334 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1338 if (i != output_menu_bundles.end()) {
1342 output_menu_bundles.push_back (b);
1344 MenuList& citems = output_menu.items();
1346 std::string n = b->name ();
1347 replace_all (n, "_", " ");
1349 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1353 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1356 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1358 if (std::find (current.begin(), current.end(), c) == current.end()) {
1359 _route->output()->connect_ports_to_bundle (c, true, this);
1361 _route->output()->disconnect_ports_from_bundle (c, this);
1366 MonitorSection::output_release (GdkEventButton *ev)
1368 switch (ev->button) {
1370 edit_output_configuration ();
1377 struct RouteCompareByName {
1378 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1379 return a->name().compare (b->name()) < 0;
1384 MonitorSection::output_press (GdkEventButton *ev)
1386 using namespace Menu_Helpers;
1388 MessageDialog msg (_("No session - no I/O changes are possible"));
1393 MenuList& citems = output_menu.items();
1394 switch (ev->button) {
1397 return false; //wait for the mouse-up to pop the dialog
1401 output_menu.set_name ("ArdourContextMenu");
1403 output_menu_bundles.clear ();
1405 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1407 citems.push_back (SeparatorElem());
1408 uint32_t const n_with_separator = citems.size ();
1410 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1412 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1414 /* give user bundles first chance at being in the menu */
1416 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1417 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1418 maybe_add_bundle_to_output_menu (*i, current);
1422 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1423 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1424 maybe_add_bundle_to_output_menu (*i, current);
1428 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1429 RouteList copy = *routes;
1430 copy.sort (RouteCompareByName ());
1431 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1432 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1435 if (citems.size() == n_with_separator) {
1436 /* no routes added; remove the separator */
1440 citems.push_back (SeparatorElem());
1441 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1443 output_menu.popup (1, ev->time);
1454 MonitorSection::update_output_display ()
1456 if (!_route || !_monitor || _session->deletion_in_progress()) {
1462 boost::shared_ptr<Port> port;
1463 vector<string> port_connections;
1465 uint32_t total_connection_count = 0;
1466 uint32_t io_connection_count = 0;
1467 uint32_t ardour_connection_count = 0;
1468 uint32_t system_connection_count = 0;
1469 uint32_t other_connection_count = 0;
1471 ostringstream label;
1473 bool have_label = false;
1474 bool each_io_has_one_connection = true;
1476 string connection_name;
1477 string ardour_track_name;
1478 string other_connection_type;
1479 string system_ports;
1482 ostringstream tooltip;
1483 char * tooltip_cstr;
1485 io_count = _route->n_outputs().n_total();
1486 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1489 for (io_index = 0; io_index < io_count; ++io_index) {
1491 port = _route->output()->nth (io_index);
1493 //ignore any port connections that don't match our DataType
1494 if (port->type() != DataType::AUDIO) {
1498 port_connections.clear ();
1499 port->get_connections(port_connections);
1500 io_connection_count = 0;
1502 if (!port_connections.empty()) {
1503 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1505 string& connection_name (*i);
1507 if (connection_name.find("system:") == 0) {
1508 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1511 if (io_connection_count == 0) {
1512 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1514 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1517 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1520 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1521 if (ardour_track_name.empty()) {
1522 // "ardour:Master/in 1" -> "ardour:Master/"
1523 string::size_type slash = connection_name.find("/");
1524 if (slash != string::npos) {
1525 ardour_track_name = connection_name.substr(0, slash + 1);
1529 if (connection_name.find(ardour_track_name) == 0) {
1530 ++ardour_connection_count;
1532 } else if (!pn.empty()) {
1533 if (system_ports.empty()) {
1536 system_ports += "/" + pn;
1538 if (connection_name.find("system:") == 0) {
1539 ++system_connection_count;
1541 } else if (connection_name.find("system:") == 0) {
1542 // "system:playback_123" -> "123"
1543 system_port = connection_name.substr(16);
1544 if (system_ports.empty()) {
1545 system_ports += system_port;
1547 system_ports += "/" + system_port;
1550 ++system_connection_count;
1552 if (other_connection_type.empty()) {
1553 // "jamin:in 1" -> "jamin:"
1554 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1557 if (connection_name.find(other_connection_type) == 0) {
1558 ++other_connection_count;
1562 ++total_connection_count;
1563 ++io_connection_count;
1567 if (io_connection_count != 1) {
1568 each_io_has_one_connection = false;
1572 if (total_connection_count == 0) {
1573 tooltip << endl << _("Disconnected");
1576 tooltip_cstr = new char[tooltip.str().size() + 1];
1577 strcpy(tooltip_cstr, tooltip.str().c_str());
1579 set_tooltip (output_button, tooltip_cstr, "");
1581 if (each_io_has_one_connection) {
1582 if (total_connection_count == ardour_connection_count) {
1583 // all connections are to the same track in ardour
1584 // "ardour:Master/" -> "Master"
1585 string::size_type slash = ardour_track_name.find("/");
1586 if (slash != string::npos) {
1587 label << ardour_track_name.substr(7, slash - 7);
1590 } else if (total_connection_count == system_connection_count) {
1591 // all connections are to system ports
1592 label << system_ports;
1594 } else if (total_connection_count == other_connection_count) {
1595 // all connections are to the same external program eg jamin
1596 // "jamin:" -> "jamin"
1597 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1603 if (total_connection_count == 0) {
1607 // Odd configuration
1608 label << "*" << total_connection_count << "*";
1612 output_button->set_text (label.str());
1616 MonitorSection::disconnect_output ()
1619 _route->output()->disconnect(this);
1624 MonitorSection::edit_output_configuration ()
1626 if (_output_selector == 0) {
1627 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1629 _output_selector->present ();
1633 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1638 boost::shared_ptr<Port> a = wa.lock ();
1639 boost::shared_ptr<Port> b = wb.lock ();
1640 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1641 update_output_display ();
1646 MonitorSection::load_bindings ()
1648 bindings = Bindings::get_bindings (X_("Monitor Section"));
1652 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1654 boost::shared_ptr<Processor> processor (p.lock ());
1655 if (!processor || !processor->display_to_user()) {
1658 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1665 MonitorSection::count_processors ()
1667 uint32_t processor_count = 0;
1669 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1671 return processor_count;
1675 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1677 update_processor_box ();
1681 MonitorSection::action_proxy0 (enum MonitorActions action)
1683 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1697 case ToggleExclusiveSolo:
1698 ms->toggle_exclusive_solo ();
1700 case ToggleMuteOverridesSolo:
1701 ms->toggle_mute_overrides_solo ();
1703 case SoloUseInPlace:
1704 ms->solo_use_in_place ();
1707 ms->solo_use_afl ();
1710 ms->solo_use_pfl ();
1712 case ToggleMonitorProcessorBox:
1713 ms->update_processor_box ();
1719 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1721 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1727 ms->cut_channel (chn);
1730 ms->dim_channel (chn);
1733 ms->solo_channel (chn);
1736 ms->invert_channel (chn);