2 Copyright (C) 2012 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gdkmm/pixbuf.h>
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
26 #include "gtkmm2ext/bindable_button.h"
27 #include "gtkmm2ext/tearoff.h"
28 #include "gtkmm2ext/actions.h"
29 #include "gtkmm2ext/utils.h"
31 #include <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
34 #include "ardour/amp.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/monitor_processor.h"
37 #include "ardour/port.h"
38 #include "ardour/route.h"
39 #include "ardour/solo_isolate_control.h"
40 #include "ardour/user_bundle.h"
41 #include "ardour/plugin_manager.h"
43 #include "ardour_ui.h"
44 #include "gui_thread.h"
46 #include "monitor_section.h"
47 #include "public_editor.h"
50 #include "ui_config.h"
55 using namespace ARDOUR;
56 using namespace ARDOUR_UI_UTILS;
58 using namespace Gtkmm2ext;
62 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
63 Gtkmm2ext::ActionMap MonitorSection::myactions (X_("monitor section"));
64 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
66 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
68 MonitorSection::MonitorSection (Session* s)
69 : SessionHandlePtr (s)
73 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
74 , *channel_table_scroller.get_vadjustment ())
77 , solo_boost_control (0)
78 , solo_cut_control (0)
81 , solo_boost_display (0)
82 , solo_cut_display (0)
83 , _output_selector (0)
84 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
85 , afl_button (_("AFL"), ArdourButton::led_default_elements)
86 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
87 , exclusive_solo_button (ArdourButton::led_default_elements)
88 , solo_mute_override_button (ArdourButton::led_default_elements)
89 , toggle_processorbox_button (ArdourButton::default_elements)
90 , _inhibit_solo_model_update (false)
91 , _ui_initialized (false)
94 using namespace Menu_Helpers;
96 Glib::RefPtr<Action> act;
98 if (!monitor_actions) {
103 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
105 set_data ("ardour-bindings", bindings);
107 _plugin_selector = new PluginSelector (PluginManager::instance());
108 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
109 insert_box->set_no_show_all ();
111 // TODO allow keyboard shortcuts in ProcessorBox
115 /* Rude Solo & Solo Isolated */
116 rude_solo_button.set_text (_("Soloing"));
117 rude_solo_button.set_name ("rude solo");
118 rude_solo_button.show ();
120 rude_iso_button.set_text (_("Isolated"));
121 rude_iso_button.set_name ("rude isolate");
122 rude_iso_button.show ();
124 rude_audition_button.set_text (_("Auditioning"));
125 rude_audition_button.set_name ("rude audition");
126 rude_audition_button.show ();
128 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
130 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
131 rude_solo_button.set_related_action (act);
132 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
134 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
135 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
137 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
138 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
140 /* SIP, AFL, PFL radio */
142 solo_in_place_button.set_name ("monitor section solo model");
143 afl_button.set_name ("monitor section solo model");
144 pfl_button.set_name ("monitor section solo model");
146 solo_in_place_button.set_led_left (true);
147 afl_button.set_led_left (true);
148 pfl_button.set_led_left (true);
150 solo_in_place_button.show ();
154 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
155 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
157 solo_in_place_button.set_related_action (act);
160 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
161 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
163 afl_button.set_related_action (act);
166 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
167 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
169 pfl_button.set_related_action (act);
172 /* Solo option buttons */
173 exclusive_solo_button.set_text (_("Excl. Solo"));
174 exclusive_solo_button.set_name (X_("monitor section solo option"));
175 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
177 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
179 exclusive_solo_button.set_related_action (act);
182 solo_mute_override_button.set_text (_("Solo ยป Mute"));
183 solo_mute_override_button.set_name (X_("monitor section solo option"));
184 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
186 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
188 solo_mute_override_button.set_related_action (act);
191 /* Processor Box hide/shos */
192 toggle_processorbox_button.set_text (_("Processors"));
193 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
194 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
196 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
197 toggle_processorbox_button.set_related_action (proctoggle);
200 Label* solo_boost_label;
201 Label* solo_cut_label;
204 /* Solo Boost Knob */
206 solo_boost_control = new ArdourKnob ();
207 solo_boost_control->set_name("monitor section knob");
208 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
209 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
211 solo_boost_display = new ArdourDisplay ();
212 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
213 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
214 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
215 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
216 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
218 solo_boost_label = manage (new Label (_("Solo Boost")));
222 solo_cut_control = new ArdourKnob ();
223 solo_cut_control->set_name ("monitor section knob");
224 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
225 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
227 solo_cut_display = new ArdourDisplay ();
228 solo_cut_display->set_name("monitor section dropdown"); // XXX
229 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
230 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
231 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
232 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
233 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
234 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
236 solo_cut_label = manage (new Label (_("SiP Cut")));
240 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
241 dim_control->set_name ("monitor section knob");
242 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
243 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
245 dim_display = new ArdourDisplay ();
246 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
247 dim_display->add_controllable_preset(_("0 dB"), 0.0);
248 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
249 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
250 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
251 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
253 dim_label = manage (new Label (_("Dim")));
256 cut_all_button.set_text (_("Mute"));
257 cut_all_button.set_name ("mute button");
258 cut_all_button.set_size_request (-1, PX_SCALE(30));
259 cut_all_button.show ();
261 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
263 cut_all_button.set_related_action (act);
267 dim_all_button.set_text (_("Dim"));
268 dim_all_button.set_name ("monitor section dim");
269 dim_all_button.set_size_request (-1, PX_SCALE(25));
270 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
272 dim_all_button.set_related_action (act);
276 mono_button.set_text (_("Mono"));
277 mono_button.set_name ("monitor section mono");
278 mono_button.set_size_request (-1, PX_SCALE(25));
279 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
281 mono_button.set_related_action (act);
286 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
287 gain_control->set_name("monitor section knob");
288 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
290 gain_display = new ArdourDisplay ();
291 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
292 gain_display->add_controllable_preset(_("0 dB"), 0.0);
293 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
294 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
295 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
296 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
297 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
299 Label* output_label = manage (new Label (_("Output")));
300 output_label->set_name (X_("MonitorSectionLabel"));
302 output_button = new ArdourButton ();
303 output_button->set_text (_("Output"));
304 output_button->set_name (X_("monitor section cut")); // XXX
305 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
306 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
308 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
309 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
310 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
311 channel_table_scroller.show ();
312 channel_table_scroller.add (channel_table_viewport);
314 channel_size_group->add_widget (channel_table_header);
315 channel_table_header.resize (1, 5);
317 Label* l1 = manage (new Label (X_(" ")));
318 l1->set_name (X_("MonitorSectionLabel"));
319 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
321 l1 = manage (new Label (_("Mute")));
322 l1->set_name (X_("MonitorSectionLabel"));
323 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
325 l1 = manage (new Label (_("Dim")));
326 l1->set_name (X_("MonitorSectionLabel"));
327 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
329 l1 = manage (new Label (_("Solo")));
330 l1->set_name (X_("MonitorSectionLabel"));
331 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
333 l1 = manage (new Label (_("Inv")));
334 l1->set_name (X_("MonitorSectionLabel"));
335 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
337 channel_table_header.show ();
340 /****************************************************************************
341 * LAYOUT top to bottom
344 // solo, iso information
345 HBox* rude_box = manage (new HBox);
346 rude_box->set_spacing (PX_SCALE(4));
347 rude_box->set_homogeneous (true);
348 rude_box->pack_start (rude_solo_button, true, true);
349 rude_box->pack_start (rude_iso_button, true, true);
351 // solo options (right align)
352 HBox* tbx1 = manage (new HBox);
353 tbx1->pack_end (exclusive_solo_button, false, false);
355 HBox* tbx2 = manage (new HBox);
356 tbx2->pack_end (solo_mute_override_button, false, false);
358 HBox* tbx3 = manage (new HBox);
359 tbx3->pack_end (toggle_processorbox_button, false, false);
361 HBox* tbx0 = manage (new HBox); // space
363 // combined solo mode (Sip, AFL, PFL) & solo options
364 Table *solo_tbl = manage (new Table);
365 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
366 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
369 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
370 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
371 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
373 // boost, cut, dim volume control
374 Table *level_tbl = manage (new Table);
375 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
379 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
383 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
384 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
385 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
388 HBox* mono_dim_box = manage (new HBox);
389 mono_dim_box->set_spacing (PX_SCALE(4));
390 mono_dim_box->set_homogeneous (true);
391 mono_dim_box->pack_start (mono_button, true, true);
392 mono_dim_box->pack_end (dim_all_button, true, true);
395 Label* spin_label = manage (new Label (_("Monitor")));
396 VBox* spin_packer = manage (new VBox);
397 spin_packer->set_spacing (PX_SCALE(2));
398 spin_packer->pack_start (*spin_label, false, false);
399 spin_packer->pack_start (*gain_control, false, false);
400 spin_packer->pack_start (*gain_display, false, false);
402 master_packer.pack_start (*spin_packer, true, false);
404 // combined gain section (channels, mute, dim)
405 VBox* lower_packer = manage (new VBox);
406 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
407 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
408 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
409 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
411 // calc height of mixer scrollbar
412 int scrollbar_height = 0;
414 Gtk::Window window (WINDOW_TOPLEVEL);
415 HScrollbar scrollbar;
416 window.add (scrollbar);
417 scrollbar.set_name ("MixerWindow");
418 scrollbar.ensure_style();
419 Gtk::Requisition requisition(scrollbar.size_request ());
420 scrollbar_height = requisition.height;
423 // output port select
424 VBox* out_packer = manage (new VBox);
425 out_packer->set_spacing (PX_SCALE(2));
426 out_packer->pack_start (*output_label, false, false);
427 out_packer->pack_start (*output_button, false, false);
429 /****************************************************************************
432 vpacker.set_border_width (PX_SCALE(3));
433 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
434 vpacker.pack_start (rude_audition_button, false, false, 0);
435 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
436 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
437 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
438 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
439 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
440 vpacker.pack_end (*out_packer, false, false,
442 scrollbar_height - 2 /* no outer frame */
444 scrollbar_height + 2 /* frame borders */
448 hpacker.set_spacing (0);
449 hpacker.pack_start (vpacker, true, true);
453 gain_control->show_all ();
454 gain_display->show_all ();
455 dim_control->show_all ();
456 dim_display->show_all();
457 solo_boost_control->show_all ();
458 solo_boost_display->show_all();
460 mono_dim_box->show ();
461 spin_packer->show ();
462 master_packer.show ();
465 solo_tbl->show_all();
467 lower_packer->show ();
474 assign_controllables ();
476 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
477 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
479 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
480 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
481 set_flags (CAN_FOCUS);
483 _tearoff = new TearOff (*this);
485 if (!UIConfiguration::instance().get_floating_monitor_section()) {
486 /* if torn off, make this a normal window
487 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
489 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
491 _tearoff->tearoff_window().set_title (X_("Monitor"));
492 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
494 update_output_display ();
495 update_processor_box ();
496 _ui_initialized = true;
498 /* catch changes that affect us */
499 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
500 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
502 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
505 MonitorSection::~MonitorSection ()
507 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
511 _channel_buttons.clear ();
512 output_changed_connections.drop_connections ();
514 delete insert_box; insert_box = 0;
515 delete output_button; output_button = 0;
516 delete gain_control; gain_control = 0;
517 delete gain_display; gain_display = 0;
518 delete dim_control; dim_control = 0;
519 delete dim_display; dim_display = 0;
520 delete solo_boost_control; solo_boost_control = 0;
521 delete solo_boost_display; solo_boost_display = 0;
522 delete solo_cut_control; solo_cut_control = 0;
523 delete solo_cut_display; solo_cut_display = 0;
524 delete _tearoff; _tearoff = 0;
525 delete _output_selector; _output_selector = 0;
526 delete channel_table; channel_table = 0;
530 MonitorSection::enter_handler (GdkEventCrossing* ev)
537 MonitorSection::leave_handler (GdkEventCrossing* ev)
539 switch (ev->detail) {
540 case GDK_NOTIFY_INFERIOR:
546 /* cancel focus if we're not torn off. With X11 WM's that do
547 * focus-follows-mouse, focus will be taken from us anyway.
550 Widget* top = get_toplevel();
552 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
553 Window* win = dynamic_cast<Window*> (top);
554 gtk_window_set_focus (win->gobj(), 0);
561 MonitorSection::update_processor_box ()
563 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
565 if (count_processors () > 0 && !show_processor_box) {
566 toggle_processorbox_button.set_name (X_("monitor section processors present"));
568 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
571 if (insert_box->is_visible() == show_processor_box) {
575 if (show_processor_box) {
576 if (master_packer.get_parent()) {
577 master_packer.get_parent()->remove (master_packer);
580 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
582 if (master_packer.get_parent()) {
583 master_packer.get_parent()->remove (master_packer);
586 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
591 MonitorSection::set_session (Session* s)
593 RouteUI::set_session (s);
594 _plugin_selector->set_session (_session);
598 _route = _session->monitor_out ();
601 /* session with monitor section */
602 _monitor = _route->monitor_control ();
603 assign_controllables ();
604 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
605 boost::bind (&MonitorSection::update_output_display, this),
607 insert_box->set_route (_route);
608 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
609 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
610 if (_ui_initialized) {
611 update_processor_box ();
614 /* session with no monitor section */
615 output_changed_connections.drop_connections();
618 delete _output_selector;
619 _output_selector = 0;
627 output_changed_connections.drop_connections();
630 control_connections.drop_connections ();
631 rude_iso_button.unset_active_state ();
632 rude_solo_button.unset_active_state ();
633 delete _output_selector;
634 _output_selector = 0;
636 assign_controllables ();
640 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
642 cut.set_name (X_("mute button"));
643 dim.set_name (X_("monitor section dim"));
644 solo.set_name (X_("solo button"));
645 invert.set_name (X_("invert button"));
647 cut.unset_flags (Gtk::CAN_FOCUS);
648 dim.unset_flags (Gtk::CAN_FOCUS);
649 solo.unset_flags (Gtk::CAN_FOCUS);
650 invert.unset_flags (Gtk::CAN_FOCUS);
654 MonitorSection::populate_buttons ()
661 channel_size_group->remove_widget (*channel_table);
662 delete channel_table;
665 channel_table = new Gtk::Table();
667 channel_table->set_col_spacings (6);
668 channel_table->set_row_spacings (6);
669 channel_table->set_homogeneous (true);
671 channel_size_group->add_widget (*channel_table);
672 channel_table->show ();
673 table_hpacker.pack_start (*channel_table, true, true);
675 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
678 _channel_buttons.clear ();
680 Glib::RefPtr<Action> act;
681 uint32_t nchans = _monitor->output_streams().n_audio();
683 channel_table->resize (nchans, 5);
685 const uint32_t row_offset = 0;
687 for (uint32_t i = 0; i < nchans; ++i) {
700 snprintf (buf, sizeof (buf), "%d", i+1);
704 Label* label = manage (new Label (l));
705 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
707 ChannelButtonSet* cbs = new ChannelButtonSet;
709 _channel_buttons.push_back (cbs);
711 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
712 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
713 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
714 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
716 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
717 act = ActionManager::get_action (X_("Monitor"), buf);
719 cbs->cut.set_related_action (act);
722 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
723 act = ActionManager::get_action (X_("Monitor"), buf);
725 cbs->dim.set_related_action (act);
728 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
729 act = ActionManager::get_action (X_("Monitor"), buf);
731 cbs->solo.set_related_action (act);
734 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
735 act = ActionManager::get_action (X_("Monitor"), buf);
737 cbs->invert.set_related_action (act);
741 channel_table->show_all ();
743 if (channel_table_scroller.get_parent()) {
744 /* scroller is packed, so remove it */
745 channel_table_packer.remove (channel_table_scroller);
748 if (table_hpacker.get_parent () == &channel_table_packer) {
749 /* this occurs when the table hpacker is directly
750 packed, so remove it.
752 channel_table_packer.remove (table_hpacker);
753 } else if (table_hpacker.get_parent()) {
754 channel_table_viewport.remove ();
758 /* put the table into a scrolled window, and then put
759 * that into the channel vpacker, after the table header
761 channel_table_viewport.add (table_hpacker);
762 channel_table_packer.pack_start (channel_table_scroller, true, true);
763 channel_table_viewport.show ();
764 channel_table_scroller.show ();
767 /* just put the channel table itself into the channel
768 * vpacker, after the table header
770 channel_table_packer.pack_start (table_hpacker, true, true);
771 channel_table_scroller.hide ();
773 table_hpacker.show ();
774 channel_table->show ();
778 MonitorSection::toggle_exclusive_solo ()
784 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
786 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
787 Config->set_exclusive_solo (tact->get_active());
793 MonitorSection::toggle_mute_overrides_solo ()
799 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
801 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
802 Config->set_solo_mute_override (tact->get_active());
807 MonitorSection::dim_all ()
813 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
815 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
816 _monitor->set_dim_all (tact->get_active());
822 MonitorSection::cut_all ()
828 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
830 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
831 _monitor->set_cut_all (tact->get_active());
836 MonitorSection::mono ()
842 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
844 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
845 _monitor->set_mono (tact->get_active());
850 MonitorSection::cut_channel (uint32_t chn)
857 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
859 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
861 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
862 _monitor->set_cut (chn, tact->get_active());
867 MonitorSection::dim_channel (uint32_t chn)
874 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
876 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
878 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
879 _monitor->set_dim (chn, tact->get_active());
885 MonitorSection::solo_channel (uint32_t chn)
892 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
894 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
896 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
897 _monitor->set_solo (chn, tact->get_active());
903 MonitorSection::invert_channel (uint32_t chn)
910 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
912 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
914 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
915 _monitor->set_polarity (chn, tact->get_active());
920 MonitorSection::register_actions ()
924 Glib::RefPtr<Action> act;
926 monitor_actions = myactions.create_action_group (X_("Monitor"));
928 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
929 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
931 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
932 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
934 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
935 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
937 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
938 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
940 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
941 tact->set_active (Config->get_exclusive_solo());
943 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
944 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
946 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
947 tact->set_active (Config->get_solo_mute_override());
949 for (uint32_t chn = 0; chn < 16; ++chn) {
951 action_name = string_compose (X_("monitor-cut-%1"), chn);
952 action_descr = string_compose (_("Cut monitor channel %1"), chn);
953 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
954 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
956 action_name = string_compose (X_("monitor-dim-%1"), chn);
957 action_descr = string_compose (_("Dim monitor channel %1"), chn);
958 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
959 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
961 action_name = string_compose (X_("monitor-solo-%1"), chn);
962 action_descr = string_compose (_("Solo monitor channel %1"), chn);
963 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
964 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
966 action_name = string_compose (X_("monitor-invert-%1"), chn);
967 action_descr = string_compose (_("Invert monitor channel %1"), chn);
968 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
969 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
974 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
975 RadioAction::Group solo_group;
977 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
978 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
979 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
980 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
981 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
982 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
984 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
985 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
990 MonitorSection::solo_use_in_place ()
992 /* this is driven by a toggle on a radio group, and so is invoked twice,
993 once for the item that became inactive and once for the one that became
997 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
1000 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1002 if (!ract->get_active ()) {
1003 /* We are turning SiP off, which means that AFL or PFL will be turned on
1004 shortly; don't update the solo model in the mean time, as if the currently
1005 configured listen position is not the one that is about to be turned on,
1006 things will go wrong.
1008 _inhibit_solo_model_update = true;
1010 Config->set_solo_control_is_listen_control (!ract->get_active());
1011 _inhibit_solo_model_update = false;
1017 MonitorSection::solo_use_afl ()
1019 /* this is driven by a toggle on a radio group, and so is invoked twice,
1020 once for the item that became inactive and once for the one that became
1024 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1026 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1028 if (ract->get_active()) {
1029 Config->set_solo_control_is_listen_control (true);
1030 Config->set_listen_position (AfterFaderListen);
1037 MonitorSection::solo_use_pfl ()
1039 /* this is driven by a toggle on a radio group, and so is invoked twice,
1040 once for the item that became inactive and once for the one that became
1044 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1046 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1048 if (ract->get_active()) {
1049 Config->set_solo_control_is_listen_control (true);
1050 Config->set_listen_position (PreFaderListen);
1057 MonitorSection::update_solo_model ()
1059 if (_inhibit_solo_model_update) {
1063 const char* action_name = 0;
1064 Glib::RefPtr<Action> act;
1066 if (Config->get_solo_control_is_listen_control()) {
1067 switch (Config->get_listen_position()) {
1068 case AfterFaderListen:
1069 action_name = X_("solo-use-afl");
1071 case PreFaderListen:
1072 action_name = X_("solo-use-pfl");
1076 action_name = X_("solo-use-in-place");
1079 act = ActionManager::get_action (X_("Solo"), action_name);
1082 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1084 /* because these are radio buttons, one of them will be
1085 active no matter what. to trigger a change in the
1086 action so that the view picks it up, toggle it.
1088 if (ract->get_active()) {
1089 ract->set_active (false);
1091 ract->set_active (true);
1098 MonitorSection::map_state ()
1100 if (!_route || !_monitor) {
1104 Glib::RefPtr<Action> act;
1106 update_solo_model ();
1108 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1110 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1112 tact->set_active (_monitor->cut_all());
1116 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1118 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1120 tact->set_active (_monitor->dim_all());
1124 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1126 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1128 tact->set_active (_monitor->mono());
1132 uint32_t nchans = _monitor->output_streams().n_audio();
1134 assert (nchans == _channel_buttons.size ());
1136 for (uint32_t n = 0; n < nchans; ++n) {
1138 char action_name[32];
1140 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1141 act = ActionManager::get_action (X_("Monitor"), action_name);
1143 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1145 tact->set_active (_monitor->cut (n));
1149 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1150 act = ActionManager::get_action (X_("Monitor"), action_name);
1152 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1154 tact->set_active (_monitor->dimmed (n));
1158 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1159 act = ActionManager::get_action (X_("Monitor"), action_name);
1161 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1163 tact->set_active (_monitor->soloed (n));
1167 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1168 act = ActionManager::get_action (X_("Monitor"), action_name);
1170 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1172 tact->set_active (_monitor->inverted (n));
1179 MonitorSection::do_blink (bool onoff)
1182 audition_blink (onoff);
1186 MonitorSection::audition_blink (bool onoff)
1188 if (_session == 0) {
1192 if (_session->is_auditioning()) {
1193 rude_audition_button.set_active (onoff);
1195 rude_audition_button.set_active (false);
1200 MonitorSection::solo_blink (bool onoff)
1202 if (_session == 0) {
1206 if (_session->soloing() || _session->listening()) {
1207 rude_solo_button.set_active (onoff);
1209 if (_session->soloing()) {
1210 if (_session->solo_isolated()) {
1211 rude_iso_button.set_active (onoff);
1213 rude_iso_button.set_active (false);
1218 rude_solo_button.set_active (false);
1219 rude_iso_button.set_active (false);
1224 MonitorSection::cancel_isolate (GdkEventButton*)
1227 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1228 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1235 MonitorSection::cancel_audition (GdkEventButton*)
1238 _session->cancel_audition();
1243 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1245 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1246 if (tact && tact->get_active() != value) { \
1247 tact->set_active(value); \
1252 MonitorSection::parameter_changed (std::string name)
1254 if (name == "solo-control-is-listen-control") {
1255 update_solo_model ();
1256 } else if (name == "listen-position") {
1257 update_solo_model ();
1258 } else if (name == "solo-mute-override") {
1259 SYNCHRONIZE_TOGGLE_ACTION(
1260 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1261 Config->get_solo_mute_override ())
1262 } else if (name == "exclusive-solo") {
1263 SYNCHRONIZE_TOGGLE_ACTION(
1264 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1265 Config->get_exclusive_solo ())
1270 MonitorSection::assign_controllables ()
1272 boost::shared_ptr<Controllable> none;
1274 if (!gain_control) {
1275 /* too early - GUI controls not set up yet */
1280 solo_cut_control->set_controllable (_session->solo_cut_control());
1281 solo_cut_display->set_controllable (_session->solo_cut_control());
1283 solo_cut_control->set_controllable (none);
1284 solo_cut_display->set_controllable (none);
1288 gain_control->set_controllable (_route->gain_control());
1289 gain_display->set_controllable (_route->gain_control());
1291 gain_control->set_controllable (none);
1296 cut_all_button.set_controllable (_monitor->cut_control());
1297 cut_all_button.watch ();
1298 dim_all_button.set_controllable (_monitor->dim_control());
1299 dim_all_button.watch ();
1300 mono_button.set_controllable (_monitor->mono_control());
1301 mono_button.watch ();
1303 dim_control->set_controllable (_monitor->dim_level_control ());
1304 dim_display->set_controllable (_monitor->dim_level_control ());
1305 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1306 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1310 cut_all_button.set_controllable (none);
1311 dim_all_button.set_controllable (none);
1312 mono_button.set_controllable (none);
1314 dim_control->set_controllable (none);
1315 dim_display->set_controllable (none);
1316 solo_boost_control->set_controllable (none);
1317 solo_boost_display->set_controllable (none);
1322 MonitorSection::state_id() const
1324 return "monitor-section";
1328 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1330 using namespace Menu_Helpers;
1332 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1336 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1337 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1341 if (i != output_menu_bundles.end()) {
1345 output_menu_bundles.push_back (b);
1347 MenuList& citems = output_menu.items();
1349 std::string n = b->name ();
1350 replace_all (n, "_", " ");
1352 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1356 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1359 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1361 if (std::find (current.begin(), current.end(), c) == current.end()) {
1362 _route->output()->connect_ports_to_bundle (c, true, this);
1364 _route->output()->disconnect_ports_from_bundle (c, this);
1369 MonitorSection::output_release (GdkEventButton *ev)
1371 switch (ev->button) {
1373 edit_output_configuration ();
1380 struct RouteCompareByName {
1381 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1382 return a->name().compare (b->name()) < 0;
1387 MonitorSection::output_press (GdkEventButton *ev)
1389 using namespace Menu_Helpers;
1391 MessageDialog msg (_("No session - no I/O changes are possible"));
1396 MenuList& citems = output_menu.items();
1397 switch (ev->button) {
1400 return false; //wait for the mouse-up to pop the dialog
1404 output_menu.set_name ("ArdourContextMenu");
1406 output_menu_bundles.clear ();
1408 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1410 citems.push_back (SeparatorElem());
1411 uint32_t const n_with_separator = citems.size ();
1413 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1415 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1417 /* give user bundles first chance at being in the menu */
1419 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1420 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1421 maybe_add_bundle_to_output_menu (*i, current);
1425 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1426 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1427 maybe_add_bundle_to_output_menu (*i, current);
1431 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1432 RouteList copy = *routes;
1433 copy.sort (RouteCompareByName ());
1434 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1435 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1438 if (citems.size() == n_with_separator) {
1439 /* no routes added; remove the separator */
1443 citems.push_back (SeparatorElem());
1444 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1446 output_menu.popup (1, ev->time);
1457 MonitorSection::update_output_display ()
1459 if (!_route || !_monitor || _session->deletion_in_progress()) {
1465 boost::shared_ptr<Port> port;
1466 vector<string> port_connections;
1468 uint32_t total_connection_count = 0;
1469 uint32_t io_connection_count = 0;
1470 uint32_t ardour_connection_count = 0;
1471 uint32_t system_connection_count = 0;
1472 uint32_t other_connection_count = 0;
1474 ostringstream label;
1476 bool have_label = false;
1477 bool each_io_has_one_connection = true;
1479 string connection_name;
1480 string ardour_track_name;
1481 string other_connection_type;
1482 string system_ports;
1485 ostringstream tooltip;
1486 char * tooltip_cstr;
1488 io_count = _route->n_outputs().n_total();
1489 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1492 for (io_index = 0; io_index < io_count; ++io_index) {
1494 port = _route->output()->nth (io_index);
1496 //ignore any port connections that don't match our DataType
1497 if (port->type() != DataType::AUDIO) {
1501 port_connections.clear ();
1502 port->get_connections(port_connections);
1503 io_connection_count = 0;
1505 if (!port_connections.empty()) {
1506 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1508 string& connection_name (*i);
1510 if (connection_name.find("system:") == 0) {
1511 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1514 if (io_connection_count == 0) {
1515 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1517 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1520 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1523 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1524 if (ardour_track_name.empty()) {
1525 // "ardour:Master/in 1" -> "ardour:Master/"
1526 string::size_type slash = connection_name.find("/");
1527 if (slash != string::npos) {
1528 ardour_track_name = connection_name.substr(0, slash + 1);
1532 if (connection_name.find(ardour_track_name) == 0) {
1533 ++ardour_connection_count;
1535 } else if (!pn.empty()) {
1536 if (system_ports.empty()) {
1539 system_ports += "/" + pn;
1541 if (connection_name.find("system:") == 0) {
1542 ++system_connection_count;
1544 } else if (connection_name.find("system:") == 0) {
1545 // "system:playback_123" -> "123"
1546 system_port = connection_name.substr(16);
1547 if (system_ports.empty()) {
1548 system_ports += system_port;
1550 system_ports += "/" + system_port;
1553 ++system_connection_count;
1555 if (other_connection_type.empty()) {
1556 // "jamin:in 1" -> "jamin:"
1557 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1560 if (connection_name.find(other_connection_type) == 0) {
1561 ++other_connection_count;
1565 ++total_connection_count;
1566 ++io_connection_count;
1570 if (io_connection_count != 1) {
1571 each_io_has_one_connection = false;
1575 if (total_connection_count == 0) {
1576 tooltip << endl << _("Disconnected");
1579 tooltip_cstr = new char[tooltip.str().size() + 1];
1580 strcpy(tooltip_cstr, tooltip.str().c_str());
1582 set_tooltip (output_button, tooltip_cstr, "");
1584 if (each_io_has_one_connection) {
1585 if (total_connection_count == ardour_connection_count) {
1586 // all connections are to the same track in ardour
1587 // "ardour:Master/" -> "Master"
1588 string::size_type slash = ardour_track_name.find("/");
1589 if (slash != string::npos) {
1590 label << ardour_track_name.substr(7, slash - 7);
1593 } else if (total_connection_count == system_connection_count) {
1594 // all connections are to system ports
1595 label << system_ports;
1597 } else if (total_connection_count == other_connection_count) {
1598 // all connections are to the same external program eg jamin
1599 // "jamin:" -> "jamin"
1600 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1606 if (total_connection_count == 0) {
1610 // Odd configuration
1611 label << "*" << total_connection_count << "*";
1615 output_button->set_text (label.str());
1619 MonitorSection::disconnect_output ()
1622 _route->output()->disconnect(this);
1627 MonitorSection::edit_output_configuration ()
1629 if (_output_selector == 0) {
1630 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1632 _output_selector->present ();
1636 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1641 boost::shared_ptr<Port> a = wa.lock ();
1642 boost::shared_ptr<Port> b = wb.lock ();
1643 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1644 update_output_display ();
1649 MonitorSection::load_bindings ()
1651 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1655 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1657 boost::shared_ptr<Processor> processor (p.lock ());
1658 if (!processor || !processor->display_to_user()) {
1661 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1668 MonitorSection::count_processors ()
1670 uint32_t processor_count = 0;
1672 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1674 return processor_count;
1678 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1680 update_processor_box ();
1684 MonitorSection::action_proxy0 (enum MonitorActions action)
1686 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1700 case ToggleExclusiveSolo:
1701 ms->toggle_exclusive_solo ();
1703 case ToggleMuteOverridesSolo:
1704 ms->toggle_mute_overrides_solo ();
1706 case SoloUseInPlace:
1707 ms->solo_use_in_place ();
1710 ms->solo_use_afl ();
1713 ms->solo_use_pfl ();
1715 case ToggleMonitorProcessorBox:
1716 ms->update_processor_box ();
1722 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1724 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1730 ms->cut_channel (chn);
1733 ms->dim_channel (chn);
1736 ms->solo_channel (chn);
1739 ms->invert_channel (chn);