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 (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));
967 Glib::RefPtr<ActionGroup> solo_actions = ActionManager::create_action_group (X_("Solo"));
968 RadioAction::Group solo_group;
970 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
971 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
972 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
973 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
974 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
975 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
977 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
978 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
983 MonitorSection::solo_use_in_place ()
985 /* this is driven by a toggle on a radio group, and so is invoked twice,
986 once for the item that became inactive and once for the one that became
990 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
993 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
995 if (!ract->get_active ()) {
996 /* We are turning SiP off, which means that AFL or PFL will be turned on
997 shortly; don't update the solo model in the mean time, as if the currently
998 configured listen position is not the one that is about to be turned on,
999 things will go wrong.
1001 _inhibit_solo_model_update = true;
1003 Config->set_solo_control_is_listen_control (!ract->get_active());
1004 _inhibit_solo_model_update = false;
1010 MonitorSection::solo_use_afl ()
1012 /* this is driven by a toggle on a radio group, and so is invoked twice,
1013 once for the item that became inactive and once for the one that became
1017 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1019 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1021 if (ract->get_active()) {
1022 Config->set_solo_control_is_listen_control (true);
1023 Config->set_listen_position (AfterFaderListen);
1030 MonitorSection::solo_use_pfl ()
1032 /* this is driven by a toggle on a radio group, and so is invoked twice,
1033 once for the item that became inactive and once for the one that became
1037 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1039 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1041 if (ract->get_active()) {
1042 Config->set_solo_control_is_listen_control (true);
1043 Config->set_listen_position (PreFaderListen);
1050 MonitorSection::update_solo_model ()
1052 if (_inhibit_solo_model_update) {
1056 const char* action_name = 0;
1057 Glib::RefPtr<Action> act;
1059 if (Config->get_solo_control_is_listen_control()) {
1060 switch (Config->get_listen_position()) {
1061 case AfterFaderListen:
1062 action_name = X_("solo-use-afl");
1064 case PreFaderListen:
1065 action_name = X_("solo-use-pfl");
1069 action_name = X_("solo-use-in-place");
1072 act = ActionManager::get_action (X_("Solo"), action_name);
1075 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1077 /* because these are radio buttons, one of them will be
1078 active no matter what. to trigger a change in the
1079 action so that the view picks it up, toggle it.
1081 if (ract->get_active()) {
1082 ract->set_active (false);
1084 ract->set_active (true);
1091 MonitorSection::map_state ()
1093 if (!_route || !_monitor) {
1097 update_solo_model ();
1099 Glib::RefPtr<Action> act;
1100 Glib::RefPtr<ToggleAction> tact;
1102 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1104 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1106 tact->set_active (_monitor->cut_all());
1110 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1112 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1114 tact->set_active (_monitor->dim_all());
1118 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1120 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1122 tact->set_active (_monitor->mono());
1126 uint32_t nchans = _monitor->output_streams().n_audio();
1128 assert (nchans == _channel_buttons.size ());
1130 for (uint32_t n = 0; n < nchans; ++n) {
1132 char action_name[32];
1134 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1135 act = ActionManager::get_action (X_("Monitor"), action_name);
1137 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1139 tact->set_active (_monitor->cut (n));
1143 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1144 act = ActionManager::get_action (X_("Monitor"), action_name);
1146 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1148 tact->set_active (_monitor->dimmed (n));
1152 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1153 act = ActionManager::get_action (X_("Monitor"), action_name);
1155 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1157 tact->set_active (_monitor->soloed (n));
1161 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1162 act = ActionManager::get_action (X_("Monitor"), action_name);
1164 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1166 tact->set_active (_monitor->inverted (n));
1173 MonitorSection::do_blink (bool onoff)
1175 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1180 audition_blink (onoff);
1184 MonitorSection::audition_blink (bool onoff)
1186 if (_session == 0) {
1190 if (_session->is_auditioning()) {
1191 rude_audition_button.set_active (onoff);
1193 rude_audition_button.set_active (false);
1198 MonitorSection::solo_blink (bool onoff)
1200 if (_session == 0) {
1204 if (_session->soloing() || _session->listening()) {
1205 rude_solo_button.set_active (onoff);
1207 if (_session->soloing()) {
1208 if (_session->solo_isolated()) {
1209 rude_iso_button.set_active (onoff);
1211 rude_iso_button.set_active (false);
1216 rude_solo_button.set_active (false);
1217 rude_iso_button.set_active (false);
1222 MonitorSection::cancel_isolate (GdkEventButton*)
1225 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1226 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1233 MonitorSection::cancel_audition (GdkEventButton*)
1236 _session->cancel_audition();
1241 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1243 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1244 if (tact && tact->get_active() != value) { \
1245 tact->set_active(value); \
1250 MonitorSection::parameter_changed (std::string name)
1252 if (name == "solo-control-is-listen-control") {
1253 update_solo_model ();
1254 } else if (name == "listen-position") {
1255 update_solo_model ();
1256 } else if (name == "solo-mute-override") {
1257 SYNCHRONIZE_TOGGLE_ACTION(
1258 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1259 Config->get_solo_mute_override ())
1260 } else if (name == "exclusive-solo") {
1261 SYNCHRONIZE_TOGGLE_ACTION(
1262 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1263 Config->get_exclusive_solo ())
1268 MonitorSection::assign_controllables ()
1270 boost::shared_ptr<Controllable> none;
1272 if (!gain_control) {
1273 /* too early - GUI controls not set up yet */
1278 solo_cut_control->set_controllable (_session->solo_cut_control());
1279 solo_cut_display->set_controllable (_session->solo_cut_control());
1281 solo_cut_control->set_controllable (none);
1282 solo_cut_display->set_controllable (none);
1286 gain_control->set_controllable (_route->gain_control());
1287 gain_display->set_controllable (_route->gain_control());
1289 gain_control->set_controllable (none);
1294 cut_all_button.set_controllable (_monitor->cut_control());
1295 cut_all_button.watch ();
1296 dim_all_button.set_controllable (_monitor->dim_control());
1297 dim_all_button.watch ();
1298 mono_button.set_controllable (_monitor->mono_control());
1299 mono_button.watch ();
1301 dim_control->set_controllable (_monitor->dim_level_control ());
1302 dim_display->set_controllable (_monitor->dim_level_control ());
1303 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1304 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1308 cut_all_button.set_controllable (none);
1309 dim_all_button.set_controllable (none);
1310 mono_button.set_controllable (none);
1312 dim_control->set_controllable (none);
1313 dim_display->set_controllable (none);
1314 solo_boost_control->set_controllable (none);
1315 solo_boost_display->set_controllable (none);
1320 MonitorSection::state_id() const
1322 return "monitor-section";
1326 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1328 using namespace Menu_Helpers;
1330 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1334 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1335 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1339 if (i != output_menu_bundles.end()) {
1343 output_menu_bundles.push_back (b);
1345 MenuList& citems = output_menu.items();
1347 std::string n = b->name ();
1348 replace_all (n, "_", " ");
1350 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1354 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1357 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1359 if (std::find (current.begin(), current.end(), c) == current.end()) {
1360 _route->output()->connect_ports_to_bundle (c, true, this);
1362 _route->output()->disconnect_ports_from_bundle (c, this);
1367 MonitorSection::output_release (GdkEventButton *ev)
1369 switch (ev->button) {
1371 edit_output_configuration ();
1378 struct RouteCompareByName {
1379 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1380 return a->name().compare (b->name()) < 0;
1385 MonitorSection::output_press (GdkEventButton *ev)
1387 using namespace Menu_Helpers;
1389 MessageDialog msg (_("No session - no I/O changes are possible"));
1394 MenuList& citems = output_menu.items();
1395 switch (ev->button) {
1398 return false; //wait for the mouse-up to pop the dialog
1402 output_menu.set_name ("ArdourContextMenu");
1404 output_menu_bundles.clear ();
1406 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1408 citems.push_back (SeparatorElem());
1409 uint32_t const n_with_separator = citems.size ();
1411 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1413 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1415 /* give user bundles first chance at being in the menu */
1417 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1418 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1419 maybe_add_bundle_to_output_menu (*i, current);
1423 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1424 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1425 maybe_add_bundle_to_output_menu (*i, current);
1429 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1430 RouteList copy = *routes;
1431 copy.sort (RouteCompareByName ());
1432 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1433 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1436 if (citems.size() == n_with_separator) {
1437 /* no routes added; remove the separator */
1441 citems.push_back (SeparatorElem());
1442 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1444 output_menu.popup (1, ev->time);
1455 MonitorSection::update_output_display ()
1457 if (!_route || !_monitor || _session->deletion_in_progress()) {
1463 boost::shared_ptr<Port> port;
1464 vector<string> port_connections;
1466 uint32_t total_connection_count = 0;
1467 uint32_t io_connection_count = 0;
1468 uint32_t ardour_connection_count = 0;
1469 uint32_t system_connection_count = 0;
1470 uint32_t other_connection_count = 0;
1472 ostringstream label;
1474 bool have_label = false;
1475 bool each_io_has_one_connection = true;
1477 string connection_name;
1478 string ardour_track_name;
1479 string other_connection_type;
1480 string system_ports;
1483 ostringstream tooltip;
1484 char * tooltip_cstr;
1486 io_count = _route->n_outputs().n_total();
1487 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1490 for (io_index = 0; io_index < io_count; ++io_index) {
1492 port = _route->output()->nth (io_index);
1494 //ignore any port connections that don't match our DataType
1495 if (port->type() != DataType::AUDIO) {
1499 port_connections.clear ();
1500 port->get_connections(port_connections);
1501 io_connection_count = 0;
1503 if (!port_connections.empty()) {
1504 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1506 string& connection_name (*i);
1508 if (connection_name.find("system:") == 0) {
1509 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1512 if (io_connection_count == 0) {
1513 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1515 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1518 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1521 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1522 if (ardour_track_name.empty()) {
1523 // "ardour:Master/in 1" -> "ardour:Master/"
1524 string::size_type slash = connection_name.find("/");
1525 if (slash != string::npos) {
1526 ardour_track_name = connection_name.substr(0, slash + 1);
1530 if (connection_name.find(ardour_track_name) == 0) {
1531 ++ardour_connection_count;
1533 } else if (!pn.empty()) {
1534 if (system_ports.empty()) {
1537 system_ports += "/" + pn;
1539 if (connection_name.find("system:") == 0) {
1540 ++system_connection_count;
1542 } else if (connection_name.find("system:") == 0) {
1543 // "system:playback_123" -> "123"
1544 system_port = connection_name.substr(16);
1545 if (system_ports.empty()) {
1546 system_ports += system_port;
1548 system_ports += "/" + system_port;
1551 ++system_connection_count;
1553 if (other_connection_type.empty()) {
1554 // "jamin:in 1" -> "jamin:"
1555 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1558 if (connection_name.find(other_connection_type) == 0) {
1559 ++other_connection_count;
1563 ++total_connection_count;
1564 ++io_connection_count;
1568 if (io_connection_count != 1) {
1569 each_io_has_one_connection = false;
1573 if (total_connection_count == 0) {
1574 tooltip << endl << _("Disconnected");
1577 tooltip_cstr = new char[tooltip.str().size() + 1];
1578 strcpy(tooltip_cstr, tooltip.str().c_str());
1580 set_tooltip (output_button, tooltip_cstr, "");
1582 if (each_io_has_one_connection) {
1583 if (total_connection_count == ardour_connection_count) {
1584 // all connections are to the same track in ardour
1585 // "ardour:Master/" -> "Master"
1586 string::size_type slash = ardour_track_name.find("/");
1587 if (slash != string::npos) {
1588 label << ardour_track_name.substr(7, slash - 7);
1591 } else if (total_connection_count == system_connection_count) {
1592 // all connections are to system ports
1593 label << system_ports;
1595 } else if (total_connection_count == other_connection_count) {
1596 // all connections are to the same external program eg jamin
1597 // "jamin:" -> "jamin"
1598 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1604 if (total_connection_count == 0) {
1608 // Odd configuration
1609 label << "*" << total_connection_count << "*";
1613 output_button->set_text (label.str());
1617 MonitorSection::disconnect_output ()
1620 _route->output()->disconnect(this);
1625 MonitorSection::edit_output_configuration ()
1627 if (_output_selector == 0) {
1628 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1630 _output_selector->present ();
1634 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1639 boost::shared_ptr<Port> a = wa.lock ();
1640 boost::shared_ptr<Port> b = wb.lock ();
1641 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1642 update_output_display ();
1647 MonitorSection::load_bindings ()
1649 bindings = Bindings::get_bindings (X_("Monitor Section"));
1653 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1655 boost::shared_ptr<Processor> processor (p.lock ());
1656 if (!processor || !processor->display_to_user()) {
1659 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1666 MonitorSection::count_processors ()
1668 uint32_t processor_count = 0;
1670 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1672 return processor_count;
1676 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1678 update_processor_box ();
1682 MonitorSection::action_proxy0 (enum MonitorActions action)
1684 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1698 case ToggleExclusiveSolo:
1699 ms->toggle_exclusive_solo ();
1701 case ToggleMuteOverridesSolo:
1702 ms->toggle_mute_overrides_solo ();
1704 case SoloUseInPlace:
1705 ms->solo_use_in_place ();
1708 ms->solo_use_afl ();
1711 ms->solo_use_pfl ();
1713 case ToggleMonitorProcessorBox:
1714 ms->update_processor_box ();
1720 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1722 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1728 ms->cut_channel (chn);
1731 ms->dim_channel (chn);
1734 ms->solo_channel (chn);
1737 ms->invert_channel (chn);