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 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
65 MonitorSection::MonitorSection ()
66 : RouteUI ((Session*) 0)
69 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
70 , *channel_table_scroller.get_vadjustment ())
73 , solo_boost_control (0)
74 , solo_cut_control (0)
77 , solo_boost_display (0)
78 , solo_cut_display (0)
79 , _output_selector (0)
80 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
81 , afl_button (_("AFL"), ArdourButton::led_default_elements)
82 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
83 , exclusive_solo_button (ArdourButton::led_default_elements)
84 , solo_mute_override_button (ArdourButton::led_default_elements)
85 , toggle_processorbox_button (ArdourButton::default_elements)
86 , _inhibit_solo_model_update (false)
88 , _ui_initialized (false)
90 using namespace Menu_Helpers;
92 Glib::RefPtr<Action> act;
96 set_data ("ardour-bindings", bindings);
98 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
100 _plugin_selector = new PluginSelector (PluginManager::instance());
101 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
102 insert_box->set_no_show_all ();
104 // TODO allow keyboard shortcuts in ProcessorBox
106 /* Rude Solo & Solo Isolated */
107 rude_solo_button.set_text (_("Soloing"));
108 rude_solo_button.set_name ("rude solo");
109 rude_solo_button.show ();
111 rude_iso_button.set_text (_("Isolated"));
112 rude_iso_button.set_name ("rude isolate");
113 rude_iso_button.show ();
115 rude_audition_button.set_text (_("Auditioning"));
116 rude_audition_button.set_name ("rude audition");
117 rude_audition_button.show ();
119 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
121 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
123 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
124 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
126 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
127 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
129 /* SIP, AFL, PFL radio */
131 solo_in_place_button.set_name ("monitor section solo model");
132 afl_button.set_name ("monitor section solo model");
133 pfl_button.set_name ("monitor section solo model");
135 solo_in_place_button.set_led_left (true);
136 afl_button.set_led_left (true);
137 pfl_button.set_led_left (true);
139 solo_in_place_button.show ();
143 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
144 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
146 solo_in_place_button.set_related_action (act);
149 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
150 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
152 afl_button.set_related_action (act);
155 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
156 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
158 pfl_button.set_related_action (act);
161 /* Solo option buttons */
162 exclusive_solo_button.set_text (_("Excl. Solo"));
163 exclusive_solo_button.set_name (X_("monitor section solo option"));
164 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
166 act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
168 exclusive_solo_button.set_related_action (act);
171 solo_mute_override_button.set_text (_("Solo ยป Mute"));
172 solo_mute_override_button.set_name (X_("monitor section solo option"));
173 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
175 solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
177 /* Processor Box hide/shos */
178 toggle_processorbox_button.set_text (_("Processors"));
179 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
180 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
182 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
183 toggle_processorbox_button.set_related_action (proctoggle);
186 Label* solo_boost_label;
187 Label* solo_cut_label;
190 /* Solo Boost Knob */
192 solo_boost_control = new ArdourKnob ();
193 solo_boost_control->set_name("monitor section knob");
194 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
195 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
197 solo_boost_display = new ArdourDisplay ();
198 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
199 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
200 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
201 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
202 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
204 solo_boost_label = manage (new Label (_("Solo Boost")));
208 solo_cut_control = new ArdourKnob ();
209 solo_cut_control->set_name ("monitor section knob");
210 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
211 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
213 solo_cut_display = new ArdourDisplay ();
214 solo_cut_display->set_name("monitor section dropdown"); // XXX
215 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
216 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
217 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
218 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
219 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
220 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
222 solo_cut_label = manage (new Label (_("SiP Cut")));
226 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
227 dim_control->set_name ("monitor section knob");
228 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
229 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
231 dim_display = new ArdourDisplay ();
232 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
233 dim_display->add_controllable_preset(_("0 dB"), 0.0);
234 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
235 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
236 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
237 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
239 dim_label = manage (new Label (_("Dim")));
242 cut_all_button.set_text (_("Mute"));
243 cut_all_button.set_name ("mute button");
244 cut_all_button.set_size_request (-1, PX_SCALE(30));
245 cut_all_button.show ();
247 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
249 cut_all_button.set_related_action (act);
253 dim_all_button.set_text (_("Dim"));
254 dim_all_button.set_name ("monitor section dim");
255 dim_all_button.set_size_request (-1, PX_SCALE(25));
256 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
258 dim_all_button.set_related_action (act);
262 mono_button.set_text (_("Mono"));
263 mono_button.set_name ("monitor section mono");
264 mono_button.set_size_request (-1, PX_SCALE(25));
265 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
267 mono_button.set_related_action (act);
272 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
273 gain_control->set_name("monitor section knob");
274 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
276 gain_display = new ArdourDisplay ();
277 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
278 gain_display->add_controllable_preset(_("0 dB"), 0.0);
279 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
280 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
281 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
282 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
283 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
285 Label* output_label = manage (new Label (_("Output")));
286 output_label->set_name (X_("MonitorSectionLabel"));
288 output_button = new ArdourButton ();
289 output_button->set_text (_("Output"));
290 output_button->set_name (X_("monitor section cut")); // XXX
291 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
292 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
294 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
295 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
296 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
297 channel_table_scroller.show ();
298 channel_table_scroller.add (channel_table_viewport);
300 channel_size_group->add_widget (channel_table_header);
301 channel_table_header.resize (1, 5);
303 Label* l1 = manage (new Label (X_(" ")));
304 l1->set_name (X_("MonitorSectionLabel"));
305 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
307 l1 = manage (new Label (_("Mute")));
308 l1->set_name (X_("MonitorSectionLabel"));
309 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
311 l1 = manage (new Label (_("Dim")));
312 l1->set_name (X_("MonitorSectionLabel"));
313 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
315 l1 = manage (new Label (_("Solo")));
316 l1->set_name (X_("MonitorSectionLabel"));
317 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
319 l1 = manage (new Label (_("Inv")));
320 l1->set_name (X_("MonitorSectionLabel"));
321 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
323 channel_table_header.show ();
326 /****************************************************************************
327 * LAYOUT top to bottom
330 // solo, iso information
331 HBox* rude_box = manage (new HBox);
332 rude_box->set_spacing (PX_SCALE(4));
333 rude_box->set_homogeneous (true);
334 rude_box->pack_start (rude_solo_button, true, true);
335 rude_box->pack_start (rude_iso_button, true, true);
337 // solo options (right align)
338 HBox* tbx1 = manage (new HBox);
339 tbx1->pack_end (exclusive_solo_button, false, false);
341 HBox* tbx2 = manage (new HBox);
342 tbx2->pack_end (solo_mute_override_button, false, false);
344 HBox* tbx3 = manage (new HBox);
345 tbx3->pack_end (toggle_processorbox_button, false, false);
347 HBox* tbx0 = manage (new HBox); // space
349 // combined solo mode (Sip, AFL, PFL) & solo options
350 Table *solo_tbl = manage (new Table);
351 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
352 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
353 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
354 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
355 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
356 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
357 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
359 // boost, cut, dim volume control
360 Table *level_tbl = manage (new Table);
361 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
362 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
363 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
365 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
366 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
367 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
369 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
370 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
371 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
374 HBox* mono_dim_box = manage (new HBox);
375 mono_dim_box->set_spacing (PX_SCALE(4));
376 mono_dim_box->set_homogeneous (true);
377 mono_dim_box->pack_start (mono_button, true, true);
378 mono_dim_box->pack_end (dim_all_button, true, true);
381 Label* spin_label = manage (new Label (_("Monitor")));
382 VBox* spin_packer = manage (new VBox);
383 spin_packer->set_spacing (PX_SCALE(2));
384 spin_packer->pack_start (*spin_label, false, false);
385 spin_packer->pack_start (*gain_control, false, false);
386 spin_packer->pack_start (*gain_display, false, false);
388 master_packer.pack_start (*spin_packer, true, false);
390 // combined gain section (channels, mute, dim)
391 VBox* lower_packer = manage (new VBox);
392 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
393 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
394 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
395 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
397 // calc height of mixer scrollbar
398 int scrollbar_height = 0;
400 Gtk::Window window (WINDOW_TOPLEVEL);
401 HScrollbar scrollbar;
402 window.add (scrollbar);
403 scrollbar.set_name ("MixerWindow");
404 scrollbar.ensure_style();
405 Gtk::Requisition requisition(scrollbar.size_request ());
406 scrollbar_height = requisition.height;
409 // output port select
410 VBox* out_packer = manage (new VBox);
411 out_packer->set_spacing (PX_SCALE(2));
412 out_packer->pack_start (*output_label, false, false);
413 out_packer->pack_start (*output_button, false, false);
415 /****************************************************************************
418 vpacker.set_border_width (PX_SCALE(3));
419 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
420 vpacker.pack_start (rude_audition_button, false, false, 0);
421 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
422 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
423 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
424 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
425 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
426 vpacker.pack_end (*out_packer, false, false,
428 scrollbar_height - 2 /* no outer sample */
430 scrollbar_height + 2 /* sample borders */
434 hpacker.set_spacing (0);
435 hpacker.pack_start (vpacker, true, true);
439 gain_control->show_all ();
440 gain_display->show_all ();
441 dim_control->show_all ();
442 dim_display->show_all();
443 solo_boost_control->show_all ();
444 solo_boost_display->show_all();
446 mono_dim_box->show ();
447 spin_packer->show ();
448 master_packer.show ();
451 solo_tbl->show_all();
453 lower_packer->show ();
460 assign_controllables ();
462 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
463 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
465 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
466 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
467 set_flags (CAN_FOCUS);
469 _tearoff = new TearOff (*this);
471 if (!UIConfiguration::instance().get_floating_monitor_section()) {
472 /* if torn off, make this a normal window
473 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
475 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
477 _tearoff->tearoff_window().set_title (X_("Monitor"));
478 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
480 update_output_display ();
481 update_processor_box ();
482 _ui_initialized = true;
484 /* catch changes that affect us */
485 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
486 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
488 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
491 MonitorSection::~MonitorSection ()
493 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
497 _channel_buttons.clear ();
498 output_changed_connections.drop_connections ();
500 delete insert_box; insert_box = 0;
501 delete output_button; output_button = 0;
502 delete gain_control; gain_control = 0;
503 delete gain_display; gain_display = 0;
504 delete dim_control; dim_control = 0;
505 delete dim_display; dim_display = 0;
506 delete solo_boost_control; solo_boost_control = 0;
507 delete solo_boost_display; solo_boost_display = 0;
508 delete solo_cut_control; solo_cut_control = 0;
509 delete solo_cut_display; solo_cut_display = 0;
510 delete _tearoff; _tearoff = 0;
511 delete _output_selector; _output_selector = 0;
512 delete channel_table; channel_table = 0;
516 MonitorSection::enter_handler (GdkEventCrossing* ev)
523 MonitorSection::leave_handler (GdkEventCrossing* ev)
525 switch (ev->detail) {
526 case GDK_NOTIFY_INFERIOR:
532 /* cancel focus if we're not torn off. With X11 WM's that do
533 * focus-follows-mouse, focus will be taken from us anyway.
536 Widget* top = get_toplevel();
538 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
539 Window* win = dynamic_cast<Window*> (top);
540 gtk_window_set_focus (win->gobj(), 0);
547 MonitorSection::update_processor_box ()
549 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
551 if (count_processors () > 0 && !show_processor_box) {
552 toggle_processorbox_button.set_name (X_("monitor section processors present"));
554 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
557 if (insert_box->is_visible() == show_processor_box) {
561 if (show_processor_box) {
562 if (master_packer.get_parent()) {
563 master_packer.get_parent()->remove (master_packer);
566 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
568 if (master_packer.get_parent()) {
569 master_packer.get_parent()->remove (master_packer);
572 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
577 MonitorSection::set_session (Session* s)
579 RouteUI::set_session (s);
580 _plugin_selector->set_session (_session);
584 /* These are not actually dependent on the Session, but they
585 * need to be set after construction, not during, and
586 * this is as good a place as any.
589 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
590 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
592 _route = _session->monitor_out ();
595 /* session with monitor section */
596 _monitor = _route->monitor_control ();
597 assign_controllables ();
598 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
599 boost::bind (&MonitorSection::update_output_display, this),
601 insert_box->set_route (_route);
602 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
603 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
604 if (_ui_initialized) {
605 update_processor_box ();
608 ActionManager::set_sensitive (monitor_actions, true);
609 ActionManager::set_sensitive (solo_actions, true);
612 /* session with no monitor section */
613 output_changed_connections.drop_connections();
616 delete _output_selector;
617 _output_selector = 0;
619 ActionManager::set_sensitive (monitor_actions, false);
620 ActionManager::set_sensitive (solo_actions, true);
630 output_changed_connections.drop_connections();
633 control_connections.drop_connections ();
634 rude_iso_button.unset_active_state ();
635 rude_solo_button.unset_active_state ();
636 delete _output_selector;
637 _output_selector = 0;
639 assign_controllables ();
641 ActionManager::set_sensitive (monitor_actions, false);
642 ActionManager::set_sensitive (solo_actions, false);
646 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
648 cut.set_name (X_("mute button"));
649 dim.set_name (X_("monitor section dim"));
650 solo.set_name (X_("solo button"));
651 invert.set_name (X_("invert button"));
653 cut.unset_flags (Gtk::CAN_FOCUS);
654 dim.unset_flags (Gtk::CAN_FOCUS);
655 solo.unset_flags (Gtk::CAN_FOCUS);
656 invert.unset_flags (Gtk::CAN_FOCUS);
660 MonitorSection::populate_buttons ()
667 channel_size_group->remove_widget (*channel_table);
668 delete channel_table;
671 channel_table = new Gtk::Table();
673 channel_table->set_col_spacings (6);
674 channel_table->set_row_spacings (6);
675 channel_table->set_homogeneous (true);
677 channel_size_group->add_widget (*channel_table);
678 channel_table->show ();
679 table_hpacker.pack_start (*channel_table, true, true);
681 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
684 _channel_buttons.clear ();
686 Glib::RefPtr<Action> act;
687 uint32_t nchans = _monitor->output_streams().n_audio();
689 channel_table->resize (nchans, 5);
691 const uint32_t row_offset = 0;
693 for (uint32_t i = 0; i < nchans; ++i) {
706 snprintf (buf, sizeof (buf), "%d", i+1);
710 Label* label = manage (new Label (l));
711 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
713 ChannelButtonSet* cbs = new ChannelButtonSet;
715 _channel_buttons.push_back (cbs);
717 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
718 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
719 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
720 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
722 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
723 act = ActionManager::get_action (X_("Monitor"), buf);
725 cbs->cut.set_related_action (act);
728 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
729 act = ActionManager::get_action (X_("Monitor"), buf);
731 cbs->dim.set_related_action (act);
734 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
735 act = ActionManager::get_action (X_("Monitor"), buf);
737 cbs->solo.set_related_action (act);
740 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
741 act = ActionManager::get_action (X_("Monitor"), buf);
743 cbs->invert.set_related_action (act);
747 channel_table->show_all ();
749 if (channel_table_scroller.get_parent()) {
750 /* scroller is packed, so remove it */
751 channel_table_packer.remove (channel_table_scroller);
754 if (table_hpacker.get_parent () == &channel_table_packer) {
755 /* this occurs when the table hpacker is directly
756 packed, so remove it.
758 channel_table_packer.remove (table_hpacker);
759 } else if (table_hpacker.get_parent()) {
760 channel_table_viewport.remove ();
764 /* put the table into a scrolled window, and then put
765 * that into the channel vpacker, after the table header
767 channel_table_viewport.add (table_hpacker);
768 channel_table_packer.pack_start (channel_table_scroller, true, true);
769 channel_table_viewport.show ();
770 channel_table_scroller.show ();
773 /* just put the channel table itself into the channel
774 * vpacker, after the table header
776 channel_table_packer.pack_start (table_hpacker, true, true);
777 channel_table_scroller.hide ();
779 table_hpacker.show ();
780 channel_table->show ();
784 MonitorSection::toggle_exclusive_solo ()
790 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
794 MonitorSection::toggle_mute_overrides_solo ()
800 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), "toggle-mute-overrides-solo");
802 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
803 Config->set_solo_mute_override (tact->get_active());
808 MonitorSection::dim_all ()
814 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
816 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
817 _monitor->set_dim_all (tact->get_active());
823 MonitorSection::cut_all ()
829 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
831 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
832 _monitor->set_cut_all (tact->get_active());
837 MonitorSection::mono ()
843 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
845 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
846 _monitor->set_mono (tact->get_active());
851 MonitorSection::cut_channel (uint32_t chn)
858 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
860 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
862 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
863 _monitor->set_cut (chn, tact->get_active());
868 MonitorSection::dim_channel (uint32_t chn)
875 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
877 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
879 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
880 _monitor->set_dim (chn, tact->get_active());
886 MonitorSection::solo_channel (uint32_t chn)
893 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
895 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
897 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
898 _monitor->set_solo (chn, tact->get_active());
904 MonitorSection::invert_channel (uint32_t chn)
911 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
913 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
915 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
916 _monitor->set_polarity (chn, tact->get_active());
921 MonitorSection::register_actions ()
925 Glib::RefPtr<Action> act;
927 /* ...will get sensitized if a mon-session is added */
929 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
930 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
932 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
933 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", _("Monitor Section: Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
934 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", _("Monitor Section: Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
935 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", _("Monitor Section: Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
937 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
938 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
941 for (uint32_t chn = 0; chn < 16; ++chn) {
943 action_name = string_compose (X_("monitor-cut-%1"), chn);
944 action_descr = string_compose (_("Cut monitor channel %1"), chn);
945 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
946 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
948 action_name = string_compose (X_("monitor-dim-%1"), chn);
949 action_descr = string_compose (_("Dim monitor channel %1"), chn);
950 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
951 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
953 action_name = string_compose (X_("monitor-solo-%1"), chn);
954 action_descr = string_compose (_("Solo monitor channel %1"), chn);
955 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
956 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
958 action_name = string_compose (X_("monitor-invert-%1"), chn);
959 action_descr = string_compose (_("Invert monitor channel %1"), chn);
960 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
961 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
965 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
966 RadioAction::Group solo_group;
968 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
969 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
970 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
971 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
972 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
973 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
975 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
976 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
977 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
978 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
982 MonitorSection::solo_use_in_place ()
984 /* this is driven by a toggle on a radio group, and so is invoked twice,
985 once for the item that became inactive and once for the one that became
989 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
992 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
994 if (!ract->get_active ()) {
995 /* We are turning SiP off, which means that AFL or PFL will be turned on
996 shortly; don't update the solo model in the mean time, as if the currently
997 configured listen position is not the one that is about to be turned on,
998 things will go wrong.
1000 _inhibit_solo_model_update = true;
1002 Config->set_solo_control_is_listen_control (!ract->get_active());
1003 _inhibit_solo_model_update = false;
1009 MonitorSection::solo_use_afl ()
1011 /* this is driven by a toggle on a radio group, and so is invoked twice,
1012 once for the item that became inactive and once for the one that became
1016 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1018 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1020 if (ract->get_active()) {
1021 Config->set_solo_control_is_listen_control (true);
1022 Config->set_listen_position (AfterFaderListen);
1029 MonitorSection::solo_use_pfl ()
1031 /* this is driven by a toggle on a radio group, and so is invoked twice,
1032 once for the item that became inactive and once for the one that became
1036 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1038 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1040 if (ract->get_active()) {
1041 Config->set_solo_control_is_listen_control (true);
1042 Config->set_listen_position (PreFaderListen);
1049 MonitorSection::update_solo_model ()
1051 if (_inhibit_solo_model_update) {
1055 const char* action_name = 0;
1056 Glib::RefPtr<Action> act;
1058 if (Config->get_solo_control_is_listen_control()) {
1059 switch (Config->get_listen_position()) {
1060 case AfterFaderListen:
1061 action_name = X_("solo-use-afl");
1063 case PreFaderListen:
1064 action_name = X_("solo-use-pfl");
1068 action_name = X_("solo-use-in-place");
1071 act = ActionManager::get_action (X_("Solo"), action_name);
1074 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1076 /* because these are radio buttons, one of them will be
1077 active no matter what. to trigger a change in the
1078 action so that the view picks it up, toggle it.
1080 if (ract->get_active()) {
1081 ract->set_active (false);
1083 ract->set_active (true);
1090 MonitorSection::map_state ()
1092 if (!_route || !_monitor) {
1096 update_solo_model ();
1098 Glib::RefPtr<Action> act;
1099 Glib::RefPtr<ToggleAction> tact;
1101 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1103 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1105 tact->set_active (_monitor->cut_all());
1109 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1111 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1113 tact->set_active (_monitor->dim_all());
1117 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1119 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1121 tact->set_active (_monitor->mono());
1125 uint32_t nchans = _monitor->output_streams().n_audio();
1127 assert (nchans == _channel_buttons.size ());
1129 for (uint32_t n = 0; n < nchans; ++n) {
1131 char action_name[32];
1133 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1134 act = ActionManager::get_action (X_("Monitor"), action_name);
1136 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1138 tact->set_active (_monitor->cut (n));
1142 snprintf (action_name, sizeof (action_name), "monitor-dim-%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->dimmed (n));
1151 snprintf (action_name, sizeof (action_name), "monitor-solo-%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->soloed (n));
1160 snprintf (action_name, sizeof (action_name), "monitor-invert-%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->inverted (n));
1172 MonitorSection::do_blink (bool onoff)
1174 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1179 audition_blink (onoff);
1183 MonitorSection::audition_blink (bool onoff)
1185 if (_session == 0) {
1189 if (_session->is_auditioning()) {
1190 rude_audition_button.set_active (onoff);
1192 rude_audition_button.set_active (false);
1197 MonitorSection::solo_blink (bool onoff)
1199 if (_session == 0) {
1203 if (_session->soloing() || _session->listening()) {
1204 rude_solo_button.set_active (onoff);
1206 if (_session->soloing()) {
1207 if (_session->solo_isolated()) {
1208 rude_iso_button.set_active (onoff);
1210 rude_iso_button.set_active (false);
1215 rude_solo_button.set_active (false);
1216 rude_iso_button.set_active (false);
1221 MonitorSection::cancel_isolate (GdkEventButton*)
1224 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1225 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1232 MonitorSection::cancel_audition (GdkEventButton*)
1235 _session->cancel_audition();
1240 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1241 if (action && action->get_active() != value) { \
1242 action->set_active(value); \
1246 MonitorSection::parameter_changed (std::string name)
1248 if (name == "solo-control-is-listen-control") {
1249 update_solo_model ();
1250 } else if (name == "listen-position") {
1251 update_solo_model ();
1252 } else if (name == "solo-mute-override") {
1253 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1254 } else if (name == "exclusive-solo") {
1255 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1260 MonitorSection::assign_controllables ()
1262 boost::shared_ptr<Controllable> none;
1264 if (!gain_control) {
1265 /* too early - GUI controls not set up yet */
1270 solo_cut_control->set_controllable (_session->solo_cut_control());
1271 solo_cut_display->set_controllable (_session->solo_cut_control());
1273 solo_cut_control->set_controllable (none);
1274 solo_cut_display->set_controllable (none);
1278 gain_control->set_controllable (_route->gain_control());
1279 gain_display->set_controllable (_route->gain_control());
1281 gain_control->set_controllable (none);
1286 cut_all_button.set_controllable (_monitor->cut_control());
1287 cut_all_button.watch ();
1288 dim_all_button.set_controllable (_monitor->dim_control());
1289 dim_all_button.watch ();
1290 mono_button.set_controllable (_monitor->mono_control());
1291 mono_button.watch ();
1293 dim_control->set_controllable (_monitor->dim_level_control ());
1294 dim_display->set_controllable (_monitor->dim_level_control ());
1295 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1296 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1300 cut_all_button.set_controllable (none);
1301 dim_all_button.set_controllable (none);
1302 mono_button.set_controllable (none);
1304 dim_control->set_controllable (none);
1305 dim_display->set_controllable (none);
1306 solo_boost_control->set_controllable (none);
1307 solo_boost_display->set_controllable (none);
1312 MonitorSection::state_id() const
1314 return "monitor-section";
1318 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1320 using namespace Menu_Helpers;
1322 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1326 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1327 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1331 if (i != output_menu_bundles.end()) {
1335 output_menu_bundles.push_back (b);
1337 MenuList& citems = output_menu.items();
1339 std::string n = b->name ();
1340 replace_all (n, "_", " ");
1342 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1346 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1349 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1351 if (std::find (current.begin(), current.end(), c) == current.end()) {
1352 _route->output()->connect_ports_to_bundle (c, true, this);
1354 _route->output()->disconnect_ports_from_bundle (c, this);
1359 MonitorSection::output_release (GdkEventButton *ev)
1361 switch (ev->button) {
1363 edit_output_configuration ();
1370 struct RouteCompareByName {
1371 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1372 return a->name().compare (b->name()) < 0;
1377 MonitorSection::output_press (GdkEventButton *ev)
1379 using namespace Menu_Helpers;
1381 MessageDialog msg (_("No session - no I/O changes are possible"));
1386 MenuList& citems = output_menu.items();
1387 switch (ev->button) {
1390 return false; //wait for the mouse-up to pop the dialog
1394 output_menu.set_name ("ArdourContextMenu");
1396 output_menu_bundles.clear ();
1398 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1400 citems.push_back (SeparatorElem());
1401 uint32_t const n_with_separator = citems.size ();
1403 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1405 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1407 /* give user bundles first chance at being in the menu */
1409 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1410 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1411 maybe_add_bundle_to_output_menu (*i, current);
1415 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1416 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1417 maybe_add_bundle_to_output_menu (*i, current);
1421 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1422 RouteList copy = *routes;
1423 copy.sort (RouteCompareByName ());
1424 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1425 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1428 if (citems.size() == n_with_separator) {
1429 /* no routes added; remove the separator */
1433 citems.push_back (SeparatorElem());
1434 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1436 output_menu.popup (1, ev->time);
1447 MonitorSection::update_output_display ()
1449 if (!_route || !_monitor || _session->deletion_in_progress()) {
1455 boost::shared_ptr<Port> port;
1456 vector<string> port_connections;
1458 uint32_t total_connection_count = 0;
1459 uint32_t io_connection_count = 0;
1460 uint32_t ardour_connection_count = 0;
1461 uint32_t system_connection_count = 0;
1462 uint32_t other_connection_count = 0;
1464 ostringstream label;
1466 bool have_label = false;
1467 bool each_io_has_one_connection = true;
1469 string connection_name;
1470 string ardour_track_name;
1471 string other_connection_type;
1472 string system_ports;
1475 ostringstream tooltip;
1476 char * tooltip_cstr;
1478 io_count = _route->n_outputs().n_total();
1479 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1482 for (io_index = 0; io_index < io_count; ++io_index) {
1484 port = _route->output()->nth (io_index);
1486 //ignore any port connections that don't match our DataType
1487 if (port->type() != DataType::AUDIO) {
1491 port_connections.clear ();
1492 port->get_connections(port_connections);
1493 io_connection_count = 0;
1495 if (!port_connections.empty()) {
1496 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1498 string& connection_name (*i);
1500 if (connection_name.find("system:") == 0) {
1501 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1504 if (io_connection_count == 0) {
1505 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1507 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1510 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1513 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1514 if (ardour_track_name.empty()) {
1515 // "ardour:Master/in 1" -> "ardour:Master/"
1516 string::size_type slash = connection_name.find("/");
1517 if (slash != string::npos) {
1518 ardour_track_name = connection_name.substr(0, slash + 1);
1522 if (connection_name.find(ardour_track_name) == 0) {
1523 ++ardour_connection_count;
1525 } else if (!pn.empty()) {
1526 if (system_ports.empty()) {
1529 system_ports += "/" + pn;
1531 if (connection_name.find("system:") == 0) {
1532 ++system_connection_count;
1534 } else if (connection_name.find("system:") == 0) {
1535 // "system:playback_123" -> "123"
1536 system_port = connection_name.substr(16);
1537 if (system_ports.empty()) {
1538 system_ports += system_port;
1540 system_ports += "/" + system_port;
1543 ++system_connection_count;
1545 if (other_connection_type.empty()) {
1546 // "jamin:in 1" -> "jamin:"
1547 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1550 if (connection_name.find(other_connection_type) == 0) {
1551 ++other_connection_count;
1555 ++total_connection_count;
1556 ++io_connection_count;
1560 if (io_connection_count != 1) {
1561 each_io_has_one_connection = false;
1565 if (total_connection_count == 0) {
1566 tooltip << endl << _("Disconnected");
1569 tooltip_cstr = new char[tooltip.str().size() + 1];
1570 strcpy(tooltip_cstr, tooltip.str().c_str());
1572 set_tooltip (output_button, tooltip_cstr, "");
1574 if (each_io_has_one_connection) {
1575 if (total_connection_count == ardour_connection_count) {
1576 // all connections are to the same track in ardour
1577 // "ardour:Master/" -> "Master"
1578 string::size_type slash = ardour_track_name.find("/");
1579 if (slash != string::npos) {
1580 label << ardour_track_name.substr(7, slash - 7);
1583 } else if (total_connection_count == system_connection_count) {
1584 // all connections are to system ports
1585 label << system_ports;
1587 } else if (total_connection_count == other_connection_count) {
1588 // all connections are to the same external program eg jamin
1589 // "jamin:" -> "jamin"
1590 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1596 if (total_connection_count == 0) {
1600 // Odd configuration
1601 label << "*" << total_connection_count << "*";
1605 output_button->set_text (label.str());
1609 MonitorSection::disconnect_output ()
1612 _route->output()->disconnect(this);
1617 MonitorSection::edit_output_configuration ()
1619 if (_output_selector == 0) {
1620 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1622 _output_selector->present ();
1626 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1631 boost::shared_ptr<Port> a = wa.lock ();
1632 boost::shared_ptr<Port> b = wb.lock ();
1633 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1634 update_output_display ();
1639 MonitorSection::load_bindings ()
1641 bindings = Bindings::get_bindings (X_("Monitor Section"));
1645 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1647 boost::shared_ptr<Processor> processor (p.lock ());
1648 if (!processor || !processor->display_to_user()) {
1651 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1658 MonitorSection::count_processors ()
1660 uint32_t processor_count = 0;
1662 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1664 return processor_count;
1668 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1670 update_processor_box ();
1674 MonitorSection::use_others_actions ()
1676 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1680 MonitorSection::toggle_use_monitor_section ()
1686 bool yn = ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active();
1689 _session->add_monitor_section ();
1691 _session->remove_monitor_section ();
1694 Config->set_use_monitor_bus (yn);