2 Copyright (C) 2012 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gdkmm/pixbuf.h>
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
26 #include "gtkmm2ext/actions.h"
27 #include "gtkmm2ext/utils.h"
29 #include <gtkmm/menu.h>
30 #include <gtkmm/menuitem.h>
32 #include "widgets/tearoff.h"
33 #include "widgets/tooltips.h"
35 #include "ardour/amp.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/monitor_processor.h"
38 #include "ardour/port.h"
39 #include "ardour/route.h"
40 #include "ardour/solo_isolate_control.h"
41 #include "ardour/user_bundle.h"
42 #include "ardour/plugin_manager.h"
44 #include "ardour_ui.h"
45 #include "gui_thread.h"
47 #include "monitor_section.h"
48 #include "public_editor.h"
50 #include "ui_config.h"
55 using namespace ARDOUR;
56 using namespace ArdourWidgets;
57 using namespace ARDOUR_UI_UTILS;
59 using namespace Gtkmm2ext;
63 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
64 Gtkmm2ext::ActionMap MonitorSection::myactions (X_("monitor section"));
65 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
67 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
69 MonitorSection::MonitorSection (Session* s)
70 : SessionHandlePtr (s)
74 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
75 , *channel_table_scroller.get_vadjustment ())
78 , solo_boost_control (0)
79 , solo_cut_control (0)
82 , solo_boost_display (0)
83 , solo_cut_display (0)
84 , _output_selector (0)
85 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
86 , afl_button (_("AFL"), ArdourButton::led_default_elements)
87 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
88 , exclusive_solo_button (ArdourButton::led_default_elements)
89 , solo_mute_override_button (ArdourButton::led_default_elements)
90 , toggle_processorbox_button (ArdourButton::default_elements)
91 , _inhibit_solo_model_update (false)
93 , _ui_initialized (false)
96 using namespace Menu_Helpers;
98 Glib::RefPtr<Action> act;
100 if (!monitor_actions) {
105 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
107 set_data ("ardour-bindings", bindings);
109 _plugin_selector = new PluginSelector (PluginManager::instance());
110 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
111 insert_box->set_no_show_all ();
113 // TODO allow keyboard shortcuts in ProcessorBox
117 /* Rude Solo & Solo Isolated */
118 rude_solo_button.set_text (_("Soloing"));
119 rude_solo_button.set_name ("rude solo");
120 rude_solo_button.show ();
122 rude_iso_button.set_text (_("Isolated"));
123 rude_iso_button.set_name ("rude isolate");
124 rude_iso_button.show ();
126 rude_audition_button.set_text (_("Auditioning"));
127 rude_audition_button.set_name ("rude audition");
128 rude_audition_button.show ();
130 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
132 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
133 rude_solo_button.set_related_action (act);
134 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
136 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
137 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
139 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
140 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
142 /* SIP, AFL, PFL radio */
144 solo_in_place_button.set_name ("monitor section solo model");
145 afl_button.set_name ("monitor section solo model");
146 pfl_button.set_name ("monitor section solo model");
148 solo_in_place_button.set_led_left (true);
149 afl_button.set_led_left (true);
150 pfl_button.set_led_left (true);
152 solo_in_place_button.show ();
156 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
157 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
159 solo_in_place_button.set_related_action (act);
162 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
163 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
165 afl_button.set_related_action (act);
168 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
169 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
171 pfl_button.set_related_action (act);
174 /* Solo option buttons */
175 exclusive_solo_button.set_text (_("Excl. Solo"));
176 exclusive_solo_button.set_name (X_("monitor section solo option"));
177 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
179 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
181 exclusive_solo_button.set_related_action (act);
184 solo_mute_override_button.set_text (_("Solo ยป Mute"));
185 solo_mute_override_button.set_name (X_("monitor section solo option"));
186 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
188 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
190 solo_mute_override_button.set_related_action (act);
193 /* Processor Box hide/shos */
194 toggle_processorbox_button.set_text (_("Processors"));
195 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
196 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
198 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
199 toggle_processorbox_button.set_related_action (proctoggle);
202 Label* solo_boost_label;
203 Label* solo_cut_label;
206 /* Solo Boost Knob */
208 solo_boost_control = new ArdourKnob ();
209 solo_boost_control->set_name("monitor section knob");
210 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
211 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
213 solo_boost_display = new ArdourDisplay ();
214 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
215 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
216 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
217 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
218 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
220 solo_boost_label = manage (new Label (_("Solo Boost")));
224 solo_cut_control = new ArdourKnob ();
225 solo_cut_control->set_name ("monitor section knob");
226 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
227 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
229 solo_cut_display = new ArdourDisplay ();
230 solo_cut_display->set_name("monitor section dropdown"); // XXX
231 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
232 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
233 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
234 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
235 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
236 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
238 solo_cut_label = manage (new Label (_("SiP Cut")));
242 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
243 dim_control->set_name ("monitor section knob");
244 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
245 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
247 dim_display = new ArdourDisplay ();
248 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
249 dim_display->add_controllable_preset(_("0 dB"), 0.0);
250 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
251 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
252 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
253 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
255 dim_label = manage (new Label (_("Dim")));
258 cut_all_button.set_text (_("Mute"));
259 cut_all_button.set_name ("mute button");
260 cut_all_button.set_size_request (-1, PX_SCALE(30));
261 cut_all_button.show ();
263 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
265 cut_all_button.set_related_action (act);
269 dim_all_button.set_text (_("Dim"));
270 dim_all_button.set_name ("monitor section dim");
271 dim_all_button.set_size_request (-1, PX_SCALE(25));
272 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
274 dim_all_button.set_related_action (act);
278 mono_button.set_text (_("Mono"));
279 mono_button.set_name ("monitor section mono");
280 mono_button.set_size_request (-1, PX_SCALE(25));
281 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
283 mono_button.set_related_action (act);
288 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
289 gain_control->set_name("monitor section knob");
290 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
292 gain_display = new ArdourDisplay ();
293 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
294 gain_display->add_controllable_preset(_("0 dB"), 0.0);
295 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
296 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
297 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
298 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
299 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
301 Label* output_label = manage (new Label (_("Output")));
302 output_label->set_name (X_("MonitorSectionLabel"));
304 output_button = new ArdourButton ();
305 output_button->set_text (_("Output"));
306 output_button->set_name (X_("monitor section cut")); // XXX
307 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
308 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
310 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
311 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
312 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
313 channel_table_scroller.show ();
314 channel_table_scroller.add (channel_table_viewport);
316 channel_size_group->add_widget (channel_table_header);
317 channel_table_header.resize (1, 5);
319 Label* l1 = manage (new Label (X_(" ")));
320 l1->set_name (X_("MonitorSectionLabel"));
321 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
323 l1 = manage (new Label (_("Mute")));
324 l1->set_name (X_("MonitorSectionLabel"));
325 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
327 l1 = manage (new Label (_("Dim")));
328 l1->set_name (X_("MonitorSectionLabel"));
329 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
331 l1 = manage (new Label (_("Solo")));
332 l1->set_name (X_("MonitorSectionLabel"));
333 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
335 l1 = manage (new Label (_("Inv")));
336 l1->set_name (X_("MonitorSectionLabel"));
337 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
339 channel_table_header.show ();
342 /****************************************************************************
343 * LAYOUT top to bottom
346 // solo, iso information
347 HBox* rude_box = manage (new HBox);
348 rude_box->set_spacing (PX_SCALE(4));
349 rude_box->set_homogeneous (true);
350 rude_box->pack_start (rude_solo_button, true, true);
351 rude_box->pack_start (rude_iso_button, true, true);
353 // solo options (right align)
354 HBox* tbx1 = manage (new HBox);
355 tbx1->pack_end (exclusive_solo_button, false, false);
357 HBox* tbx2 = manage (new HBox);
358 tbx2->pack_end (solo_mute_override_button, false, false);
360 HBox* tbx3 = manage (new HBox);
361 tbx3->pack_end (toggle_processorbox_button, false, false);
363 HBox* tbx0 = manage (new HBox); // space
365 // combined solo mode (Sip, AFL, PFL) & solo options
366 Table *solo_tbl = manage (new Table);
367 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
369 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
370 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
371 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
372 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
373 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
375 // boost, cut, dim volume control
376 Table *level_tbl = manage (new Table);
377 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
378 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
379 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
381 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
382 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
383 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
385 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
386 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
387 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
390 HBox* mono_dim_box = manage (new HBox);
391 mono_dim_box->set_spacing (PX_SCALE(4));
392 mono_dim_box->set_homogeneous (true);
393 mono_dim_box->pack_start (mono_button, true, true);
394 mono_dim_box->pack_end (dim_all_button, true, true);
397 Label* spin_label = manage (new Label (_("Monitor")));
398 VBox* spin_packer = manage (new VBox);
399 spin_packer->set_spacing (PX_SCALE(2));
400 spin_packer->pack_start (*spin_label, false, false);
401 spin_packer->pack_start (*gain_control, false, false);
402 spin_packer->pack_start (*gain_display, false, false);
404 master_packer.pack_start (*spin_packer, true, false);
406 // combined gain section (channels, mute, dim)
407 VBox* lower_packer = manage (new VBox);
408 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
409 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
410 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
411 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
413 // calc height of mixer scrollbar
414 int scrollbar_height = 0;
416 Gtk::Window window (WINDOW_TOPLEVEL);
417 HScrollbar scrollbar;
418 window.add (scrollbar);
419 scrollbar.set_name ("MixerWindow");
420 scrollbar.ensure_style();
421 Gtk::Requisition requisition(scrollbar.size_request ());
422 scrollbar_height = requisition.height;
425 // output port select
426 VBox* out_packer = manage (new VBox);
427 out_packer->set_spacing (PX_SCALE(2));
428 out_packer->pack_start (*output_label, false, false);
429 out_packer->pack_start (*output_button, false, false);
431 /****************************************************************************
434 vpacker.set_border_width (PX_SCALE(3));
435 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
436 vpacker.pack_start (rude_audition_button, false, false, 0);
437 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
438 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
439 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
440 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
441 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
442 vpacker.pack_end (*out_packer, false, false,
444 scrollbar_height - 2 /* no outer sample */
446 scrollbar_height + 2 /* sample borders */
450 hpacker.set_spacing (0);
451 hpacker.pack_start (vpacker, true, true);
455 gain_control->show_all ();
456 gain_display->show_all ();
457 dim_control->show_all ();
458 dim_display->show_all();
459 solo_boost_control->show_all ();
460 solo_boost_display->show_all();
462 mono_dim_box->show ();
463 spin_packer->show ();
464 master_packer.show ();
467 solo_tbl->show_all();
469 lower_packer->show ();
476 assign_controllables ();
478 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
479 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
481 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
482 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
483 set_flags (CAN_FOCUS);
485 _tearoff = new TearOff (*this);
487 if (!UIConfiguration::instance().get_floating_monitor_section()) {
488 /* if torn off, make this a normal window
489 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
491 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
493 _tearoff->tearoff_window().set_title (X_("Monitor"));
494 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
496 update_output_display ();
497 update_processor_box ();
498 _ui_initialized = true;
500 /* catch changes that affect us */
501 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
502 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
504 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
507 MonitorSection::~MonitorSection ()
509 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
513 _channel_buttons.clear ();
514 output_changed_connections.drop_connections ();
516 delete insert_box; insert_box = 0;
517 delete output_button; output_button = 0;
518 delete gain_control; gain_control = 0;
519 delete gain_display; gain_display = 0;
520 delete dim_control; dim_control = 0;
521 delete dim_display; dim_display = 0;
522 delete solo_boost_control; solo_boost_control = 0;
523 delete solo_boost_display; solo_boost_display = 0;
524 delete solo_cut_control; solo_cut_control = 0;
525 delete solo_cut_display; solo_cut_display = 0;
526 delete _tearoff; _tearoff = 0;
527 delete _output_selector; _output_selector = 0;
528 delete channel_table; channel_table = 0;
532 MonitorSection::enter_handler (GdkEventCrossing* ev)
539 MonitorSection::leave_handler (GdkEventCrossing* ev)
541 switch (ev->detail) {
542 case GDK_NOTIFY_INFERIOR:
548 /* cancel focus if we're not torn off. With X11 WM's that do
549 * focus-follows-mouse, focus will be taken from us anyway.
552 Widget* top = get_toplevel();
554 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
555 Window* win = dynamic_cast<Window*> (top);
556 gtk_window_set_focus (win->gobj(), 0);
563 MonitorSection::update_processor_box ()
565 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
567 if (count_processors () > 0 && !show_processor_box) {
568 toggle_processorbox_button.set_name (X_("monitor section processors present"));
570 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
573 if (insert_box->is_visible() == show_processor_box) {
577 if (show_processor_box) {
578 if (master_packer.get_parent()) {
579 master_packer.get_parent()->remove (master_packer);
582 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
584 if (master_packer.get_parent()) {
585 master_packer.get_parent()->remove (master_packer);
588 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
593 MonitorSection::set_session (Session* s)
595 RouteUI::set_session (s);
596 _plugin_selector->set_session (_session);
600 _route = _session->monitor_out ();
603 /* session with monitor section */
604 _monitor = _route->monitor_control ();
605 assign_controllables ();
606 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
607 boost::bind (&MonitorSection::update_output_display, this),
609 insert_box->set_route (_route);
610 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
611 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
612 if (_ui_initialized) {
613 update_processor_box ();
616 /* session with no monitor section */
617 output_changed_connections.drop_connections();
620 delete _output_selector;
621 _output_selector = 0;
629 output_changed_connections.drop_connections();
632 control_connections.drop_connections ();
633 rude_iso_button.unset_active_state ();
634 rude_solo_button.unset_active_state ();
635 delete _output_selector;
636 _output_selector = 0;
638 assign_controllables ();
642 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
644 cut.set_name (X_("mute button"));
645 dim.set_name (X_("monitor section dim"));
646 solo.set_name (X_("solo button"));
647 invert.set_name (X_("invert button"));
649 cut.unset_flags (Gtk::CAN_FOCUS);
650 dim.unset_flags (Gtk::CAN_FOCUS);
651 solo.unset_flags (Gtk::CAN_FOCUS);
652 invert.unset_flags (Gtk::CAN_FOCUS);
656 MonitorSection::populate_buttons ()
663 channel_size_group->remove_widget (*channel_table);
664 delete channel_table;
667 channel_table = new Gtk::Table();
669 channel_table->set_col_spacings (6);
670 channel_table->set_row_spacings (6);
671 channel_table->set_homogeneous (true);
673 channel_size_group->add_widget (*channel_table);
674 channel_table->show ();
675 table_hpacker.pack_start (*channel_table, true, true);
677 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
680 _channel_buttons.clear ();
682 Glib::RefPtr<Action> act;
683 uint32_t nchans = _monitor->output_streams().n_audio();
685 channel_table->resize (nchans, 5);
687 const uint32_t row_offset = 0;
689 for (uint32_t i = 0; i < nchans; ++i) {
702 snprintf (buf, sizeof (buf), "%d", i+1);
706 Label* label = manage (new Label (l));
707 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
709 ChannelButtonSet* cbs = new ChannelButtonSet;
711 _channel_buttons.push_back (cbs);
713 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
714 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
715 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
716 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
718 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
719 act = ActionManager::get_action (X_("Monitor"), buf);
721 cbs->cut.set_related_action (act);
724 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
725 act = ActionManager::get_action (X_("Monitor"), buf);
727 cbs->dim.set_related_action (act);
730 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
731 act = ActionManager::get_action (X_("Monitor"), buf);
733 cbs->solo.set_related_action (act);
736 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
737 act = ActionManager::get_action (X_("Monitor"), buf);
739 cbs->invert.set_related_action (act);
743 channel_table->show_all ();
745 if (channel_table_scroller.get_parent()) {
746 /* scroller is packed, so remove it */
747 channel_table_packer.remove (channel_table_scroller);
750 if (table_hpacker.get_parent () == &channel_table_packer) {
751 /* this occurs when the table hpacker is directly
752 packed, so remove it.
754 channel_table_packer.remove (table_hpacker);
755 } else if (table_hpacker.get_parent()) {
756 channel_table_viewport.remove ();
760 /* put the table into a scrolled window, and then put
761 * that into the channel vpacker, after the table header
763 channel_table_viewport.add (table_hpacker);
764 channel_table_packer.pack_start (channel_table_scroller, true, true);
765 channel_table_viewport.show ();
766 channel_table_scroller.show ();
769 /* just put the channel table itself into the channel
770 * vpacker, after the table header
772 channel_table_packer.pack_start (table_hpacker, true, true);
773 channel_table_scroller.hide ();
775 table_hpacker.show ();
776 channel_table->show ();
780 MonitorSection::toggle_exclusive_solo ()
786 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
788 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
789 Config->set_exclusive_solo (tact->get_active());
795 MonitorSection::toggle_mute_overrides_solo ()
801 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
803 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
804 Config->set_solo_mute_override (tact->get_active());
809 MonitorSection::dim_all ()
815 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
817 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
818 _monitor->set_dim_all (tact->get_active());
824 MonitorSection::cut_all ()
830 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
832 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
833 _monitor->set_cut_all (tact->get_active());
838 MonitorSection::mono ()
844 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
846 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
847 _monitor->set_mono (tact->get_active());
852 MonitorSection::cut_channel (uint32_t chn)
859 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
861 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
863 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
864 _monitor->set_cut (chn, tact->get_active());
869 MonitorSection::dim_channel (uint32_t chn)
876 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
878 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
880 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
881 _monitor->set_dim (chn, tact->get_active());
887 MonitorSection::solo_channel (uint32_t chn)
894 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
896 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
898 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
899 _monitor->set_solo (chn, tact->get_active());
905 MonitorSection::invert_channel (uint32_t chn)
912 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
914 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
916 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
917 _monitor->set_polarity (chn, tact->get_active());
922 MonitorSection::register_actions ()
926 Glib::RefPtr<Action> act;
928 monitor_actions = myactions.create_action_group (X_("Monitor"));
930 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
931 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
933 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
934 tact->set_active (Config->get_exclusive_solo());
936 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
937 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
939 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
940 tact->set_active (Config->get_solo_mute_override());
942 for (uint32_t chn = 0; chn < 16; ++chn) {
944 action_name = string_compose (X_("monitor-cut-%1"), chn);
945 action_descr = string_compose (_("Cut monitor channel %1"), chn);
946 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
947 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
949 action_name = string_compose (X_("monitor-dim-%1"), chn);
950 action_descr = string_compose (_("Dim monitor channel %1"), chn);
951 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
952 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
954 action_name = string_compose (X_("monitor-solo-%1"), chn);
955 action_descr = string_compose (_("Solo monitor channel %1"), chn);
956 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
957 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
959 action_name = string_compose (X_("monitor-invert-%1"), chn);
960 action_descr = string_compose (_("Invert monitor channel %1"), chn);
961 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
962 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
967 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
968 RadioAction::Group solo_group;
970 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
971 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
972 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
973 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
974 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
975 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
977 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
978 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
983 MonitorSection::solo_use_in_place ()
985 /* this is driven by a toggle on a radio group, and so is invoked twice,
986 once for the item that became inactive and once for the one that became
990 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
993 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
995 if (!ract->get_active ()) {
996 /* We are turning SiP off, which means that AFL or PFL will be turned on
997 shortly; don't update the solo model in the mean time, as if the currently
998 configured listen position is not the one that is about to be turned on,
999 things will go wrong.
1001 _inhibit_solo_model_update = true;
1003 Config->set_solo_control_is_listen_control (!ract->get_active());
1004 _inhibit_solo_model_update = false;
1010 MonitorSection::solo_use_afl ()
1012 /* this is driven by a toggle on a radio group, and so is invoked twice,
1013 once for the item that became inactive and once for the one that became
1017 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1019 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1021 if (ract->get_active()) {
1022 Config->set_solo_control_is_listen_control (true);
1023 Config->set_listen_position (AfterFaderListen);
1030 MonitorSection::solo_use_pfl ()
1032 /* this is driven by a toggle on a radio group, and so is invoked twice,
1033 once for the item that became inactive and once for the one that became
1037 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1039 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1041 if (ract->get_active()) {
1042 Config->set_solo_control_is_listen_control (true);
1043 Config->set_listen_position (PreFaderListen);
1050 MonitorSection::update_solo_model ()
1052 if (_inhibit_solo_model_update) {
1056 const char* action_name = 0;
1057 Glib::RefPtr<Action> act;
1059 if (Config->get_solo_control_is_listen_control()) {
1060 switch (Config->get_listen_position()) {
1061 case AfterFaderListen:
1062 action_name = X_("solo-use-afl");
1064 case PreFaderListen:
1065 action_name = X_("solo-use-pfl");
1069 action_name = X_("solo-use-in-place");
1072 act = ActionManager::get_action (X_("Solo"), action_name);
1075 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1077 /* because these are radio buttons, one of them will be
1078 active no matter what. to trigger a change in the
1079 action so that the view picks it up, toggle it.
1081 if (ract->get_active()) {
1082 ract->set_active (false);
1084 ract->set_active (true);
1091 MonitorSection::map_state ()
1093 if (!_route || !_monitor) {
1097 update_solo_model ();
1099 Glib::RefPtr<Action> act;
1100 Glib::RefPtr<ToggleAction> tact;
1102 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1104 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1106 tact->set_active (_monitor->cut_all());
1110 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1112 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1114 tact->set_active (_monitor->dim_all());
1118 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1120 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1122 tact->set_active (_monitor->mono());
1126 uint32_t nchans = _monitor->output_streams().n_audio();
1128 assert (nchans == _channel_buttons.size ());
1130 for (uint32_t n = 0; n < nchans; ++n) {
1132 char action_name[32];
1134 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1135 act = ActionManager::get_action (X_("Monitor"), action_name);
1137 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1139 tact->set_active (_monitor->cut (n));
1143 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1144 act = ActionManager::get_action (X_("Monitor"), action_name);
1146 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1148 tact->set_active (_monitor->dimmed (n));
1152 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1153 act = ActionManager::get_action (X_("Monitor"), action_name);
1155 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1157 tact->set_active (_monitor->soloed (n));
1161 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1162 act = ActionManager::get_action (X_("Monitor"), action_name);
1164 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1166 tact->set_active (_monitor->inverted (n));
1173 MonitorSection::do_blink (bool onoff)
1175 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1180 audition_blink (onoff);
1184 MonitorSection::audition_blink (bool onoff)
1186 if (_session == 0) {
1190 if (_session->is_auditioning()) {
1191 rude_audition_button.set_active (onoff);
1193 rude_audition_button.set_active (false);
1198 MonitorSection::solo_blink (bool onoff)
1200 if (_session == 0) {
1204 if (_session->soloing() || _session->listening()) {
1205 rude_solo_button.set_active (onoff);
1207 if (_session->soloing()) {
1208 if (_session->solo_isolated()) {
1209 rude_iso_button.set_active (onoff);
1211 rude_iso_button.set_active (false);
1216 rude_solo_button.set_active (false);
1217 rude_iso_button.set_active (false);
1222 MonitorSection::cancel_isolate (GdkEventButton*)
1225 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1226 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1233 MonitorSection::cancel_audition (GdkEventButton*)
1236 _session->cancel_audition();
1241 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1243 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1244 if (tact && tact->get_active() != value) { \
1245 tact->set_active(value); \
1250 MonitorSection::parameter_changed (std::string name)
1252 if (name == "solo-control-is-listen-control") {
1253 update_solo_model ();
1254 } else if (name == "listen-position") {
1255 update_solo_model ();
1256 } else if (name == "solo-mute-override") {
1257 SYNCHRONIZE_TOGGLE_ACTION(
1258 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1259 Config->get_solo_mute_override ())
1260 } else if (name == "exclusive-solo") {
1261 SYNCHRONIZE_TOGGLE_ACTION(
1262 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1263 Config->get_exclusive_solo ())
1268 MonitorSection::assign_controllables ()
1270 boost::shared_ptr<Controllable> none;
1272 if (!gain_control) {
1273 /* too early - GUI controls not set up yet */
1278 solo_cut_control->set_controllable (_session->solo_cut_control());
1279 solo_cut_display->set_controllable (_session->solo_cut_control());
1281 solo_cut_control->set_controllable (none);
1282 solo_cut_display->set_controllable (none);
1286 gain_control->set_controllable (_route->gain_control());
1287 gain_display->set_controllable (_route->gain_control());
1289 gain_control->set_controllable (none);
1294 cut_all_button.set_controllable (_monitor->cut_control());
1295 cut_all_button.watch ();
1296 dim_all_button.set_controllable (_monitor->dim_control());
1297 dim_all_button.watch ();
1298 mono_button.set_controllable (_monitor->mono_control());
1299 mono_button.watch ();
1301 dim_control->set_controllable (_monitor->dim_level_control ());
1302 dim_display->set_controllable (_monitor->dim_level_control ());
1303 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1304 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1308 cut_all_button.set_controllable (none);
1309 dim_all_button.set_controllable (none);
1310 mono_button.set_controllable (none);
1312 dim_control->set_controllable (none);
1313 dim_display->set_controllable (none);
1314 solo_boost_control->set_controllable (none);
1315 solo_boost_display->set_controllable (none);
1320 MonitorSection::state_id() const
1322 return "monitor-section";
1326 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1328 using namespace Menu_Helpers;
1330 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1334 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1335 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1339 if (i != output_menu_bundles.end()) {
1343 output_menu_bundles.push_back (b);
1345 MenuList& citems = output_menu.items();
1347 std::string n = b->name ();
1348 replace_all (n, "_", " ");
1350 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1354 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1357 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1359 if (std::find (current.begin(), current.end(), c) == current.end()) {
1360 _route->output()->connect_ports_to_bundle (c, true, this);
1362 _route->output()->disconnect_ports_from_bundle (c, this);
1367 MonitorSection::output_release (GdkEventButton *ev)
1369 switch (ev->button) {
1371 edit_output_configuration ();
1378 struct RouteCompareByName {
1379 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1380 return a->name().compare (b->name()) < 0;
1385 MonitorSection::output_press (GdkEventButton *ev)
1387 using namespace Menu_Helpers;
1389 MessageDialog msg (_("No session - no I/O changes are possible"));
1394 MenuList& citems = output_menu.items();
1395 switch (ev->button) {
1398 return false; //wait for the mouse-up to pop the dialog
1402 output_menu.set_name ("ArdourContextMenu");
1404 output_menu_bundles.clear ();
1406 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1408 citems.push_back (SeparatorElem());
1409 uint32_t const n_with_separator = citems.size ();
1411 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1413 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1415 /* give user bundles first chance at being in the menu */
1417 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1418 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1419 maybe_add_bundle_to_output_menu (*i, current);
1423 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1424 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1425 maybe_add_bundle_to_output_menu (*i, current);
1429 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1430 RouteList copy = *routes;
1431 copy.sort (RouteCompareByName ());
1432 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1433 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1436 if (citems.size() == n_with_separator) {
1437 /* no routes added; remove the separator */
1441 citems.push_back (SeparatorElem());
1442 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1444 output_menu.popup (1, ev->time);
1455 MonitorSection::update_output_display ()
1457 if (!_route || !_monitor || _session->deletion_in_progress()) {
1463 boost::shared_ptr<Port> port;
1464 vector<string> port_connections;
1466 uint32_t total_connection_count = 0;
1467 uint32_t io_connection_count = 0;
1468 uint32_t ardour_connection_count = 0;
1469 uint32_t system_connection_count = 0;
1470 uint32_t other_connection_count = 0;
1472 ostringstream label;
1474 bool have_label = false;
1475 bool each_io_has_one_connection = true;
1477 string connection_name;
1478 string ardour_track_name;
1479 string other_connection_type;
1480 string system_ports;
1483 ostringstream tooltip;
1484 char * tooltip_cstr;
1486 io_count = _route->n_outputs().n_total();
1487 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1490 for (io_index = 0; io_index < io_count; ++io_index) {
1492 port = _route->output()->nth (io_index);
1494 //ignore any port connections that don't match our DataType
1495 if (port->type() != DataType::AUDIO) {
1499 port_connections.clear ();
1500 port->get_connections(port_connections);
1501 io_connection_count = 0;
1503 if (!port_connections.empty()) {
1504 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1506 string& connection_name (*i);
1508 if (connection_name.find("system:") == 0) {
1509 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1512 if (io_connection_count == 0) {
1513 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1515 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1518 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1521 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1522 if (ardour_track_name.empty()) {
1523 // "ardour:Master/in 1" -> "ardour:Master/"
1524 string::size_type slash = connection_name.find("/");
1525 if (slash != string::npos) {
1526 ardour_track_name = connection_name.substr(0, slash + 1);
1530 if (connection_name.find(ardour_track_name) == 0) {
1531 ++ardour_connection_count;
1533 } else if (!pn.empty()) {
1534 if (system_ports.empty()) {
1537 system_ports += "/" + pn;
1539 if (connection_name.find("system:") == 0) {
1540 ++system_connection_count;
1542 } else if (connection_name.find("system:") == 0) {
1543 // "system:playback_123" -> "123"
1544 system_port = connection_name.substr(16);
1545 if (system_ports.empty()) {
1546 system_ports += system_port;
1548 system_ports += "/" + system_port;
1551 ++system_connection_count;
1553 if (other_connection_type.empty()) {
1554 // "jamin:in 1" -> "jamin:"
1555 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1558 if (connection_name.find(other_connection_type) == 0) {
1559 ++other_connection_count;
1563 ++total_connection_count;
1564 ++io_connection_count;
1568 if (io_connection_count != 1) {
1569 each_io_has_one_connection = false;
1573 if (total_connection_count == 0) {
1574 tooltip << endl << _("Disconnected");
1577 tooltip_cstr = new char[tooltip.str().size() + 1];
1578 strcpy(tooltip_cstr, tooltip.str().c_str());
1580 set_tooltip (output_button, tooltip_cstr, "");
1582 if (each_io_has_one_connection) {
1583 if (total_connection_count == ardour_connection_count) {
1584 // all connections are to the same track in ardour
1585 // "ardour:Master/" -> "Master"
1586 string::size_type slash = ardour_track_name.find("/");
1587 if (slash != string::npos) {
1588 label << ardour_track_name.substr(7, slash - 7);
1591 } else if (total_connection_count == system_connection_count) {
1592 // all connections are to system ports
1593 label << system_ports;
1595 } else if (total_connection_count == other_connection_count) {
1596 // all connections are to the same external program eg jamin
1597 // "jamin:" -> "jamin"
1598 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1604 if (total_connection_count == 0) {
1608 // Odd configuration
1609 label << "*" << total_connection_count << "*";
1613 output_button->set_text (label.str());
1617 MonitorSection::disconnect_output ()
1620 _route->output()->disconnect(this);
1625 MonitorSection::edit_output_configuration ()
1627 if (_output_selector == 0) {
1628 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1630 _output_selector->present ();
1634 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1639 boost::shared_ptr<Port> a = wa.lock ();
1640 boost::shared_ptr<Port> b = wb.lock ();
1641 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1642 update_output_display ();
1647 MonitorSection::load_bindings ()
1649 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1653 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1655 boost::shared_ptr<Processor> processor (p.lock ());
1656 if (!processor || !processor->display_to_user()) {
1659 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1666 MonitorSection::count_processors ()
1668 uint32_t processor_count = 0;
1670 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1672 return processor_count;
1676 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1678 update_processor_box ();
1682 MonitorSection::action_proxy0 (enum MonitorActions action)
1684 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1698 case ToggleExclusiveSolo:
1699 ms->toggle_exclusive_solo ();
1701 case ToggleMuteOverridesSolo:
1702 ms->toggle_mute_overrides_solo ();
1704 case SoloUseInPlace:
1705 ms->solo_use_in_place ();
1708 ms->solo_use_afl ();
1711 ms->solo_use_pfl ();
1713 case ToggleMonitorProcessorBox:
1714 ms->update_processor_box ();
1720 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1722 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1728 ms->cut_channel (chn);
1731 ms->dim_channel (chn);
1734 ms->solo_channel (chn);
1737 ms->invert_channel (chn);