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)
92 , _ui_initialized (false)
95 using namespace Menu_Helpers;
97 Glib::RefPtr<Action> act;
99 if (!monitor_actions) {
104 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
106 set_data ("ardour-bindings", bindings);
108 _plugin_selector = new PluginSelector (PluginManager::instance());
109 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
110 insert_box->set_no_show_all ();
112 // TODO allow keyboard shortcuts in ProcessorBox
116 /* Rude Solo & Solo Isolated */
117 rude_solo_button.set_text (_("Soloing"));
118 rude_solo_button.set_name ("rude solo");
119 rude_solo_button.show ();
121 rude_iso_button.set_text (_("Isolated"));
122 rude_iso_button.set_name ("rude isolate");
123 rude_iso_button.show ();
125 rude_audition_button.set_text (_("Auditioning"));
126 rude_audition_button.set_name ("rude audition");
127 rude_audition_button.show ();
129 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
131 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
132 rude_solo_button.set_related_action (act);
133 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
135 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
136 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
138 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
139 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
141 /* SIP, AFL, PFL radio */
143 solo_in_place_button.set_name ("monitor section solo model");
144 afl_button.set_name ("monitor section solo model");
145 pfl_button.set_name ("monitor section solo model");
147 solo_in_place_button.set_led_left (true);
148 afl_button.set_led_left (true);
149 pfl_button.set_led_left (true);
151 solo_in_place_button.show ();
155 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
156 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
158 solo_in_place_button.set_related_action (act);
161 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
162 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
164 afl_button.set_related_action (act);
167 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
168 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
170 pfl_button.set_related_action (act);
173 /* Solo option buttons */
174 exclusive_solo_button.set_text (_("Excl. Solo"));
175 exclusive_solo_button.set_name (X_("monitor section solo option"));
176 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
178 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
180 exclusive_solo_button.set_related_action (act);
183 solo_mute_override_button.set_text (_("Solo ยป Mute"));
184 solo_mute_override_button.set_name (X_("monitor section solo option"));
185 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
187 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
189 solo_mute_override_button.set_related_action (act);
192 /* Processor Box hide/shos */
193 toggle_processorbox_button.set_text (_("Processors"));
194 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
195 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
197 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
198 toggle_processorbox_button.set_related_action (proctoggle);
201 Label* solo_boost_label;
202 Label* solo_cut_label;
205 /* Solo Boost Knob */
207 solo_boost_control = new ArdourKnob ();
208 solo_boost_control->set_name("monitor section knob");
209 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
210 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
212 solo_boost_display = new ArdourDisplay ();
213 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
214 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
215 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
216 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
217 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
219 solo_boost_label = manage (new Label (_("Solo Boost")));
223 solo_cut_control = new ArdourKnob ();
224 solo_cut_control->set_name ("monitor section knob");
225 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
226 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
228 solo_cut_display = new ArdourDisplay ();
229 solo_cut_display->set_name("monitor section dropdown"); // XXX
230 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
231 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
232 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
233 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
234 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
235 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
237 solo_cut_label = manage (new Label (_("SiP Cut")));
241 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
242 dim_control->set_name ("monitor section knob");
243 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
244 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
246 dim_display = new ArdourDisplay ();
247 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
248 dim_display->add_controllable_preset(_("0 dB"), 0.0);
249 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
250 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
251 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
252 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
254 dim_label = manage (new Label (_("Dim")));
257 cut_all_button.set_text (_("Mute"));
258 cut_all_button.set_name ("mute button");
259 cut_all_button.set_size_request (-1, PX_SCALE(30));
260 cut_all_button.show ();
262 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
264 cut_all_button.set_related_action (act);
268 dim_all_button.set_text (_("Dim"));
269 dim_all_button.set_name ("monitor section dim");
270 dim_all_button.set_size_request (-1, PX_SCALE(25));
271 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
273 dim_all_button.set_related_action (act);
277 mono_button.set_text (_("Mono"));
278 mono_button.set_name ("monitor section mono");
279 mono_button.set_size_request (-1, PX_SCALE(25));
280 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
282 mono_button.set_related_action (act);
287 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
288 gain_control->set_name("monitor section knob");
289 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
291 gain_display = new ArdourDisplay ();
292 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
293 gain_display->add_controllable_preset(_("0 dB"), 0.0);
294 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
295 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
296 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
297 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
298 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
300 Label* output_label = manage (new Label (_("Output")));
301 output_label->set_name (X_("MonitorSectionLabel"));
303 output_button = new ArdourButton ();
304 output_button->set_text (_("Output"));
305 output_button->set_name (X_("monitor section cut")); // XXX
306 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
307 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
309 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
310 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
311 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
312 channel_table_scroller.show ();
313 channel_table_scroller.add (channel_table_viewport);
315 channel_size_group->add_widget (channel_table_header);
316 channel_table_header.resize (1, 5);
318 Label* l1 = manage (new Label (X_(" ")));
319 l1->set_name (X_("MonitorSectionLabel"));
320 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
322 l1 = manage (new Label (_("Mute")));
323 l1->set_name (X_("MonitorSectionLabel"));
324 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
326 l1 = manage (new Label (_("Dim")));
327 l1->set_name (X_("MonitorSectionLabel"));
328 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
330 l1 = manage (new Label (_("Solo")));
331 l1->set_name (X_("MonitorSectionLabel"));
332 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
334 l1 = manage (new Label (_("Inv")));
335 l1->set_name (X_("MonitorSectionLabel"));
336 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
338 channel_table_header.show ();
341 /****************************************************************************
342 * LAYOUT top to bottom
345 // solo, iso information
346 HBox* rude_box = manage (new HBox);
347 rude_box->set_spacing (PX_SCALE(4));
348 rude_box->set_homogeneous (true);
349 rude_box->pack_start (rude_solo_button, true, true);
350 rude_box->pack_start (rude_iso_button, true, true);
352 // solo options (right align)
353 HBox* tbx1 = manage (new HBox);
354 tbx1->pack_end (exclusive_solo_button, false, false);
356 HBox* tbx2 = manage (new HBox);
357 tbx2->pack_end (solo_mute_override_button, false, false);
359 HBox* tbx3 = manage (new HBox);
360 tbx3->pack_end (toggle_processorbox_button, false, false);
362 HBox* tbx0 = manage (new HBox); // space
364 // combined solo mode (Sip, AFL, PFL) & solo options
365 Table *solo_tbl = manage (new Table);
366 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
369 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
370 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
371 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
372 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
374 // boost, cut, dim volume control
375 Table *level_tbl = manage (new Table);
376 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
378 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
380 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
382 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
384 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
385 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
386 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
389 HBox* mono_dim_box = manage (new HBox);
390 mono_dim_box->set_spacing (PX_SCALE(4));
391 mono_dim_box->set_homogeneous (true);
392 mono_dim_box->pack_start (mono_button, true, true);
393 mono_dim_box->pack_end (dim_all_button, true, true);
396 Label* spin_label = manage (new Label (_("Monitor")));
397 VBox* spin_packer = manage (new VBox);
398 spin_packer->set_spacing (PX_SCALE(2));
399 spin_packer->pack_start (*spin_label, false, false);
400 spin_packer->pack_start (*gain_control, false, false);
401 spin_packer->pack_start (*gain_display, false, false);
403 master_packer.pack_start (*spin_packer, true, false);
405 // combined gain section (channels, mute, dim)
406 VBox* lower_packer = manage (new VBox);
407 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
408 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
409 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
410 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
412 // calc height of mixer scrollbar
413 int scrollbar_height = 0;
415 Gtk::Window window (WINDOW_TOPLEVEL);
416 HScrollbar scrollbar;
417 window.add (scrollbar);
418 scrollbar.set_name ("MixerWindow");
419 scrollbar.ensure_style();
420 Gtk::Requisition requisition(scrollbar.size_request ());
421 scrollbar_height = requisition.height;
424 // output port select
425 VBox* out_packer = manage (new VBox);
426 out_packer->set_spacing (PX_SCALE(2));
427 out_packer->pack_start (*output_label, false, false);
428 out_packer->pack_start (*output_button, false, false);
430 /****************************************************************************
433 vpacker.set_border_width (PX_SCALE(3));
434 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
435 vpacker.pack_start (rude_audition_button, false, false, 0);
436 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
437 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
438 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
439 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
440 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
441 vpacker.pack_end (*out_packer, false, false,
443 scrollbar_height - 2 /* no outer frame */
445 scrollbar_height + 2 /* frame borders */
449 hpacker.set_spacing (0);
450 hpacker.pack_start (vpacker, true, true);
454 gain_control->show_all ();
455 gain_display->show_all ();
456 dim_control->show_all ();
457 dim_display->show_all();
458 solo_boost_control->show_all ();
459 solo_boost_display->show_all();
461 mono_dim_box->show ();
462 spin_packer->show ();
463 master_packer.show ();
466 solo_tbl->show_all();
468 lower_packer->show ();
475 assign_controllables ();
477 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
478 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
480 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
481 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
482 set_flags (CAN_FOCUS);
484 _tearoff = new TearOff (*this);
486 if (!UIConfiguration::instance().get_floating_monitor_section()) {
487 /* if torn off, make this a normal window
488 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
490 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
492 _tearoff->tearoff_window().set_title (X_("Monitor"));
493 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
495 update_output_display ();
496 update_processor_box ();
497 _ui_initialized = true;
499 /* catch changes that affect us */
500 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
501 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
503 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
506 MonitorSection::~MonitorSection ()
508 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
512 _channel_buttons.clear ();
513 output_changed_connections.drop_connections ();
515 delete insert_box; insert_box = 0;
516 delete output_button; output_button = 0;
517 delete gain_control; gain_control = 0;
518 delete gain_display; gain_display = 0;
519 delete dim_control; dim_control = 0;
520 delete dim_display; dim_display = 0;
521 delete solo_boost_control; solo_boost_control = 0;
522 delete solo_boost_display; solo_boost_display = 0;
523 delete solo_cut_control; solo_cut_control = 0;
524 delete solo_cut_display; solo_cut_display = 0;
525 delete _tearoff; _tearoff = 0;
526 delete _output_selector; _output_selector = 0;
527 delete channel_table; channel_table = 0;
531 MonitorSection::enter_handler (GdkEventCrossing* ev)
538 MonitorSection::leave_handler (GdkEventCrossing* ev)
540 switch (ev->detail) {
541 case GDK_NOTIFY_INFERIOR:
547 /* cancel focus if we're not torn off. With X11 WM's that do
548 * focus-follows-mouse, focus will be taken from us anyway.
551 Widget* top = get_toplevel();
553 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
554 Window* win = dynamic_cast<Window*> (top);
555 gtk_window_set_focus (win->gobj(), 0);
562 MonitorSection::update_processor_box ()
564 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
566 if (count_processors () > 0 && !show_processor_box) {
567 toggle_processorbox_button.set_name (X_("monitor section processors present"));
569 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
572 if (insert_box->is_visible() == show_processor_box) {
576 if (show_processor_box) {
577 if (master_packer.get_parent()) {
578 master_packer.get_parent()->remove (master_packer);
581 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
583 if (master_packer.get_parent()) {
584 master_packer.get_parent()->remove (master_packer);
587 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
592 MonitorSection::set_session (Session* s)
594 RouteUI::set_session (s);
595 _plugin_selector->set_session (_session);
599 _route = _session->monitor_out ();
602 /* session with monitor section */
603 _monitor = _route->monitor_control ();
604 assign_controllables ();
605 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
606 boost::bind (&MonitorSection::update_output_display, this),
608 insert_box->set_route (_route);
609 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
610 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
611 if (_ui_initialized) {
612 update_processor_box ();
615 /* session with no monitor section */
616 output_changed_connections.drop_connections();
619 delete _output_selector;
620 _output_selector = 0;
628 output_changed_connections.drop_connections();
631 control_connections.drop_connections ();
632 rude_iso_button.unset_active_state ();
633 rude_solo_button.unset_active_state ();
634 delete _output_selector;
635 _output_selector = 0;
637 assign_controllables ();
641 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
643 cut.set_name (X_("mute button"));
644 dim.set_name (X_("monitor section dim"));
645 solo.set_name (X_("solo button"));
646 invert.set_name (X_("invert button"));
648 cut.unset_flags (Gtk::CAN_FOCUS);
649 dim.unset_flags (Gtk::CAN_FOCUS);
650 solo.unset_flags (Gtk::CAN_FOCUS);
651 invert.unset_flags (Gtk::CAN_FOCUS);
655 MonitorSection::populate_buttons ()
662 channel_size_group->remove_widget (*channel_table);
663 delete channel_table;
666 channel_table = new Gtk::Table();
668 channel_table->set_col_spacings (6);
669 channel_table->set_row_spacings (6);
670 channel_table->set_homogeneous (true);
672 channel_size_group->add_widget (*channel_table);
673 channel_table->show ();
674 table_hpacker.pack_start (*channel_table, true, true);
676 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
679 _channel_buttons.clear ();
681 Glib::RefPtr<Action> act;
682 uint32_t nchans = _monitor->output_streams().n_audio();
684 channel_table->resize (nchans, 5);
686 const uint32_t row_offset = 0;
688 for (uint32_t i = 0; i < nchans; ++i) {
701 snprintf (buf, sizeof (buf), "%d", i+1);
705 Label* label = manage (new Label (l));
706 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
708 ChannelButtonSet* cbs = new ChannelButtonSet;
710 _channel_buttons.push_back (cbs);
712 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
713 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
714 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
715 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
717 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
718 act = ActionManager::get_action (X_("Monitor"), buf);
720 cbs->cut.set_related_action (act);
723 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
724 act = ActionManager::get_action (X_("Monitor"), buf);
726 cbs->dim.set_related_action (act);
729 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
730 act = ActionManager::get_action (X_("Monitor"), buf);
732 cbs->solo.set_related_action (act);
735 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
736 act = ActionManager::get_action (X_("Monitor"), buf);
738 cbs->invert.set_related_action (act);
742 channel_table->show_all ();
744 if (channel_table_scroller.get_parent()) {
745 /* scroller is packed, so remove it */
746 channel_table_packer.remove (channel_table_scroller);
749 if (table_hpacker.get_parent () == &channel_table_packer) {
750 /* this occurs when the table hpacker is directly
751 packed, so remove it.
753 channel_table_packer.remove (table_hpacker);
754 } else if (table_hpacker.get_parent()) {
755 channel_table_viewport.remove ();
759 /* put the table into a scrolled window, and then put
760 * that into the channel vpacker, after the table header
762 channel_table_viewport.add (table_hpacker);
763 channel_table_packer.pack_start (channel_table_scroller, true, true);
764 channel_table_viewport.show ();
765 channel_table_scroller.show ();
768 /* just put the channel table itself into the channel
769 * vpacker, after the table header
771 channel_table_packer.pack_start (table_hpacker, true, true);
772 channel_table_scroller.hide ();
774 table_hpacker.show ();
775 channel_table->show ();
779 MonitorSection::toggle_exclusive_solo ()
785 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
787 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
788 Config->set_exclusive_solo (tact->get_active());
794 MonitorSection::toggle_mute_overrides_solo ()
800 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
802 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
803 Config->set_solo_mute_override (tact->get_active());
808 MonitorSection::dim_all ()
814 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
816 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
817 _monitor->set_dim_all (tact->get_active());
823 MonitorSection::cut_all ()
829 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
831 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
832 _monitor->set_cut_all (tact->get_active());
837 MonitorSection::mono ()
843 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
845 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
846 _monitor->set_mono (tact->get_active());
851 MonitorSection::cut_channel (uint32_t chn)
858 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
860 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
862 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
863 _monitor->set_cut (chn, tact->get_active());
868 MonitorSection::dim_channel (uint32_t chn)
875 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
877 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
879 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
880 _monitor->set_dim (chn, tact->get_active());
886 MonitorSection::solo_channel (uint32_t chn)
893 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
895 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
897 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
898 _monitor->set_solo (chn, tact->get_active());
904 MonitorSection::invert_channel (uint32_t chn)
911 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
913 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
915 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
916 _monitor->set_polarity (chn, tact->get_active());
921 MonitorSection::register_actions ()
925 Glib::RefPtr<Action> act;
927 monitor_actions = myactions.create_action_group (X_("Monitor"));
929 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
930 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
932 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
933 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
935 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
936 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
938 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
939 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
941 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
942 tact->set_active (Config->get_exclusive_solo());
944 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
945 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
947 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
948 tact->set_active (Config->get_solo_mute_override());
950 for (uint32_t chn = 0; chn < 16; ++chn) {
952 action_name = string_compose (X_("monitor-cut-%1"), chn);
953 action_descr = string_compose (_("Cut monitor channel %1"), chn);
954 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
955 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
957 action_name = string_compose (X_("monitor-dim-%1"), chn);
958 action_descr = string_compose (_("Dim monitor channel %1"), chn);
959 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
960 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
962 action_name = string_compose (X_("monitor-solo-%1"), chn);
963 action_descr = string_compose (_("Solo monitor channel %1"), chn);
964 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
965 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
967 action_name = string_compose (X_("monitor-invert-%1"), chn);
968 action_descr = string_compose (_("Invert monitor channel %1"), chn);
969 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
970 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
975 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
976 RadioAction::Group solo_group;
978 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
979 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
980 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
981 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
982 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
983 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
985 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
986 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
991 MonitorSection::solo_use_in_place ()
993 /* this is driven by a toggle on a radio group, and so is invoked twice,
994 once for the item that became inactive and once for the one that became
998 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
1001 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1003 if (!ract->get_active ()) {
1004 /* We are turning SiP off, which means that AFL or PFL will be turned on
1005 shortly; don't update the solo model in the mean time, as if the currently
1006 configured listen position is not the one that is about to be turned on,
1007 things will go wrong.
1009 _inhibit_solo_model_update = true;
1011 Config->set_solo_control_is_listen_control (!ract->get_active());
1012 _inhibit_solo_model_update = false;
1018 MonitorSection::solo_use_afl ()
1020 /* this is driven by a toggle on a radio group, and so is invoked twice,
1021 once for the item that became inactive and once for the one that became
1025 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1027 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1029 if (ract->get_active()) {
1030 Config->set_solo_control_is_listen_control (true);
1031 Config->set_listen_position (AfterFaderListen);
1038 MonitorSection::solo_use_pfl ()
1040 /* this is driven by a toggle on a radio group, and so is invoked twice,
1041 once for the item that became inactive and once for the one that became
1045 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1047 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1049 if (ract->get_active()) {
1050 Config->set_solo_control_is_listen_control (true);
1051 Config->set_listen_position (PreFaderListen);
1058 MonitorSection::update_solo_model ()
1060 if (_inhibit_solo_model_update) {
1064 const char* action_name = 0;
1065 Glib::RefPtr<Action> act;
1067 if (Config->get_solo_control_is_listen_control()) {
1068 switch (Config->get_listen_position()) {
1069 case AfterFaderListen:
1070 action_name = X_("solo-use-afl");
1072 case PreFaderListen:
1073 action_name = X_("solo-use-pfl");
1077 action_name = X_("solo-use-in-place");
1080 act = ActionManager::get_action (X_("Solo"), action_name);
1083 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1085 /* because these are radio buttons, one of them will be
1086 active no matter what. to trigger a change in the
1087 action so that the view picks it up, toggle it.
1089 if (ract->get_active()) {
1090 ract->set_active (false);
1092 ract->set_active (true);
1099 MonitorSection::map_state ()
1101 if (!_route || !_monitor) {
1105 Glib::RefPtr<Action> act;
1107 update_solo_model ();
1109 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1111 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1113 tact->set_active (_monitor->cut_all());
1117 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1119 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1121 tact->set_active (_monitor->dim_all());
1125 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1127 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1129 tact->set_active (_monitor->mono());
1133 uint32_t nchans = _monitor->output_streams().n_audio();
1135 assert (nchans == _channel_buttons.size ());
1137 for (uint32_t n = 0; n < nchans; ++n) {
1139 char action_name[32];
1141 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1142 act = ActionManager::get_action (X_("Monitor"), action_name);
1144 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1146 tact->set_active (_monitor->cut (n));
1150 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1151 act = ActionManager::get_action (X_("Monitor"), action_name);
1153 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1155 tact->set_active (_monitor->dimmed (n));
1159 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1160 act = ActionManager::get_action (X_("Monitor"), action_name);
1162 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1164 tact->set_active (_monitor->soloed (n));
1168 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1169 act = ActionManager::get_action (X_("Monitor"), action_name);
1171 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1173 tact->set_active (_monitor->inverted (n));
1180 MonitorSection::do_blink (bool onoff)
1182 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1187 audition_blink (onoff);
1191 MonitorSection::audition_blink (bool onoff)
1193 if (_session == 0) {
1197 if (_session->is_auditioning()) {
1198 rude_audition_button.set_active (onoff);
1200 rude_audition_button.set_active (false);
1205 MonitorSection::solo_blink (bool onoff)
1207 if (_session == 0) {
1211 if (_session->soloing() || _session->listening()) {
1212 rude_solo_button.set_active (onoff);
1214 if (_session->soloing()) {
1215 if (_session->solo_isolated()) {
1216 rude_iso_button.set_active (onoff);
1218 rude_iso_button.set_active (false);
1223 rude_solo_button.set_active (false);
1224 rude_iso_button.set_active (false);
1229 MonitorSection::cancel_isolate (GdkEventButton*)
1232 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1233 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1240 MonitorSection::cancel_audition (GdkEventButton*)
1243 _session->cancel_audition();
1248 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1250 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1251 if (tact && tact->get_active() != value) { \
1252 tact->set_active(value); \
1257 MonitorSection::parameter_changed (std::string name)
1259 if (name == "solo-control-is-listen-control") {
1260 update_solo_model ();
1261 } else if (name == "listen-position") {
1262 update_solo_model ();
1263 } else if (name == "solo-mute-override") {
1264 SYNCHRONIZE_TOGGLE_ACTION(
1265 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1266 Config->get_solo_mute_override ())
1267 } else if (name == "exclusive-solo") {
1268 SYNCHRONIZE_TOGGLE_ACTION(
1269 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1270 Config->get_exclusive_solo ())
1275 MonitorSection::assign_controllables ()
1277 boost::shared_ptr<Controllable> none;
1279 if (!gain_control) {
1280 /* too early - GUI controls not set up yet */
1285 solo_cut_control->set_controllable (_session->solo_cut_control());
1286 solo_cut_display->set_controllable (_session->solo_cut_control());
1288 solo_cut_control->set_controllable (none);
1289 solo_cut_display->set_controllable (none);
1293 gain_control->set_controllable (_route->gain_control());
1294 gain_display->set_controllable (_route->gain_control());
1296 gain_control->set_controllable (none);
1301 cut_all_button.set_controllable (_monitor->cut_control());
1302 cut_all_button.watch ();
1303 dim_all_button.set_controllable (_monitor->dim_control());
1304 dim_all_button.watch ();
1305 mono_button.set_controllable (_monitor->mono_control());
1306 mono_button.watch ();
1308 dim_control->set_controllable (_monitor->dim_level_control ());
1309 dim_display->set_controllable (_monitor->dim_level_control ());
1310 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1311 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1315 cut_all_button.set_controllable (none);
1316 dim_all_button.set_controllable (none);
1317 mono_button.set_controllable (none);
1319 dim_control->set_controllable (none);
1320 dim_display->set_controllable (none);
1321 solo_boost_control->set_controllable (none);
1322 solo_boost_display->set_controllable (none);
1327 MonitorSection::state_id() const
1329 return "monitor-section";
1333 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1335 using namespace Menu_Helpers;
1337 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1341 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1342 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1346 if (i != output_menu_bundles.end()) {
1350 output_menu_bundles.push_back (b);
1352 MenuList& citems = output_menu.items();
1354 std::string n = b->name ();
1355 replace_all (n, "_", " ");
1357 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1361 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1364 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1366 if (std::find (current.begin(), current.end(), c) == current.end()) {
1367 _route->output()->connect_ports_to_bundle (c, true, this);
1369 _route->output()->disconnect_ports_from_bundle (c, this);
1374 MonitorSection::output_release (GdkEventButton *ev)
1376 switch (ev->button) {
1378 edit_output_configuration ();
1385 struct RouteCompareByName {
1386 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1387 return a->name().compare (b->name()) < 0;
1392 MonitorSection::output_press (GdkEventButton *ev)
1394 using namespace Menu_Helpers;
1396 MessageDialog msg (_("No session - no I/O changes are possible"));
1401 MenuList& citems = output_menu.items();
1402 switch (ev->button) {
1405 return false; //wait for the mouse-up to pop the dialog
1409 output_menu.set_name ("ArdourContextMenu");
1411 output_menu_bundles.clear ();
1413 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1415 citems.push_back (SeparatorElem());
1416 uint32_t const n_with_separator = citems.size ();
1418 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1420 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1422 /* give user bundles first chance at being in the menu */
1424 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1425 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1426 maybe_add_bundle_to_output_menu (*i, current);
1430 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1431 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1432 maybe_add_bundle_to_output_menu (*i, current);
1436 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1437 RouteList copy = *routes;
1438 copy.sort (RouteCompareByName ());
1439 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1440 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1443 if (citems.size() == n_with_separator) {
1444 /* no routes added; remove the separator */
1448 citems.push_back (SeparatorElem());
1449 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1451 output_menu.popup (1, ev->time);
1462 MonitorSection::update_output_display ()
1464 if (!_route || !_monitor || _session->deletion_in_progress()) {
1470 boost::shared_ptr<Port> port;
1471 vector<string> port_connections;
1473 uint32_t total_connection_count = 0;
1474 uint32_t io_connection_count = 0;
1475 uint32_t ardour_connection_count = 0;
1476 uint32_t system_connection_count = 0;
1477 uint32_t other_connection_count = 0;
1479 ostringstream label;
1481 bool have_label = false;
1482 bool each_io_has_one_connection = true;
1484 string connection_name;
1485 string ardour_track_name;
1486 string other_connection_type;
1487 string system_ports;
1490 ostringstream tooltip;
1491 char * tooltip_cstr;
1493 io_count = _route->n_outputs().n_total();
1494 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1497 for (io_index = 0; io_index < io_count; ++io_index) {
1499 port = _route->output()->nth (io_index);
1501 //ignore any port connections that don't match our DataType
1502 if (port->type() != DataType::AUDIO) {
1506 port_connections.clear ();
1507 port->get_connections(port_connections);
1508 io_connection_count = 0;
1510 if (!port_connections.empty()) {
1511 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1513 string& connection_name (*i);
1515 if (connection_name.find("system:") == 0) {
1516 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1519 if (io_connection_count == 0) {
1520 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1522 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1525 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1528 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1529 if (ardour_track_name.empty()) {
1530 // "ardour:Master/in 1" -> "ardour:Master/"
1531 string::size_type slash = connection_name.find("/");
1532 if (slash != string::npos) {
1533 ardour_track_name = connection_name.substr(0, slash + 1);
1537 if (connection_name.find(ardour_track_name) == 0) {
1538 ++ardour_connection_count;
1540 } else if (!pn.empty()) {
1541 if (system_ports.empty()) {
1544 system_ports += "/" + pn;
1546 if (connection_name.find("system:") == 0) {
1547 ++system_connection_count;
1549 } else if (connection_name.find("system:") == 0) {
1550 // "system:playback_123" -> "123"
1551 system_port = connection_name.substr(16);
1552 if (system_ports.empty()) {
1553 system_ports += system_port;
1555 system_ports += "/" + system_port;
1558 ++system_connection_count;
1560 if (other_connection_type.empty()) {
1561 // "jamin:in 1" -> "jamin:"
1562 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1565 if (connection_name.find(other_connection_type) == 0) {
1566 ++other_connection_count;
1570 ++total_connection_count;
1571 ++io_connection_count;
1575 if (io_connection_count != 1) {
1576 each_io_has_one_connection = false;
1580 if (total_connection_count == 0) {
1581 tooltip << endl << _("Disconnected");
1584 tooltip_cstr = new char[tooltip.str().size() + 1];
1585 strcpy(tooltip_cstr, tooltip.str().c_str());
1587 set_tooltip (output_button, tooltip_cstr, "");
1589 if (each_io_has_one_connection) {
1590 if (total_connection_count == ardour_connection_count) {
1591 // all connections are to the same track in ardour
1592 // "ardour:Master/" -> "Master"
1593 string::size_type slash = ardour_track_name.find("/");
1594 if (slash != string::npos) {
1595 label << ardour_track_name.substr(7, slash - 7);
1598 } else if (total_connection_count == system_connection_count) {
1599 // all connections are to system ports
1600 label << system_ports;
1602 } else if (total_connection_count == other_connection_count) {
1603 // all connections are to the same external program eg jamin
1604 // "jamin:" -> "jamin"
1605 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1611 if (total_connection_count == 0) {
1615 // Odd configuration
1616 label << "*" << total_connection_count << "*";
1620 output_button->set_text (label.str());
1624 MonitorSection::disconnect_output ()
1627 _route->output()->disconnect(this);
1632 MonitorSection::edit_output_configuration ()
1634 if (_output_selector == 0) {
1635 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1637 _output_selector->present ();
1641 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1646 boost::shared_ptr<Port> a = wa.lock ();
1647 boost::shared_ptr<Port> b = wb.lock ();
1648 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1649 update_output_display ();
1654 MonitorSection::load_bindings ()
1656 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1660 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1662 boost::shared_ptr<Processor> processor (p.lock ());
1663 if (!processor || !processor->display_to_user()) {
1666 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1673 MonitorSection::count_processors ()
1675 uint32_t processor_count = 0;
1677 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1679 return processor_count;
1683 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1685 update_processor_box ();
1689 MonitorSection::action_proxy0 (enum MonitorActions action)
1691 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1705 case ToggleExclusiveSolo:
1706 ms->toggle_exclusive_solo ();
1708 case ToggleMuteOverridesSolo:
1709 ms->toggle_mute_overrides_solo ();
1711 case SoloUseInPlace:
1712 ms->solo_use_in_place ();
1715 ms->solo_use_afl ();
1718 ms->solo_use_pfl ();
1720 case ToggleMonitorProcessorBox:
1721 ms->update_processor_box ();
1727 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1729 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1735 ms->cut_channel (chn);
1738 ms->dim_channel (chn);
1741 ms->solo_channel (chn);
1744 ms->invert_channel (chn);