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 "widgets/tooltips.h"
36 #include "ardour/amp.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/monitor_processor.h"
39 #include "ardour/port.h"
40 #include "ardour/route.h"
41 #include "ardour/solo_isolate_control.h"
42 #include "ardour/user_bundle.h"
43 #include "ardour/plugin_manager.h"
45 #include "ardour_ui.h"
46 #include "gui_thread.h"
48 #include "monitor_section.h"
49 #include "public_editor.h"
51 #include "ui_config.h"
56 using namespace ARDOUR;
57 using namespace ArdourWidgets;
58 using namespace ARDOUR_UI_UTILS;
60 using namespace Gtkmm2ext;
64 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
65 Gtkmm2ext::ActionMap MonitorSection::myactions (X_("monitor section"));
66 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
68 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
70 MonitorSection::MonitorSection (Session* s)
71 : SessionHandlePtr (s)
75 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
76 , *channel_table_scroller.get_vadjustment ())
79 , solo_boost_control (0)
80 , solo_cut_control (0)
83 , solo_boost_display (0)
84 , solo_cut_display (0)
85 , _output_selector (0)
86 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
87 , afl_button (_("AFL"), ArdourButton::led_default_elements)
88 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
89 , exclusive_solo_button (ArdourButton::led_default_elements)
90 , solo_mute_override_button (ArdourButton::led_default_elements)
91 , toggle_processorbox_button (ArdourButton::default_elements)
92 , _inhibit_solo_model_update (false)
94 , _ui_initialized (false)
97 using namespace Menu_Helpers;
99 Glib::RefPtr<Action> act;
101 if (!monitor_actions) {
106 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
108 set_data ("ardour-bindings", bindings);
110 _plugin_selector = new PluginSelector (PluginManager::instance());
111 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
112 insert_box->set_no_show_all ();
114 // TODO allow keyboard shortcuts in ProcessorBox
118 /* Rude Solo & Solo Isolated */
119 rude_solo_button.set_text (_("Soloing"));
120 rude_solo_button.set_name ("rude solo");
121 rude_solo_button.show ();
123 rude_iso_button.set_text (_("Isolated"));
124 rude_iso_button.set_name ("rude isolate");
125 rude_iso_button.show ();
127 rude_audition_button.set_text (_("Auditioning"));
128 rude_audition_button.set_name ("rude audition");
129 rude_audition_button.show ();
131 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
133 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
134 rude_solo_button.set_related_action (act);
135 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
137 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
138 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
140 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
141 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
143 /* SIP, AFL, PFL radio */
145 solo_in_place_button.set_name ("monitor section solo model");
146 afl_button.set_name ("monitor section solo model");
147 pfl_button.set_name ("monitor section solo model");
149 solo_in_place_button.set_led_left (true);
150 afl_button.set_led_left (true);
151 pfl_button.set_led_left (true);
153 solo_in_place_button.show ();
157 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
158 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
160 solo_in_place_button.set_related_action (act);
163 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
164 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
166 afl_button.set_related_action (act);
169 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
170 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
172 pfl_button.set_related_action (act);
175 /* Solo option buttons */
176 exclusive_solo_button.set_text (_("Excl. Solo"));
177 exclusive_solo_button.set_name (X_("monitor section solo option"));
178 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
180 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
182 exclusive_solo_button.set_related_action (act);
185 solo_mute_override_button.set_text (_("Solo ยป Mute"));
186 solo_mute_override_button.set_name (X_("monitor section solo option"));
187 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
189 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
191 solo_mute_override_button.set_related_action (act);
194 /* Processor Box hide/shos */
195 toggle_processorbox_button.set_text (_("Processors"));
196 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
197 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
199 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
200 toggle_processorbox_button.set_related_action (proctoggle);
203 Label* solo_boost_label;
204 Label* solo_cut_label;
207 /* Solo Boost Knob */
209 solo_boost_control = new ArdourKnob ();
210 solo_boost_control->set_name("monitor section knob");
211 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
212 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
214 solo_boost_display = new ArdourDisplay ();
215 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
216 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
217 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
218 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
219 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
221 solo_boost_label = manage (new Label (_("Solo Boost")));
225 solo_cut_control = new ArdourKnob ();
226 solo_cut_control->set_name ("monitor section knob");
227 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
228 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
230 solo_cut_display = new ArdourDisplay ();
231 solo_cut_display->set_name("monitor section dropdown"); // XXX
232 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
233 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
234 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
235 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
236 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
237 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
239 solo_cut_label = manage (new Label (_("SiP Cut")));
243 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
244 dim_control->set_name ("monitor section knob");
245 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
246 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
248 dim_display = new ArdourDisplay ();
249 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
250 dim_display->add_controllable_preset(_("0 dB"), 0.0);
251 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
252 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
253 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
254 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
256 dim_label = manage (new Label (_("Dim")));
259 cut_all_button.set_text (_("Mute"));
260 cut_all_button.set_name ("mute button");
261 cut_all_button.set_size_request (-1, PX_SCALE(30));
262 cut_all_button.show ();
264 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
266 cut_all_button.set_related_action (act);
270 dim_all_button.set_text (_("Dim"));
271 dim_all_button.set_name ("monitor section dim");
272 dim_all_button.set_size_request (-1, PX_SCALE(25));
273 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
275 dim_all_button.set_related_action (act);
279 mono_button.set_text (_("Mono"));
280 mono_button.set_name ("monitor section mono");
281 mono_button.set_size_request (-1, PX_SCALE(25));
282 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
284 mono_button.set_related_action (act);
289 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
290 gain_control->set_name("monitor section knob");
291 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
293 gain_display = new ArdourDisplay ();
294 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
295 gain_display->add_controllable_preset(_("0 dB"), 0.0);
296 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
297 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
298 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
299 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
300 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
302 Label* output_label = manage (new Label (_("Output")));
303 output_label->set_name (X_("MonitorSectionLabel"));
305 output_button = new ArdourButton ();
306 output_button->set_text (_("Output"));
307 output_button->set_name (X_("monitor section cut")); // XXX
308 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
309 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
311 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
312 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
313 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
314 channel_table_scroller.show ();
315 channel_table_scroller.add (channel_table_viewport);
317 channel_size_group->add_widget (channel_table_header);
318 channel_table_header.resize (1, 5);
320 Label* l1 = manage (new Label (X_(" ")));
321 l1->set_name (X_("MonitorSectionLabel"));
322 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
324 l1 = manage (new Label (_("Mute")));
325 l1->set_name (X_("MonitorSectionLabel"));
326 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
328 l1 = manage (new Label (_("Dim")));
329 l1->set_name (X_("MonitorSectionLabel"));
330 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
332 l1 = manage (new Label (_("Solo")));
333 l1->set_name (X_("MonitorSectionLabel"));
334 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
336 l1 = manage (new Label (_("Inv")));
337 l1->set_name (X_("MonitorSectionLabel"));
338 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
340 channel_table_header.show ();
343 /****************************************************************************
344 * LAYOUT top to bottom
347 // solo, iso information
348 HBox* rude_box = manage (new HBox);
349 rude_box->set_spacing (PX_SCALE(4));
350 rude_box->set_homogeneous (true);
351 rude_box->pack_start (rude_solo_button, true, true);
352 rude_box->pack_start (rude_iso_button, true, true);
354 // solo options (right align)
355 HBox* tbx1 = manage (new HBox);
356 tbx1->pack_end (exclusive_solo_button, false, false);
358 HBox* tbx2 = manage (new HBox);
359 tbx2->pack_end (solo_mute_override_button, false, false);
361 HBox* tbx3 = manage (new HBox);
362 tbx3->pack_end (toggle_processorbox_button, false, false);
364 HBox* tbx0 = manage (new HBox); // space
366 // combined solo mode (Sip, AFL, PFL) & solo options
367 Table *solo_tbl = manage (new Table);
368 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
369 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
370 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
371 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
372 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
373 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
374 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
376 // boost, cut, dim volume control
377 Table *level_tbl = manage (new Table);
378 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
379 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
382 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
383 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
384 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
386 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
387 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
388 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
391 HBox* mono_dim_box = manage (new HBox);
392 mono_dim_box->set_spacing (PX_SCALE(4));
393 mono_dim_box->set_homogeneous (true);
394 mono_dim_box->pack_start (mono_button, true, true);
395 mono_dim_box->pack_end (dim_all_button, true, true);
398 Label* spin_label = manage (new Label (_("Monitor")));
399 VBox* spin_packer = manage (new VBox);
400 spin_packer->set_spacing (PX_SCALE(2));
401 spin_packer->pack_start (*spin_label, false, false);
402 spin_packer->pack_start (*gain_control, false, false);
403 spin_packer->pack_start (*gain_display, false, false);
405 master_packer.pack_start (*spin_packer, true, false);
407 // combined gain section (channels, mute, dim)
408 VBox* lower_packer = manage (new VBox);
409 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
410 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
411 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
412 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
414 // calc height of mixer scrollbar
415 int scrollbar_height = 0;
417 Gtk::Window window (WINDOW_TOPLEVEL);
418 HScrollbar scrollbar;
419 window.add (scrollbar);
420 scrollbar.set_name ("MixerWindow");
421 scrollbar.ensure_style();
422 Gtk::Requisition requisition(scrollbar.size_request ());
423 scrollbar_height = requisition.height;
426 // output port select
427 VBox* out_packer = manage (new VBox);
428 out_packer->set_spacing (PX_SCALE(2));
429 out_packer->pack_start (*output_label, false, false);
430 out_packer->pack_start (*output_button, false, false);
432 /****************************************************************************
435 vpacker.set_border_width (PX_SCALE(3));
436 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
437 vpacker.pack_start (rude_audition_button, false, false, 0);
438 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
439 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
440 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
441 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
442 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
443 vpacker.pack_end (*out_packer, false, false,
445 scrollbar_height - 2 /* no outer frame */
447 scrollbar_height + 2 /* frame borders */
451 hpacker.set_spacing (0);
452 hpacker.pack_start (vpacker, true, true);
456 gain_control->show_all ();
457 gain_display->show_all ();
458 dim_control->show_all ();
459 dim_display->show_all();
460 solo_boost_control->show_all ();
461 solo_boost_display->show_all();
463 mono_dim_box->show ();
464 spin_packer->show ();
465 master_packer.show ();
468 solo_tbl->show_all();
470 lower_packer->show ();
477 assign_controllables ();
479 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
480 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
482 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
483 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
484 set_flags (CAN_FOCUS);
486 _tearoff = new TearOff (*this);
488 if (!UIConfiguration::instance().get_floating_monitor_section()) {
489 /* if torn off, make this a normal window
490 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
492 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
494 _tearoff->tearoff_window().set_title (X_("Monitor"));
495 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
497 update_output_display ();
498 update_processor_box ();
499 _ui_initialized = true;
501 /* catch changes that affect us */
502 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
503 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
505 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
508 MonitorSection::~MonitorSection ()
510 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
514 _channel_buttons.clear ();
515 output_changed_connections.drop_connections ();
517 delete insert_box; insert_box = 0;
518 delete output_button; output_button = 0;
519 delete gain_control; gain_control = 0;
520 delete gain_display; gain_display = 0;
521 delete dim_control; dim_control = 0;
522 delete dim_display; dim_display = 0;
523 delete solo_boost_control; solo_boost_control = 0;
524 delete solo_boost_display; solo_boost_display = 0;
525 delete solo_cut_control; solo_cut_control = 0;
526 delete solo_cut_display; solo_cut_display = 0;
527 delete _tearoff; _tearoff = 0;
528 delete _output_selector; _output_selector = 0;
529 delete channel_table; channel_table = 0;
533 MonitorSection::enter_handler (GdkEventCrossing* ev)
540 MonitorSection::leave_handler (GdkEventCrossing* ev)
542 switch (ev->detail) {
543 case GDK_NOTIFY_INFERIOR:
549 /* cancel focus if we're not torn off. With X11 WM's that do
550 * focus-follows-mouse, focus will be taken from us anyway.
553 Widget* top = get_toplevel();
555 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
556 Window* win = dynamic_cast<Window*> (top);
557 gtk_window_set_focus (win->gobj(), 0);
564 MonitorSection::update_processor_box ()
566 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
568 if (count_processors () > 0 && !show_processor_box) {
569 toggle_processorbox_button.set_name (X_("monitor section processors present"));
571 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
574 if (insert_box->is_visible() == show_processor_box) {
578 if (show_processor_box) {
579 if (master_packer.get_parent()) {
580 master_packer.get_parent()->remove (master_packer);
583 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
585 if (master_packer.get_parent()) {
586 master_packer.get_parent()->remove (master_packer);
589 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
594 MonitorSection::set_session (Session* s)
596 RouteUI::set_session (s);
597 _plugin_selector->set_session (_session);
601 _route = _session->monitor_out ();
604 /* session with monitor section */
605 _monitor = _route->monitor_control ();
606 assign_controllables ();
607 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
608 boost::bind (&MonitorSection::update_output_display, this),
610 insert_box->set_route (_route);
611 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
612 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
613 if (_ui_initialized) {
614 update_processor_box ();
617 /* session with no monitor section */
618 output_changed_connections.drop_connections();
621 delete _output_selector;
622 _output_selector = 0;
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 ();
643 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
645 cut.set_name (X_("mute button"));
646 dim.set_name (X_("monitor section dim"));
647 solo.set_name (X_("solo button"));
648 invert.set_name (X_("invert button"));
650 cut.unset_flags (Gtk::CAN_FOCUS);
651 dim.unset_flags (Gtk::CAN_FOCUS);
652 solo.unset_flags (Gtk::CAN_FOCUS);
653 invert.unset_flags (Gtk::CAN_FOCUS);
657 MonitorSection::populate_buttons ()
664 channel_size_group->remove_widget (*channel_table);
665 delete channel_table;
668 channel_table = new Gtk::Table();
670 channel_table->set_col_spacings (6);
671 channel_table->set_row_spacings (6);
672 channel_table->set_homogeneous (true);
674 channel_size_group->add_widget (*channel_table);
675 channel_table->show ();
676 table_hpacker.pack_start (*channel_table, true, true);
678 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
681 _channel_buttons.clear ();
683 Glib::RefPtr<Action> act;
684 uint32_t nchans = _monitor->output_streams().n_audio();
686 channel_table->resize (nchans, 5);
688 const uint32_t row_offset = 0;
690 for (uint32_t i = 0; i < nchans; ++i) {
703 snprintf (buf, sizeof (buf), "%d", i+1);
707 Label* label = manage (new Label (l));
708 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
710 ChannelButtonSet* cbs = new ChannelButtonSet;
712 _channel_buttons.push_back (cbs);
714 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
715 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
716 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
717 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
719 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
720 act = ActionManager::get_action (X_("Monitor"), buf);
722 cbs->cut.set_related_action (act);
725 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
726 act = ActionManager::get_action (X_("Monitor"), buf);
728 cbs->dim.set_related_action (act);
731 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
732 act = ActionManager::get_action (X_("Monitor"), buf);
734 cbs->solo.set_related_action (act);
737 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
738 act = ActionManager::get_action (X_("Monitor"), buf);
740 cbs->invert.set_related_action (act);
744 channel_table->show_all ();
746 if (channel_table_scroller.get_parent()) {
747 /* scroller is packed, so remove it */
748 channel_table_packer.remove (channel_table_scroller);
751 if (table_hpacker.get_parent () == &channel_table_packer) {
752 /* this occurs when the table hpacker is directly
753 packed, so remove it.
755 channel_table_packer.remove (table_hpacker);
756 } else if (table_hpacker.get_parent()) {
757 channel_table_viewport.remove ();
761 /* put the table into a scrolled window, and then put
762 * that into the channel vpacker, after the table header
764 channel_table_viewport.add (table_hpacker);
765 channel_table_packer.pack_start (channel_table_scroller, true, true);
766 channel_table_viewport.show ();
767 channel_table_scroller.show ();
770 /* just put the channel table itself into the channel
771 * vpacker, after the table header
773 channel_table_packer.pack_start (table_hpacker, true, true);
774 channel_table_scroller.hide ();
776 table_hpacker.show ();
777 channel_table->show ();
781 MonitorSection::toggle_exclusive_solo ()
787 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
789 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
790 Config->set_exclusive_solo (tact->get_active());
796 MonitorSection::toggle_mute_overrides_solo ()
802 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
804 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
805 Config->set_solo_mute_override (tact->get_active());
810 MonitorSection::dim_all ()
816 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
818 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
819 _monitor->set_dim_all (tact->get_active());
825 MonitorSection::cut_all ()
831 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
833 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
834 _monitor->set_cut_all (tact->get_active());
839 MonitorSection::mono ()
845 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
847 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
848 _monitor->set_mono (tact->get_active());
853 MonitorSection::cut_channel (uint32_t chn)
860 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
862 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
864 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
865 _monitor->set_cut (chn, tact->get_active());
870 MonitorSection::dim_channel (uint32_t chn)
877 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
879 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
881 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
882 _monitor->set_dim (chn, tact->get_active());
888 MonitorSection::solo_channel (uint32_t chn)
895 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
897 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
899 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
900 _monitor->set_solo (chn, tact->get_active());
906 MonitorSection::invert_channel (uint32_t chn)
913 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
915 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
917 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
918 _monitor->set_polarity (chn, tact->get_active());
923 MonitorSection::register_actions ()
927 Glib::RefPtr<Action> act;
929 monitor_actions = myactions.create_action_group (X_("Monitor"));
931 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
932 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
934 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
935 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
937 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
938 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
940 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
941 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
943 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
944 tact->set_active (Config->get_exclusive_solo());
946 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
947 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
949 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
950 tact->set_active (Config->get_solo_mute_override());
952 for (uint32_t chn = 0; chn < 16; ++chn) {
954 action_name = string_compose (X_("monitor-cut-%1"), chn);
955 action_descr = string_compose (_("Cut monitor channel %1"), chn);
956 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
957 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
959 action_name = string_compose (X_("monitor-dim-%1"), chn);
960 action_descr = string_compose (_("Dim monitor channel %1"), chn);
961 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
962 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
964 action_name = string_compose (X_("monitor-solo-%1"), chn);
965 action_descr = string_compose (_("Solo monitor channel %1"), chn);
966 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
967 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
969 action_name = string_compose (X_("monitor-invert-%1"), chn);
970 action_descr = string_compose (_("Invert monitor channel %1"), chn);
971 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
972 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
977 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
978 RadioAction::Group solo_group;
980 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
981 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
982 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
983 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
984 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
985 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
987 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
988 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
993 MonitorSection::solo_use_in_place ()
995 /* this is driven by a toggle on a radio group, and so is invoked twice,
996 once for the item that became inactive and once for the one that became
1000 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
1003 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1005 if (!ract->get_active ()) {
1006 /* We are turning SiP off, which means that AFL or PFL will be turned on
1007 shortly; don't update the solo model in the mean time, as if the currently
1008 configured listen position is not the one that is about to be turned on,
1009 things will go wrong.
1011 _inhibit_solo_model_update = true;
1013 Config->set_solo_control_is_listen_control (!ract->get_active());
1014 _inhibit_solo_model_update = false;
1020 MonitorSection::solo_use_afl ()
1022 /* this is driven by a toggle on a radio group, and so is invoked twice,
1023 once for the item that became inactive and once for the one that became
1027 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1029 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1031 if (ract->get_active()) {
1032 Config->set_solo_control_is_listen_control (true);
1033 Config->set_listen_position (AfterFaderListen);
1040 MonitorSection::solo_use_pfl ()
1042 /* this is driven by a toggle on a radio group, and so is invoked twice,
1043 once for the item that became inactive and once for the one that became
1047 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1049 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1051 if (ract->get_active()) {
1052 Config->set_solo_control_is_listen_control (true);
1053 Config->set_listen_position (PreFaderListen);
1060 MonitorSection::update_solo_model ()
1062 if (_inhibit_solo_model_update) {
1066 const char* action_name = 0;
1067 Glib::RefPtr<Action> act;
1069 if (Config->get_solo_control_is_listen_control()) {
1070 switch (Config->get_listen_position()) {
1071 case AfterFaderListen:
1072 action_name = X_("solo-use-afl");
1074 case PreFaderListen:
1075 action_name = X_("solo-use-pfl");
1079 action_name = X_("solo-use-in-place");
1082 act = ActionManager::get_action (X_("Solo"), action_name);
1085 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1087 /* because these are radio buttons, one of them will be
1088 active no matter what. to trigger a change in the
1089 action so that the view picks it up, toggle it.
1091 if (ract->get_active()) {
1092 ract->set_active (false);
1094 ract->set_active (true);
1101 MonitorSection::map_state ()
1103 if (!_route || !_monitor) {
1107 Glib::RefPtr<Action> act;
1109 update_solo_model ();
1111 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1113 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1115 tact->set_active (_monitor->cut_all());
1119 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1121 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1123 tact->set_active (_monitor->dim_all());
1127 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1129 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1131 tact->set_active (_monitor->mono());
1135 uint32_t nchans = _monitor->output_streams().n_audio();
1137 assert (nchans == _channel_buttons.size ());
1139 for (uint32_t n = 0; n < nchans; ++n) {
1141 char action_name[32];
1143 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1144 act = ActionManager::get_action (X_("Monitor"), action_name);
1146 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1148 tact->set_active (_monitor->cut (n));
1152 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1153 act = ActionManager::get_action (X_("Monitor"), action_name);
1155 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1157 tact->set_active (_monitor->dimmed (n));
1161 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1162 act = ActionManager::get_action (X_("Monitor"), action_name);
1164 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1166 tact->set_active (_monitor->soloed (n));
1170 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1171 act = ActionManager::get_action (X_("Monitor"), action_name);
1173 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1175 tact->set_active (_monitor->inverted (n));
1182 MonitorSection::do_blink (bool onoff)
1184 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1189 audition_blink (onoff);
1193 MonitorSection::audition_blink (bool onoff)
1195 if (_session == 0) {
1199 if (_session->is_auditioning()) {
1200 rude_audition_button.set_active (onoff);
1202 rude_audition_button.set_active (false);
1207 MonitorSection::solo_blink (bool onoff)
1209 if (_session == 0) {
1213 if (_session->soloing() || _session->listening()) {
1214 rude_solo_button.set_active (onoff);
1216 if (_session->soloing()) {
1217 if (_session->solo_isolated()) {
1218 rude_iso_button.set_active (onoff);
1220 rude_iso_button.set_active (false);
1225 rude_solo_button.set_active (false);
1226 rude_iso_button.set_active (false);
1231 MonitorSection::cancel_isolate (GdkEventButton*)
1234 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1235 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1242 MonitorSection::cancel_audition (GdkEventButton*)
1245 _session->cancel_audition();
1250 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1252 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1253 if (tact && tact->get_active() != value) { \
1254 tact->set_active(value); \
1259 MonitorSection::parameter_changed (std::string name)
1261 if (name == "solo-control-is-listen-control") {
1262 update_solo_model ();
1263 } else if (name == "listen-position") {
1264 update_solo_model ();
1265 } else if (name == "solo-mute-override") {
1266 SYNCHRONIZE_TOGGLE_ACTION(
1267 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1268 Config->get_solo_mute_override ())
1269 } else if (name == "exclusive-solo") {
1270 SYNCHRONIZE_TOGGLE_ACTION(
1271 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1272 Config->get_exclusive_solo ())
1277 MonitorSection::assign_controllables ()
1279 boost::shared_ptr<Controllable> none;
1281 if (!gain_control) {
1282 /* too early - GUI controls not set up yet */
1287 solo_cut_control->set_controllable (_session->solo_cut_control());
1288 solo_cut_display->set_controllable (_session->solo_cut_control());
1290 solo_cut_control->set_controllable (none);
1291 solo_cut_display->set_controllable (none);
1295 gain_control->set_controllable (_route->gain_control());
1296 gain_display->set_controllable (_route->gain_control());
1298 gain_control->set_controllable (none);
1303 cut_all_button.set_controllable (_monitor->cut_control());
1304 cut_all_button.watch ();
1305 dim_all_button.set_controllable (_monitor->dim_control());
1306 dim_all_button.watch ();
1307 mono_button.set_controllable (_monitor->mono_control());
1308 mono_button.watch ();
1310 dim_control->set_controllable (_monitor->dim_level_control ());
1311 dim_display->set_controllable (_monitor->dim_level_control ());
1312 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1313 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1317 cut_all_button.set_controllable (none);
1318 dim_all_button.set_controllable (none);
1319 mono_button.set_controllable (none);
1321 dim_control->set_controllable (none);
1322 dim_display->set_controllable (none);
1323 solo_boost_control->set_controllable (none);
1324 solo_boost_display->set_controllable (none);
1329 MonitorSection::state_id() const
1331 return "monitor-section";
1335 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1337 using namespace Menu_Helpers;
1339 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1343 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1344 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1348 if (i != output_menu_bundles.end()) {
1352 output_menu_bundles.push_back (b);
1354 MenuList& citems = output_menu.items();
1356 std::string n = b->name ();
1357 replace_all (n, "_", " ");
1359 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1363 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1366 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1368 if (std::find (current.begin(), current.end(), c) == current.end()) {
1369 _route->output()->connect_ports_to_bundle (c, true, this);
1371 _route->output()->disconnect_ports_from_bundle (c, this);
1376 MonitorSection::output_release (GdkEventButton *ev)
1378 switch (ev->button) {
1380 edit_output_configuration ();
1387 struct RouteCompareByName {
1388 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1389 return a->name().compare (b->name()) < 0;
1394 MonitorSection::output_press (GdkEventButton *ev)
1396 using namespace Menu_Helpers;
1398 MessageDialog msg (_("No session - no I/O changes are possible"));
1403 MenuList& citems = output_menu.items();
1404 switch (ev->button) {
1407 return false; //wait for the mouse-up to pop the dialog
1411 output_menu.set_name ("ArdourContextMenu");
1413 output_menu_bundles.clear ();
1415 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1417 citems.push_back (SeparatorElem());
1418 uint32_t const n_with_separator = citems.size ();
1420 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1422 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1424 /* give user bundles first chance at being in the menu */
1426 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1427 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1428 maybe_add_bundle_to_output_menu (*i, current);
1432 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1433 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1434 maybe_add_bundle_to_output_menu (*i, current);
1438 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1439 RouteList copy = *routes;
1440 copy.sort (RouteCompareByName ());
1441 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1442 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1445 if (citems.size() == n_with_separator) {
1446 /* no routes added; remove the separator */
1450 citems.push_back (SeparatorElem());
1451 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1453 output_menu.popup (1, ev->time);
1464 MonitorSection::update_output_display ()
1466 if (!_route || !_monitor || _session->deletion_in_progress()) {
1472 boost::shared_ptr<Port> port;
1473 vector<string> port_connections;
1475 uint32_t total_connection_count = 0;
1476 uint32_t io_connection_count = 0;
1477 uint32_t ardour_connection_count = 0;
1478 uint32_t system_connection_count = 0;
1479 uint32_t other_connection_count = 0;
1481 ostringstream label;
1483 bool have_label = false;
1484 bool each_io_has_one_connection = true;
1486 string connection_name;
1487 string ardour_track_name;
1488 string other_connection_type;
1489 string system_ports;
1492 ostringstream tooltip;
1493 char * tooltip_cstr;
1495 io_count = _route->n_outputs().n_total();
1496 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1499 for (io_index = 0; io_index < io_count; ++io_index) {
1501 port = _route->output()->nth (io_index);
1503 //ignore any port connections that don't match our DataType
1504 if (port->type() != DataType::AUDIO) {
1508 port_connections.clear ();
1509 port->get_connections(port_connections);
1510 io_connection_count = 0;
1512 if (!port_connections.empty()) {
1513 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1515 string& connection_name (*i);
1517 if (connection_name.find("system:") == 0) {
1518 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1521 if (io_connection_count == 0) {
1522 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1524 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1527 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1530 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1531 if (ardour_track_name.empty()) {
1532 // "ardour:Master/in 1" -> "ardour:Master/"
1533 string::size_type slash = connection_name.find("/");
1534 if (slash != string::npos) {
1535 ardour_track_name = connection_name.substr(0, slash + 1);
1539 if (connection_name.find(ardour_track_name) == 0) {
1540 ++ardour_connection_count;
1542 } else if (!pn.empty()) {
1543 if (system_ports.empty()) {
1546 system_ports += "/" + pn;
1548 if (connection_name.find("system:") == 0) {
1549 ++system_connection_count;
1551 } else if (connection_name.find("system:") == 0) {
1552 // "system:playback_123" -> "123"
1553 system_port = connection_name.substr(16);
1554 if (system_ports.empty()) {
1555 system_ports += system_port;
1557 system_ports += "/" + system_port;
1560 ++system_connection_count;
1562 if (other_connection_type.empty()) {
1563 // "jamin:in 1" -> "jamin:"
1564 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1567 if (connection_name.find(other_connection_type) == 0) {
1568 ++other_connection_count;
1572 ++total_connection_count;
1573 ++io_connection_count;
1577 if (io_connection_count != 1) {
1578 each_io_has_one_connection = false;
1582 if (total_connection_count == 0) {
1583 tooltip << endl << _("Disconnected");
1586 tooltip_cstr = new char[tooltip.str().size() + 1];
1587 strcpy(tooltip_cstr, tooltip.str().c_str());
1589 set_tooltip (output_button, tooltip_cstr, "");
1591 if (each_io_has_one_connection) {
1592 if (total_connection_count == ardour_connection_count) {
1593 // all connections are to the same track in ardour
1594 // "ardour:Master/" -> "Master"
1595 string::size_type slash = ardour_track_name.find("/");
1596 if (slash != string::npos) {
1597 label << ardour_track_name.substr(7, slash - 7);
1600 } else if (total_connection_count == system_connection_count) {
1601 // all connections are to system ports
1602 label << system_ports;
1604 } else if (total_connection_count == other_connection_count) {
1605 // all connections are to the same external program eg jamin
1606 // "jamin:" -> "jamin"
1607 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1613 if (total_connection_count == 0) {
1617 // Odd configuration
1618 label << "*" << total_connection_count << "*";
1622 output_button->set_text (label.str());
1626 MonitorSection::disconnect_output ()
1629 _route->output()->disconnect(this);
1634 MonitorSection::edit_output_configuration ()
1636 if (_output_selector == 0) {
1637 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1639 _output_selector->present ();
1643 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1648 boost::shared_ptr<Port> a = wa.lock ();
1649 boost::shared_ptr<Port> b = wb.lock ();
1650 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1651 update_output_display ();
1656 MonitorSection::load_bindings ()
1658 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1662 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1664 boost::shared_ptr<Processor> processor (p.lock ());
1665 if (!processor || !processor->display_to_user()) {
1668 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1675 MonitorSection::count_processors ()
1677 uint32_t processor_count = 0;
1679 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1681 return processor_count;
1685 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1687 update_processor_box ();
1691 MonitorSection::action_proxy0 (enum MonitorActions action)
1693 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1707 case ToggleExclusiveSolo:
1708 ms->toggle_exclusive_solo ();
1710 case ToggleMuteOverridesSolo:
1711 ms->toggle_mute_overrides_solo ();
1713 case SoloUseInPlace:
1714 ms->solo_use_in_place ();
1717 ms->solo_use_afl ();
1720 ms->solo_use_pfl ();
1722 case ToggleMonitorProcessorBox:
1723 ms->update_processor_box ();
1729 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1731 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1737 ms->cut_channel (chn);
1740 ms->dim_channel (chn);
1743 ms->solo_channel (chn);
1746 ms->invert_channel (chn);