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)
73 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
74 , *channel_table_scroller.get_vadjustment ())
77 , solo_boost_control (0)
78 , solo_cut_control (0)
81 , solo_boost_display (0)
82 , solo_cut_display (0)
83 , _output_selector (0)
84 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
85 , afl_button (_("AFL"), ArdourButton::led_default_elements)
86 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
87 , exclusive_solo_button (ArdourButton::led_default_elements)
88 , solo_mute_override_button (ArdourButton::led_default_elements)
89 , toggle_processorbox_button (ArdourButton::default_elements)
90 , _inhibit_solo_model_update (false)
91 , _ui_initialized (false)
94 using namespace Menu_Helpers;
96 Glib::RefPtr<Action> act;
98 if (!monitor_actions) {
103 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
105 set_data ("ardour-bindings", bindings);
107 _plugin_selector = new PluginSelector (PluginManager::instance());
108 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
109 insert_box->set_no_show_all ();
111 // TODO allow keyboard shortcuts in ProcessorBox
115 /* Rude Solo & Solo Isolated */
116 rude_solo_button.set_text (_("Soloing"));
117 rude_solo_button.set_name ("rude solo");
118 rude_solo_button.show ();
120 rude_iso_button.set_text (_("Isolated"));
121 rude_iso_button.set_name ("rude isolate");
122 rude_iso_button.show ();
124 rude_audition_button.set_text (_("Auditioning"));
125 rude_audition_button.set_name ("rude audition");
126 rude_audition_button.show ();
128 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
130 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
131 rude_solo_button.set_related_action (act);
132 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
134 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
135 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
137 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
138 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
140 /* SIP, AFL, PFL radio */
142 solo_in_place_button.set_name ("monitor section solo model");
143 afl_button.set_name ("monitor section solo model");
144 pfl_button.set_name ("monitor section solo model");
146 solo_in_place_button.set_led_left (true);
147 afl_button.set_led_left (true);
148 pfl_button.set_led_left (true);
150 solo_in_place_button.show ();
154 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
155 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
157 solo_in_place_button.set_related_action (act);
160 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
161 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
163 afl_button.set_related_action (act);
166 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
167 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
169 pfl_button.set_related_action (act);
172 /* Solo option buttons */
173 exclusive_solo_button.set_text (_("Excl. Solo"));
174 exclusive_solo_button.set_name (X_("monitor section solo option"));
175 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
177 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
179 exclusive_solo_button.set_related_action (act);
182 solo_mute_override_button.set_text (_("Solo ยป Mute"));
183 solo_mute_override_button.set_name (X_("monitor section solo option"));
184 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
186 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
188 solo_mute_override_button.set_related_action (act);
191 /* Processor Box hide/shos */
192 toggle_processorbox_button.set_text (_("Processors"));
193 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
194 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
196 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
197 toggle_processorbox_button.set_related_action (proctoggle);
200 Label* solo_boost_label;
201 Label* solo_cut_label;
204 /* Solo Boost Knob */
206 solo_boost_control = new ArdourKnob ();
207 solo_boost_control->set_name("monitor section knob");
208 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
209 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
211 solo_boost_display = new ArdourDisplay ();
212 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
213 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
214 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
215 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
216 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
218 solo_boost_label = manage (new Label (_("Solo Boost")));
222 solo_cut_control = new ArdourKnob ();
223 solo_cut_control->set_name ("monitor section knob");
224 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
225 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
227 solo_cut_display = new ArdourDisplay ();
228 solo_cut_display->set_name("monitor section dropdown"); // XXX
229 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
230 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
231 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
232 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
233 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
234 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
236 solo_cut_label = manage (new Label (_("SiP Cut")));
240 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
241 dim_control->set_name ("monitor section knob");
242 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
243 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
245 dim_display = new ArdourDisplay ();
246 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
247 dim_display->add_controllable_preset(_("0 dB"), 0.0);
248 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
249 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
250 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
251 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
253 dim_label = manage (new Label (_("Dim")));
256 cut_all_button.set_text (_("Mute"));
257 cut_all_button.set_name ("mute button");
258 cut_all_button.set_size_request (-1, PX_SCALE(30));
259 cut_all_button.show ();
261 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
263 cut_all_button.set_related_action (act);
267 dim_all_button.set_text (_("Dim"));
268 dim_all_button.set_name ("monitor section dim");
269 dim_all_button.set_size_request (-1, PX_SCALE(25));
270 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
272 dim_all_button.set_related_action (act);
276 mono_button.set_text (_("Mono"));
277 mono_button.set_name ("monitor section mono");
278 mono_button.set_size_request (-1, PX_SCALE(25));
279 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
281 mono_button.set_related_action (act);
286 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
287 gain_control->set_name("monitor section knob");
288 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
290 gain_display = new ArdourDisplay ();
291 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
292 gain_display->add_controllable_preset(_("0 dB"), 0.0);
293 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
294 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
295 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
296 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
297 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
299 Label* output_label = manage (new Label (_("Output")));
300 output_label->set_name (X_("MonitorSectionLabel"));
302 output_button = new ArdourButton ();
303 output_button->set_text (_("Output"));
304 output_button->set_name (X_("monitor section cut")); // XXX
305 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
306 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
308 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
309 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
310 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
311 channel_table_scroller.show ();
312 channel_table_scroller.add (channel_table_viewport);
314 channel_size_group->add_widget (channel_table_header);
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);
388 HBox* mono_dim_box = manage (new HBox);
389 mono_dim_box->set_spacing (PX_SCALE(4));
390 mono_dim_box->set_homogeneous (true);
391 mono_dim_box->pack_start (mono_button, true, true);
392 mono_dim_box->pack_end (dim_all_button, true, true);
395 Label* spin_label = manage (new Label (_("Monitor")));
396 VBox* spin_packer = manage (new VBox);
397 spin_packer->set_spacing (PX_SCALE(2));
398 spin_packer->pack_start (*spin_label, false, false);
399 spin_packer->pack_start (*gain_control, false, false);
400 spin_packer->pack_start (*gain_display, false, false);
402 master_packer.pack_start (*spin_packer, true, false);
404 // combined gain section (channels, mute, dim)
405 VBox* lower_packer = manage (new VBox);
406 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
407 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
408 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
409 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
411 // calc height of mixer scrollbar
412 int scrollbar_height = 0;
414 Gtk::Window window (WINDOW_TOPLEVEL);
415 HScrollbar scrollbar;
416 window.add (scrollbar);
417 scrollbar.set_name ("MixerWindow");
418 scrollbar.ensure_style();
419 Gtk::Requisition requisition(scrollbar.size_request ());
420 scrollbar_height = requisition.height;
423 // output port select
424 VBox* out_packer = manage (new VBox);
425 out_packer->set_spacing (PX_SCALE(2));
426 out_packer->pack_start (*output_label, false, false);
427 out_packer->pack_start (*output_button, false, false);
429 /****************************************************************************
432 vpacker.set_border_width (PX_SCALE(3));
433 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
434 vpacker.pack_start (rude_audition_button, false, false, 0);
435 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
436 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
437 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
438 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
439 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
440 vpacker.pack_end (*out_packer, false, false,
442 scrollbar_height - 2 /* no outer frame */
444 scrollbar_height + 2 /* frame borders */
448 hpacker.set_spacing (0);
449 hpacker.pack_start (vpacker, true, true);
453 gain_control->show_all ();
454 gain_display->show_all ();
455 dim_control->show_all ();
456 dim_display->show_all();
457 solo_boost_control->show_all ();
458 solo_boost_display->show_all();
460 mono_dim_box->show ();
461 spin_packer->show ();
462 master_packer.show ();
465 solo_tbl->show_all();
467 lower_packer->show ();
474 assign_controllables ();
476 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
477 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
479 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
480 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
481 set_flags (CAN_FOCUS);
483 _tearoff = new TearOff (*this);
485 if (!UIConfiguration::instance().get_floating_monitor_section()) {
486 /* if torn off, make this a normal window
487 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
489 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
491 _tearoff->tearoff_window().set_title (X_("Monitor"));
492 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
494 update_output_display ();
495 update_processor_box ();
496 _ui_initialized = true;
498 /* catch changes that affect us */
499 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
500 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
502 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
505 MonitorSection::~MonitorSection ()
507 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
511 _channel_buttons.clear ();
512 output_changed_connections.drop_connections ();
514 delete insert_box; insert_box = 0;
515 delete output_button; output_button = 0;
516 delete gain_control; gain_control = 0;
517 delete gain_display; gain_display = 0;
518 delete dim_control; dim_control = 0;
519 delete dim_display; dim_display = 0;
520 delete solo_boost_control; solo_boost_control = 0;
521 delete solo_boost_display; solo_boost_display = 0;
522 delete solo_cut_control; solo_cut_control = 0;
523 delete solo_cut_display; solo_cut_display = 0;
524 delete _tearoff; _tearoff = 0;
525 delete _output_selector; _output_selector = 0;
526 delete channel_table; channel_table = 0;
530 MonitorSection::enter_handler (GdkEventCrossing* ev)
537 MonitorSection::leave_handler (GdkEventCrossing* ev)
539 switch (ev->detail) {
540 case GDK_NOTIFY_INFERIOR:
546 /* cancel focus if we're not torn off. With X11 WM's that do
547 * focus-follows-mouse, focus will be taken from us anyway.
550 Widget* top = get_toplevel();
552 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
553 Window* win = dynamic_cast<Window*> (top);
554 gtk_window_set_focus (win->gobj(), 0);
561 MonitorSection::update_processor_box ()
563 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
565 if (count_processors () > 0 && !show_processor_box) {
566 toggle_processorbox_button.set_name (X_("monitor section processors present"));
568 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
571 if (insert_box->is_visible() == show_processor_box) {
575 if (show_processor_box) {
576 if (master_packer.get_parent()) {
577 master_packer.get_parent()->remove (master_packer);
580 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
582 if (master_packer.get_parent()) {
583 master_packer.get_parent()->remove (master_packer);
586 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
591 MonitorSection::set_session (Session* s)
593 RouteUI::set_session (s);
594 _plugin_selector->set_session (_session);
598 _route = _session->monitor_out ();
601 /* session with monitor section */
602 _monitor = _route->monitor_control ();
603 assign_controllables ();
604 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
605 boost::bind (&MonitorSection::update_output_display, this),
607 insert_box->set_route (_route);
608 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
609 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
610 if (_ui_initialized) {
611 update_processor_box ();
614 /* session with no monitor section */
615 output_changed_connections.drop_connections();
618 delete _output_selector;
619 _output_selector = 0;
627 output_changed_connections.drop_connections();
630 control_connections.drop_connections ();
631 rude_iso_button.unset_active_state ();
632 rude_solo_button.unset_active_state ();
633 delete _output_selector;
634 _output_selector = 0;
636 assign_controllables ();
640 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
642 cut.set_name (X_("mute button"));
643 dim.set_name (X_("monitor section dim"));
644 solo.set_name (X_("solo button"));
645 invert.set_name (X_("invert button"));
647 cut.unset_flags (Gtk::CAN_FOCUS);
648 dim.unset_flags (Gtk::CAN_FOCUS);
649 solo.unset_flags (Gtk::CAN_FOCUS);
650 invert.unset_flags (Gtk::CAN_FOCUS);
654 MonitorSection::populate_buttons ()
661 channel_size_group->remove_widget (*channel_table);
662 delete channel_table;
665 channel_table = new Gtk::Table();
667 channel_table->set_col_spacings (6);
668 channel_table->set_row_spacings (6);
669 channel_table->set_homogeneous (true);
671 channel_size_group->add_widget (*channel_table);
672 channel_table->show ();
673 table_hpacker.pack_start (*channel_table, true, true);
675 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
678 _channel_buttons.clear ();
680 Glib::RefPtr<Action> act;
681 uint32_t nchans = _monitor->output_streams().n_audio();
683 channel_table->resize (nchans, 5);
685 const uint32_t row_offset = 0;
687 for (uint32_t i = 0; i < nchans; ++i) {
700 snprintf (buf, sizeof (buf), "%d", i+1);
704 Label* label = manage (new Label (l));
705 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
707 ChannelButtonSet* cbs = new ChannelButtonSet;
709 _channel_buttons.push_back (cbs);
711 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
712 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
713 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
714 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
716 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
717 act = ActionManager::get_action (X_("Monitor"), buf);
719 cbs->cut.set_related_action (act);
722 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
723 act = ActionManager::get_action (X_("Monitor"), buf);
725 cbs->dim.set_related_action (act);
728 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
729 act = ActionManager::get_action (X_("Monitor"), buf);
731 cbs->solo.set_related_action (act);
734 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
735 act = ActionManager::get_action (X_("Monitor"), buf);
737 cbs->invert.set_related_action (act);
741 channel_table->show_all ();
743 if (channel_table_scroller.get_parent()) {
744 /* scroller is packed, so remove it */
745 channel_table_packer.remove (channel_table_scroller);
748 if (table_hpacker.get_parent () == &channel_table_packer) {
749 /* this occurs when the table hpacker is directly
750 packed, so remove it.
752 channel_table_packer.remove (table_hpacker);
753 } else if (table_hpacker.get_parent()) {
754 channel_table_viewport.remove ();
758 /* put the table into a scrolled window, and then put
759 * that into the channel vpacker, after the table header
761 channel_table_viewport.add (table_hpacker);
762 channel_table_packer.pack_start (channel_table_scroller, true, true);
763 channel_table_viewport.show ();
764 channel_table_scroller.show ();
767 /* just put the channel table itself into the channel
768 * vpacker, after the table header
770 channel_table_packer.pack_start (table_hpacker, true, true);
771 channel_table_scroller.hide ();
773 table_hpacker.show ();
774 channel_table->show ();
778 MonitorSection::toggle_exclusive_solo ()
784 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
786 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
787 Config->set_exclusive_solo (tact->get_active());
793 MonitorSection::toggle_mute_overrides_solo ()
799 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
801 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
802 Config->set_solo_mute_override (tact->get_active());
807 MonitorSection::dim_all ()
813 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
815 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
816 _monitor->set_dim_all (tact->get_active());
822 MonitorSection::cut_all ()
828 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
830 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
831 _monitor->set_cut_all (tact->get_active());
836 MonitorSection::mono ()
842 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
844 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
845 _monitor->set_mono (tact->get_active());
850 MonitorSection::cut_channel (uint32_t chn)
857 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
859 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
861 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
862 _monitor->set_cut (chn, tact->get_active());
867 MonitorSection::dim_channel (uint32_t chn)
874 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
876 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
878 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
879 _monitor->set_dim (chn, tact->get_active());
885 MonitorSection::solo_channel (uint32_t chn)
892 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
894 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
896 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
897 _monitor->set_solo (chn, tact->get_active());
903 MonitorSection::invert_channel (uint32_t chn)
910 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
912 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
914 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
915 _monitor->set_polarity (chn, tact->get_active());
920 MonitorSection::register_actions ()
924 Glib::RefPtr<Action> act;
926 monitor_actions = myactions.create_action_group (X_("Monitor"));
928 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
929 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
931 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
932 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
934 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
935 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
937 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
938 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
940 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
941 tact->set_active (Config->get_exclusive_solo());
943 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
944 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
946 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
947 tact->set_active (Config->get_solo_mute_override());
949 for (uint32_t chn = 0; chn < 16; ++chn) {
951 action_name = string_compose (X_("monitor-cut-%1"), chn);
952 action_descr = string_compose (_("Cut monitor channel %1"), chn);
953 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
954 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
956 action_name = string_compose (X_("monitor-dim-%1"), chn);
957 action_descr = string_compose (_("Dim monitor channel %1"), chn);
958 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
959 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
961 action_name = string_compose (X_("monitor-solo-%1"), chn);
962 action_descr = string_compose (_("Solo monitor channel %1"), chn);
963 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
964 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
966 action_name = string_compose (X_("monitor-invert-%1"), chn);
967 action_descr = string_compose (_("Invert monitor channel %1"), chn);
968 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
969 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
974 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
975 RadioAction::Group solo_group;
977 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
978 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
979 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
980 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
981 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
982 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
984 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
985 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
990 MonitorSection::solo_use_in_place ()
992 /* this is driven by a toggle on a radio group, and so is invoked twice,
993 once for the item that became inactive and once for the one that became
997 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
1000 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1002 if (!ract->get_active ()) {
1003 /* We are turning SiP off, which means that AFL or PFL will be turned on
1004 shortly; don't update the solo model in the mean time, as if the currently
1005 configured listen position is not the one that is about to be turned on,
1006 things will go wrong.
1008 _inhibit_solo_model_update = true;
1010 Config->set_solo_control_is_listen_control (!ract->get_active());
1011 _inhibit_solo_model_update = false;
1017 MonitorSection::solo_use_afl ()
1019 /* this is driven by a toggle on a radio group, and so is invoked twice,
1020 once for the item that became inactive and once for the one that became
1024 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1026 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1028 if (ract->get_active()) {
1029 Config->set_solo_control_is_listen_control (true);
1030 Config->set_listen_position (AfterFaderListen);
1037 MonitorSection::solo_use_pfl ()
1039 /* this is driven by a toggle on a radio group, and so is invoked twice,
1040 once for the item that became inactive and once for the one that became
1044 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1046 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1048 if (ract->get_active()) {
1049 Config->set_solo_control_is_listen_control (true);
1050 Config->set_listen_position (PreFaderListen);
1057 MonitorSection::update_solo_model ()
1059 if (_inhibit_solo_model_update) {
1063 const char* action_name = 0;
1064 Glib::RefPtr<Action> act;
1066 if (Config->get_solo_control_is_listen_control()) {
1067 switch (Config->get_listen_position()) {
1068 case AfterFaderListen:
1069 action_name = X_("solo-use-afl");
1071 case PreFaderListen:
1072 action_name = X_("solo-use-pfl");
1076 action_name = X_("solo-use-in-place");
1079 act = ActionManager::get_action (X_("Solo"), action_name);
1082 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1084 /* because these are radio buttons, one of them will be
1085 active no matter what. to trigger a change in the
1086 action so that the view picks it up, toggle it.
1088 if (ract->get_active()) {
1089 ract->set_active (false);
1091 ract->set_active (true);
1098 MonitorSection::map_state ()
1100 if (!_route || !_monitor) {
1104 Glib::RefPtr<Action> act;
1106 update_solo_model ();
1108 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1110 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1112 tact->set_active (_monitor->cut_all());
1116 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1118 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1120 tact->set_active (_monitor->dim_all());
1124 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1126 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1128 tact->set_active (_monitor->mono());
1132 uint32_t nchans = _monitor->output_streams().n_audio();
1134 assert (nchans == _channel_buttons.size ());
1136 for (uint32_t n = 0; n < nchans; ++n) {
1138 char action_name[32];
1140 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1141 act = ActionManager::get_action (X_("Monitor"), action_name);
1143 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1145 tact->set_active (_monitor->cut (n));
1149 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1150 act = ActionManager::get_action (X_("Monitor"), action_name);
1152 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1154 tact->set_active (_monitor->dimmed (n));
1158 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1159 act = ActionManager::get_action (X_("Monitor"), action_name);
1161 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1163 tact->set_active (_monitor->soloed (n));
1167 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1168 act = ActionManager::get_action (X_("Monitor"), action_name);
1170 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1172 tact->set_active (_monitor->inverted (n));
1179 MonitorSection::do_blink (bool onoff)
1181 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1186 audition_blink (onoff);
1190 MonitorSection::audition_blink (bool onoff)
1192 if (_session == 0) {
1196 if (_session->is_auditioning()) {
1197 rude_audition_button.set_active (onoff);
1199 rude_audition_button.set_active (false);
1204 MonitorSection::solo_blink (bool onoff)
1206 if (_session == 0) {
1210 if (_session->soloing() || _session->listening()) {
1211 rude_solo_button.set_active (onoff);
1213 if (_session->soloing()) {
1214 if (_session->solo_isolated()) {
1215 rude_iso_button.set_active (onoff);
1217 rude_iso_button.set_active (false);
1222 rude_solo_button.set_active (false);
1223 rude_iso_button.set_active (false);
1228 MonitorSection::cancel_isolate (GdkEventButton*)
1231 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1232 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1239 MonitorSection::cancel_audition (GdkEventButton*)
1242 _session->cancel_audition();
1247 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1249 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1250 if (tact && tact->get_active() != value) { \
1251 tact->set_active(value); \
1256 MonitorSection::parameter_changed (std::string name)
1258 if (name == "solo-control-is-listen-control") {
1259 update_solo_model ();
1260 } else if (name == "listen-position") {
1261 update_solo_model ();
1262 } else if (name == "solo-mute-override") {
1263 SYNCHRONIZE_TOGGLE_ACTION(
1264 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1265 Config->get_solo_mute_override ())
1266 } else if (name == "exclusive-solo") {
1267 SYNCHRONIZE_TOGGLE_ACTION(
1268 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1269 Config->get_exclusive_solo ())
1274 MonitorSection::assign_controllables ()
1276 boost::shared_ptr<Controllable> none;
1278 if (!gain_control) {
1279 /* too early - GUI controls not set up yet */
1284 solo_cut_control->set_controllable (_session->solo_cut_control());
1285 solo_cut_display->set_controllable (_session->solo_cut_control());
1287 solo_cut_control->set_controllable (none);
1288 solo_cut_display->set_controllable (none);
1292 gain_control->set_controllable (_route->gain_control());
1293 gain_display->set_controllable (_route->gain_control());
1295 gain_control->set_controllable (none);
1300 cut_all_button.set_controllable (_monitor->cut_control());
1301 cut_all_button.watch ();
1302 dim_all_button.set_controllable (_monitor->dim_control());
1303 dim_all_button.watch ();
1304 mono_button.set_controllable (_monitor->mono_control());
1305 mono_button.watch ();
1307 dim_control->set_controllable (_monitor->dim_level_control ());
1308 dim_display->set_controllable (_monitor->dim_level_control ());
1309 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1310 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1314 cut_all_button.set_controllable (none);
1315 dim_all_button.set_controllable (none);
1316 mono_button.set_controllable (none);
1318 dim_control->set_controllable (none);
1319 dim_display->set_controllable (none);
1320 solo_boost_control->set_controllable (none);
1321 solo_boost_display->set_controllable (none);
1326 MonitorSection::state_id() const
1328 return "monitor-section";
1332 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1334 using namespace Menu_Helpers;
1336 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1340 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1341 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1345 if (i != output_menu_bundles.end()) {
1349 output_menu_bundles.push_back (b);
1351 MenuList& citems = output_menu.items();
1353 std::string n = b->name ();
1354 replace_all (n, "_", " ");
1356 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1360 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1363 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1365 if (std::find (current.begin(), current.end(), c) == current.end()) {
1366 _route->output()->connect_ports_to_bundle (c, true, this);
1368 _route->output()->disconnect_ports_from_bundle (c, this);
1373 MonitorSection::output_release (GdkEventButton *ev)
1375 switch (ev->button) {
1377 edit_output_configuration ();
1384 struct RouteCompareByName {
1385 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1386 return a->name().compare (b->name()) < 0;
1391 MonitorSection::output_press (GdkEventButton *ev)
1393 using namespace Menu_Helpers;
1395 MessageDialog msg (_("No session - no I/O changes are possible"));
1400 MenuList& citems = output_menu.items();
1401 switch (ev->button) {
1404 return false; //wait for the mouse-up to pop the dialog
1408 output_menu.set_name ("ArdourContextMenu");
1410 output_menu_bundles.clear ();
1412 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1414 citems.push_back (SeparatorElem());
1415 uint32_t const n_with_separator = citems.size ();
1417 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1419 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1421 /* give user bundles first chance at being in the menu */
1423 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1424 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1425 maybe_add_bundle_to_output_menu (*i, current);
1429 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1430 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1431 maybe_add_bundle_to_output_menu (*i, current);
1435 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1436 RouteList copy = *routes;
1437 copy.sort (RouteCompareByName ());
1438 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1439 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1442 if (citems.size() == n_with_separator) {
1443 /* no routes added; remove the separator */
1447 citems.push_back (SeparatorElem());
1448 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1450 output_menu.popup (1, ev->time);
1461 MonitorSection::update_output_display ()
1463 if (!_route || !_monitor || _session->deletion_in_progress()) {
1469 boost::shared_ptr<Port> port;
1470 vector<string> port_connections;
1472 uint32_t total_connection_count = 0;
1473 uint32_t io_connection_count = 0;
1474 uint32_t ardour_connection_count = 0;
1475 uint32_t system_connection_count = 0;
1476 uint32_t other_connection_count = 0;
1478 ostringstream label;
1480 bool have_label = false;
1481 bool each_io_has_one_connection = true;
1483 string connection_name;
1484 string ardour_track_name;
1485 string other_connection_type;
1486 string system_ports;
1489 ostringstream tooltip;
1490 char * tooltip_cstr;
1492 io_count = _route->n_outputs().n_total();
1493 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1496 for (io_index = 0; io_index < io_count; ++io_index) {
1498 port = _route->output()->nth (io_index);
1500 //ignore any port connections that don't match our DataType
1501 if (port->type() != DataType::AUDIO) {
1505 port_connections.clear ();
1506 port->get_connections(port_connections);
1507 io_connection_count = 0;
1509 if (!port_connections.empty()) {
1510 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1512 string& connection_name (*i);
1514 if (connection_name.find("system:") == 0) {
1515 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1518 if (io_connection_count == 0) {
1519 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1521 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1524 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1527 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1528 if (ardour_track_name.empty()) {
1529 // "ardour:Master/in 1" -> "ardour:Master/"
1530 string::size_type slash = connection_name.find("/");
1531 if (slash != string::npos) {
1532 ardour_track_name = connection_name.substr(0, slash + 1);
1536 if (connection_name.find(ardour_track_name) == 0) {
1537 ++ardour_connection_count;
1539 } else if (!pn.empty()) {
1540 if (system_ports.empty()) {
1543 system_ports += "/" + pn;
1545 if (connection_name.find("system:") == 0) {
1546 ++system_connection_count;
1548 } else if (connection_name.find("system:") == 0) {
1549 // "system:playback_123" -> "123"
1550 system_port = connection_name.substr(16);
1551 if (system_ports.empty()) {
1552 system_ports += system_port;
1554 system_ports += "/" + system_port;
1557 ++system_connection_count;
1559 if (other_connection_type.empty()) {
1560 // "jamin:in 1" -> "jamin:"
1561 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1564 if (connection_name.find(other_connection_type) == 0) {
1565 ++other_connection_count;
1569 ++total_connection_count;
1570 ++io_connection_count;
1574 if (io_connection_count != 1) {
1575 each_io_has_one_connection = false;
1579 if (total_connection_count == 0) {
1580 tooltip << endl << _("Disconnected");
1583 tooltip_cstr = new char[tooltip.str().size() + 1];
1584 strcpy(tooltip_cstr, tooltip.str().c_str());
1586 set_tooltip (output_button, tooltip_cstr, "");
1588 if (each_io_has_one_connection) {
1589 if (total_connection_count == ardour_connection_count) {
1590 // all connections are to the same track in ardour
1591 // "ardour:Master/" -> "Master"
1592 string::size_type slash = ardour_track_name.find("/");
1593 if (slash != string::npos) {
1594 label << ardour_track_name.substr(7, slash - 7);
1597 } else if (total_connection_count == system_connection_count) {
1598 // all connections are to system ports
1599 label << system_ports;
1601 } else if (total_connection_count == other_connection_count) {
1602 // all connections are to the same external program eg jamin
1603 // "jamin:" -> "jamin"
1604 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1610 if (total_connection_count == 0) {
1614 // Odd configuration
1615 label << "*" << total_connection_count << "*";
1619 output_button->set_text (label.str());
1623 MonitorSection::disconnect_output ()
1626 _route->output()->disconnect(this);
1631 MonitorSection::edit_output_configuration ()
1633 if (_output_selector == 0) {
1634 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1636 _output_selector->present ();
1640 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1645 boost::shared_ptr<Port> a = wa.lock ();
1646 boost::shared_ptr<Port> b = wb.lock ();
1647 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1648 update_output_display ();
1653 MonitorSection::load_bindings ()
1655 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1659 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1661 boost::shared_ptr<Processor> processor (p.lock ());
1662 if (!processor || !processor->display_to_user()) {
1665 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1672 MonitorSection::count_processors ()
1674 uint32_t processor_count = 0;
1676 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1678 return processor_count;
1682 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1684 update_processor_box ();
1688 MonitorSection::action_proxy0 (enum MonitorActions action)
1690 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1704 case ToggleExclusiveSolo:
1705 ms->toggle_exclusive_solo ();
1707 case ToggleMuteOverridesSolo:
1708 ms->toggle_mute_overrides_solo ();
1710 case SoloUseInPlace:
1711 ms->solo_use_in_place ();
1714 ms->solo_use_afl ();
1717 ms->solo_use_pfl ();
1719 case ToggleMonitorProcessorBox:
1720 ms->update_processor_box ();
1726 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1728 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1734 ms->cut_channel (chn);
1737 ms->dim_channel (chn);
1740 ms->solo_channel (chn);
1743 ms->invert_channel (chn);