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 = ToggleAction::create ();
189 toggle_processorbox_button.set_related_action (proctoggle);
190 proctoggle->signal_toggled().connect (sigc::mem_fun(*this, &MonitorSection::update_processor_box), false);
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 = 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));
916 MonitorSection::connect_actions ()
918 Glib::RefPtr<Action> act;
919 Glib::RefPtr<ToggleAction> tact;
921 #define MON_TOG(NAME, FUNC) \
922 act = ActionManager::get_action (X_("Monitor"), NAME); \
923 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
925 tact->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
927 MON_TOG("monitor-mono", mono);
928 MON_TOG("monitor-cut-all", cut_all);
929 MON_TOG("monitor-dim-all", dim_all);
931 MON_TOG("toggle-exclusive-solo", toggle_exclusive_solo);
932 tact->set_active (Config->get_exclusive_solo());
934 MON_TOG("toggle-mute-overrides-solo", toggle_mute_overrides_solo);
935 tact->set_active (Config->get_solo_mute_override());
938 #define MON_BIND(NAME, FUNC, ARG) \
939 act = ActionManager::get_action (X_("Monitor"), NAME); \
940 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
942 tact->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::FUNC), ARG));
944 for (uint32_t chn = 0; chn < 16; ++chn) {
945 std::string action_name = string_compose (X_("monitor-cut-%1"), chn);
946 MON_BIND(action_name.c_str(), cut_channel, chn);
947 action_name = string_compose (X_("monitor-dim-%1"), chn);
948 MON_BIND(action_name.c_str(), dim_channel, chn);
949 action_name = string_compose (X_("monitor-solo-%1"), chn);
950 MON_BIND(action_name.c_str(), solo_channel, chn);
951 action_name = string_compose (X_("monitor-invert-%1"), chn);
952 MON_BIND(action_name.c_str(), invert_channel, chn);
956 #define SOLO_RADIO(NAME, FUNC) \
957 act = ActionManager::get_action (X_("Solo"), NAME); \
958 ract = Glib::RefPtr<RadioAction>::cast_dynamic (act); \
960 ract->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
962 Glib::RefPtr<RadioAction> ract;
963 SOLO_RADIO ("solo-use-in-place", solo_use_in_place);
964 SOLO_RADIO ("solo-use-afl", solo_use_afl);
965 SOLO_RADIO ("solo-use-pfl", solo_use_pfl);
970 MonitorSection::solo_use_in_place ()
972 /* this is driven by a toggle on a radio group, and so is invoked twice,
973 once for the item that became inactive and once for the one that became
977 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
980 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
982 if (!ract->get_active ()) {
983 /* We are turning SiP off, which means that AFL or PFL will be turned on
984 shortly; don't update the solo model in the mean time, as if the currently
985 configured listen position is not the one that is about to be turned on,
986 things will go wrong.
988 _inhibit_solo_model_update = true;
990 Config->set_solo_control_is_listen_control (!ract->get_active());
991 _inhibit_solo_model_update = false;
997 MonitorSection::solo_use_afl ()
999 /* this is driven by a toggle on a radio group, and so is invoked twice,
1000 once for the item that became inactive and once for the one that became
1004 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1006 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1008 if (ract->get_active()) {
1009 Config->set_solo_control_is_listen_control (true);
1010 Config->set_listen_position (AfterFaderListen);
1017 MonitorSection::solo_use_pfl ()
1019 /* this is driven by a toggle on a radio group, and so is invoked twice,
1020 once for the item that became inactive and once for the one that became
1024 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1026 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1028 if (ract->get_active()) {
1029 Config->set_solo_control_is_listen_control (true);
1030 Config->set_listen_position (PreFaderListen);
1037 MonitorSection::update_solo_model ()
1039 if (_inhibit_solo_model_update) {
1043 const char* action_name = 0;
1044 Glib::RefPtr<Action> act;
1046 if (Config->get_solo_control_is_listen_control()) {
1047 switch (Config->get_listen_position()) {
1048 case AfterFaderListen:
1049 action_name = X_("solo-use-afl");
1051 case PreFaderListen:
1052 action_name = X_("solo-use-pfl");
1056 action_name = X_("solo-use-in-place");
1059 act = ActionManager::get_action (X_("Solo"), action_name);
1062 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1064 /* because these are radio buttons, one of them will be
1065 active no matter what. to trigger a change in the
1066 action so that the view picks it up, toggle it.
1068 if (ract->get_active()) {
1069 ract->set_active (false);
1071 ract->set_active (true);
1078 MonitorSection::map_state ()
1080 if (!_route || !_monitor) {
1084 Glib::RefPtr<Action> act;
1086 update_solo_model ();
1088 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1090 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1092 tact->set_active (_monitor->cut_all());
1096 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1098 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1100 tact->set_active (_monitor->dim_all());
1104 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1106 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1108 tact->set_active (_monitor->mono());
1112 uint32_t nchans = _monitor->output_streams().n_audio();
1114 assert (nchans == _channel_buttons.size ());
1116 for (uint32_t n = 0; n < nchans; ++n) {
1118 char action_name[32];
1120 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1121 act = ActionManager::get_action (X_("Monitor"), action_name);
1123 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1125 tact->set_active (_monitor->cut (n));
1129 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1130 act = ActionManager::get_action (X_("Monitor"), action_name);
1132 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1134 tact->set_active (_monitor->dimmed (n));
1138 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1139 act = ActionManager::get_action (X_("Monitor"), action_name);
1141 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1143 tact->set_active (_monitor->soloed (n));
1147 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1148 act = ActionManager::get_action (X_("Monitor"), action_name);
1150 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1152 tact->set_active (_monitor->inverted (n));
1159 MonitorSection::do_blink (bool onoff)
1162 audition_blink (onoff);
1166 MonitorSection::audition_blink (bool onoff)
1168 if (_session == 0) {
1172 if (_session->is_auditioning()) {
1173 rude_audition_button.set_active (onoff);
1175 rude_audition_button.set_active (false);
1180 MonitorSection::solo_blink (bool onoff)
1182 if (_session == 0) {
1186 if (_session->soloing() || _session->listening()) {
1187 rude_solo_button.set_active (onoff);
1189 if (_session->soloing()) {
1190 if (_session->solo_isolated()) {
1191 rude_iso_button.set_active (onoff);
1193 rude_iso_button.set_active (false);
1198 rude_solo_button.set_active (false);
1199 rude_iso_button.set_active (false);
1204 MonitorSection::cancel_isolate (GdkEventButton*)
1207 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1208 _session->set_solo_isolated (rl, false, Session::rt_cleanup, Controllable::NoGroup);
1215 MonitorSection::cancel_audition (GdkEventButton*)
1218 _session->cancel_audition();
1223 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1225 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1226 if (tact && tact->get_active() != value) { \
1227 tact->set_active(value); \
1232 MonitorSection::parameter_changed (std::string name)
1234 if (name == "solo-control-is-listen-control") {
1235 update_solo_model ();
1236 } else if (name == "listen-position") {
1237 update_solo_model ();
1238 } else if (name == "solo-mute-override") {
1239 SYNCHRONIZE_TOGGLE_ACTION(
1240 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1241 Config->get_solo_mute_override ())
1242 } else if (name == "exclusive-solo") {
1243 SYNCHRONIZE_TOGGLE_ACTION(
1244 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1245 Config->get_exclusive_solo ())
1250 MonitorSection::assign_controllables ()
1252 boost::shared_ptr<Controllable> none;
1254 if (!gain_control) {
1255 /* too early - GUI controls not set up yet */
1260 solo_cut_control->set_controllable (_session->solo_cut_control());
1261 solo_cut_display->set_controllable (_session->solo_cut_control());
1263 solo_cut_control->set_controllable (none);
1264 solo_cut_display->set_controllable (none);
1268 gain_control->set_controllable (_route->gain_control());
1269 gain_display->set_controllable (_route->gain_control());
1271 gain_control->set_controllable (none);
1276 cut_all_button.set_controllable (_monitor->cut_control());
1277 cut_all_button.watch ();
1278 dim_all_button.set_controllable (_monitor->dim_control());
1279 dim_all_button.watch ();
1280 mono_button.set_controllable (_monitor->mono_control());
1281 mono_button.watch ();
1283 dim_control->set_controllable (_monitor->dim_level_control ());
1284 dim_display->set_controllable (_monitor->dim_level_control ());
1285 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1286 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1290 cut_all_button.set_controllable (none);
1291 dim_all_button.set_controllable (none);
1292 mono_button.set_controllable (none);
1294 dim_control->set_controllable (none);
1295 dim_display->set_controllable (none);
1296 solo_boost_control->set_controllable (none);
1297 solo_boost_display->set_controllable (none);
1302 MonitorSection::state_id() const
1304 return "monitor-section";
1308 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1310 using namespace Menu_Helpers;
1312 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1316 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1317 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1321 if (i != output_menu_bundles.end()) {
1325 output_menu_bundles.push_back (b);
1327 MenuList& citems = output_menu.items();
1329 std::string n = b->name ();
1330 replace_all (n, "_", " ");
1332 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1336 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1339 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1341 if (std::find (current.begin(), current.end(), c) == current.end()) {
1342 _route->output()->connect_ports_to_bundle (c, true, this);
1344 _route->output()->disconnect_ports_from_bundle (c, this);
1349 MonitorSection::output_release (GdkEventButton *ev)
1351 switch (ev->button) {
1353 edit_output_configuration ();
1360 struct RouteCompareByName {
1361 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1362 return a->name().compare (b->name()) < 0;
1367 MonitorSection::output_press (GdkEventButton *ev)
1369 using namespace Menu_Helpers;
1371 MessageDialog msg (_("No session - no I/O changes are possible"));
1376 MenuList& citems = output_menu.items();
1377 switch (ev->button) {
1380 return false; //wait for the mouse-up to pop the dialog
1384 output_menu.set_name ("ArdourContextMenu");
1386 output_menu_bundles.clear ();
1388 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1390 citems.push_back (SeparatorElem());
1391 uint32_t const n_with_separator = citems.size ();
1393 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1395 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1397 /* give user bundles first chance at being in the menu */
1399 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1400 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1401 maybe_add_bundle_to_output_menu (*i, current);
1405 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1406 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1407 maybe_add_bundle_to_output_menu (*i, current);
1411 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1412 RouteList copy = *routes;
1413 copy.sort (RouteCompareByName ());
1414 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1415 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1418 if (citems.size() == n_with_separator) {
1419 /* no routes added; remove the separator */
1423 citems.push_back (SeparatorElem());
1424 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1426 output_menu.popup (1, ev->time);
1437 MonitorSection::update_output_display ()
1439 if (!_route || !_monitor || _session->deletion_in_progress()) {
1445 boost::shared_ptr<Port> port;
1446 vector<string> port_connections;
1448 uint32_t total_connection_count = 0;
1449 uint32_t io_connection_count = 0;
1450 uint32_t ardour_connection_count = 0;
1451 uint32_t system_connection_count = 0;
1452 uint32_t other_connection_count = 0;
1454 ostringstream label;
1456 bool have_label = false;
1457 bool each_io_has_one_connection = true;
1459 string connection_name;
1460 string ardour_track_name;
1461 string other_connection_type;
1462 string system_ports;
1465 ostringstream tooltip;
1466 char * tooltip_cstr;
1468 io_count = _route->n_outputs().n_total();
1469 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1472 for (io_index = 0; io_index < io_count; ++io_index) {
1474 port = _route->output()->nth (io_index);
1476 //ignore any port connections that don't match our DataType
1477 if (port->type() != DataType::AUDIO) {
1481 port_connections.clear ();
1482 port->get_connections(port_connections);
1483 io_connection_count = 0;
1485 if (!port_connections.empty()) {
1486 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1488 string& connection_name (*i);
1490 if (connection_name.find("system:") == 0) {
1491 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1494 if (io_connection_count == 0) {
1495 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1497 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1500 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1503 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1504 if (ardour_track_name.empty()) {
1505 // "ardour:Master/in 1" -> "ardour:Master/"
1506 string::size_type slash = connection_name.find("/");
1507 if (slash != string::npos) {
1508 ardour_track_name = connection_name.substr(0, slash + 1);
1512 if (connection_name.find(ardour_track_name) == 0) {
1513 ++ardour_connection_count;
1515 } else if (!pn.empty()) {
1516 if (system_ports.empty()) {
1519 system_ports += "/" + pn;
1521 if (connection_name.find("system:") == 0) {
1522 ++system_connection_count;
1524 } else if (connection_name.find("system:") == 0) {
1525 // "system:playback_123" -> "123"
1526 system_port = connection_name.substr(16);
1527 if (system_ports.empty()) {
1528 system_ports += system_port;
1530 system_ports += "/" + system_port;
1533 ++system_connection_count;
1535 if (other_connection_type.empty()) {
1536 // "jamin:in 1" -> "jamin:"
1537 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1540 if (connection_name.find(other_connection_type) == 0) {
1541 ++other_connection_count;
1545 ++total_connection_count;
1546 ++io_connection_count;
1550 if (io_connection_count != 1) {
1551 each_io_has_one_connection = false;
1555 if (total_connection_count == 0) {
1556 tooltip << endl << _("Disconnected");
1559 tooltip_cstr = new char[tooltip.str().size() + 1];
1560 strcpy(tooltip_cstr, tooltip.str().c_str());
1562 set_tooltip (output_button, tooltip_cstr, "");
1564 if (each_io_has_one_connection) {
1565 if (total_connection_count == ardour_connection_count) {
1566 // all connections are to the same track in ardour
1567 // "ardour:Master/" -> "Master"
1568 string::size_type slash = ardour_track_name.find("/");
1569 if (slash != string::npos) {
1570 label << ardour_track_name.substr(7, slash - 7);
1573 } else if (total_connection_count == system_connection_count) {
1574 // all connections are to system ports
1575 label << system_ports;
1577 } else if (total_connection_count == other_connection_count) {
1578 // all connections are to the same external program eg jamin
1579 // "jamin:" -> "jamin"
1580 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1586 if (total_connection_count == 0) {
1590 // Odd configuration
1591 label << "*" << total_connection_count << "*";
1595 output_button->set_text (label.str());
1599 MonitorSection::disconnect_output ()
1602 _route->output()->disconnect(this);
1607 MonitorSection::edit_output_configuration ()
1609 if (_output_selector == 0) {
1610 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1612 _output_selector->present ();
1616 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1621 boost::shared_ptr<Port> a = wa.lock ();
1622 boost::shared_ptr<Port> b = wb.lock ();
1623 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1624 update_output_display ();
1629 MonitorSection::load_bindings ()
1631 bindings = Bindings::get_bindings (X_("monitor-section"), myactions);
1635 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1637 boost::shared_ptr<Processor> processor (p.lock ());
1638 if (!processor || !processor->display_to_user()) {
1641 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1648 MonitorSection::count_processors ()
1650 uint32_t processor_count = 0;
1652 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1654 return processor_count;
1658 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1660 update_processor_box ();