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/bindable_button.h"
27 #include "gtkmm2ext/tearoff.h"
28 #include "gtkmm2ext/actions.h"
29 #include "gtkmm2ext/utils.h"
31 #include <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
34 #include "ardour/amp.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/monitor_processor.h"
37 #include "ardour/port.h"
38 #include "ardour/route.h"
39 #include "ardour/solo_isolate_control.h"
40 #include "ardour/user_bundle.h"
41 #include "ardour/plugin_manager.h"
43 #include "ardour_ui.h"
44 #include "gui_thread.h"
46 #include "monitor_section.h"
47 #include "public_editor.h"
50 #include "ui_config.h"
55 using namespace ARDOUR;
56 using namespace ARDOUR_UI_UTILS;
58 using namespace Gtkmm2ext;
62 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
63 Gtkmm2ext::ActionMap MonitorSection::myactions (X_("monitor section"));
64 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
66 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
68 MonitorSection::MonitorSection (Session* s)
69 : SessionHandlePtr (s)
72 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
73 , *channel_table_scroller.get_vadjustment ())
76 , solo_boost_control (0)
77 , solo_cut_control (0)
80 , solo_boost_display (0)
81 , solo_cut_display (0)
82 , _output_selector (0)
83 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
84 , afl_button (_("AFL"), ArdourButton::led_default_elements)
85 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
86 , exclusive_solo_button (ArdourButton::led_default_elements)
87 , solo_mute_override_button (ArdourButton::led_default_elements)
88 , toggle_processorbox_button (ArdourButton::default_elements)
89 , _inhibit_solo_model_update (false)
90 , _ui_initialized (false)
93 using namespace Menu_Helpers;
95 Glib::RefPtr<Action> act;
97 if (!monitor_actions) {
102 set_data ("ardour-bindings", bindings);
104 _plugin_selector = new PluginSelector (PluginManager::instance());
105 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
106 insert_box->set_no_show_all ();
108 // TODO allow keyboard shortcuts in ProcessorBox
112 /* Rude Solo & Solo Isolated */
113 rude_solo_button.set_text (_("Soloing"));
114 rude_solo_button.set_name ("rude solo");
115 rude_solo_button.show ();
117 rude_iso_button.set_text (_("Isolated"));
118 rude_iso_button.set_name ("rude isolate");
119 rude_iso_button.show ();
121 rude_audition_button.set_text (_("Auditioning"));
122 rude_audition_button.set_name ("rude audition");
123 rude_audition_button.show ();
125 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
127 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
128 rude_solo_button.set_related_action (act);
129 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
131 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
132 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
134 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
135 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
137 /* SIP, AFL, PFL radio */
139 solo_in_place_button.set_name ("monitor section solo model");
140 afl_button.set_name ("monitor section solo model");
141 pfl_button.set_name ("monitor section solo model");
143 solo_in_place_button.set_led_left (true);
144 afl_button.set_led_left (true);
145 pfl_button.set_led_left (true);
147 solo_in_place_button.show ();
151 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
152 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
154 solo_in_place_button.set_related_action (act);
157 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
158 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
160 afl_button.set_related_action (act);
163 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
164 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
166 pfl_button.set_related_action (act);
169 /* Solo option buttons */
170 exclusive_solo_button.set_text (_("Excl. Solo"));
171 exclusive_solo_button.set_name (X_("monitor section solo option"));
172 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
174 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
176 exclusive_solo_button.set_related_action (act);
179 solo_mute_override_button.set_text (_("Solo ยป Mute"));
180 solo_mute_override_button.set_name (X_("monitor section solo option"));
181 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
183 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
185 solo_mute_override_button.set_related_action (act);
188 /* Processor Box hide/shos */
189 toggle_processorbox_button.set_text (_("Processors"));
190 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
191 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
193 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
194 toggle_processorbox_button.set_related_action (proctoggle);
197 Label* solo_boost_label;
198 Label* solo_cut_label;
201 /* Solo Boost Knob */
203 solo_boost_control = new ArdourKnob ();
204 solo_boost_control->set_name("monitor section knob");
205 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
206 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
208 solo_boost_display = new ArdourDisplay ();
209 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
210 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
211 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
212 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
213 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
215 solo_boost_label = manage (new Label (_("Solo Boost")));
219 solo_cut_control = new ArdourKnob ();
220 solo_cut_control->set_name ("monitor section knob");
221 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
222 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
224 solo_cut_display = new ArdourDisplay ();
225 solo_cut_display->set_name("monitor section dropdown"); // XXX
226 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
227 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
228 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
229 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
230 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
231 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
233 solo_cut_label = manage (new Label (_("SiP Cut")));
237 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
238 dim_control->set_name ("monitor section knob");
239 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
240 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
242 dim_display = new ArdourDisplay ();
243 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
244 dim_display->add_controllable_preset(_("0 dB"), 0.0);
245 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
246 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
247 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
248 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
250 dim_label = manage (new Label (_("Dim")));
253 cut_all_button.set_text (_("Mute"));
254 cut_all_button.set_name ("mute button");
255 cut_all_button.set_size_request (-1, PX_SCALE(30));
256 cut_all_button.show ();
258 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
260 cut_all_button.set_related_action (act);
264 dim_all_button.set_text (_("Dim"));
265 dim_all_button.set_name ("monitor section dim");
266 dim_all_button.set_size_request (-1, PX_SCALE(25));
267 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
269 dim_all_button.set_related_action (act);
273 mono_button.set_text (_("Mono"));
274 mono_button.set_name ("monitor section mono");
275 mono_button.set_size_request (-1, PX_SCALE(25));
276 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
278 mono_button.set_related_action (act);
283 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
284 gain_control->set_name("monitor section knob");
285 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
287 gain_display = new ArdourDisplay ();
288 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
289 gain_display->add_controllable_preset(_("0 dB"), 0.0);
290 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
291 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
292 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
293 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
294 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
296 Label* output_label = manage (new Label (_("Output")));
297 output_label->set_name (X_("MonitorSectionLabel"));
299 output_button = new ArdourButton ();
300 output_button->set_text (_("Output"));
301 output_button->set_name (X_("monitor section cut")); // XXX
302 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
303 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
305 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
306 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
307 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
308 channel_table_scroller.show ();
309 channel_table_scroller.add (channel_table_viewport);
311 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
312 channel_size_group->add_widget (channel_table_header);
313 channel_size_group->add_widget (channel_table);
315 channel_table_header.resize (1, 5);
317 Label* l1 = manage (new Label (X_(" ")));
318 l1->set_name (X_("MonitorSectionLabel"));
319 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
321 l1 = manage (new Label (_("Mute")));
322 l1->set_name (X_("MonitorSectionLabel"));
323 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
325 l1 = manage (new Label (_("Dim")));
326 l1->set_name (X_("MonitorSectionLabel"));
327 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
329 l1 = manage (new Label (_("Solo")));
330 l1->set_name (X_("MonitorSectionLabel"));
331 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
333 l1 = manage (new Label (_("Inv")));
334 l1->set_name (X_("MonitorSectionLabel"));
335 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
337 channel_table_header.show ();
340 /****************************************************************************
341 * LAYOUT top to bottom
344 // solo, iso information
345 HBox* rude_box = manage (new HBox);
346 rude_box->set_spacing (PX_SCALE(4));
347 rude_box->set_homogeneous (true);
348 rude_box->pack_start (rude_solo_button, true, true);
349 rude_box->pack_start (rude_iso_button, true, true);
351 // solo options (right align)
352 HBox* tbx1 = manage (new HBox);
353 tbx1->pack_end (exclusive_solo_button, false, false);
355 HBox* tbx2 = manage (new HBox);
356 tbx2->pack_end (solo_mute_override_button, false, false);
358 HBox* tbx3 = manage (new HBox);
359 tbx3->pack_end (toggle_processorbox_button, false, false);
361 HBox* tbx0 = manage (new HBox); // space
363 // combined solo mode (Sip, AFL, PFL) & solo options
364 Table *solo_tbl = manage (new Table);
365 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
366 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
369 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
370 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
371 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
373 // boost, cut, dim volume control
374 Table *level_tbl = manage (new Table);
375 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
379 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
383 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
384 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
385 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
387 /* note that we don't pack the table_hpacker till later
388 * -> top level channel_table_packer */
389 table_hpacker.pack_start (channel_table, true, true);
392 HBox* mono_dim_box = manage (new HBox);
393 mono_dim_box->set_spacing (PX_SCALE(4));
394 mono_dim_box->set_homogeneous (true);
395 mono_dim_box->pack_start (mono_button, true, true);
396 mono_dim_box->pack_end (dim_all_button, true, true);
399 Label* spin_label = manage (new Label (_("Monitor")));
400 VBox* spin_packer = manage (new VBox);
401 spin_packer->set_spacing (PX_SCALE(2));
402 spin_packer->pack_start (*spin_label, false, false);
403 spin_packer->pack_start (*gain_control, false, false);
404 spin_packer->pack_start (*gain_display, false, false);
406 master_packer.pack_start (*spin_packer, true, false);
408 // combined gain section (channels, mute, dim)
409 VBox* lower_packer = manage (new VBox);
410 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
411 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
412 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
413 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
415 // calc height of mixer scrollbar
416 int scrollbar_height = 0;
418 Gtk::Window window (WINDOW_TOPLEVEL);
419 HScrollbar scrollbar;
420 window.add (scrollbar);
421 scrollbar.set_name ("MixerWindow");
422 scrollbar.ensure_style();
423 Gtk::Requisition requisition(scrollbar.size_request ());
424 scrollbar_height = requisition.height;
427 // output port select
428 VBox* out_packer = manage (new VBox);
429 out_packer->set_spacing (PX_SCALE(2));
430 out_packer->pack_start (*output_label, false, false);
431 out_packer->pack_start (*output_button, false, false);
433 /****************************************************************************
436 vpacker.set_border_width (PX_SCALE(3));
437 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
438 vpacker.pack_start (rude_audition_button, false, false, 0);
439 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
440 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
441 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
442 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
443 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
444 vpacker.pack_end (*out_packer, false, false,
446 scrollbar_height - 2 /* no outer frame */
448 scrollbar_height + 2 /* frame borders */
452 hpacker.set_spacing (0);
453 hpacker.pack_start (vpacker, true, true);
457 gain_control->show_all ();
458 gain_display->show_all ();
459 dim_control->show_all ();
460 dim_display->show_all();
461 solo_boost_control->show_all ();
462 solo_boost_display->show_all();
464 mono_dim_box->show ();
465 spin_packer->show ();
466 master_packer.show ();
467 channel_table.show ();
470 solo_tbl->show_all();
472 lower_packer->show ();
480 assign_controllables ();
482 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
483 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
485 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
486 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
487 set_flags (CAN_FOCUS);
489 _tearoff = new TearOff (*this);
491 if (!UIConfiguration::instance().get_floating_monitor_section()) {
492 /* if torn off, make this a normal window
493 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
495 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
497 _tearoff->tearoff_window().set_title (X_("Monitor"));
498 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
500 update_output_display ();
501 update_processor_box ();
502 _ui_initialized = true;
504 /* catch changes that affect us */
505 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
506 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
508 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
511 MonitorSection::~MonitorSection ()
513 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
517 _channel_buttons.clear ();
518 _output_changed_connection.disconnect ();
520 delete insert_box; insert_box = 0;
521 delete output_button; output_button = 0;
522 delete gain_control; gain_control = 0;
523 delete gain_display; gain_display = 0;
524 delete dim_control; dim_control = 0;
525 delete dim_display; dim_display = 0;
526 delete solo_boost_control; solo_boost_control = 0;
527 delete solo_boost_display; solo_boost_display = 0;
528 delete solo_cut_control; solo_cut_control = 0;
529 delete solo_cut_display; solo_cut_display = 0;
530 delete _tearoff; _tearoff = 0;
531 delete _output_selector; _output_selector = 0;
535 MonitorSection::enter_handler (GdkEventCrossing* ev)
542 MonitorSection::leave_handler (GdkEventCrossing* ev)
544 switch (ev->detail) {
545 case GDK_NOTIFY_INFERIOR:
551 /* cancel focus if we're not torn off. With X11 WM's that do
552 * focus-follows-mouse, focus will be taken from us anyway.
555 Widget* top = get_toplevel();
557 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
558 Window* win = dynamic_cast<Window*> (top);
559 gtk_window_set_focus (win->gobj(), 0);
566 MonitorSection::update_processor_box ()
568 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
570 if (count_processors () > 0 && !show_processor_box) {
571 toggle_processorbox_button.set_name (X_("monitor section processors present"));
573 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
576 if (insert_box->is_visible() == show_processor_box) {
580 if (show_processor_box) {
581 if (master_packer.get_parent()) {
582 master_packer.get_parent()->remove (master_packer);
585 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
587 if (master_packer.get_parent()) {
588 master_packer.get_parent()->remove (master_packer);
591 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
596 MonitorSection::set_session (Session* s)
598 RouteUI::set_session (s);
599 _plugin_selector->set_session (_session);
603 _route = _session->monitor_out ();
606 /* session with monitor section */
607 _monitor = _route->monitor_control ();
608 assign_controllables ();
609 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
610 boost::bind (&MonitorSection::update_output_display, this),
612 insert_box->set_route (_route);
613 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
614 if (_ui_initialized) {
615 update_processor_box ();
618 /* session with no monitor section */
619 _output_changed_connection.disconnect();
622 delete _output_selector;
623 _output_selector = 0;
626 if (channel_table_scroller.get_parent()) {
627 /* scroller is packed, so remove it */
628 channel_table_packer.remove (channel_table_scroller);
631 if (table_hpacker.get_parent () == &channel_table_packer) {
632 /* this occurs when the table hpacker is directly
633 packed, so remove it.
635 channel_table_packer.remove (table_hpacker);
636 } else if (table_hpacker.get_parent()) {
637 channel_table_viewport.remove ();
640 if (_monitor->output_streams().n_audio() > 7) {
641 /* put the table into a scrolled window, and then put
642 * that into the channel vpacker, after the table header
644 channel_table_viewport.add (table_hpacker);
645 channel_table_packer.pack_start (channel_table_scroller, true, true);
646 channel_table_viewport.show ();
647 channel_table_scroller.show ();
650 /* just put the channel table itself into the channel
651 * vpacker, after the table header
654 channel_table_packer.pack_start (table_hpacker, true, true);
655 channel_table_scroller.hide ();
658 table_hpacker.show ();
659 channel_table.show ();
664 _output_changed_connection.disconnect();
667 control_connections.drop_connections ();
668 rude_iso_button.unset_active_state ();
669 rude_solo_button.unset_active_state ();
670 delete _output_selector;
671 _output_selector = 0;
673 assign_controllables ();
677 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
679 cut.set_name (X_("mute button"));
680 dim.set_name (X_("monitor section dim"));
681 solo.set_name (X_("solo button"));
682 invert.set_name (X_("invert button"));
684 cut.unset_flags (Gtk::CAN_FOCUS);
685 dim.unset_flags (Gtk::CAN_FOCUS);
686 solo.unset_flags (Gtk::CAN_FOCUS);
687 invert.unset_flags (Gtk::CAN_FOCUS);
691 MonitorSection::populate_buttons ()
697 Glib::RefPtr<Action> act;
698 uint32_t nchans = _monitor->output_streams().n_audio();
700 channel_table.resize (nchans, 5);
701 channel_table.set_col_spacings (6);
702 channel_table.set_row_spacings (6);
703 channel_table.set_homogeneous (true);
705 const uint32_t row_offset = 0;
707 for (uint32_t i = 0; i < nchans; ++i) {
720 snprintf (buf, sizeof (buf), "%d", i+1);
724 Label* label = manage (new Label (l));
725 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
727 ChannelButtonSet* cbs = new ChannelButtonSet;
729 _channel_buttons.push_back (cbs);
731 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
732 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
733 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
734 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
736 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
737 act = ActionManager::get_action (X_("Monitor"), buf);
739 cbs->cut.set_related_action (act);
742 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
743 act = ActionManager::get_action (X_("Monitor"), buf);
745 cbs->dim.set_related_action (act);
748 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
749 act = ActionManager::get_action (X_("Monitor"), buf);
751 cbs->solo.set_related_action (act);
754 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
755 act = ActionManager::get_action (X_("Monitor"), buf);
757 cbs->invert.set_related_action (act);
761 channel_table.show_all ();
765 MonitorSection::toggle_exclusive_solo ()
771 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
773 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
774 Config->set_exclusive_solo (tact->get_active());
780 MonitorSection::toggle_mute_overrides_solo ()
786 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
788 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
789 Config->set_solo_mute_override (tact->get_active());
794 MonitorSection::dim_all ()
800 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
802 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
803 _monitor->set_dim_all (tact->get_active());
809 MonitorSection::cut_all ()
815 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
817 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
818 _monitor->set_cut_all (tact->get_active());
823 MonitorSection::mono ()
829 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
831 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
832 _monitor->set_mono (tact->get_active());
837 MonitorSection::cut_channel (uint32_t chn)
844 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
846 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
848 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
849 _monitor->set_cut (chn, tact->get_active());
854 MonitorSection::dim_channel (uint32_t chn)
861 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
863 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
865 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
866 _monitor->set_dim (chn, tact->get_active());
872 MonitorSection::solo_channel (uint32_t chn)
879 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
881 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
883 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
884 _monitor->set_solo (chn, tact->get_active());
890 MonitorSection::invert_channel (uint32_t chn)
897 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
899 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
901 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
902 _monitor->set_polarity (chn, tact->get_active());
907 MonitorSection::register_actions ()
911 Glib::RefPtr<Action> act;
913 monitor_actions = myactions.create_action_group (X_("Monitor"));
915 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
916 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
918 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
919 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
921 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
922 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
924 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
925 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
927 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
928 tact->set_active (Config->get_exclusive_solo());
930 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
931 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
933 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
934 tact->set_active (Config->get_solo_mute_override());
936 for (uint32_t chn = 0; chn < 16; ++chn) {
938 action_name = string_compose (X_("monitor-cut-%1"), chn);
939 action_descr = string_compose (_("Cut monitor channel %1"), chn);
940 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
941 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
943 action_name = string_compose (X_("monitor-dim-%1"), chn);
944 action_descr = string_compose (_("Dim monitor channel %1"), chn);
945 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
946 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
948 action_name = string_compose (X_("monitor-solo-%1"), chn);
949 action_descr = string_compose (_("Solo monitor channel %1"), chn);
950 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
951 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
953 action_name = string_compose (X_("monitor-invert-%1"), chn);
954 action_descr = string_compose (_("Invert monitor channel %1"), chn);
955 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
956 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
961 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
962 RadioAction::Group solo_group;
964 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
965 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
966 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
967 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
968 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
969 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
971 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
972 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
977 MonitorSection::solo_use_in_place ()
979 /* this is driven by a toggle on a radio group, and so is invoked twice,
980 once for the item that became inactive and once for the one that became
984 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
987 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
989 if (!ract->get_active ()) {
990 /* We are turning SiP off, which means that AFL or PFL will be turned on
991 shortly; don't update the solo model in the mean time, as if the currently
992 configured listen position is not the one that is about to be turned on,
993 things will go wrong.
995 _inhibit_solo_model_update = true;
997 Config->set_solo_control_is_listen_control (!ract->get_active());
998 _inhibit_solo_model_update = false;
1004 MonitorSection::solo_use_afl ()
1006 /* this is driven by a toggle on a radio group, and so is invoked twice,
1007 once for the item that became inactive and once for the one that became
1011 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1013 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1015 if (ract->get_active()) {
1016 Config->set_solo_control_is_listen_control (true);
1017 Config->set_listen_position (AfterFaderListen);
1024 MonitorSection::solo_use_pfl ()
1026 /* this is driven by a toggle on a radio group, and so is invoked twice,
1027 once for the item that became inactive and once for the one that became
1031 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1033 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1035 if (ract->get_active()) {
1036 Config->set_solo_control_is_listen_control (true);
1037 Config->set_listen_position (PreFaderListen);
1044 MonitorSection::update_solo_model ()
1046 if (_inhibit_solo_model_update) {
1050 const char* action_name = 0;
1051 Glib::RefPtr<Action> act;
1053 if (Config->get_solo_control_is_listen_control()) {
1054 switch (Config->get_listen_position()) {
1055 case AfterFaderListen:
1056 action_name = X_("solo-use-afl");
1058 case PreFaderListen:
1059 action_name = X_("solo-use-pfl");
1063 action_name = X_("solo-use-in-place");
1066 act = ActionManager::get_action (X_("Solo"), action_name);
1069 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1071 /* because these are radio buttons, one of them will be
1072 active no matter what. to trigger a change in the
1073 action so that the view picks it up, toggle it.
1075 if (ract->get_active()) {
1076 ract->set_active (false);
1078 ract->set_active (true);
1085 MonitorSection::map_state ()
1087 if (!_route || !_monitor) {
1091 Glib::RefPtr<Action> act;
1093 update_solo_model ();
1095 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1097 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1099 tact->set_active (_monitor->cut_all());
1103 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1105 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1107 tact->set_active (_monitor->dim_all());
1111 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1113 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1115 tact->set_active (_monitor->mono());
1119 uint32_t nchans = _monitor->output_streams().n_audio();
1121 assert (nchans == _channel_buttons.size ());
1123 for (uint32_t n = 0; n < nchans; ++n) {
1125 char action_name[32];
1127 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1128 act = ActionManager::get_action (X_("Monitor"), action_name);
1130 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1132 tact->set_active (_monitor->cut (n));
1136 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1137 act = ActionManager::get_action (X_("Monitor"), action_name);
1139 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1141 tact->set_active (_monitor->dimmed (n));
1145 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1146 act = ActionManager::get_action (X_("Monitor"), action_name);
1148 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1150 tact->set_active (_monitor->soloed (n));
1154 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1155 act = ActionManager::get_action (X_("Monitor"), action_name);
1157 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1159 tact->set_active (_monitor->inverted (n));
1166 MonitorSection::do_blink (bool onoff)
1169 audition_blink (onoff);
1173 MonitorSection::audition_blink (bool onoff)
1175 if (_session == 0) {
1179 if (_session->is_auditioning()) {
1180 rude_audition_button.set_active (onoff);
1182 rude_audition_button.set_active (false);
1187 MonitorSection::solo_blink (bool onoff)
1189 if (_session == 0) {
1193 if (_session->soloing() || _session->listening()) {
1194 rude_solo_button.set_active (onoff);
1196 if (_session->soloing()) {
1197 if (_session->solo_isolated()) {
1198 rude_iso_button.set_active (onoff);
1200 rude_iso_button.set_active (false);
1205 rude_solo_button.set_active (false);
1206 rude_iso_button.set_active (false);
1211 MonitorSection::cancel_isolate (GdkEventButton*)
1214 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1215 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1222 MonitorSection::cancel_audition (GdkEventButton*)
1225 _session->cancel_audition();
1230 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1232 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1233 if (tact && tact->get_active() != value) { \
1234 tact->set_active(value); \
1239 MonitorSection::parameter_changed (std::string name)
1241 if (name == "solo-control-is-listen-control") {
1242 update_solo_model ();
1243 } else if (name == "listen-position") {
1244 update_solo_model ();
1245 } else if (name == "solo-mute-override") {
1246 SYNCHRONIZE_TOGGLE_ACTION(
1247 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1248 Config->get_solo_mute_override ())
1249 } else if (name == "exclusive-solo") {
1250 SYNCHRONIZE_TOGGLE_ACTION(
1251 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1252 Config->get_exclusive_solo ())
1257 MonitorSection::assign_controllables ()
1259 boost::shared_ptr<Controllable> none;
1261 if (!gain_control) {
1262 /* too early - GUI controls not set up yet */
1267 solo_cut_control->set_controllable (_session->solo_cut_control());
1268 solo_cut_display->set_controllable (_session->solo_cut_control());
1270 solo_cut_control->set_controllable (none);
1271 solo_cut_display->set_controllable (none);
1275 gain_control->set_controllable (_route->gain_control());
1276 gain_display->set_controllable (_route->gain_control());
1278 gain_control->set_controllable (none);
1283 cut_all_button.set_controllable (_monitor->cut_control());
1284 cut_all_button.watch ();
1285 dim_all_button.set_controllable (_monitor->dim_control());
1286 dim_all_button.watch ();
1287 mono_button.set_controllable (_monitor->mono_control());
1288 mono_button.watch ();
1290 dim_control->set_controllable (_monitor->dim_level_control ());
1291 dim_display->set_controllable (_monitor->dim_level_control ());
1292 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1293 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1297 cut_all_button.set_controllable (none);
1298 dim_all_button.set_controllable (none);
1299 mono_button.set_controllable (none);
1301 dim_control->set_controllable (none);
1302 dim_display->set_controllable (none);
1303 solo_boost_control->set_controllable (none);
1304 solo_boost_display->set_controllable (none);
1309 MonitorSection::state_id() const
1311 return "monitor-section";
1315 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1317 using namespace Menu_Helpers;
1319 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1323 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1324 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1328 if (i != output_menu_bundles.end()) {
1332 output_menu_bundles.push_back (b);
1334 MenuList& citems = output_menu.items();
1336 std::string n = b->name ();
1337 replace_all (n, "_", " ");
1339 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1343 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1346 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1348 if (std::find (current.begin(), current.end(), c) == current.end()) {
1349 _route->output()->connect_ports_to_bundle (c, true, this);
1351 _route->output()->disconnect_ports_from_bundle (c, this);
1356 MonitorSection::output_release (GdkEventButton *ev)
1358 switch (ev->button) {
1360 edit_output_configuration ();
1367 struct RouteCompareByName {
1368 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1369 return a->name().compare (b->name()) < 0;
1374 MonitorSection::output_press (GdkEventButton *ev)
1376 using namespace Menu_Helpers;
1378 MessageDialog msg (_("No session - no I/O changes are possible"));
1383 MenuList& citems = output_menu.items();
1384 switch (ev->button) {
1387 return false; //wait for the mouse-up to pop the dialog
1391 output_menu.set_name ("ArdourContextMenu");
1393 output_menu_bundles.clear ();
1395 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1397 citems.push_back (SeparatorElem());
1398 uint32_t const n_with_separator = citems.size ();
1400 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1402 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1404 /* give user bundles first chance at being in the menu */
1406 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1407 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1408 maybe_add_bundle_to_output_menu (*i, current);
1412 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1413 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1414 maybe_add_bundle_to_output_menu (*i, current);
1418 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1419 RouteList copy = *routes;
1420 copy.sort (RouteCompareByName ());
1421 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1422 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1425 if (citems.size() == n_with_separator) {
1426 /* no routes added; remove the separator */
1430 citems.push_back (SeparatorElem());
1431 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1433 output_menu.popup (1, ev->time);
1444 MonitorSection::update_output_display ()
1446 if (!_route || !_monitor || _session->deletion_in_progress()) {
1452 boost::shared_ptr<Port> port;
1453 vector<string> port_connections;
1455 uint32_t total_connection_count = 0;
1456 uint32_t io_connection_count = 0;
1457 uint32_t ardour_connection_count = 0;
1458 uint32_t system_connection_count = 0;
1459 uint32_t other_connection_count = 0;
1461 ostringstream label;
1463 bool have_label = false;
1464 bool each_io_has_one_connection = true;
1466 string connection_name;
1467 string ardour_track_name;
1468 string other_connection_type;
1469 string system_ports;
1472 ostringstream tooltip;
1473 char * tooltip_cstr;
1475 io_count = _route->n_outputs().n_total();
1476 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1479 for (io_index = 0; io_index < io_count; ++io_index) {
1481 port = _route->output()->nth (io_index);
1483 //ignore any port connections that don't match our DataType
1484 if (port->type() != DataType::AUDIO) {
1488 port_connections.clear ();
1489 port->get_connections(port_connections);
1490 io_connection_count = 0;
1492 if (!port_connections.empty()) {
1493 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1495 string& connection_name (*i);
1497 if (connection_name.find("system:") == 0) {
1498 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1501 if (io_connection_count == 0) {
1502 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1504 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1507 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1510 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1511 if (ardour_track_name.empty()) {
1512 // "ardour:Master/in 1" -> "ardour:Master/"
1513 string::size_type slash = connection_name.find("/");
1514 if (slash != string::npos) {
1515 ardour_track_name = connection_name.substr(0, slash + 1);
1519 if (connection_name.find(ardour_track_name) == 0) {
1520 ++ardour_connection_count;
1522 } else if (!pn.empty()) {
1523 if (system_ports.empty()) {
1526 system_ports += "/" + pn;
1528 if (connection_name.find("system:") == 0) {
1529 ++system_connection_count;
1531 } else if (connection_name.find("system:") == 0) {
1532 // "system:playback_123" -> "123"
1533 system_port = connection_name.substr(16);
1534 if (system_ports.empty()) {
1535 system_ports += system_port;
1537 system_ports += "/" + system_port;
1540 ++system_connection_count;
1542 if (other_connection_type.empty()) {
1543 // "jamin:in 1" -> "jamin:"
1544 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1547 if (connection_name.find(other_connection_type) == 0) {
1548 ++other_connection_count;
1552 ++total_connection_count;
1553 ++io_connection_count;
1557 if (io_connection_count != 1) {
1558 each_io_has_one_connection = false;
1562 if (total_connection_count == 0) {
1563 tooltip << endl << _("Disconnected");
1566 tooltip_cstr = new char[tooltip.str().size() + 1];
1567 strcpy(tooltip_cstr, tooltip.str().c_str());
1569 set_tooltip (output_button, tooltip_cstr, "");
1571 if (each_io_has_one_connection) {
1572 if (total_connection_count == ardour_connection_count) {
1573 // all connections are to the same track in ardour
1574 // "ardour:Master/" -> "Master"
1575 string::size_type slash = ardour_track_name.find("/");
1576 if (slash != string::npos) {
1577 label << ardour_track_name.substr(7, slash - 7);
1580 } else if (total_connection_count == system_connection_count) {
1581 // all connections are to system ports
1582 label << system_ports;
1584 } else if (total_connection_count == other_connection_count) {
1585 // all connections are to the same external program eg jamin
1586 // "jamin:" -> "jamin"
1587 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1593 if (total_connection_count == 0) {
1597 // Odd configuration
1598 label << "*" << total_connection_count << "*";
1602 output_button->set_text (label.str());
1606 MonitorSection::disconnect_output ()
1609 _route->output()->disconnect(this);
1614 MonitorSection::edit_output_configuration ()
1616 if (_output_selector == 0) {
1617 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1619 _output_selector->present ();
1623 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1628 boost::shared_ptr<Port> a = wa.lock ();
1629 boost::shared_ptr<Port> b = wb.lock ();
1630 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1631 update_output_display ();
1636 MonitorSection::load_bindings ()
1638 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1642 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1644 boost::shared_ptr<Processor> processor (p.lock ());
1645 if (!processor || !processor->display_to_user()) {
1648 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1655 MonitorSection::count_processors ()
1657 uint32_t processor_count = 0;
1659 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1661 return processor_count;
1665 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1667 update_processor_box ();
1671 MonitorSection::action_proxy0 (enum MonitorActions action)
1673 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1687 case ToggleExclusiveSolo:
1688 ms->toggle_exclusive_solo ();
1690 case ToggleMuteOverridesSolo:
1691 ms->toggle_mute_overrides_solo ();
1693 case SoloUseInPlace:
1694 ms->solo_use_in_place ();
1697 ms->solo_use_afl ();
1700 ms->solo_use_pfl ();
1702 case ToggleMonitorProcessorBox:
1703 ms->update_processor_box ();
1709 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1711 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1717 ms->cut_channel (chn);
1720 ms->dim_channel (chn);
1723 ms->solo_channel (chn);
1726 ms->invert_channel (chn);