2 Copyright (C) 2012 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gdkmm/pixbuf.h>
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
26 #include "gtkmm2ext/bindable_button.h"
27 #include "gtkmm2ext/tearoff.h"
28 #include "gtkmm2ext/actions.h"
29 #include "gtkmm2ext/utils.h"
31 #include <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
34 #include "ardour/amp.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/monitor_processor.h"
37 #include "ardour/port.h"
38 #include "ardour/route.h"
39 #include "ardour/user_bundle.h"
40 #include "ardour/plugin_manager.h"
42 #include "gui_thread.h"
43 #include "monitor_section.h"
44 #include "public_editor.h"
47 #include "ui_config.h"
52 using namespace ARDOUR;
53 using namespace ARDOUR_UI_UTILS;
55 using namespace Gtkmm2ext;
59 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
61 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
63 MonitorSection::MonitorSection (Session* s)
67 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
68 , *channel_table_scroller.get_vadjustment ())
71 , solo_boost_control (0)
72 , solo_cut_control (0)
75 , solo_boost_display (0)
76 , solo_cut_display (0)
77 , _output_selector (0)
78 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
79 , afl_button (_("AFL"), ArdourButton::led_default_elements)
80 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
81 , exclusive_solo_button (ArdourButton::led_default_elements)
82 , solo_mute_override_button (ArdourButton::led_default_elements)
83 , toggle_processorbox_button (ArdourButton::default_elements)
84 , _inhibit_solo_model_update (false)
85 , _ui_initialized (false)
86 , myactions (X_("monitor section"))
90 using namespace Menu_Helpers;
92 Glib::RefPtr<Action> act;
94 if (!monitor_actions) {
99 _plugin_selector = new PluginSelector (PluginManager::instance());
100 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
101 insert_box->set_no_show_all ();
103 // TODO allow keyboard shortcuts in ProcessorBox
107 /* Rude Solo & Solo Isolated */
108 rude_solo_button.set_text (_("Soloing"));
109 rude_solo_button.set_name ("rude solo");
110 rude_solo_button.show ();
112 rude_iso_button.set_text (_("Isolated"));
113 rude_iso_button.set_name ("rude isolate");
114 rude_iso_button.show ();
116 rude_audition_button.set_text (_("Auditioning"));
117 rude_audition_button.set_name ("rude audition");
118 rude_audition_button.show ();
120 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
122 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
123 rude_solo_button.set_related_action (act);
124 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
126 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
127 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
129 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
130 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
132 /* SIP, AFL, PFL radio */
134 solo_in_place_button.set_name ("monitor section solo model");
135 afl_button.set_name ("monitor section solo model");
136 pfl_button.set_name ("monitor section solo model");
138 solo_in_place_button.set_led_left (true);
139 afl_button.set_led_left (true);
140 pfl_button.set_led_left (true);
142 solo_in_place_button.show ();
146 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
147 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
149 solo_in_place_button.set_related_action (act);
152 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
153 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
155 afl_button.set_related_action (act);
158 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
159 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
161 pfl_button.set_related_action (act);
164 /* Solo option buttons */
165 exclusive_solo_button.set_text (_("Excl. Solo"));
166 exclusive_solo_button.set_name (X_("monitor section solo option"));
167 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
169 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
171 exclusive_solo_button.set_related_action (act);
174 solo_mute_override_button.set_text (_("Solo ยป Mute"));
175 solo_mute_override_button.set_name (X_("monitor section solo option"));
176 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
178 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
180 solo_mute_override_button.set_related_action (act);
183 /* Processor Box hide/shos */
184 toggle_processorbox_button.set_text (_("Processors"));
185 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
186 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
188 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
190 toggle_processorbox_button.set_related_action (proctoggle);
193 Label* solo_boost_label;
194 Label* solo_cut_label;
197 /* Solo Boost Knob */
199 solo_boost_control = new ArdourKnob ();
200 solo_boost_control->set_name("monitor section knob");
201 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
202 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
204 solo_boost_display = new ArdourDisplay ();
205 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
206 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
207 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
208 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
209 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
211 solo_boost_label = manage (new Label (_("Solo Boost")));
215 solo_cut_control = new ArdourKnob ();
216 solo_cut_control->set_name ("monitor section knob");
217 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
218 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
220 solo_cut_display = new ArdourDisplay ();
221 solo_cut_display->set_name("monitor section dropdown"); // XXX
222 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
223 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
224 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
225 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
226 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
227 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
229 solo_cut_label = manage (new Label (_("SiP Cut")));
233 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
234 dim_control->set_name ("monitor section knob");
235 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
236 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
238 dim_display = new ArdourDisplay ();
239 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
240 dim_display->add_controllable_preset(_("0 dB"), 0.0);
241 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
242 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
243 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
244 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
246 dim_label = manage (new Label (_("Dim")));
249 cut_all_button.set_text (_("Mute"));
250 cut_all_button.set_name ("mute button");
251 cut_all_button.set_size_request (-1, PX_SCALE(30));
252 cut_all_button.show ();
254 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
256 cut_all_button.set_related_action (act);
260 dim_all_button.set_text (_("Dim"));
261 dim_all_button.set_name ("monitor section dim");
262 dim_all_button.set_size_request (-1, PX_SCALE(25));
263 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
265 dim_all_button.set_related_action (act);
269 mono_button.set_text (_("Mono"));
270 mono_button.set_name ("monitor section mono");
271 mono_button.set_size_request (-1, PX_SCALE(25));
272 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
274 mono_button.set_related_action (act);
279 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
280 gain_control->set_name("monitor section knob");
281 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
283 gain_display = new ArdourDisplay ();
284 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
285 gain_display->add_controllable_preset(_("0 dB"), 0.0);
286 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
287 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
288 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
289 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
290 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
292 Label* output_label = manage (new Label (_("Output")));
293 output_label->set_name (X_("MonitorSectionLabel"));
295 output_button = new ArdourButton ();
296 output_button->set_text (_("Output"));
297 output_button->set_name (X_("monitor section cut")); // XXX
298 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
299 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
301 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
302 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
303 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
304 channel_table_scroller.show ();
305 channel_table_scroller.add (channel_table_viewport);
307 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
308 channel_size_group->add_widget (channel_table_header);
309 channel_size_group->add_widget (channel_table);
311 channel_table_header.resize (1, 5);
313 Label* l1 = manage (new Label (X_(" ")));
314 l1->set_name (X_("MonitorSectionLabel"));
315 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
317 l1 = manage (new Label (_("Mute")));
318 l1->set_name (X_("MonitorSectionLabel"));
319 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
321 l1 = manage (new Label (_("Dim")));
322 l1->set_name (X_("MonitorSectionLabel"));
323 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
325 l1 = manage (new Label (_("Solo")));
326 l1->set_name (X_("MonitorSectionLabel"));
327 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
329 l1 = manage (new Label (_("Inv")));
330 l1->set_name (X_("MonitorSectionLabel"));
331 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
333 channel_table_header.show ();
336 /****************************************************************************
337 * LAYOUT top to bottom
340 // solo, iso information
341 HBox* rude_box = manage (new HBox);
342 rude_box->set_spacing (PX_SCALE(4));
343 rude_box->set_homogeneous (true);
344 rude_box->pack_start (rude_solo_button, true, true);
345 rude_box->pack_start (rude_iso_button, true, true);
347 // solo options (right align)
348 HBox* tbx1 = manage (new HBox);
349 tbx1->pack_end (exclusive_solo_button, false, false);
351 HBox* tbx2 = manage (new HBox);
352 tbx2->pack_end (solo_mute_override_button, false, false);
354 HBox* tbx3 = manage (new HBox);
355 tbx3->pack_end (toggle_processorbox_button, false, false);
357 HBox* tbx0 = manage (new HBox); // space
359 // combined solo mode (Sip, AFL, PFL) & solo options
360 Table *solo_tbl = manage (new Table);
361 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
362 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
363 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
364 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
365 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
366 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
369 // boost, cut, dim volume control
370 Table *level_tbl = manage (new Table);
371 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
372 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
373 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
375 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
379 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
383 /* note that we don't pack the table_hpacker till later
384 * -> top level channel_table_packer */
385 table_hpacker.pack_start (channel_table, true, true);
388 HBox* mono_dim_box = manage (new HBox);
389 mono_dim_box->set_spacing (PX_SCALE(4));
390 mono_dim_box->set_homogeneous (true);
391 mono_dim_box->pack_start (mono_button, true, true);
392 mono_dim_box->pack_end (dim_all_button, true, true);
395 Label* spin_label = manage (new Label (_("Monitor")));
396 VBox* spin_packer = manage (new VBox);
397 spin_packer->set_spacing (PX_SCALE(2));
398 spin_packer->pack_start (*spin_label, false, false);
399 spin_packer->pack_start (*gain_control, false, false);
400 spin_packer->pack_start (*gain_display, false, false);
402 master_packer.pack_start (*spin_packer, true, false);
404 // combined gain section (channels, mute, dim)
405 VBox* lower_packer = manage (new VBox);
406 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
407 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
408 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
409 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
411 // output port select
412 VBox* out_packer = manage (new VBox);
413 out_packer->set_spacing (PX_SCALE(2));
414 out_packer->pack_start (*output_label, false, false);
415 out_packer->pack_start (*output_button, false, false);
417 /****************************************************************************
420 vpacker.set_border_width (PX_SCALE(3));
421 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
422 vpacker.pack_start (rude_audition_button, false, false, 0);
423 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
424 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
425 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
426 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
427 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
428 vpacker.pack_end (*out_packer, false, false, PX_SCALE(3));
430 hpacker.set_spacing (0);
431 hpacker.pack_start (vpacker, true, true);
433 gain_control->show_all ();
434 gain_display->show_all ();
435 dim_control->show_all ();
436 dim_display->show_all();
437 solo_boost_control->show_all ();
438 solo_boost_display->show_all();
440 mono_dim_box->show ();
441 spin_packer->show ();
442 master_packer.show ();
443 channel_table.show ();
446 solo_tbl->show_all();
448 lower_packer->show ();
456 assign_controllables ();
458 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
459 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
461 _tearoff = new TearOff (hpacker);
463 if (!UIConfiguration::instance().get_floating_monitor_section()) {
464 /* if torn off, make this a normal window
465 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
467 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
469 _tearoff->tearoff_window().set_title (X_("Monitor"));
470 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
472 update_output_display ();
473 update_processor_box ();
474 _ui_initialized = true;
476 /* catch changes that affect us */
477 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
478 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
480 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
483 MonitorSection::~MonitorSection ()
485 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
489 _channel_buttons.clear ();
490 _output_changed_connection.disconnect ();
493 delete output_button;
498 delete solo_boost_control;
499 delete solo_boost_display;
500 delete solo_cut_control;
501 delete solo_cut_display;
503 delete _output_selector;
504 _output_selector = 0;
509 MonitorSection::update_processor_box ()
511 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
513 if (count_processors () > 0 && !show_processor_box) {
514 toggle_processorbox_button.set_name (X_("monitor section processors present"));
516 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
519 if (insert_box->is_visible() == show_processor_box) {
523 if (show_processor_box) {
524 if (master_packer.get_parent()) {
525 master_packer.get_parent()->remove (master_packer);
528 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
530 if (master_packer.get_parent()) {
531 master_packer.get_parent()->remove (master_packer);
534 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
539 MonitorSection::set_session (Session* s)
541 AxisView::set_session (s);
542 _plugin_selector->set_session (_session);
546 _route = _session->monitor_out ();
549 /* session with monitor section */
550 _monitor = _route->monitor_control ();
551 assign_controllables ();
552 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
553 boost::bind (&MonitorSection::update_output_display, this),
555 insert_box->set_route (_route);
556 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
557 if (_ui_initialized) {
558 update_processor_box ();
561 /* session with no monitor section */
562 _output_changed_connection.disconnect();
565 delete _output_selector;
566 _output_selector = 0;
569 if (channel_table_scroller.get_parent()) {
570 /* scroller is packed, so remove it */
571 channel_table_packer.remove (channel_table_scroller);
574 if (table_hpacker.get_parent () == &channel_table_packer) {
575 /* this occurs when the table hpacker is directly
576 packed, so remove it.
578 channel_table_packer.remove (table_hpacker);
579 } else if (table_hpacker.get_parent()) {
580 channel_table_viewport.remove ();
583 if (_monitor->output_streams().n_audio() > 7) {
584 /* put the table into a scrolled window, and then put
585 * that into the channel vpacker, after the table header
587 channel_table_viewport.add (table_hpacker);
588 channel_table_packer.pack_start (channel_table_scroller, true, true);
589 channel_table_viewport.show ();
590 channel_table_scroller.show ();
593 /* just put the channel table itself into the channel
594 * vpacker, after the table header
597 channel_table_packer.pack_start (table_hpacker, true, true);
598 channel_table_scroller.hide ();
601 table_hpacker.show ();
602 channel_table.show ();
607 _output_changed_connection.disconnect();
610 control_connections.drop_connections ();
611 rude_iso_button.unset_active_state ();
612 rude_solo_button.unset_active_state ();
613 delete _output_selector;
614 _output_selector = 0;
616 assign_controllables ();
620 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
622 cut.set_name (X_("mute button"));
623 dim.set_name (X_("monitor section dim"));
624 solo.set_name (X_("solo button"));
625 invert.set_name (X_("invert button"));
627 cut.unset_flags (Gtk::CAN_FOCUS);
628 dim.unset_flags (Gtk::CAN_FOCUS);
629 solo.unset_flags (Gtk::CAN_FOCUS);
630 invert.unset_flags (Gtk::CAN_FOCUS);
634 MonitorSection::populate_buttons ()
640 Glib::RefPtr<Action> act;
641 uint32_t nchans = _monitor->output_streams().n_audio();
643 channel_table.resize (nchans, 5);
644 channel_table.set_col_spacings (6);
645 channel_table.set_row_spacings (6);
646 channel_table.set_homogeneous (true);
648 const uint32_t row_offset = 0;
650 for (uint32_t i = 0; i < nchans; ++i) {
663 snprintf (buf, sizeof (buf), "%d", i+1);
667 Label* label = manage (new Label (l));
668 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
670 ChannelButtonSet* cbs = new ChannelButtonSet;
672 _channel_buttons.push_back (cbs);
674 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
675 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
676 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
677 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
679 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
680 act = ActionManager::get_action (X_("Monitor"), buf);
682 cbs->cut.set_related_action (act);
685 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
686 act = ActionManager::get_action (X_("Monitor"), buf);
688 cbs->dim.set_related_action (act);
691 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
692 act = ActionManager::get_action (X_("Monitor"), buf);
694 cbs->solo.set_related_action (act);
697 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
698 act = ActionManager::get_action (X_("Monitor"), buf);
700 cbs->invert.set_related_action (act);
704 channel_table.show_all ();
708 MonitorSection::toggle_exclusive_solo ()
714 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
716 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
717 Config->set_exclusive_solo (tact->get_active());
723 MonitorSection::toggle_mute_overrides_solo ()
729 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
731 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
732 Config->set_solo_mute_override (tact->get_active());
737 MonitorSection::dim_all ()
743 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
745 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
746 _monitor->set_dim_all (tact->get_active());
752 MonitorSection::cut_all ()
758 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
760 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
761 _monitor->set_cut_all (tact->get_active());
766 MonitorSection::mono ()
772 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
774 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
775 _monitor->set_mono (tact->get_active());
780 MonitorSection::cut_channel (uint32_t chn)
787 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
789 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
791 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
792 _monitor->set_cut (chn, tact->get_active());
797 MonitorSection::dim_channel (uint32_t chn)
804 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
806 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
808 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
809 _monitor->set_dim (chn, tact->get_active());
815 MonitorSection::solo_channel (uint32_t chn)
822 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
824 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
826 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
827 _monitor->set_solo (chn, tact->get_active());
833 MonitorSection::invert_channel (uint32_t chn)
840 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
842 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
844 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
845 _monitor->set_polarity (chn, tact->get_active());
850 MonitorSection::register_actions ()
854 Glib::RefPtr<Action> act;
856 monitor_actions = myactions.create_action_group (X_("Monitor"));
858 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
859 sigc::mem_fun (*this, &MonitorSection::mono));
861 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
862 sigc::mem_fun (*this, &MonitorSection::cut_all));
864 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
865 sigc::mem_fun (*this, &MonitorSection::dim_all));
867 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
868 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
870 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
871 tact->set_active (Config->get_exclusive_solo());
873 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
874 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
876 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
877 tact->set_active (Config->get_solo_mute_override());
879 for (uint32_t chn = 0; chn < 16; ++chn) {
881 action_name = string_compose (X_("monitor-cut-%1"), chn);
882 action_descr = string_compose (_("Cut monitor channel %1"), chn);
883 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
884 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
886 action_name = string_compose (X_("monitor-dim-%1"), chn);
887 action_descr = string_compose (_("Dim monitor channel %1"), chn);
888 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
889 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
891 action_name = string_compose (X_("monitor-solo-%1"), chn);
892 action_descr = string_compose (_("Solo monitor channel %1"), chn);
893 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
894 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
896 action_name = string_compose (X_("monitor-invert-%1"), chn);
897 action_descr = string_compose (_("Invert monitor channel %1"), chn);
898 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
899 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
904 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
905 RadioAction::Group solo_group;
907 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
908 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
909 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
910 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
911 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
912 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
914 proctoggle = myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
915 sigc::mem_fun(*this, &MonitorSection::update_processor_box));
919 MonitorSection::connect_actions ()
921 Glib::RefPtr<Action> act;
922 Glib::RefPtr<ToggleAction> tact;
924 #define MON_TOG(NAME, FUNC) \
925 act = ActionManager::get_action (X_("Monitor"), NAME); \
926 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
928 tact->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
930 MON_TOG("monitor-mono", mono);
931 MON_TOG("monitor-cut-all", cut_all);
932 MON_TOG("monitor-dim-all", dim_all);
934 MON_TOG("toggle-exclusive-solo", toggle_exclusive_solo);
935 tact->set_active (Config->get_exclusive_solo());
937 MON_TOG("toggle-mute-overrides-solo", toggle_mute_overrides_solo);
938 tact->set_active (Config->get_solo_mute_override());
941 #define MON_BIND(NAME, FUNC, ARG) \
942 act = ActionManager::get_action (X_("Monitor"), NAME); \
943 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
945 tact->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::FUNC), ARG));
947 for (uint32_t chn = 0; chn < 16; ++chn) {
948 std::string action_name = string_compose (X_("monitor-cut-%1"), chn);
949 MON_BIND(action_name.c_str(), cut_channel, chn);
950 action_name = string_compose (X_("monitor-dim-%1"), chn);
951 MON_BIND(action_name.c_str(), dim_channel, chn);
952 action_name = string_compose (X_("monitor-solo-%1"), chn);
953 MON_BIND(action_name.c_str(), solo_channel, chn);
954 action_name = string_compose (X_("monitor-invert-%1"), chn);
955 MON_BIND(action_name.c_str(), invert_channel, chn);
959 #define SOLO_RADIO(NAME, FUNC) \
960 act = ActionManager::get_action (X_("Solo"), NAME); \
961 ract = Glib::RefPtr<RadioAction>::cast_dynamic (act); \
963 ract->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
965 Glib::RefPtr<RadioAction> ract;
966 SOLO_RADIO ("solo-use-in-place", solo_use_in_place);
967 SOLO_RADIO ("solo-use-afl", solo_use_afl);
968 SOLO_RADIO ("solo-use-pfl", solo_use_pfl);
973 MonitorSection::solo_use_in_place ()
975 /* this is driven by a toggle on a radio group, and so is invoked twice,
976 once for the item that became inactive and once for the one that became
980 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
983 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
985 if (!ract->get_active ()) {
986 /* We are turning SiP off, which means that AFL or PFL will be turned on
987 shortly; don't update the solo model in the mean time, as if the currently
988 configured listen position is not the one that is about to be turned on,
989 things will go wrong.
991 _inhibit_solo_model_update = true;
993 Config->set_solo_control_is_listen_control (!ract->get_active());
994 _inhibit_solo_model_update = false;
1000 MonitorSection::solo_use_afl ()
1002 /* this is driven by a toggle on a radio group, and so is invoked twice,
1003 once for the item that became inactive and once for the one that became
1007 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1009 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1011 if (ract->get_active()) {
1012 Config->set_solo_control_is_listen_control (true);
1013 Config->set_listen_position (AfterFaderListen);
1020 MonitorSection::solo_use_pfl ()
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-pfl"));
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 (PreFaderListen);
1040 MonitorSection::update_solo_model ()
1042 if (_inhibit_solo_model_update) {
1046 const char* action_name = 0;
1047 Glib::RefPtr<Action> act;
1049 if (Config->get_solo_control_is_listen_control()) {
1050 switch (Config->get_listen_position()) {
1051 case AfterFaderListen:
1052 action_name = X_("solo-use-afl");
1054 case PreFaderListen:
1055 action_name = X_("solo-use-pfl");
1059 action_name = X_("solo-use-in-place");
1062 act = ActionManager::get_action (X_("Solo"), action_name);
1065 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1067 /* because these are radio buttons, one of them will be
1068 active no matter what. to trigger a change in the
1069 action so that the view picks it up, toggle it.
1071 if (ract->get_active()) {
1072 ract->set_active (false);
1074 ract->set_active (true);
1081 MonitorSection::map_state ()
1083 if (!_route || !_monitor) {
1087 Glib::RefPtr<Action> act;
1089 update_solo_model ();
1091 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1093 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1095 tact->set_active (_monitor->cut_all());
1099 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1101 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1103 tact->set_active (_monitor->dim_all());
1107 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1109 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1111 tact->set_active (_monitor->mono());
1115 uint32_t nchans = _monitor->output_streams().n_audio();
1117 assert (nchans == _channel_buttons.size ());
1119 for (uint32_t n = 0; n < nchans; ++n) {
1121 char action_name[32];
1123 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1124 act = ActionManager::get_action (X_("Monitor"), action_name);
1126 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1128 tact->set_active (_monitor->cut (n));
1132 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1133 act = ActionManager::get_action (X_("Monitor"), action_name);
1135 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1137 tact->set_active (_monitor->dimmed (n));
1141 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1142 act = ActionManager::get_action (X_("Monitor"), action_name);
1144 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1146 tact->set_active (_monitor->soloed (n));
1150 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1151 act = ActionManager::get_action (X_("Monitor"), action_name);
1153 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1155 tact->set_active (_monitor->inverted (n));
1162 MonitorSection::do_blink (bool onoff)
1165 audition_blink (onoff);
1169 MonitorSection::audition_blink (bool onoff)
1171 if (_session == 0) {
1175 if (_session->is_auditioning()) {
1176 rude_audition_button.set_active (onoff);
1178 rude_audition_button.set_active (false);
1183 MonitorSection::solo_blink (bool onoff)
1185 if (_session == 0) {
1189 if (_session->soloing() || _session->listening()) {
1190 rude_solo_button.set_active (onoff);
1192 if (_session->soloing()) {
1193 if (_session->solo_isolated()) {
1194 rude_iso_button.set_active (onoff);
1196 rude_iso_button.set_active (false);
1201 rude_solo_button.set_active (false);
1202 rude_iso_button.set_active (false);
1207 MonitorSection::cancel_isolate (GdkEventButton*)
1210 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1211 _session->set_solo_isolated (rl, false, Session::rt_cleanup, Controllable::NoGroup);
1218 MonitorSection::cancel_audition (GdkEventButton*)
1221 _session->cancel_audition();
1226 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1228 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1229 if (tact && tact->get_active() != value) { \
1230 tact->set_active(value); \
1235 MonitorSection::parameter_changed (std::string name)
1237 if (name == "solo-control-is-listen-control") {
1238 update_solo_model ();
1239 } else if (name == "listen-position") {
1240 update_solo_model ();
1241 } else if (name == "solo-mute-override") {
1242 SYNCHRONIZE_TOGGLE_ACTION(
1243 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1244 Config->get_solo_mute_override ())
1245 } else if (name == "exclusive-solo") {
1246 SYNCHRONIZE_TOGGLE_ACTION(
1247 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1248 Config->get_exclusive_solo ())
1253 MonitorSection::assign_controllables ()
1255 boost::shared_ptr<Controllable> none;
1257 if (!gain_control) {
1258 /* too early - GUI controls not set up yet */
1263 solo_cut_control->set_controllable (_session->solo_cut_control());
1264 solo_cut_display->set_controllable (_session->solo_cut_control());
1266 solo_cut_control->set_controllable (none);
1267 solo_cut_display->set_controllable (none);
1271 gain_control->set_controllable (_route->gain_control());
1272 gain_display->set_controllable (_route->gain_control());
1274 gain_control->set_controllable (none);
1279 cut_all_button.set_controllable (_monitor->cut_control());
1280 cut_all_button.watch ();
1281 dim_all_button.set_controllable (_monitor->dim_control());
1282 dim_all_button.watch ();
1283 mono_button.set_controllable (_monitor->mono_control());
1284 mono_button.watch ();
1286 dim_control->set_controllable (_monitor->dim_level_control ());
1287 dim_display->set_controllable (_monitor->dim_level_control ());
1288 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1289 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1293 cut_all_button.set_controllable (none);
1294 dim_all_button.set_controllable (none);
1295 mono_button.set_controllable (none);
1297 dim_control->set_controllable (none);
1298 dim_display->set_controllable (none);
1299 solo_boost_control->set_controllable (none);
1300 solo_boost_display->set_controllable (none);
1305 MonitorSection::state_id() const
1307 return "monitor-section";
1311 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1313 using namespace Menu_Helpers;
1315 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1319 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1320 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1324 if (i != output_menu_bundles.end()) {
1328 output_menu_bundles.push_back (b);
1330 MenuList& citems = output_menu.items();
1332 std::string n = b->name ();
1333 replace_all (n, "_", " ");
1335 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1339 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1342 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1344 if (std::find (current.begin(), current.end(), c) == current.end()) {
1345 _route->output()->connect_ports_to_bundle (c, true, this);
1347 _route->output()->disconnect_ports_from_bundle (c, this);
1352 MonitorSection::output_release (GdkEventButton *ev)
1354 switch (ev->button) {
1356 edit_output_configuration ();
1363 struct RouteCompareByName {
1364 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1365 return a->name().compare (b->name()) < 0;
1370 MonitorSection::output_press (GdkEventButton *ev)
1372 using namespace Menu_Helpers;
1374 MessageDialog msg (_("No session - no I/O changes are possible"));
1379 MenuList& citems = output_menu.items();
1380 switch (ev->button) {
1383 return false; //wait for the mouse-up to pop the dialog
1387 output_menu.set_name ("ArdourContextMenu");
1389 output_menu_bundles.clear ();
1391 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1393 citems.push_back (SeparatorElem());
1394 uint32_t const n_with_separator = citems.size ();
1396 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1398 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1400 /* give user bundles first chance at being in the menu */
1402 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1403 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1404 maybe_add_bundle_to_output_menu (*i, current);
1408 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1409 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1410 maybe_add_bundle_to_output_menu (*i, current);
1414 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1415 RouteList copy = *routes;
1416 copy.sort (RouteCompareByName ());
1417 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1418 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1421 if (citems.size() == n_with_separator) {
1422 /* no routes added; remove the separator */
1426 citems.push_back (SeparatorElem());
1427 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1429 output_menu.popup (1, ev->time);
1440 MonitorSection::update_output_display ()
1442 if (!_route || !_monitor || _session->deletion_in_progress()) {
1448 boost::shared_ptr<Port> port;
1449 vector<string> port_connections;
1451 uint32_t total_connection_count = 0;
1452 uint32_t io_connection_count = 0;
1453 uint32_t ardour_connection_count = 0;
1454 uint32_t system_connection_count = 0;
1455 uint32_t other_connection_count = 0;
1457 ostringstream label;
1459 bool have_label = false;
1460 bool each_io_has_one_connection = true;
1462 string connection_name;
1463 string ardour_track_name;
1464 string other_connection_type;
1465 string system_ports;
1468 ostringstream tooltip;
1469 char * tooltip_cstr;
1471 io_count = _route->n_outputs().n_total();
1472 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1475 for (io_index = 0; io_index < io_count; ++io_index) {
1477 port = _route->output()->nth (io_index);
1479 //ignore any port connections that don't match our DataType
1480 if (port->type() != DataType::AUDIO) {
1484 port_connections.clear ();
1485 port->get_connections(port_connections);
1486 io_connection_count = 0;
1488 if (!port_connections.empty()) {
1489 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1491 string& connection_name (*i);
1493 if (connection_name.find("system:") == 0) {
1494 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1497 if (io_connection_count == 0) {
1498 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1500 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1503 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1506 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1507 if (ardour_track_name.empty()) {
1508 // "ardour:Master/in 1" -> "ardour:Master/"
1509 string::size_type slash = connection_name.find("/");
1510 if (slash != string::npos) {
1511 ardour_track_name = connection_name.substr(0, slash + 1);
1515 if (connection_name.find(ardour_track_name) == 0) {
1516 ++ardour_connection_count;
1518 } else if (!pn.empty()) {
1519 if (system_ports.empty()) {
1522 system_ports += "/" + pn;
1524 if (connection_name.find("system:") == 0) {
1525 ++system_connection_count;
1527 } else if (connection_name.find("system:") == 0) {
1528 // "system:playback_123" -> "123"
1529 system_port = connection_name.substr(16);
1530 if (system_ports.empty()) {
1531 system_ports += system_port;
1533 system_ports += "/" + system_port;
1536 ++system_connection_count;
1538 if (other_connection_type.empty()) {
1539 // "jamin:in 1" -> "jamin:"
1540 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1543 if (connection_name.find(other_connection_type) == 0) {
1544 ++other_connection_count;
1548 ++total_connection_count;
1549 ++io_connection_count;
1553 if (io_connection_count != 1) {
1554 each_io_has_one_connection = false;
1558 if (total_connection_count == 0) {
1559 tooltip << endl << _("Disconnected");
1562 tooltip_cstr = new char[tooltip.str().size() + 1];
1563 strcpy(tooltip_cstr, tooltip.str().c_str());
1565 set_tooltip (output_button, tooltip_cstr, "");
1567 if (each_io_has_one_connection) {
1568 if (total_connection_count == ardour_connection_count) {
1569 // all connections are to the same track in ardour
1570 // "ardour:Master/" -> "Master"
1571 string::size_type slash = ardour_track_name.find("/");
1572 if (slash != string::npos) {
1573 label << ardour_track_name.substr(7, slash - 7);
1576 } else if (total_connection_count == system_connection_count) {
1577 // all connections are to system ports
1578 label << system_ports;
1580 } else if (total_connection_count == other_connection_count) {
1581 // all connections are to the same external program eg jamin
1582 // "jamin:" -> "jamin"
1583 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1589 if (total_connection_count == 0) {
1593 // Odd configuration
1594 label << "*" << total_connection_count << "*";
1598 output_button->set_text (label.str());
1602 MonitorSection::disconnect_output ()
1605 _route->output()->disconnect(this);
1610 MonitorSection::edit_output_configuration ()
1612 if (_output_selector == 0) {
1613 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1615 _output_selector->present ();
1619 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1624 boost::shared_ptr<Port> a = wa.lock ();
1625 boost::shared_ptr<Port> b = wb.lock ();
1626 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1627 update_output_display ();
1632 MonitorSection::load_bindings ()
1634 bindings = Bindings::get_bindings (X_("monitor-section"), myactions);
1638 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1640 boost::shared_ptr<Processor> processor (p.lock ());
1641 if (!processor || !processor->display_to_user()) {
1644 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1651 MonitorSection::count_processors ()
1653 uint32_t processor_count = 0;
1655 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1657 return processor_count;
1661 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1663 update_processor_box ();