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 frame */
446 scrollbar_height + 2 /* frame 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 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
931 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
933 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
934 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
936 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
937 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
939 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
940 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
942 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
943 tact->set_active (Config->get_exclusive_solo());
945 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
946 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
948 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
949 tact->set_active (Config->get_solo_mute_override());
951 for (uint32_t chn = 0; chn < 16; ++chn) {
953 action_name = string_compose (X_("monitor-cut-%1"), chn);
954 action_descr = string_compose (_("Cut monitor channel %1"), chn);
955 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
956 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
958 action_name = string_compose (X_("monitor-dim-%1"), chn);
959 action_descr = string_compose (_("Dim monitor channel %1"), chn);
960 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
961 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
963 action_name = string_compose (X_("monitor-solo-%1"), chn);
964 action_descr = string_compose (_("Solo monitor channel %1"), chn);
965 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
966 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
968 action_name = string_compose (X_("monitor-invert-%1"), chn);
969 action_descr = string_compose (_("Invert monitor channel %1"), chn);
970 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
971 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
976 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
977 RadioAction::Group solo_group;
979 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
980 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
981 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
982 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
983 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
984 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
986 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
987 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
992 MonitorSection::solo_use_in_place ()
994 /* this is driven by a toggle on a radio group, and so is invoked twice,
995 once for the item that became inactive and once for the one that became
999 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
1002 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1004 if (!ract->get_active ()) {
1005 /* We are turning SiP off, which means that AFL or PFL will be turned on
1006 shortly; don't update the solo model in the mean time, as if the currently
1007 configured listen position is not the one that is about to be turned on,
1008 things will go wrong.
1010 _inhibit_solo_model_update = true;
1012 Config->set_solo_control_is_listen_control (!ract->get_active());
1013 _inhibit_solo_model_update = false;
1019 MonitorSection::solo_use_afl ()
1021 /* this is driven by a toggle on a radio group, and so is invoked twice,
1022 once for the item that became inactive and once for the one that became
1026 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1028 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1030 if (ract->get_active()) {
1031 Config->set_solo_control_is_listen_control (true);
1032 Config->set_listen_position (AfterFaderListen);
1039 MonitorSection::solo_use_pfl ()
1041 /* this is driven by a toggle on a radio group, and so is invoked twice,
1042 once for the item that became inactive and once for the one that became
1046 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1048 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1050 if (ract->get_active()) {
1051 Config->set_solo_control_is_listen_control (true);
1052 Config->set_listen_position (PreFaderListen);
1059 MonitorSection::update_solo_model ()
1061 if (_inhibit_solo_model_update) {
1065 const char* action_name = 0;
1066 Glib::RefPtr<Action> act;
1068 if (Config->get_solo_control_is_listen_control()) {
1069 switch (Config->get_listen_position()) {
1070 case AfterFaderListen:
1071 action_name = X_("solo-use-afl");
1073 case PreFaderListen:
1074 action_name = X_("solo-use-pfl");
1078 action_name = X_("solo-use-in-place");
1081 act = ActionManager::get_action (X_("Solo"), action_name);
1084 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1086 /* because these are radio buttons, one of them will be
1087 active no matter what. to trigger a change in the
1088 action so that the view picks it up, toggle it.
1090 if (ract->get_active()) {
1091 ract->set_active (false);
1093 ract->set_active (true);
1100 MonitorSection::map_state ()
1102 if (!_route || !_monitor) {
1106 Glib::RefPtr<Action> act;
1108 update_solo_model ();
1110 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1112 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1114 tact->set_active (_monitor->cut_all());
1118 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1120 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1122 tact->set_active (_monitor->dim_all());
1126 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1128 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1130 tact->set_active (_monitor->mono());
1134 uint32_t nchans = _monitor->output_streams().n_audio();
1136 assert (nchans == _channel_buttons.size ());
1138 for (uint32_t n = 0; n < nchans; ++n) {
1140 char action_name[32];
1142 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1143 act = ActionManager::get_action (X_("Monitor"), action_name);
1145 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1147 tact->set_active (_monitor->cut (n));
1151 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1152 act = ActionManager::get_action (X_("Monitor"), action_name);
1154 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1156 tact->set_active (_monitor->dimmed (n));
1160 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1161 act = ActionManager::get_action (X_("Monitor"), action_name);
1163 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1165 tact->set_active (_monitor->soloed (n));
1169 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1170 act = ActionManager::get_action (X_("Monitor"), action_name);
1172 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1174 tact->set_active (_monitor->inverted (n));
1181 MonitorSection::do_blink (bool onoff)
1183 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1188 audition_blink (onoff);
1192 MonitorSection::audition_blink (bool onoff)
1194 if (_session == 0) {
1198 if (_session->is_auditioning()) {
1199 rude_audition_button.set_active (onoff);
1201 rude_audition_button.set_active (false);
1206 MonitorSection::solo_blink (bool onoff)
1208 if (_session == 0) {
1212 if (_session->soloing() || _session->listening()) {
1213 rude_solo_button.set_active (onoff);
1215 if (_session->soloing()) {
1216 if (_session->solo_isolated()) {
1217 rude_iso_button.set_active (onoff);
1219 rude_iso_button.set_active (false);
1224 rude_solo_button.set_active (false);
1225 rude_iso_button.set_active (false);
1230 MonitorSection::cancel_isolate (GdkEventButton*)
1233 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1234 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1241 MonitorSection::cancel_audition (GdkEventButton*)
1244 _session->cancel_audition();
1249 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1251 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1252 if (tact && tact->get_active() != value) { \
1253 tact->set_active(value); \
1258 MonitorSection::parameter_changed (std::string name)
1260 if (name == "solo-control-is-listen-control") {
1261 update_solo_model ();
1262 } else if (name == "listen-position") {
1263 update_solo_model ();
1264 } else if (name == "solo-mute-override") {
1265 SYNCHRONIZE_TOGGLE_ACTION(
1266 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1267 Config->get_solo_mute_override ())
1268 } else if (name == "exclusive-solo") {
1269 SYNCHRONIZE_TOGGLE_ACTION(
1270 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1271 Config->get_exclusive_solo ())
1276 MonitorSection::assign_controllables ()
1278 boost::shared_ptr<Controllable> none;
1280 if (!gain_control) {
1281 /* too early - GUI controls not set up yet */
1286 solo_cut_control->set_controllable (_session->solo_cut_control());
1287 solo_cut_display->set_controllable (_session->solo_cut_control());
1289 solo_cut_control->set_controllable (none);
1290 solo_cut_display->set_controllable (none);
1294 gain_control->set_controllable (_route->gain_control());
1295 gain_display->set_controllable (_route->gain_control());
1297 gain_control->set_controllable (none);
1302 cut_all_button.set_controllable (_monitor->cut_control());
1303 cut_all_button.watch ();
1304 dim_all_button.set_controllable (_monitor->dim_control());
1305 dim_all_button.watch ();
1306 mono_button.set_controllable (_monitor->mono_control());
1307 mono_button.watch ();
1309 dim_control->set_controllable (_monitor->dim_level_control ());
1310 dim_display->set_controllable (_monitor->dim_level_control ());
1311 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1312 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1316 cut_all_button.set_controllable (none);
1317 dim_all_button.set_controllable (none);
1318 mono_button.set_controllable (none);
1320 dim_control->set_controllable (none);
1321 dim_display->set_controllable (none);
1322 solo_boost_control->set_controllable (none);
1323 solo_boost_display->set_controllable (none);
1328 MonitorSection::state_id() const
1330 return "monitor-section";
1334 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1336 using namespace Menu_Helpers;
1338 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1342 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1343 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1347 if (i != output_menu_bundles.end()) {
1351 output_menu_bundles.push_back (b);
1353 MenuList& citems = output_menu.items();
1355 std::string n = b->name ();
1356 replace_all (n, "_", " ");
1358 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1362 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1365 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1367 if (std::find (current.begin(), current.end(), c) == current.end()) {
1368 _route->output()->connect_ports_to_bundle (c, true, this);
1370 _route->output()->disconnect_ports_from_bundle (c, this);
1375 MonitorSection::output_release (GdkEventButton *ev)
1377 switch (ev->button) {
1379 edit_output_configuration ();
1386 struct RouteCompareByName {
1387 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1388 return a->name().compare (b->name()) < 0;
1393 MonitorSection::output_press (GdkEventButton *ev)
1395 using namespace Menu_Helpers;
1397 MessageDialog msg (_("No session - no I/O changes are possible"));
1402 MenuList& citems = output_menu.items();
1403 switch (ev->button) {
1406 return false; //wait for the mouse-up to pop the dialog
1410 output_menu.set_name ("ArdourContextMenu");
1412 output_menu_bundles.clear ();
1414 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1416 citems.push_back (SeparatorElem());
1417 uint32_t const n_with_separator = citems.size ();
1419 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1421 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1423 /* give user bundles first chance at being in the menu */
1425 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1426 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1427 maybe_add_bundle_to_output_menu (*i, current);
1431 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1432 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1433 maybe_add_bundle_to_output_menu (*i, current);
1437 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1438 RouteList copy = *routes;
1439 copy.sort (RouteCompareByName ());
1440 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1441 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1444 if (citems.size() == n_with_separator) {
1445 /* no routes added; remove the separator */
1449 citems.push_back (SeparatorElem());
1450 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1452 output_menu.popup (1, ev->time);
1463 MonitorSection::update_output_display ()
1465 if (!_route || !_monitor || _session->deletion_in_progress()) {
1471 boost::shared_ptr<Port> port;
1472 vector<string> port_connections;
1474 uint32_t total_connection_count = 0;
1475 uint32_t io_connection_count = 0;
1476 uint32_t ardour_connection_count = 0;
1477 uint32_t system_connection_count = 0;
1478 uint32_t other_connection_count = 0;
1480 ostringstream label;
1482 bool have_label = false;
1483 bool each_io_has_one_connection = true;
1485 string connection_name;
1486 string ardour_track_name;
1487 string other_connection_type;
1488 string system_ports;
1491 ostringstream tooltip;
1492 char * tooltip_cstr;
1494 io_count = _route->n_outputs().n_total();
1495 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1498 for (io_index = 0; io_index < io_count; ++io_index) {
1500 port = _route->output()->nth (io_index);
1502 //ignore any port connections that don't match our DataType
1503 if (port->type() != DataType::AUDIO) {
1507 port_connections.clear ();
1508 port->get_connections(port_connections);
1509 io_connection_count = 0;
1511 if (!port_connections.empty()) {
1512 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1514 string& connection_name (*i);
1516 if (connection_name.find("system:") == 0) {
1517 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1520 if (io_connection_count == 0) {
1521 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1523 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1526 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1529 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1530 if (ardour_track_name.empty()) {
1531 // "ardour:Master/in 1" -> "ardour:Master/"
1532 string::size_type slash = connection_name.find("/");
1533 if (slash != string::npos) {
1534 ardour_track_name = connection_name.substr(0, slash + 1);
1538 if (connection_name.find(ardour_track_name) == 0) {
1539 ++ardour_connection_count;
1541 } else if (!pn.empty()) {
1542 if (system_ports.empty()) {
1545 system_ports += "/" + pn;
1547 if (connection_name.find("system:") == 0) {
1548 ++system_connection_count;
1550 } else if (connection_name.find("system:") == 0) {
1551 // "system:playback_123" -> "123"
1552 system_port = connection_name.substr(16);
1553 if (system_ports.empty()) {
1554 system_ports += system_port;
1556 system_ports += "/" + system_port;
1559 ++system_connection_count;
1561 if (other_connection_type.empty()) {
1562 // "jamin:in 1" -> "jamin:"
1563 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1566 if (connection_name.find(other_connection_type) == 0) {
1567 ++other_connection_count;
1571 ++total_connection_count;
1572 ++io_connection_count;
1576 if (io_connection_count != 1) {
1577 each_io_has_one_connection = false;
1581 if (total_connection_count == 0) {
1582 tooltip << endl << _("Disconnected");
1585 tooltip_cstr = new char[tooltip.str().size() + 1];
1586 strcpy(tooltip_cstr, tooltip.str().c_str());
1588 set_tooltip (output_button, tooltip_cstr, "");
1590 if (each_io_has_one_connection) {
1591 if (total_connection_count == ardour_connection_count) {
1592 // all connections are to the same track in ardour
1593 // "ardour:Master/" -> "Master"
1594 string::size_type slash = ardour_track_name.find("/");
1595 if (slash != string::npos) {
1596 label << ardour_track_name.substr(7, slash - 7);
1599 } else if (total_connection_count == system_connection_count) {
1600 // all connections are to system ports
1601 label << system_ports;
1603 } else if (total_connection_count == other_connection_count) {
1604 // all connections are to the same external program eg jamin
1605 // "jamin:" -> "jamin"
1606 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1612 if (total_connection_count == 0) {
1616 // Odd configuration
1617 label << "*" << total_connection_count << "*";
1621 output_button->set_text (label.str());
1625 MonitorSection::disconnect_output ()
1628 _route->output()->disconnect(this);
1633 MonitorSection::edit_output_configuration ()
1635 if (_output_selector == 0) {
1636 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1638 _output_selector->present ();
1642 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1647 boost::shared_ptr<Port> a = wa.lock ();
1648 boost::shared_ptr<Port> b = wb.lock ();
1649 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1650 update_output_display ();
1655 MonitorSection::load_bindings ()
1657 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1661 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1663 boost::shared_ptr<Processor> processor (p.lock ());
1664 if (!processor || !processor->display_to_user()) {
1667 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1674 MonitorSection::count_processors ()
1676 uint32_t processor_count = 0;
1678 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1680 return processor_count;
1684 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1686 update_processor_box ();
1690 MonitorSection::action_proxy0 (enum MonitorActions action)
1692 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1706 case ToggleExclusiveSolo:
1707 ms->toggle_exclusive_solo ();
1709 case ToggleMuteOverridesSolo:
1710 ms->toggle_mute_overrides_solo ();
1712 case SoloUseInPlace:
1713 ms->solo_use_in_place ();
1716 ms->solo_use_afl ();
1719 ms->solo_use_pfl ();
1721 case ToggleMonitorProcessorBox:
1722 ms->update_processor_box ();
1728 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1730 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1736 ms->cut_channel (chn);
1739 ms->dim_channel (chn);
1742 ms->solo_channel (chn);
1745 ms->invert_channel (chn);