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/motionfeedback.h"
30 #include "gtkmm2ext/utils.h"
32 #include <gtkmm/menu.h>
33 #include <gtkmm/menuitem.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/user_bundle.h"
41 #include "ardour/plugin_manager.h"
43 #include "gui_thread.h"
44 #include "monitor_section.h"
45 #include "public_editor.h"
48 #include "volume_controller.h"
49 #include "ui_config.h"
54 using namespace ARDOUR;
55 using namespace ARDOUR_UI_UTILS;
57 using namespace Gtkmm2ext;
61 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
63 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
65 MonitorSection::MonitorSection (Session* s)
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)
87 , _ui_initialized (false)
90 using namespace Menu_Helpers;
92 Glib::RefPtr<Action> act;
94 if (!monitor_actions) {
96 /* do some static stuff */
102 _plugin_selector = new PluginSelector (PluginManager::instance());
103 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
104 insert_box->set_no_show_all ();
106 // TODO allow keyboard shortcuts in ProcessorBox
110 /* Rude Solo & Solo Isolated */
111 rude_solo_button.set_text (_("Soloing"));
112 rude_solo_button.set_name ("rude solo");
113 rude_solo_button.show ();
115 rude_iso_button.set_text (_("Isolated"));
116 rude_iso_button.set_name ("rude isolate");
117 rude_iso_button.show ();
119 rude_audition_button.set_text (_("Auditioning"));
120 rude_audition_button.set_name ("rude audition");
121 rude_audition_button.show ();
123 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
125 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
126 rude_solo_button.set_related_action (act);
127 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
129 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
130 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
132 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
133 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
135 /* SIP, AFL, PFL radio */
137 solo_in_place_button.set_name ("monitor section solo model");
138 afl_button.set_name ("monitor section solo model");
139 pfl_button.set_name ("monitor section solo model");
141 solo_in_place_button.set_led_left (true);
142 afl_button.set_led_left (true);
143 pfl_button.set_led_left (true);
145 solo_in_place_button.show ();
149 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
150 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
152 solo_in_place_button.set_related_action (act);
155 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
156 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
158 afl_button.set_related_action (act);
161 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
162 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
164 pfl_button.set_related_action (act);
167 /* Solo option buttons */
168 exclusive_solo_button.set_text (_("Excl. Solo"));
169 exclusive_solo_button.set_name (X_("monitor solo exclusive"));
170 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
172 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
174 exclusive_solo_button.set_related_action (act);
177 solo_mute_override_button.set_text (_("Solo ยป Mute"));
178 solo_mute_override_button.set_name (X_("monitor solo override"));
179 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
181 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
183 solo_mute_override_button.set_related_action (act);
186 /* Processor Box hide/shos */
187 toggle_processorbox_button.set_text (_("Processors"));
188 toggle_processorbox_button.set_name (X_("monitor processors toggle"));
189 set_tooltip (&toggle_processorbox_button, _("Allow to add monitor effect processors"));
191 proctoggle = ToggleAction::create ();
192 toggle_processorbox_button.set_related_action (proctoggle);
193 proctoggle->signal_toggled().connect (sigc::mem_fun(*this, &MonitorSection::repack_processor_box), false);
196 Label* solo_boost_label;
197 Label* solo_cut_label;
200 /* Solo Boost Knob */
202 solo_boost_control = new ArdourKnob ();
203 solo_boost_control->set_name("monitor knob");
204 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
205 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
207 solo_boost_display = new ArdourDisplay ();
208 solo_boost_display->set_name("monitor section cut");
209 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
210 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
211 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
212 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
213 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
215 solo_boost_label = manage (new Label (_("Solo Boost")));
219 solo_cut_control = new ArdourKnob ();
220 solo_cut_control->set_name ("monitor knob");
221 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
222 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
224 solo_cut_display = new ArdourDisplay ();
225 solo_cut_display->set_name("monitor section cut");
226 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
227 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
228 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
229 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
230 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
231 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
233 solo_cut_label = manage (new Label (_("SiP Cut")));
237 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
238 dim_control->set_name ("monitor knob");
239 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
240 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
242 dim_display = new ArdourDisplay ();
243 dim_display->set_name("monitor section cut");
244 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
245 dim_display->add_controllable_preset(_("0 dB"), 0.0);
246 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
247 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
248 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
249 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
251 dim_label = manage (new Label (_("Dim")));
254 cut_all_button.set_text (_("Mute"));
255 cut_all_button.set_name ("monitor section cut");
256 cut_all_button.set_name (X_("monitor section cut"));
257 cut_all_button.set_size_request (-1, PX_SCALE(30));
258 cut_all_button.show ();
260 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
262 cut_all_button.set_related_action (act);
266 dim_all_button.set_text (_("Dim"));
267 dim_all_button.set_name ("monitor section dim");
268 dim_all_button.set_size_request (-1, PX_SCALE(25));
269 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
271 dim_all_button.set_related_action (act);
275 mono_button.set_text (_("Mono"));
276 mono_button.set_name ("monitor section mono");
277 mono_button.set_size_request (-1, PX_SCALE(25));
278 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
280 mono_button.set_related_action (act);
285 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
286 gain_control->set_name("monitor knob");
287 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
289 gain_display = new ArdourDisplay ();
290 gain_display->set_name("monitor section cut");
291 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
292 gain_display->add_controllable_preset(_("0 dB"), 0.0);
293 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
294 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
295 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
296 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
297 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
299 Label* output_label = manage (new Label (_("Output")));
300 output_label->set_name (X_("MonitorSectionLabel"));
302 output_button = new ArdourButton ();
303 output_button->set_text (_("Output"));
304 output_button->set_name (X_("monitor section cut"));
305 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
306 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
308 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
309 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
310 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
311 channel_table_scroller.show ();
312 channel_table_scroller.add (channel_table_viewport);
314 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
315 channel_size_group->add_widget (channel_table_header);
316 channel_size_group->add_widget (channel_table);
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);
390 /* note that we don't pack the table_hpacker till later
391 * -> top level channel_table_packer */
392 table_hpacker.pack_start (channel_table, true, true);
395 HBox* mono_dim_box = manage (new HBox);
396 mono_dim_box->set_spacing (PX_SCALE(4));
397 mono_dim_box->set_homogeneous (true);
398 mono_dim_box->pack_start (mono_button, true, true);
399 mono_dim_box->pack_end (dim_all_button, true, true);
402 Label* spin_label = manage (new Label (_("Monitor")));
403 VBox* spin_packer = manage (new VBox);
404 spin_packer->set_spacing (PX_SCALE(2));
405 spin_packer->pack_start (*spin_label, false, false);
406 spin_packer->pack_start (*gain_control, false, false);
407 spin_packer->pack_start (*gain_display, false, false);
409 master_packer.pack_start (*spin_packer, true, false);
411 // combined gain section (channels, mute, dim)
412 VBox* lower_packer = manage (new VBox);
413 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
414 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
415 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
416 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
418 // output port select
419 VBox* out_packer = manage (new VBox);
420 out_packer->set_spacing (PX_SCALE(2));
421 out_packer->pack_start (*output_label, false, false);
422 out_packer->pack_start (*output_button, false, false);
424 /****************************************************************************
427 vpacker.set_border_width (PX_SCALE(3));
428 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
429 vpacker.pack_start (rude_audition_button, false, false, 0);
430 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
431 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
432 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
433 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
434 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
435 vpacker.pack_end (*out_packer, false, false, PX_SCALE(3));
437 hpacker.set_spacing (0);
438 hpacker.pack_start (vpacker, true, true);
440 gain_control->show_all ();
441 gain_display->show_all ();
442 dim_control->show_all ();
443 dim_display->show_all();
444 solo_boost_control->show_all ();
445 solo_boost_display->show_all();
447 mono_dim_box->show ();
448 spin_packer->show ();
449 master_packer.show ();
450 channel_table.show ();
453 solo_tbl->show_all();
455 lower_packer->show ();
463 assign_controllables ();
465 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
466 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
468 _tearoff = new TearOff (hpacker);
470 if (!UIConfiguration::instance().get_floating_monitor_section()) {
471 /* if torn off, make this a normal window
472 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
474 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
476 _tearoff->tearoff_window().set_title (X_("Monitor"));
477 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
479 update_output_display ();
480 repack_processor_box ();
481 _ui_initialized = true;
483 /* catch changes that affect us */
484 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
485 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
487 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
490 MonitorSection::~MonitorSection ()
492 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
496 _channel_buttons.clear ();
497 _output_changed_connection.disconnect ();
500 delete output_button;
505 delete solo_boost_control;
506 delete solo_boost_display;
507 delete solo_cut_control;
508 delete solo_cut_display;
510 delete _output_selector;
511 _output_selector = 0;
516 MonitorSection::repack_processor_box ()
518 bool show_processor_box = proctoggle->get_active ();
520 if (count_processors () > 0) {
521 proctoggle->set_active (true);
522 proctoggle->set_sensitive (false);
523 show_processor_box = true;
525 proctoggle->set_sensitive (true);
528 if (insert_box->is_visible() == show_processor_box) {
532 if (show_processor_box) {
533 if (master_packer.get_parent()) {
534 master_packer.get_parent()->remove (master_packer);
537 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
539 if (master_packer.get_parent()) {
540 master_packer.get_parent()->remove (master_packer);
543 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
548 MonitorSection::set_session (Session* s)
550 AxisView::set_session (s);
551 _plugin_selector->set_session (_session);
555 _route = _session->monitor_out ();
558 /* session with monitor section */
559 _monitor = _route->monitor_control ();
560 assign_controllables ();
561 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
562 boost::bind (&MonitorSection::update_output_display, this),
564 insert_box->set_route (_route);
565 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
566 if (_ui_initialized) {
567 repack_processor_box (); // too early
570 /* session with no monitor section */
571 _output_changed_connection.disconnect();
574 delete _output_selector;
575 _output_selector = 0;
578 if (channel_table_scroller.get_parent()) {
579 /* scroller is packed, so remove it */
580 channel_table_packer.remove (channel_table_scroller);
583 if (table_hpacker.get_parent () == &channel_table_packer) {
584 /* this occurs when the table hpacker is directly
585 packed, so remove it.
587 channel_table_packer.remove (table_hpacker);
588 } else if (table_hpacker.get_parent()) {
589 channel_table_viewport.remove ();
592 if (_monitor->output_streams().n_audio() > 7) {
593 /* put the table into a scrolled window, and then put
594 * that into the channel vpacker, after the table header
596 channel_table_viewport.add (table_hpacker);
597 channel_table_packer.pack_start (channel_table_scroller, true, true);
598 channel_table_viewport.show ();
599 channel_table_scroller.show ();
602 /* just put the channel table itself into the channel
603 * vpacker, after the table header
606 channel_table_packer.pack_start (table_hpacker, true, true);
607 channel_table_scroller.hide ();
610 table_hpacker.show ();
611 channel_table.show ();
616 _output_changed_connection.disconnect();
619 control_connections.drop_connections ();
620 rude_iso_button.unset_active_state ();
621 rude_solo_button.unset_active_state ();
622 delete _output_selector;
623 _output_selector = 0;
625 assign_controllables ();
629 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
631 cut.set_name (X_("monitor section cut"));
632 dim.set_name (X_("monitor section dim"));
633 solo.set_name (X_("monitor section solo"));
634 invert.set_name (X_("monitor section invert"));
636 cut.unset_flags (Gtk::CAN_FOCUS);
637 dim.unset_flags (Gtk::CAN_FOCUS);
638 solo.unset_flags (Gtk::CAN_FOCUS);
639 invert.unset_flags (Gtk::CAN_FOCUS);
643 MonitorSection::populate_buttons ()
649 Glib::RefPtr<Action> act;
650 uint32_t nchans = _monitor->output_streams().n_audio();
652 channel_table.resize (nchans, 5);
653 channel_table.set_col_spacings (6);
654 channel_table.set_row_spacings (6);
655 channel_table.set_homogeneous (true);
657 const uint32_t row_offset = 0;
659 for (uint32_t i = 0; i < nchans; ++i) {
672 snprintf (buf, sizeof (buf), "%d", i+1);
676 Label* label = manage (new Label (l));
677 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
679 ChannelButtonSet* cbs = new ChannelButtonSet;
681 _channel_buttons.push_back (cbs);
683 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
684 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
685 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
686 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
688 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
689 act = ActionManager::get_action (X_("Monitor"), buf);
691 cbs->cut.set_related_action (act);
694 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
695 act = ActionManager::get_action (X_("Monitor"), buf);
697 cbs->dim.set_related_action (act);
700 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
701 act = ActionManager::get_action (X_("Monitor"), buf);
703 cbs->solo.set_related_action (act);
706 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
707 act = ActionManager::get_action (X_("Monitor"), buf);
709 cbs->invert.set_related_action (act);
713 channel_table.show_all ();
717 MonitorSection::toggle_exclusive_solo ()
723 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
725 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
726 Config->set_exclusive_solo (tact->get_active());
732 MonitorSection::toggle_mute_overrides_solo ()
738 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
740 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
741 Config->set_solo_mute_override (tact->get_active());
746 MonitorSection::dim_all ()
752 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
754 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
755 _monitor->set_dim_all (tact->get_active());
761 MonitorSection::cut_all ()
767 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
769 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
770 _monitor->set_cut_all (tact->get_active());
775 MonitorSection::mono ()
781 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
783 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
784 _monitor->set_mono (tact->get_active());
789 MonitorSection::cut_channel (uint32_t chn)
796 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
798 --chn; // 0-based in backend
800 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
802 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
803 _monitor->set_cut (chn, tact->get_active());
808 MonitorSection::dim_channel (uint32_t chn)
815 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
817 --chn; // 0-based in backend
819 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
821 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
822 _monitor->set_dim (chn, tact->get_active());
828 MonitorSection::solo_channel (uint32_t chn)
835 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
837 --chn; // 0-based in backend
839 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
841 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
842 _monitor->set_solo (chn, tact->get_active());
848 MonitorSection::invert_channel (uint32_t chn)
855 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
857 --chn; // 0-based in backend
859 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
861 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
862 _monitor->set_polarity (chn, tact->get_active());
867 MonitorSection::register_actions ()
871 Glib::RefPtr<Action> act;
873 monitor_actions = ActionGroup::create (X_("Monitor"));
874 ActionManager::add_action_group (monitor_actions);
876 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
877 sigc::mem_fun (*this, &MonitorSection::mono));
879 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
880 sigc::mem_fun (*this, &MonitorSection::cut_all));
882 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
883 sigc::mem_fun (*this, &MonitorSection::dim_all));
885 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
886 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
888 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
889 tact->set_active (Config->get_exclusive_solo());
891 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
892 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
894 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
895 tact->set_active (Config->get_solo_mute_override());
898 /* note the 1-based counting (for naming - backend uses 0-based) */
900 for (uint32_t chn = 1; chn <= 16; ++chn) {
902 action_name = string_compose (X_("monitor-cut-%1"), chn);
903 action_descr = string_compose (_("Cut monitor channel %1"), chn);
904 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
905 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
907 action_name = string_compose (X_("monitor-dim-%1"), chn);
908 action_descr = string_compose (_("Dim monitor channel %1"), chn);
909 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
910 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
912 action_name = string_compose (X_("monitor-solo-%1"), chn);
913 action_descr = string_compose (_("Solo monitor channel %1"), chn);
914 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
915 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
917 action_name = string_compose (X_("monitor-invert-%1"), chn);
918 action_descr = string_compose (_("Invert monitor channel %1"), chn);
919 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
920 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
925 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
926 RadioAction::Group solo_group;
928 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
929 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
930 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
931 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
932 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
933 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
935 ActionManager::add_action_group (solo_actions);
939 MonitorSection::solo_use_in_place ()
941 /* this is driven by a toggle on a radio group, and so is invoked twice,
942 once for the item that became inactive and once for the one that became
946 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
949 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
951 if (!ract->get_active ()) {
952 /* We are turning SiP off, which means that AFL or PFL will be turned on
953 shortly; don't update the solo model in the mean time, as if the currently
954 configured listen position is not the one that is about to be turned on,
955 things will go wrong.
957 _inhibit_solo_model_update = true;
959 Config->set_solo_control_is_listen_control (!ract->get_active());
960 _inhibit_solo_model_update = false;
966 MonitorSection::solo_use_afl ()
968 /* this is driven by a toggle on a radio group, and so is invoked twice,
969 once for the item that became inactive and once for the one that became
973 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
975 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
977 if (ract->get_active()) {
978 Config->set_solo_control_is_listen_control (true);
979 Config->set_listen_position (AfterFaderListen);
986 MonitorSection::solo_use_pfl ()
988 /* this is driven by a toggle on a radio group, and so is invoked twice,
989 once for the item that became inactive and once for the one that became
993 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
995 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
997 if (ract->get_active()) {
998 Config->set_solo_control_is_listen_control (true);
999 Config->set_listen_position (PreFaderListen);
1006 MonitorSection::update_solo_model ()
1008 if (_inhibit_solo_model_update) {
1012 const char* action_name = 0;
1013 Glib::RefPtr<Action> act;
1015 if (Config->get_solo_control_is_listen_control()) {
1016 switch (Config->get_listen_position()) {
1017 case AfterFaderListen:
1018 action_name = X_("solo-use-afl");
1020 case PreFaderListen:
1021 action_name = X_("solo-use-pfl");
1025 action_name = X_("solo-use-in-place");
1028 act = ActionManager::get_action (X_("Solo"), action_name);
1031 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1033 /* because these are radio buttons, one of them will be
1034 active no matter what. to trigger a change in the
1035 action so that the view picks it up, toggle it.
1037 if (ract->get_active()) {
1038 ract->set_active (false);
1040 ract->set_active (true);
1047 MonitorSection::map_state ()
1049 if (!_route || !_monitor) {
1053 Glib::RefPtr<Action> act;
1055 update_solo_model ();
1057 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1059 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1061 tact->set_active (_monitor->cut_all());
1065 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1067 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1069 tact->set_active (_monitor->dim_all());
1073 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1075 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1077 tact->set_active (_monitor->mono());
1081 uint32_t nchans = _monitor->output_streams().n_audio();
1083 assert (nchans == _channel_buttons.size ());
1085 for (uint32_t n = 0; n < nchans; ++n) {
1087 char action_name[32];
1089 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1090 act = ActionManager::get_action (X_("Monitor"), action_name);
1092 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1094 tact->set_active (_monitor->cut (n));
1098 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1099 act = ActionManager::get_action (X_("Monitor"), action_name);
1101 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1103 tact->set_active (_monitor->dimmed (n));
1107 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1108 act = ActionManager::get_action (X_("Monitor"), action_name);
1110 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1112 tact->set_active (_monitor->soloed (n));
1116 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1117 act = ActionManager::get_action (X_("Monitor"), action_name);
1119 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1121 tact->set_active (_monitor->inverted (n));
1128 MonitorSection::do_blink (bool onoff)
1131 audition_blink (onoff);
1135 MonitorSection::audition_blink (bool onoff)
1137 if (_session == 0) {
1141 if (_session->is_auditioning()) {
1142 rude_audition_button.set_active (onoff);
1144 rude_audition_button.set_active (false);
1149 MonitorSection::solo_blink (bool onoff)
1151 if (_session == 0) {
1155 if (_session->soloing() || _session->listening()) {
1156 rude_solo_button.set_active (onoff);
1158 if (_session->soloing()) {
1159 if (_session->solo_isolated()) {
1160 rude_iso_button.set_active (onoff);
1162 rude_iso_button.set_active (false);
1167 rude_solo_button.set_active (false);
1168 rude_iso_button.set_active (false);
1173 MonitorSection::cancel_isolate (GdkEventButton*)
1176 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1177 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1184 MonitorSection::cancel_audition (GdkEventButton*)
1187 _session->cancel_audition();
1192 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1194 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1195 if (tact && tact->get_active() != value) { \
1196 tact->set_active(value); \
1201 MonitorSection::parameter_changed (std::string name)
1203 if (name == "solo-control-is-listen-control") {
1204 update_solo_model ();
1205 } else if (name == "listen-position") {
1206 update_solo_model ();
1207 } else if (name == "solo-mute-override") {
1208 SYNCHRONIZE_TOGGLE_ACTION(
1209 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1210 Config->get_solo_mute_override ())
1211 } else if (name == "exclusive-solo") {
1212 SYNCHRONIZE_TOGGLE_ACTION(
1213 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1214 Config->get_exclusive_solo ())
1219 MonitorSection::assign_controllables ()
1221 boost::shared_ptr<Controllable> none;
1223 if (!gain_control) {
1224 /* too early - GUI controls not set up yet */
1229 solo_cut_control->set_controllable (_session->solo_cut_control());
1230 solo_cut_display->set_controllable (_session->solo_cut_control());
1232 solo_cut_control->set_controllable (none);
1233 solo_cut_display->set_controllable (none);
1237 gain_control->set_controllable (_route->gain_control());
1238 gain_display->set_controllable (_route->gain_control());
1240 gain_control->set_controllable (none);
1245 cut_all_button.set_controllable (_monitor->cut_control());
1246 cut_all_button.watch ();
1247 dim_all_button.set_controllable (_monitor->dim_control());
1248 dim_all_button.watch ();
1249 mono_button.set_controllable (_monitor->mono_control());
1250 mono_button.watch ();
1252 dim_control->set_controllable (_monitor->dim_level_control ());
1253 dim_display->set_controllable (_monitor->dim_level_control ());
1254 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1255 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1259 cut_all_button.set_controllable (none);
1260 dim_all_button.set_controllable (none);
1261 mono_button.set_controllable (none);
1263 dim_control->set_controllable (none);
1264 dim_display->set_controllable (none);
1265 solo_boost_control->set_controllable (none);
1266 solo_boost_display->set_controllable (none);
1271 MonitorSection::state_id() const
1273 return "monitor-section";
1277 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1279 using namespace Menu_Helpers;
1281 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1285 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1286 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1290 if (i != output_menu_bundles.end()) {
1294 output_menu_bundles.push_back (b);
1296 MenuList& citems = output_menu.items();
1298 std::string n = b->name ();
1299 replace_all (n, "_", " ");
1301 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1305 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1308 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1310 if (std::find (current.begin(), current.end(), c) == current.end()) {
1311 _route->output()->connect_ports_to_bundle (c, true, this);
1313 _route->output()->disconnect_ports_from_bundle (c, this);
1318 MonitorSection::output_release (GdkEventButton *ev)
1320 switch (ev->button) {
1322 edit_output_configuration ();
1329 struct RouteCompareByName {
1330 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1331 return a->name().compare (b->name()) < 0;
1336 MonitorSection::output_press (GdkEventButton *ev)
1338 using namespace Menu_Helpers;
1340 MessageDialog msg (_("No session - no I/O changes are possible"));
1345 MenuList& citems = output_menu.items();
1346 switch (ev->button) {
1349 return false; //wait for the mouse-up to pop the dialog
1353 output_menu.set_name ("ArdourContextMenu");
1355 output_menu_bundles.clear ();
1357 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1359 citems.push_back (SeparatorElem());
1360 uint32_t const n_with_separator = citems.size ();
1362 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1364 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1366 /* give user bundles first chance at being in the menu */
1368 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1369 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1370 maybe_add_bundle_to_output_menu (*i, current);
1374 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1375 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1376 maybe_add_bundle_to_output_menu (*i, current);
1380 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1381 RouteList copy = *routes;
1382 copy.sort (RouteCompareByName ());
1383 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1384 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1387 if (citems.size() == n_with_separator) {
1388 /* no routes added; remove the separator */
1392 citems.push_back (SeparatorElem());
1393 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1395 output_menu.popup (1, ev->time);
1406 MonitorSection::update_output_display ()
1408 if (!_route || !_monitor || _session->deletion_in_progress()) {
1414 boost::shared_ptr<Port> port;
1415 vector<string> port_connections;
1417 uint32_t total_connection_count = 0;
1418 uint32_t io_connection_count = 0;
1419 uint32_t ardour_connection_count = 0;
1420 uint32_t system_connection_count = 0;
1421 uint32_t other_connection_count = 0;
1423 ostringstream label;
1425 bool have_label = false;
1426 bool each_io_has_one_connection = true;
1428 string connection_name;
1429 string ardour_track_name;
1430 string other_connection_type;
1431 string system_ports;
1434 ostringstream tooltip;
1435 char * tooltip_cstr;
1437 io_count = _route->n_outputs().n_total();
1438 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1441 for (io_index = 0; io_index < io_count; ++io_index) {
1443 port = _route->output()->nth (io_index);
1445 //ignore any port connections that don't match our DataType
1446 if (port->type() != DataType::AUDIO) {
1450 port_connections.clear ();
1451 port->get_connections(port_connections);
1452 io_connection_count = 0;
1454 if (!port_connections.empty()) {
1455 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1457 string& connection_name (*i);
1459 if (connection_name.find("system:") == 0) {
1460 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1463 if (io_connection_count == 0) {
1464 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1466 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1469 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1472 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1473 if (ardour_track_name.empty()) {
1474 // "ardour:Master/in 1" -> "ardour:Master/"
1475 string::size_type slash = connection_name.find("/");
1476 if (slash != string::npos) {
1477 ardour_track_name = connection_name.substr(0, slash + 1);
1481 if (connection_name.find(ardour_track_name) == 0) {
1482 ++ardour_connection_count;
1484 } else if (!pn.empty()) {
1485 if (system_ports.empty()) {
1488 system_ports += "/" + pn;
1490 if (connection_name.find("system:") == 0) {
1491 ++system_connection_count;
1493 } else if (connection_name.find("system:") == 0) {
1494 // "system:playback_123" -> "123"
1495 system_port = connection_name.substr(16);
1496 if (system_ports.empty()) {
1497 system_ports += system_port;
1499 system_ports += "/" + system_port;
1502 ++system_connection_count;
1504 if (other_connection_type.empty()) {
1505 // "jamin:in 1" -> "jamin:"
1506 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1509 if (connection_name.find(other_connection_type) == 0) {
1510 ++other_connection_count;
1514 ++total_connection_count;
1515 ++io_connection_count;
1519 if (io_connection_count != 1) {
1520 each_io_has_one_connection = false;
1524 if (total_connection_count == 0) {
1525 tooltip << endl << _("Disconnected");
1528 tooltip_cstr = new char[tooltip.str().size() + 1];
1529 strcpy(tooltip_cstr, tooltip.str().c_str());
1531 set_tooltip (output_button, tooltip_cstr, "");
1533 if (each_io_has_one_connection) {
1534 if (total_connection_count == ardour_connection_count) {
1535 // all connections are to the same track in ardour
1536 // "ardour:Master/" -> "Master"
1537 string::size_type slash = ardour_track_name.find("/");
1538 if (slash != string::npos) {
1539 label << ardour_track_name.substr(7, slash - 7);
1542 } else if (total_connection_count == system_connection_count) {
1543 // all connections are to system ports
1544 label << system_ports;
1546 } else if (total_connection_count == other_connection_count) {
1547 // all connections are to the same external program eg jamin
1548 // "jamin:" -> "jamin"
1549 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1555 if (total_connection_count == 0) {
1559 // Odd configuration
1560 label << "*" << total_connection_count << "*";
1564 output_button->set_text (label.str());
1568 MonitorSection::disconnect_output ()
1571 _route->output()->disconnect(this);
1576 MonitorSection::edit_output_configuration ()
1578 if (_output_selector == 0) {
1579 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1581 _output_selector->present ();
1585 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1590 boost::shared_ptr<Port> a = wa.lock ();
1591 boost::shared_ptr<Port> b = wb.lock ();
1592 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1593 update_output_display ();
1598 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1600 boost::shared_ptr<Processor> processor (p.lock ());
1601 if (!processor || !processor->display_to_user()) {
1604 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1611 MonitorSection::count_processors ()
1613 uint32_t processor_count = 0;
1615 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1617 return processor_count;
1621 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1623 repack_processor_box ();