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::update_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 update_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::update_processor_box ()
518 bool show_processor_box = proctoggle->get_active ();
520 if (count_processors () > 0 && !show_processor_box) {
521 toggle_processorbox_button.set_name (X_("monitor processors present"));
523 toggle_processorbox_button.set_name (X_("monitor processors toggle"));
526 if (insert_box->is_visible() == show_processor_box) {
530 if (show_processor_box) {
531 if (master_packer.get_parent()) {
532 master_packer.get_parent()->remove (master_packer);
535 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
537 if (master_packer.get_parent()) {
538 master_packer.get_parent()->remove (master_packer);
541 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
546 MonitorSection::set_session (Session* s)
548 AxisView::set_session (s);
549 _plugin_selector->set_session (_session);
553 _route = _session->monitor_out ();
556 /* session with monitor section */
557 _monitor = _route->monitor_control ();
558 assign_controllables ();
559 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
560 boost::bind (&MonitorSection::update_output_display, this),
562 insert_box->set_route (_route);
563 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
564 if (_ui_initialized) {
565 update_processor_box ();
568 /* session with no monitor section */
569 _output_changed_connection.disconnect();
572 delete _output_selector;
573 _output_selector = 0;
576 if (channel_table_scroller.get_parent()) {
577 /* scroller is packed, so remove it */
578 channel_table_packer.remove (channel_table_scroller);
581 if (table_hpacker.get_parent () == &channel_table_packer) {
582 /* this occurs when the table hpacker is directly
583 packed, so remove it.
585 channel_table_packer.remove (table_hpacker);
586 } else if (table_hpacker.get_parent()) {
587 channel_table_viewport.remove ();
590 if (_monitor->output_streams().n_audio() > 7) {
591 /* put the table into a scrolled window, and then put
592 * that into the channel vpacker, after the table header
594 channel_table_viewport.add (table_hpacker);
595 channel_table_packer.pack_start (channel_table_scroller, true, true);
596 channel_table_viewport.show ();
597 channel_table_scroller.show ();
600 /* just put the channel table itself into the channel
601 * vpacker, after the table header
604 channel_table_packer.pack_start (table_hpacker, true, true);
605 channel_table_scroller.hide ();
608 table_hpacker.show ();
609 channel_table.show ();
614 _output_changed_connection.disconnect();
617 control_connections.drop_connections ();
618 rude_iso_button.unset_active_state ();
619 rude_solo_button.unset_active_state ();
620 delete _output_selector;
621 _output_selector = 0;
623 assign_controllables ();
627 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
629 cut.set_name (X_("monitor section cut"));
630 dim.set_name (X_("monitor section dim"));
631 solo.set_name (X_("monitor section solo"));
632 invert.set_name (X_("monitor section invert"));
634 cut.unset_flags (Gtk::CAN_FOCUS);
635 dim.unset_flags (Gtk::CAN_FOCUS);
636 solo.unset_flags (Gtk::CAN_FOCUS);
637 invert.unset_flags (Gtk::CAN_FOCUS);
641 MonitorSection::populate_buttons ()
647 Glib::RefPtr<Action> act;
648 uint32_t nchans = _monitor->output_streams().n_audio();
650 channel_table.resize (nchans, 5);
651 channel_table.set_col_spacings (6);
652 channel_table.set_row_spacings (6);
653 channel_table.set_homogeneous (true);
655 const uint32_t row_offset = 0;
657 for (uint32_t i = 0; i < nchans; ++i) {
670 snprintf (buf, sizeof (buf), "%d", i+1);
674 Label* label = manage (new Label (l));
675 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
677 ChannelButtonSet* cbs = new ChannelButtonSet;
679 _channel_buttons.push_back (cbs);
681 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
682 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
683 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
684 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
686 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
687 act = ActionManager::get_action (X_("Monitor"), buf);
689 cbs->cut.set_related_action (act);
692 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
693 act = ActionManager::get_action (X_("Monitor"), buf);
695 cbs->dim.set_related_action (act);
698 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
699 act = ActionManager::get_action (X_("Monitor"), buf);
701 cbs->solo.set_related_action (act);
704 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
705 act = ActionManager::get_action (X_("Monitor"), buf);
707 cbs->invert.set_related_action (act);
711 channel_table.show_all ();
715 MonitorSection::toggle_exclusive_solo ()
721 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
723 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
724 Config->set_exclusive_solo (tact->get_active());
730 MonitorSection::toggle_mute_overrides_solo ()
736 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
738 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
739 Config->set_solo_mute_override (tact->get_active());
744 MonitorSection::dim_all ()
750 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
752 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
753 _monitor->set_dim_all (tact->get_active());
759 MonitorSection::cut_all ()
765 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
767 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
768 _monitor->set_cut_all (tact->get_active());
773 MonitorSection::mono ()
779 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
781 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
782 _monitor->set_mono (tact->get_active());
787 MonitorSection::cut_channel (uint32_t chn)
794 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
796 --chn; // 0-based in backend
798 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
800 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
801 _monitor->set_cut (chn, tact->get_active());
806 MonitorSection::dim_channel (uint32_t chn)
813 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
815 --chn; // 0-based in backend
817 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
819 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
820 _monitor->set_dim (chn, tact->get_active());
826 MonitorSection::solo_channel (uint32_t chn)
833 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
835 --chn; // 0-based in backend
837 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
839 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
840 _monitor->set_solo (chn, tact->get_active());
846 MonitorSection::invert_channel (uint32_t chn)
853 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
855 --chn; // 0-based in backend
857 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
859 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
860 _monitor->set_polarity (chn, tact->get_active());
865 MonitorSection::register_actions ()
869 Glib::RefPtr<Action> act;
871 monitor_actions = ActionGroup::create (X_("Monitor"));
872 ActionManager::add_action_group (monitor_actions);
874 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
875 sigc::mem_fun (*this, &MonitorSection::mono));
877 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
878 sigc::mem_fun (*this, &MonitorSection::cut_all));
880 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
881 sigc::mem_fun (*this, &MonitorSection::dim_all));
883 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
884 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
886 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
887 tact->set_active (Config->get_exclusive_solo());
889 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
890 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
892 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
893 tact->set_active (Config->get_solo_mute_override());
896 /* note the 1-based counting (for naming - backend uses 0-based) */
898 for (uint32_t chn = 1; chn <= 16; ++chn) {
900 action_name = string_compose (X_("monitor-cut-%1"), chn);
901 action_descr = string_compose (_("Cut monitor channel %1"), chn);
902 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
903 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
905 action_name = string_compose (X_("monitor-dim-%1"), chn);
906 action_descr = string_compose (_("Dim monitor channel %1"), chn);
907 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
908 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
910 action_name = string_compose (X_("monitor-solo-%1"), chn);
911 action_descr = string_compose (_("Solo monitor channel %1"), chn);
912 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
913 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
915 action_name = string_compose (X_("monitor-invert-%1"), chn);
916 action_descr = string_compose (_("Invert monitor channel %1"), chn);
917 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
918 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
923 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
924 RadioAction::Group solo_group;
926 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
927 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
928 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
929 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
930 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
931 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
933 ActionManager::add_action_group (solo_actions);
937 MonitorSection::solo_use_in_place ()
939 /* this is driven by a toggle on a radio group, and so is invoked twice,
940 once for the item that became inactive and once for the one that became
944 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
947 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
949 if (!ract->get_active ()) {
950 /* We are turning SiP off, which means that AFL or PFL will be turned on
951 shortly; don't update the solo model in the mean time, as if the currently
952 configured listen position is not the one that is about to be turned on,
953 things will go wrong.
955 _inhibit_solo_model_update = true;
957 Config->set_solo_control_is_listen_control (!ract->get_active());
958 _inhibit_solo_model_update = false;
964 MonitorSection::solo_use_afl ()
966 /* this is driven by a toggle on a radio group, and so is invoked twice,
967 once for the item that became inactive and once for the one that became
971 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
973 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
975 if (ract->get_active()) {
976 Config->set_solo_control_is_listen_control (true);
977 Config->set_listen_position (AfterFaderListen);
984 MonitorSection::solo_use_pfl ()
986 /* this is driven by a toggle on a radio group, and so is invoked twice,
987 once for the item that became inactive and once for the one that became
991 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
993 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
995 if (ract->get_active()) {
996 Config->set_solo_control_is_listen_control (true);
997 Config->set_listen_position (PreFaderListen);
1004 MonitorSection::update_solo_model ()
1006 if (_inhibit_solo_model_update) {
1010 const char* action_name = 0;
1011 Glib::RefPtr<Action> act;
1013 if (Config->get_solo_control_is_listen_control()) {
1014 switch (Config->get_listen_position()) {
1015 case AfterFaderListen:
1016 action_name = X_("solo-use-afl");
1018 case PreFaderListen:
1019 action_name = X_("solo-use-pfl");
1023 action_name = X_("solo-use-in-place");
1026 act = ActionManager::get_action (X_("Solo"), action_name);
1029 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1031 /* because these are radio buttons, one of them will be
1032 active no matter what. to trigger a change in the
1033 action so that the view picks it up, toggle it.
1035 if (ract->get_active()) {
1036 ract->set_active (false);
1038 ract->set_active (true);
1045 MonitorSection::map_state ()
1047 if (!_route || !_monitor) {
1051 Glib::RefPtr<Action> act;
1053 update_solo_model ();
1055 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1057 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1059 tact->set_active (_monitor->cut_all());
1063 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1065 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1067 tact->set_active (_monitor->dim_all());
1071 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1073 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1075 tact->set_active (_monitor->mono());
1079 uint32_t nchans = _monitor->output_streams().n_audio();
1081 assert (nchans == _channel_buttons.size ());
1083 for (uint32_t n = 0; n < nchans; ++n) {
1085 char action_name[32];
1087 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1088 act = ActionManager::get_action (X_("Monitor"), action_name);
1090 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1092 tact->set_active (_monitor->cut (n));
1096 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1097 act = ActionManager::get_action (X_("Monitor"), action_name);
1099 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1101 tact->set_active (_monitor->dimmed (n));
1105 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1106 act = ActionManager::get_action (X_("Monitor"), action_name);
1108 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1110 tact->set_active (_monitor->soloed (n));
1114 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1115 act = ActionManager::get_action (X_("Monitor"), action_name);
1117 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1119 tact->set_active (_monitor->inverted (n));
1126 MonitorSection::do_blink (bool onoff)
1129 audition_blink (onoff);
1133 MonitorSection::audition_blink (bool onoff)
1135 if (_session == 0) {
1139 if (_session->is_auditioning()) {
1140 rude_audition_button.set_active (onoff);
1142 rude_audition_button.set_active (false);
1147 MonitorSection::solo_blink (bool onoff)
1149 if (_session == 0) {
1153 if (_session->soloing() || _session->listening()) {
1154 rude_solo_button.set_active (onoff);
1156 if (_session->soloing()) {
1157 if (_session->solo_isolated()) {
1158 rude_iso_button.set_active (onoff);
1160 rude_iso_button.set_active (false);
1165 rude_solo_button.set_active (false);
1166 rude_iso_button.set_active (false);
1171 MonitorSection::cancel_isolate (GdkEventButton*)
1174 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1175 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1182 MonitorSection::cancel_audition (GdkEventButton*)
1185 _session->cancel_audition();
1190 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1192 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1193 if (tact && tact->get_active() != value) { \
1194 tact->set_active(value); \
1199 MonitorSection::parameter_changed (std::string name)
1201 if (name == "solo-control-is-listen-control") {
1202 update_solo_model ();
1203 } else if (name == "listen-position") {
1204 update_solo_model ();
1205 } else if (name == "solo-mute-override") {
1206 SYNCHRONIZE_TOGGLE_ACTION(
1207 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1208 Config->get_solo_mute_override ())
1209 } else if (name == "exclusive-solo") {
1210 SYNCHRONIZE_TOGGLE_ACTION(
1211 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1212 Config->get_exclusive_solo ())
1217 MonitorSection::assign_controllables ()
1219 boost::shared_ptr<Controllable> none;
1221 if (!gain_control) {
1222 /* too early - GUI controls not set up yet */
1227 solo_cut_control->set_controllable (_session->solo_cut_control());
1228 solo_cut_display->set_controllable (_session->solo_cut_control());
1230 solo_cut_control->set_controllable (none);
1231 solo_cut_display->set_controllable (none);
1235 gain_control->set_controllable (_route->gain_control());
1236 gain_display->set_controllable (_route->gain_control());
1238 gain_control->set_controllable (none);
1243 cut_all_button.set_controllable (_monitor->cut_control());
1244 cut_all_button.watch ();
1245 dim_all_button.set_controllable (_monitor->dim_control());
1246 dim_all_button.watch ();
1247 mono_button.set_controllable (_monitor->mono_control());
1248 mono_button.watch ();
1250 dim_control->set_controllable (_monitor->dim_level_control ());
1251 dim_display->set_controllable (_monitor->dim_level_control ());
1252 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1253 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1257 cut_all_button.set_controllable (none);
1258 dim_all_button.set_controllable (none);
1259 mono_button.set_controllable (none);
1261 dim_control->set_controllable (none);
1262 dim_display->set_controllable (none);
1263 solo_boost_control->set_controllable (none);
1264 solo_boost_display->set_controllable (none);
1269 MonitorSection::state_id() const
1271 return "monitor-section";
1275 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1277 using namespace Menu_Helpers;
1279 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1283 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1284 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1288 if (i != output_menu_bundles.end()) {
1292 output_menu_bundles.push_back (b);
1294 MenuList& citems = output_menu.items();
1296 std::string n = b->name ();
1297 replace_all (n, "_", " ");
1299 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1303 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1306 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1308 if (std::find (current.begin(), current.end(), c) == current.end()) {
1309 _route->output()->connect_ports_to_bundle (c, true, this);
1311 _route->output()->disconnect_ports_from_bundle (c, this);
1316 MonitorSection::output_release (GdkEventButton *ev)
1318 switch (ev->button) {
1320 edit_output_configuration ();
1327 struct RouteCompareByName {
1328 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1329 return a->name().compare (b->name()) < 0;
1334 MonitorSection::output_press (GdkEventButton *ev)
1336 using namespace Menu_Helpers;
1338 MessageDialog msg (_("No session - no I/O changes are possible"));
1343 MenuList& citems = output_menu.items();
1344 switch (ev->button) {
1347 return false; //wait for the mouse-up to pop the dialog
1351 output_menu.set_name ("ArdourContextMenu");
1353 output_menu_bundles.clear ();
1355 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1357 citems.push_back (SeparatorElem());
1358 uint32_t const n_with_separator = citems.size ();
1360 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1362 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1364 /* give user bundles first chance at being in the menu */
1366 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1367 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1368 maybe_add_bundle_to_output_menu (*i, current);
1372 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1373 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1374 maybe_add_bundle_to_output_menu (*i, current);
1378 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1379 RouteList copy = *routes;
1380 copy.sort (RouteCompareByName ());
1381 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1382 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1385 if (citems.size() == n_with_separator) {
1386 /* no routes added; remove the separator */
1390 citems.push_back (SeparatorElem());
1391 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1393 output_menu.popup (1, ev->time);
1404 MonitorSection::update_output_display ()
1406 if (!_route || !_monitor || _session->deletion_in_progress()) {
1412 boost::shared_ptr<Port> port;
1413 vector<string> port_connections;
1415 uint32_t total_connection_count = 0;
1416 uint32_t io_connection_count = 0;
1417 uint32_t ardour_connection_count = 0;
1418 uint32_t system_connection_count = 0;
1419 uint32_t other_connection_count = 0;
1421 ostringstream label;
1423 bool have_label = false;
1424 bool each_io_has_one_connection = true;
1426 string connection_name;
1427 string ardour_track_name;
1428 string other_connection_type;
1429 string system_ports;
1432 ostringstream tooltip;
1433 char * tooltip_cstr;
1435 io_count = _route->n_outputs().n_total();
1436 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1439 for (io_index = 0; io_index < io_count; ++io_index) {
1441 port = _route->output()->nth (io_index);
1443 //ignore any port connections that don't match our DataType
1444 if (port->type() != DataType::AUDIO) {
1448 port_connections.clear ();
1449 port->get_connections(port_connections);
1450 io_connection_count = 0;
1452 if (!port_connections.empty()) {
1453 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1455 string& connection_name (*i);
1457 if (connection_name.find("system:") == 0) {
1458 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1461 if (io_connection_count == 0) {
1462 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1464 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1467 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1470 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1471 if (ardour_track_name.empty()) {
1472 // "ardour:Master/in 1" -> "ardour:Master/"
1473 string::size_type slash = connection_name.find("/");
1474 if (slash != string::npos) {
1475 ardour_track_name = connection_name.substr(0, slash + 1);
1479 if (connection_name.find(ardour_track_name) == 0) {
1480 ++ardour_connection_count;
1482 } else if (!pn.empty()) {
1483 if (system_ports.empty()) {
1486 system_ports += "/" + pn;
1488 if (connection_name.find("system:") == 0) {
1489 ++system_connection_count;
1491 } else if (connection_name.find("system:") == 0) {
1492 // "system:playback_123" -> "123"
1493 system_port = connection_name.substr(16);
1494 if (system_ports.empty()) {
1495 system_ports += system_port;
1497 system_ports += "/" + system_port;
1500 ++system_connection_count;
1502 if (other_connection_type.empty()) {
1503 // "jamin:in 1" -> "jamin:"
1504 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1507 if (connection_name.find(other_connection_type) == 0) {
1508 ++other_connection_count;
1512 ++total_connection_count;
1513 ++io_connection_count;
1517 if (io_connection_count != 1) {
1518 each_io_has_one_connection = false;
1522 if (total_connection_count == 0) {
1523 tooltip << endl << _("Disconnected");
1526 tooltip_cstr = new char[tooltip.str().size() + 1];
1527 strcpy(tooltip_cstr, tooltip.str().c_str());
1529 set_tooltip (output_button, tooltip_cstr, "");
1531 if (each_io_has_one_connection) {
1532 if (total_connection_count == ardour_connection_count) {
1533 // all connections are to the same track in ardour
1534 // "ardour:Master/" -> "Master"
1535 string::size_type slash = ardour_track_name.find("/");
1536 if (slash != string::npos) {
1537 label << ardour_track_name.substr(7, slash - 7);
1540 } else if (total_connection_count == system_connection_count) {
1541 // all connections are to system ports
1542 label << system_ports;
1544 } else if (total_connection_count == other_connection_count) {
1545 // all connections are to the same external program eg jamin
1546 // "jamin:" -> "jamin"
1547 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1553 if (total_connection_count == 0) {
1557 // Odd configuration
1558 label << "*" << total_connection_count << "*";
1562 output_button->set_text (label.str());
1566 MonitorSection::disconnect_output ()
1569 _route->output()->disconnect(this);
1574 MonitorSection::edit_output_configuration ()
1576 if (_output_selector == 0) {
1577 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1579 _output_selector->present ();
1583 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1588 boost::shared_ptr<Port> a = wa.lock ();
1589 boost::shared_ptr<Port> b = wb.lock ();
1590 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1591 update_output_display ();
1596 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1598 boost::shared_ptr<Processor> processor (p.lock ());
1599 if (!processor || !processor->display_to_user()) {
1602 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1609 MonitorSection::count_processors ()
1611 uint32_t processor_count = 0;
1613 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1615 return processor_count;
1619 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1621 update_processor_box ();