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)
88 using namespace Menu_Helpers;
90 Glib::RefPtr<Action> act;
92 if (!monitor_actions) {
98 _plugin_selector = new PluginSelector (PluginManager::instance());
99 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
100 insert_box->set_no_show_all ();
102 // TODO allow keyboard shortcuts in ProcessorBox
106 /* Rude Solo & Solo Isolated */
107 rude_solo_button.set_text (_("Soloing"));
108 rude_solo_button.set_name ("rude solo");
109 rude_solo_button.show ();
111 rude_iso_button.set_text (_("Isolated"));
112 rude_iso_button.set_name ("rude isolate");
113 rude_iso_button.show ();
115 rude_audition_button.set_text (_("Auditioning"));
116 rude_audition_button.set_name ("rude audition");
117 rude_audition_button.show ();
119 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
121 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
122 rude_solo_button.set_related_action (act);
123 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
125 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
126 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
128 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
129 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
131 /* SIP, AFL, PFL radio */
133 solo_in_place_button.set_name ("monitor section solo model");
134 afl_button.set_name ("monitor section solo model");
135 pfl_button.set_name ("monitor section solo model");
137 solo_in_place_button.set_led_left (true);
138 afl_button.set_led_left (true);
139 pfl_button.set_led_left (true);
141 solo_in_place_button.show ();
145 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
146 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
148 solo_in_place_button.set_related_action (act);
151 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
152 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
154 afl_button.set_related_action (act);
157 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
158 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
160 pfl_button.set_related_action (act);
163 /* Solo option buttons */
164 exclusive_solo_button.set_text (_("Excl. Solo"));
165 exclusive_solo_button.set_name (X_("monitor section solo option"));
166 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
168 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
170 exclusive_solo_button.set_related_action (act);
173 solo_mute_override_button.set_text (_("Solo ยป Mute"));
174 solo_mute_override_button.set_name (X_("monitor section solo option"));
175 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
177 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
179 solo_mute_override_button.set_related_action (act);
182 /* Processor Box hide/shos */
183 toggle_processorbox_button.set_text (_("Processors"));
184 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
185 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
187 proctoggle = ToggleAction::create ();
188 toggle_processorbox_button.set_related_action (proctoggle);
189 proctoggle->signal_toggled().connect (sigc::mem_fun(*this, &MonitorSection::update_processor_box), false);
192 Label* solo_boost_label;
193 Label* solo_cut_label;
196 /* Solo Boost Knob */
198 solo_boost_control = new ArdourKnob ();
199 solo_boost_control->set_name("monitor section knob");
200 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
201 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
203 solo_boost_display = new ArdourDisplay ();
204 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
205 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
206 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
207 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
208 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
210 solo_boost_label = manage (new Label (_("Solo Boost")));
214 solo_cut_control = new ArdourKnob ();
215 solo_cut_control->set_name ("monitor section knob");
216 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
217 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
219 solo_cut_display = new ArdourDisplay ();
220 solo_cut_display->set_name("monitor section dropdown"); // XXX
221 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
222 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
223 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
224 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
225 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
226 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
228 solo_cut_label = manage (new Label (_("SiP Cut")));
232 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
233 dim_control->set_name ("monitor section knob");
234 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
235 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
237 dim_display = new ArdourDisplay ();
238 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
239 dim_display->add_controllable_preset(_("0 dB"), 0.0);
240 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
241 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
242 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
243 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
245 dim_label = manage (new Label (_("Dim")));
248 cut_all_button.set_text (_("Mute"));
249 cut_all_button.set_name ("mute button");
250 cut_all_button.set_size_request (-1, PX_SCALE(30));
251 cut_all_button.show ();
253 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
255 cut_all_button.set_related_action (act);
259 dim_all_button.set_text (_("Dim"));
260 dim_all_button.set_name ("monitor section dim");
261 dim_all_button.set_size_request (-1, PX_SCALE(25));
262 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
264 dim_all_button.set_related_action (act);
268 mono_button.set_text (_("Mono"));
269 mono_button.set_name ("monitor section mono");
270 mono_button.set_size_request (-1, PX_SCALE(25));
271 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
273 mono_button.set_related_action (act);
278 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
279 gain_control->set_name("monitor section knob");
280 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
282 gain_display = new ArdourDisplay ();
283 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
284 gain_display->add_controllable_preset(_("0 dB"), 0.0);
285 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
286 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
287 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
288 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
289 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
291 Label* output_label = manage (new Label (_("Output")));
292 output_label->set_name (X_("MonitorSectionLabel"));
294 output_button = new ArdourButton ();
295 output_button->set_text (_("Output"));
296 output_button->set_name (X_("monitor section cut")); // XXX
297 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
298 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
300 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
301 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
302 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
303 channel_table_scroller.show ();
304 channel_table_scroller.add (channel_table_viewport);
306 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
307 channel_size_group->add_widget (channel_table_header);
308 channel_size_group->add_widget (channel_table);
310 channel_table_header.resize (1, 5);
312 Label* l1 = manage (new Label (X_(" ")));
313 l1->set_name (X_("MonitorSectionLabel"));
314 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
316 l1 = manage (new Label (_("Mute")));
317 l1->set_name (X_("MonitorSectionLabel"));
318 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
320 l1 = manage (new Label (_("Dim")));
321 l1->set_name (X_("MonitorSectionLabel"));
322 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
324 l1 = manage (new Label (_("Solo")));
325 l1->set_name (X_("MonitorSectionLabel"));
326 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
328 l1 = manage (new Label (_("Inv")));
329 l1->set_name (X_("MonitorSectionLabel"));
330 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
332 channel_table_header.show ();
335 /****************************************************************************
336 * LAYOUT top to bottom
339 // solo, iso information
340 HBox* rude_box = manage (new HBox);
341 rude_box->set_spacing (PX_SCALE(4));
342 rude_box->set_homogeneous (true);
343 rude_box->pack_start (rude_solo_button, true, true);
344 rude_box->pack_start (rude_iso_button, true, true);
346 // solo options (right align)
347 HBox* tbx1 = manage (new HBox);
348 tbx1->pack_end (exclusive_solo_button, false, false);
350 HBox* tbx2 = manage (new HBox);
351 tbx2->pack_end (solo_mute_override_button, false, false);
353 HBox* tbx3 = manage (new HBox);
354 tbx3->pack_end (toggle_processorbox_button, false, false);
356 HBox* tbx0 = manage (new HBox); // space
358 // combined solo mode (Sip, AFL, PFL) & solo options
359 Table *solo_tbl = manage (new Table);
360 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
361 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
362 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
363 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
364 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
365 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
366 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
368 // boost, cut, dim volume control
369 Table *level_tbl = manage (new Table);
370 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
371 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
372 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
374 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
375 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
378 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
379 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
382 /* note that we don't pack the table_hpacker till later
383 * -> top level channel_table_packer */
384 table_hpacker.pack_start (channel_table, true, true);
387 HBox* mono_dim_box = manage (new HBox);
388 mono_dim_box->set_spacing (PX_SCALE(4));
389 mono_dim_box->set_homogeneous (true);
390 mono_dim_box->pack_start (mono_button, true, true);
391 mono_dim_box->pack_end (dim_all_button, true, true);
394 Label* spin_label = manage (new Label (_("Monitor")));
395 VBox* spin_packer = manage (new VBox);
396 spin_packer->set_spacing (PX_SCALE(2));
397 spin_packer->pack_start (*spin_label, false, false);
398 spin_packer->pack_start (*gain_control, false, false);
399 spin_packer->pack_start (*gain_display, false, false);
401 master_packer.pack_start (*spin_packer, true, false);
403 // combined gain section (channels, mute, dim)
404 VBox* lower_packer = manage (new VBox);
405 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
406 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
407 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
408 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
410 // output port select
411 VBox* out_packer = manage (new VBox);
412 out_packer->set_spacing (PX_SCALE(2));
413 out_packer->pack_start (*output_label, false, false);
414 out_packer->pack_start (*output_button, false, false);
416 /****************************************************************************
419 vpacker.set_border_width (PX_SCALE(3));
420 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
421 vpacker.pack_start (rude_audition_button, false, false, 0);
422 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
423 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
424 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
425 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
426 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
427 vpacker.pack_end (*out_packer, false, false, PX_SCALE(3));
429 hpacker.set_spacing (0);
430 hpacker.pack_start (vpacker, true, true);
432 gain_control->show_all ();
433 gain_display->show_all ();
434 dim_control->show_all ();
435 dim_display->show_all();
436 solo_boost_control->show_all ();
437 solo_boost_display->show_all();
439 mono_dim_box->show ();
440 spin_packer->show ();
441 master_packer.show ();
442 channel_table.show ();
445 solo_tbl->show_all();
447 lower_packer->show ();
455 assign_controllables ();
457 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
458 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
460 _tearoff = new TearOff (hpacker);
462 if (!UIConfiguration::instance().get_floating_monitor_section()) {
463 /* if torn off, make this a normal window
464 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
466 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
468 _tearoff->tearoff_window().set_title (X_("Monitor"));
469 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) 0), false);
471 update_output_display ();
472 update_processor_box ();
473 _ui_initialized = true;
475 /* catch changes that affect us */
476 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
477 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
479 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
482 MonitorSection::~MonitorSection ()
484 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
488 _channel_buttons.clear ();
489 _output_changed_connection.disconnect ();
492 delete output_button;
497 delete solo_boost_control;
498 delete solo_boost_display;
499 delete solo_cut_control;
500 delete solo_cut_display;
502 delete _output_selector;
503 _output_selector = 0;
508 MonitorSection::update_processor_box ()
510 bool show_processor_box = proctoggle->get_active ();
512 if (count_processors () > 0 && !show_processor_box) {
513 toggle_processorbox_button.set_name (X_("monitor section processors present"));
515 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
518 if (insert_box->is_visible() == show_processor_box) {
522 if (show_processor_box) {
523 if (master_packer.get_parent()) {
524 master_packer.get_parent()->remove (master_packer);
527 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
529 if (master_packer.get_parent()) {
530 master_packer.get_parent()->remove (master_packer);
533 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
538 MonitorSection::set_session (Session* s)
540 AxisView::set_session (s);
541 _plugin_selector->set_session (_session);
545 _route = _session->monitor_out ();
548 /* session with monitor section */
549 _monitor = _route->monitor_control ();
550 assign_controllables ();
551 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
552 boost::bind (&MonitorSection::update_output_display, this),
554 insert_box->set_route (_route);
555 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
556 if (_ui_initialized) {
557 update_processor_box ();
560 /* session with no monitor section */
561 _output_changed_connection.disconnect();
564 delete _output_selector;
565 _output_selector = 0;
568 if (channel_table_scroller.get_parent()) {
569 /* scroller is packed, so remove it */
570 channel_table_packer.remove (channel_table_scroller);
573 if (table_hpacker.get_parent () == &channel_table_packer) {
574 /* this occurs when the table hpacker is directly
575 packed, so remove it.
577 channel_table_packer.remove (table_hpacker);
578 } else if (table_hpacker.get_parent()) {
579 channel_table_viewport.remove ();
582 if (_monitor->output_streams().n_audio() > 7) {
583 /* put the table into a scrolled window, and then put
584 * that into the channel vpacker, after the table header
586 channel_table_viewport.add (table_hpacker);
587 channel_table_packer.pack_start (channel_table_scroller, true, true);
588 channel_table_viewport.show ();
589 channel_table_scroller.show ();
592 /* just put the channel table itself into the channel
593 * vpacker, after the table header
596 channel_table_packer.pack_start (table_hpacker, true, true);
597 channel_table_scroller.hide ();
600 table_hpacker.show ();
601 channel_table.show ();
606 _output_changed_connection.disconnect();
609 control_connections.drop_connections ();
610 rude_iso_button.unset_active_state ();
611 rude_solo_button.unset_active_state ();
612 delete _output_selector;
613 _output_selector = 0;
615 assign_controllables ();
619 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
621 cut.set_name (X_("mute button"));
622 dim.set_name (X_("monitor section dim"));
623 solo.set_name (X_("solo button"));
624 invert.set_name (X_("invert button"));
626 cut.unset_flags (Gtk::CAN_FOCUS);
627 dim.unset_flags (Gtk::CAN_FOCUS);
628 solo.unset_flags (Gtk::CAN_FOCUS);
629 invert.unset_flags (Gtk::CAN_FOCUS);
633 MonitorSection::populate_buttons ()
639 Glib::RefPtr<Action> act;
640 uint32_t nchans = _monitor->output_streams().n_audio();
642 channel_table.resize (nchans, 5);
643 channel_table.set_col_spacings (6);
644 channel_table.set_row_spacings (6);
645 channel_table.set_homogeneous (true);
647 const uint32_t row_offset = 0;
649 for (uint32_t i = 0; i < nchans; ++i) {
662 snprintf (buf, sizeof (buf), "%d", i+1);
666 Label* label = manage (new Label (l));
667 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
669 ChannelButtonSet* cbs = new ChannelButtonSet;
671 _channel_buttons.push_back (cbs);
673 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
674 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
675 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
676 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
678 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
679 act = ActionManager::get_action (X_("Monitor"), buf);
681 cbs->cut.set_related_action (act);
684 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
685 act = ActionManager::get_action (X_("Monitor"), buf);
687 cbs->dim.set_related_action (act);
690 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
691 act = ActionManager::get_action (X_("Monitor"), buf);
693 cbs->solo.set_related_action (act);
696 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
697 act = ActionManager::get_action (X_("Monitor"), buf);
699 cbs->invert.set_related_action (act);
703 channel_table.show_all ();
707 MonitorSection::toggle_exclusive_solo ()
713 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
715 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
716 Config->set_exclusive_solo (tact->get_active());
722 MonitorSection::toggle_mute_overrides_solo ()
728 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
730 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
731 Config->set_solo_mute_override (tact->get_active());
736 MonitorSection::dim_all ()
742 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
744 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
745 _monitor->set_dim_all (tact->get_active());
751 MonitorSection::cut_all ()
757 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
759 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
760 _monitor->set_cut_all (tact->get_active());
765 MonitorSection::mono ()
771 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
773 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
774 _monitor->set_mono (tact->get_active());
779 MonitorSection::cut_channel (uint32_t chn)
786 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
788 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
790 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
791 _monitor->set_cut (chn, tact->get_active());
796 MonitorSection::dim_channel (uint32_t chn)
803 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
805 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
807 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
808 _monitor->set_dim (chn, tact->get_active());
814 MonitorSection::solo_channel (uint32_t chn)
821 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
823 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
825 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
826 _monitor->set_solo (chn, tact->get_active());
832 MonitorSection::invert_channel (uint32_t chn)
839 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
841 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
843 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
844 _monitor->set_polarity (chn, tact->get_active());
849 MonitorSection::register_actions ()
853 Glib::RefPtr<Action> act;
855 monitor_actions = Actions.create_action_group (X_("Monitor"));
857 Actions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
858 sigc::mem_fun (*this, &MonitorSection::mono));
860 Actions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
861 sigc::mem_fun (*this, &MonitorSection::cut_all));
863 Actions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
864 sigc::mem_fun (*this, &MonitorSection::dim_all));
866 act = Actions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
867 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
869 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
870 tact->set_active (Config->get_exclusive_solo());
872 act = Actions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
873 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
875 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
876 tact->set_active (Config->get_solo_mute_override());
878 for (uint32_t chn = 0; chn < 16; ++chn) {
880 action_name = string_compose (X_("monitor-cut-%1"), chn);
881 action_descr = string_compose (_("Cut monitor channel %1"), chn);
882 Actions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
883 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
885 action_name = string_compose (X_("monitor-dim-%1"), chn);
886 action_descr = string_compose (_("Dim monitor channel %1"), chn);
887 Actions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
888 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
890 action_name = string_compose (X_("monitor-solo-%1"), chn);
891 action_descr = string_compose (_("Solo monitor channel %1"), chn);
892 Actions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
893 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
895 action_name = string_compose (X_("monitor-invert-%1"), chn);
896 action_descr = string_compose (_("Invert monitor channel %1"), chn);
897 Actions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
898 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
903 Glib::RefPtr<ActionGroup> solo_actions = Actions.create_action_group (X_("Solo"));
904 RadioAction::Group solo_group;
906 Actions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
907 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
908 Actions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
909 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
910 Actions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
911 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
915 MonitorSection::connect_actions ()
917 Glib::RefPtr<Action> act;
918 Glib::RefPtr<ToggleAction> tact;
920 #define MON_TOG(NAME, FUNC) \
921 act = ActionManager::get_action (X_("Monitor"), NAME); \
922 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
924 tact->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
926 MON_TOG("monitor-mono", mono);
927 MON_TOG("monitor-cut-all", cut_all);
928 MON_TOG("monitor-dim-all", dim_all);
930 MON_TOG("toggle-exclusive-solo", toggle_exclusive_solo);
931 tact->set_active (Config->get_exclusive_solo());
933 MON_TOG("toggle-mute-overrides-solo", toggle_mute_overrides_solo);
934 tact->set_active (Config->get_solo_mute_override());
937 #define MON_BIND(NAME, FUNC, ARG) \
938 act = ActionManager::get_action (X_("Monitor"), NAME); \
939 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
941 tact->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::FUNC), ARG));
943 for (uint32_t chn = 0; chn < 16; ++chn) {
944 std::string action_name = string_compose (X_("monitor-cut-%1"), chn);
945 MON_BIND(action_name.c_str(), cut_channel, chn);
946 action_name = string_compose (X_("monitor-dim-%1"), chn);
947 MON_BIND(action_name.c_str(), dim_channel, chn);
948 action_name = string_compose (X_("monitor-solo-%1"), chn);
949 MON_BIND(action_name.c_str(), solo_channel, chn);
950 action_name = string_compose (X_("monitor-invert-%1"), chn);
951 MON_BIND(action_name.c_str(), invert_channel, chn);
955 #define SOLO_RADIO(NAME, FUNC) \
956 act = ActionManager::get_action (X_("Solo"), NAME); \
957 ract = Glib::RefPtr<RadioAction>::cast_dynamic (act); \
959 ract->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
961 Glib::RefPtr<RadioAction> ract;
962 SOLO_RADIO ("solo-use-in-place", solo_use_in_place);
963 SOLO_RADIO ("solo-use-afl", solo_use_afl);
964 SOLO_RADIO ("solo-use-pfl", solo_use_pfl);
969 MonitorSection::solo_use_in_place ()
971 /* this is driven by a toggle on a radio group, and so is invoked twice,
972 once for the item that became inactive and once for the one that became
976 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
979 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
981 if (!ract->get_active ()) {
982 /* We are turning SiP off, which means that AFL or PFL will be turned on
983 shortly; don't update the solo model in the mean time, as if the currently
984 configured listen position is not the one that is about to be turned on,
985 things will go wrong.
987 _inhibit_solo_model_update = true;
989 Config->set_solo_control_is_listen_control (!ract->get_active());
990 _inhibit_solo_model_update = false;
996 MonitorSection::solo_use_afl ()
998 /* this is driven by a toggle on a radio group, and so is invoked twice,
999 once for the item that became inactive and once for the one that became
1003 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1005 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1007 if (ract->get_active()) {
1008 Config->set_solo_control_is_listen_control (true);
1009 Config->set_listen_position (AfterFaderListen);
1016 MonitorSection::solo_use_pfl ()
1018 /* this is driven by a toggle on a radio group, and so is invoked twice,
1019 once for the item that became inactive and once for the one that became
1023 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1025 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1027 if (ract->get_active()) {
1028 Config->set_solo_control_is_listen_control (true);
1029 Config->set_listen_position (PreFaderListen);
1036 MonitorSection::update_solo_model ()
1038 if (_inhibit_solo_model_update) {
1042 const char* action_name = 0;
1043 Glib::RefPtr<Action> act;
1045 if (Config->get_solo_control_is_listen_control()) {
1046 switch (Config->get_listen_position()) {
1047 case AfterFaderListen:
1048 action_name = X_("solo-use-afl");
1050 case PreFaderListen:
1051 action_name = X_("solo-use-pfl");
1055 action_name = X_("solo-use-in-place");
1058 act = ActionManager::get_action (X_("Solo"), action_name);
1061 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1063 /* because these are radio buttons, one of them will be
1064 active no matter what. to trigger a change in the
1065 action so that the view picks it up, toggle it.
1067 if (ract->get_active()) {
1068 ract->set_active (false);
1070 ract->set_active (true);
1077 MonitorSection::map_state ()
1079 if (!_route || !_monitor) {
1083 Glib::RefPtr<Action> act;
1085 update_solo_model ();
1087 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1089 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1091 tact->set_active (_monitor->cut_all());
1095 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1097 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1099 tact->set_active (_monitor->dim_all());
1103 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1105 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1107 tact->set_active (_monitor->mono());
1111 uint32_t nchans = _monitor->output_streams().n_audio();
1113 assert (nchans == _channel_buttons.size ());
1115 for (uint32_t n = 0; n < nchans; ++n) {
1117 char action_name[32];
1119 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1120 act = ActionManager::get_action (X_("Monitor"), action_name);
1122 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1124 tact->set_active (_monitor->cut (n));
1128 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1129 act = ActionManager::get_action (X_("Monitor"), action_name);
1131 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1133 tact->set_active (_monitor->dimmed (n));
1137 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1138 act = ActionManager::get_action (X_("Monitor"), action_name);
1140 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1142 tact->set_active (_monitor->soloed (n));
1146 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1147 act = ActionManager::get_action (X_("Monitor"), action_name);
1149 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1151 tact->set_active (_monitor->inverted (n));
1158 MonitorSection::do_blink (bool onoff)
1161 audition_blink (onoff);
1165 MonitorSection::audition_blink (bool onoff)
1167 if (_session == 0) {
1171 if (_session->is_auditioning()) {
1172 rude_audition_button.set_active (onoff);
1174 rude_audition_button.set_active (false);
1179 MonitorSection::solo_blink (bool onoff)
1181 if (_session == 0) {
1185 if (_session->soloing() || _session->listening()) {
1186 rude_solo_button.set_active (onoff);
1188 if (_session->soloing()) {
1189 if (_session->solo_isolated()) {
1190 rude_iso_button.set_active (onoff);
1192 rude_iso_button.set_active (false);
1197 rude_solo_button.set_active (false);
1198 rude_iso_button.set_active (false);
1203 MonitorSection::cancel_isolate (GdkEventButton*)
1206 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1207 _session->set_solo_isolated (rl, false, Session::rt_cleanup, Controllable::NoGroup);
1214 MonitorSection::cancel_audition (GdkEventButton*)
1217 _session->cancel_audition();
1222 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1224 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1225 if (tact && tact->get_active() != value) { \
1226 tact->set_active(value); \
1231 MonitorSection::parameter_changed (std::string name)
1233 if (name == "solo-control-is-listen-control") {
1234 update_solo_model ();
1235 } else if (name == "listen-position") {
1236 update_solo_model ();
1237 } else if (name == "solo-mute-override") {
1238 SYNCHRONIZE_TOGGLE_ACTION(
1239 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1240 Config->get_solo_mute_override ())
1241 } else if (name == "exclusive-solo") {
1242 SYNCHRONIZE_TOGGLE_ACTION(
1243 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1244 Config->get_exclusive_solo ())
1249 MonitorSection::assign_controllables ()
1251 boost::shared_ptr<Controllable> none;
1253 if (!gain_control) {
1254 /* too early - GUI controls not set up yet */
1259 solo_cut_control->set_controllable (_session->solo_cut_control());
1260 solo_cut_display->set_controllable (_session->solo_cut_control());
1262 solo_cut_control->set_controllable (none);
1263 solo_cut_display->set_controllable (none);
1267 gain_control->set_controllable (_route->gain_control());
1268 gain_display->set_controllable (_route->gain_control());
1270 gain_control->set_controllable (none);
1275 cut_all_button.set_controllable (_monitor->cut_control());
1276 cut_all_button.watch ();
1277 dim_all_button.set_controllable (_monitor->dim_control());
1278 dim_all_button.watch ();
1279 mono_button.set_controllable (_monitor->mono_control());
1280 mono_button.watch ();
1282 dim_control->set_controllable (_monitor->dim_level_control ());
1283 dim_display->set_controllable (_monitor->dim_level_control ());
1284 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1285 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1289 cut_all_button.set_controllable (none);
1290 dim_all_button.set_controllable (none);
1291 mono_button.set_controllable (none);
1293 dim_control->set_controllable (none);
1294 dim_display->set_controllable (none);
1295 solo_boost_control->set_controllable (none);
1296 solo_boost_display->set_controllable (none);
1301 MonitorSection::state_id() const
1303 return "monitor-section";
1307 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1309 using namespace Menu_Helpers;
1311 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1315 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1316 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1320 if (i != output_menu_bundles.end()) {
1324 output_menu_bundles.push_back (b);
1326 MenuList& citems = output_menu.items();
1328 std::string n = b->name ();
1329 replace_all (n, "_", " ");
1331 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1335 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1338 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1340 if (std::find (current.begin(), current.end(), c) == current.end()) {
1341 _route->output()->connect_ports_to_bundle (c, true, this);
1343 _route->output()->disconnect_ports_from_bundle (c, this);
1348 MonitorSection::output_release (GdkEventButton *ev)
1350 switch (ev->button) {
1352 edit_output_configuration ();
1359 struct RouteCompareByName {
1360 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1361 return a->name().compare (b->name()) < 0;
1366 MonitorSection::output_press (GdkEventButton *ev)
1368 using namespace Menu_Helpers;
1370 MessageDialog msg (_("No session - no I/O changes are possible"));
1375 MenuList& citems = output_menu.items();
1376 switch (ev->button) {
1379 return false; //wait for the mouse-up to pop the dialog
1383 output_menu.set_name ("ArdourContextMenu");
1385 output_menu_bundles.clear ();
1387 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1389 citems.push_back (SeparatorElem());
1390 uint32_t const n_with_separator = citems.size ();
1392 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1394 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1396 /* give user bundles first chance at being in the menu */
1398 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1399 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1400 maybe_add_bundle_to_output_menu (*i, current);
1404 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1405 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1406 maybe_add_bundle_to_output_menu (*i, current);
1410 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1411 RouteList copy = *routes;
1412 copy.sort (RouteCompareByName ());
1413 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1414 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1417 if (citems.size() == n_with_separator) {
1418 /* no routes added; remove the separator */
1422 citems.push_back (SeparatorElem());
1423 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1425 output_menu.popup (1, ev->time);
1436 MonitorSection::update_output_display ()
1438 if (!_route || !_monitor || _session->deletion_in_progress()) {
1444 boost::shared_ptr<Port> port;
1445 vector<string> port_connections;
1447 uint32_t total_connection_count = 0;
1448 uint32_t io_connection_count = 0;
1449 uint32_t ardour_connection_count = 0;
1450 uint32_t system_connection_count = 0;
1451 uint32_t other_connection_count = 0;
1453 ostringstream label;
1455 bool have_label = false;
1456 bool each_io_has_one_connection = true;
1458 string connection_name;
1459 string ardour_track_name;
1460 string other_connection_type;
1461 string system_ports;
1464 ostringstream tooltip;
1465 char * tooltip_cstr;
1467 io_count = _route->n_outputs().n_total();
1468 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1471 for (io_index = 0; io_index < io_count; ++io_index) {
1473 port = _route->output()->nth (io_index);
1475 //ignore any port connections that don't match our DataType
1476 if (port->type() != DataType::AUDIO) {
1480 port_connections.clear ();
1481 port->get_connections(port_connections);
1482 io_connection_count = 0;
1484 if (!port_connections.empty()) {
1485 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1487 string& connection_name (*i);
1489 if (connection_name.find("system:") == 0) {
1490 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1493 if (io_connection_count == 0) {
1494 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1496 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1499 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1502 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1503 if (ardour_track_name.empty()) {
1504 // "ardour:Master/in 1" -> "ardour:Master/"
1505 string::size_type slash = connection_name.find("/");
1506 if (slash != string::npos) {
1507 ardour_track_name = connection_name.substr(0, slash + 1);
1511 if (connection_name.find(ardour_track_name) == 0) {
1512 ++ardour_connection_count;
1514 } else if (!pn.empty()) {
1515 if (system_ports.empty()) {
1518 system_ports += "/" + pn;
1520 if (connection_name.find("system:") == 0) {
1521 ++system_connection_count;
1523 } else if (connection_name.find("system:") == 0) {
1524 // "system:playback_123" -> "123"
1525 system_port = connection_name.substr(16);
1526 if (system_ports.empty()) {
1527 system_ports += system_port;
1529 system_ports += "/" + system_port;
1532 ++system_connection_count;
1534 if (other_connection_type.empty()) {
1535 // "jamin:in 1" -> "jamin:"
1536 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1539 if (connection_name.find(other_connection_type) == 0) {
1540 ++other_connection_count;
1544 ++total_connection_count;
1545 ++io_connection_count;
1549 if (io_connection_count != 1) {
1550 each_io_has_one_connection = false;
1554 if (total_connection_count == 0) {
1555 tooltip << endl << _("Disconnected");
1558 tooltip_cstr = new char[tooltip.str().size() + 1];
1559 strcpy(tooltip_cstr, tooltip.str().c_str());
1561 set_tooltip (output_button, tooltip_cstr, "");
1563 if (each_io_has_one_connection) {
1564 if (total_connection_count == ardour_connection_count) {
1565 // all connections are to the same track in ardour
1566 // "ardour:Master/" -> "Master"
1567 string::size_type slash = ardour_track_name.find("/");
1568 if (slash != string::npos) {
1569 label << ardour_track_name.substr(7, slash - 7);
1572 } else if (total_connection_count == system_connection_count) {
1573 // all connections are to system ports
1574 label << system_ports;
1576 } else if (total_connection_count == other_connection_count) {
1577 // all connections are to the same external program eg jamin
1578 // "jamin:" -> "jamin"
1579 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1585 if (total_connection_count == 0) {
1589 // Odd configuration
1590 label << "*" << total_connection_count << "*";
1594 output_button->set_text (label.str());
1598 MonitorSection::disconnect_output ()
1601 _route->output()->disconnect(this);
1606 MonitorSection::edit_output_configuration ()
1608 if (_output_selector == 0) {
1609 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1611 _output_selector->present ();
1615 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1620 boost::shared_ptr<Port> a = wa.lock ();
1621 boost::shared_ptr<Port> b = wb.lock ();
1622 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1623 update_output_display ();
1628 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1630 boost::shared_ptr<Processor> processor (p.lock ());
1631 if (!processor || !processor->display_to_user()) {
1634 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1641 MonitorSection::count_processors ()
1643 uint32_t processor_count = 0;
1645 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1647 return processor_count;
1651 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1653 update_processor_box ();