2 Copyright (C) 2012 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gdkmm/pixbuf.h>
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
26 #include "gtkmm2ext/bindable_button.h"
27 #include "gtkmm2ext/tearoff.h"
28 #include "gtkmm2ext/actions.h"
29 #include "gtkmm2ext/motionfeedback.h"
30 #include "gtkmm2ext/utils.h"
32 #include <gtkmm/menu.h>
33 #include <gtkmm/menuitem.h>
35 #include "ardour/amp.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/monitor_processor.h"
38 #include "ardour/port.h"
39 #include "ardour/route.h"
40 #include "ardour/user_bundle.h"
41 #include "ardour/plugin_manager.h"
43 #include "gui_thread.h"
44 #include "monitor_section.h"
45 #include "public_editor.h"
48 #include "volume_controller.h"
49 #include "ui_config.h"
54 using namespace ARDOUR;
55 using namespace ARDOUR_UI_UTILS;
57 using namespace Gtkmm2ext;
61 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
63 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
65 MonitorSection::MonitorSection (Session* s)
69 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
70 , *channel_table_scroller.get_vadjustment ())
73 , solo_boost_control (0)
74 , solo_cut_control (0)
77 , solo_boost_display (0)
78 , solo_cut_display (0)
79 , _output_selector (0)
80 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
81 , afl_button (_("AFL"), ArdourButton::led_default_elements)
82 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
83 , exclusive_solo_button (ArdourButton::led_default_elements)
84 , solo_mute_override_button (ArdourButton::led_default_elements)
85 , toggle_processorbox_button (ArdourButton::default_elements)
86 , _inhibit_solo_model_update (false)
87 , _ui_initialized (false)
90 using namespace Menu_Helpers;
92 Glib::RefPtr<Action> act;
94 if (!monitor_actions) {
100 _plugin_selector = new PluginSelector (PluginManager::instance());
101 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
102 insert_box->set_no_show_all ();
104 // TODO allow keyboard shortcuts in ProcessorBox
108 /* Rude Solo & Solo Isolated */
109 rude_solo_button.set_text (_("Soloing"));
110 rude_solo_button.set_name ("rude solo");
111 rude_solo_button.show ();
113 rude_iso_button.set_text (_("Isolated"));
114 rude_iso_button.set_name ("rude isolate");
115 rude_iso_button.show ();
117 rude_audition_button.set_text (_("Auditioning"));
118 rude_audition_button.set_name ("rude audition");
119 rude_audition_button.show ();
121 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
123 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
124 rude_solo_button.set_related_action (act);
125 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
127 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
128 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
130 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
131 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
133 /* SIP, AFL, PFL radio */
135 solo_in_place_button.set_name ("monitor section solo model");
136 afl_button.set_name ("monitor section solo model");
137 pfl_button.set_name ("monitor section solo model");
139 solo_in_place_button.set_led_left (true);
140 afl_button.set_led_left (true);
141 pfl_button.set_led_left (true);
143 solo_in_place_button.show ();
147 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
148 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
150 solo_in_place_button.set_related_action (act);
153 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
154 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
156 afl_button.set_related_action (act);
159 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
160 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
162 pfl_button.set_related_action (act);
165 /* Solo option buttons */
166 exclusive_solo_button.set_text (_("Excl. Solo"));
167 exclusive_solo_button.set_name (X_("monitor section solo option"));
168 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
170 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
172 exclusive_solo_button.set_related_action (act);
175 solo_mute_override_button.set_text (_("Solo ยป Mute"));
176 solo_mute_override_button.set_name (X_("monitor section solo option"));
177 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
179 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
181 solo_mute_override_button.set_related_action (act);
184 /* Processor Box hide/shos */
185 toggle_processorbox_button.set_text (_("Processors"));
186 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
187 set_tooltip (&toggle_processorbox_button, _("Allow to add monitor effect processors"));
189 proctoggle = ToggleAction::create ();
190 toggle_processorbox_button.set_related_action (proctoggle);
191 proctoggle->signal_toggled().connect (sigc::mem_fun(*this, &MonitorSection::update_processor_box), false);
194 Label* solo_boost_label;
195 Label* solo_cut_label;
198 /* Solo Boost Knob */
200 solo_boost_control = new ArdourKnob ();
201 solo_boost_control->set_name("monitor section knob");
202 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
203 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
205 solo_boost_display = new ArdourDisplay ();
206 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
207 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
208 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
209 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
210 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
212 solo_boost_label = manage (new Label (_("Solo Boost")));
216 solo_cut_control = new ArdourKnob ();
217 solo_cut_control->set_name ("monitor section knob");
218 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
219 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
221 solo_cut_display = new ArdourDisplay ();
222 solo_cut_display->set_name("monitor section dropdown"); // XXX
223 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
224 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
225 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
226 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
227 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
228 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
230 solo_cut_label = manage (new Label (_("SiP Cut")));
234 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
235 dim_control->set_name ("monitor section knob");
236 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
237 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
239 dim_display = new ArdourDisplay ();
240 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
241 dim_display->add_controllable_preset(_("0 dB"), 0.0);
242 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
243 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
244 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
245 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
247 dim_label = manage (new Label (_("Dim")));
250 cut_all_button.set_text (_("Mute"));
251 cut_all_button.set_name ("mute button");
252 cut_all_button.set_size_request (-1, PX_SCALE(30));
253 cut_all_button.show ();
255 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
257 cut_all_button.set_related_action (act);
261 dim_all_button.set_text (_("Dim"));
262 dim_all_button.set_name ("monitor section dim");
263 dim_all_button.set_size_request (-1, PX_SCALE(25));
264 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
266 dim_all_button.set_related_action (act);
270 mono_button.set_text (_("Mono"));
271 mono_button.set_name ("monitor section mono");
272 mono_button.set_size_request (-1, PX_SCALE(25));
273 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
275 mono_button.set_related_action (act);
280 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
281 gain_control->set_name("monitor section knob");
282 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
284 gain_display = new ArdourDisplay ();
285 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
286 gain_display->add_controllable_preset(_("0 dB"), 0.0);
287 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
288 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
289 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
290 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
291 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
293 Label* output_label = manage (new Label (_("Output")));
294 output_label->set_name (X_("MonitorSectionLabel"));
296 output_button = new ArdourButton ();
297 output_button->set_text (_("Output"));
298 output_button->set_name (X_("monitor section cut")); // XXX
299 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
300 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
302 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
303 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
304 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
305 channel_table_scroller.show ();
306 channel_table_scroller.add (channel_table_viewport);
308 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
309 channel_size_group->add_widget (channel_table_header);
310 channel_size_group->add_widget (channel_table);
312 channel_table_header.resize (1, 5);
314 Label* l1 = manage (new Label (X_(" ")));
315 l1->set_name (X_("MonitorSectionLabel"));
316 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
318 l1 = manage (new Label (_("Mute")));
319 l1->set_name (X_("MonitorSectionLabel"));
320 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
322 l1 = manage (new Label (_("Dim")));
323 l1->set_name (X_("MonitorSectionLabel"));
324 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
326 l1 = manage (new Label (_("Solo")));
327 l1->set_name (X_("MonitorSectionLabel"));
328 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
330 l1 = manage (new Label (_("Inv")));
331 l1->set_name (X_("MonitorSectionLabel"));
332 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
334 channel_table_header.show ();
337 /****************************************************************************
338 * LAYOUT top to bottom
341 // solo, iso information
342 HBox* rude_box = manage (new HBox);
343 rude_box->set_spacing (PX_SCALE(4));
344 rude_box->set_homogeneous (true);
345 rude_box->pack_start (rude_solo_button, true, true);
346 rude_box->pack_start (rude_iso_button, true, true);
348 // solo options (right align)
349 HBox* tbx1 = manage (new HBox);
350 tbx1->pack_end (exclusive_solo_button, false, false);
352 HBox* tbx2 = manage (new HBox);
353 tbx2->pack_end (solo_mute_override_button, false, false);
355 HBox* tbx3 = manage (new HBox);
356 tbx3->pack_end (toggle_processorbox_button, false, false);
358 HBox* tbx0 = manage (new HBox); // space
360 // combined solo mode (Sip, AFL, PFL) & solo options
361 Table *solo_tbl = manage (new Table);
362 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
363 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
364 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
365 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
366 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
370 // boost, cut, dim volume control
371 Table *level_tbl = manage (new Table);
372 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
373 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
374 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
376 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
378 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
380 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
382 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
384 /* note that we don't pack the table_hpacker till later
385 * -> top level channel_table_packer */
386 table_hpacker.pack_start (channel_table, true, true);
389 HBox* mono_dim_box = manage (new HBox);
390 mono_dim_box->set_spacing (PX_SCALE(4));
391 mono_dim_box->set_homogeneous (true);
392 mono_dim_box->pack_start (mono_button, true, true);
393 mono_dim_box->pack_end (dim_all_button, true, true);
396 Label* spin_label = manage (new Label (_("Monitor")));
397 VBox* spin_packer = manage (new VBox);
398 spin_packer->set_spacing (PX_SCALE(2));
399 spin_packer->pack_start (*spin_label, false, false);
400 spin_packer->pack_start (*gain_control, false, false);
401 spin_packer->pack_start (*gain_display, false, false);
403 master_packer.pack_start (*spin_packer, true, false);
405 // combined gain section (channels, mute, dim)
406 VBox* lower_packer = manage (new VBox);
407 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
408 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
409 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
410 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
412 // output port select
413 VBox* out_packer = manage (new VBox);
414 out_packer->set_spacing (PX_SCALE(2));
415 out_packer->pack_start (*output_label, false, false);
416 out_packer->pack_start (*output_button, false, false);
418 /****************************************************************************
421 vpacker.set_border_width (PX_SCALE(3));
422 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
423 vpacker.pack_start (rude_audition_button, false, false, 0);
424 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
425 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
426 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
427 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
428 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
429 vpacker.pack_end (*out_packer, false, false, PX_SCALE(3));
431 hpacker.set_spacing (0);
432 hpacker.pack_start (vpacker, true, true);
434 gain_control->show_all ();
435 gain_display->show_all ();
436 dim_control->show_all ();
437 dim_display->show_all();
438 solo_boost_control->show_all ();
439 solo_boost_display->show_all();
441 mono_dim_box->show ();
442 spin_packer->show ();
443 master_packer.show ();
444 channel_table.show ();
447 solo_tbl->show_all();
449 lower_packer->show ();
457 assign_controllables ();
459 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
460 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
462 _tearoff = new TearOff (hpacker);
464 if (!UIConfiguration::instance().get_floating_monitor_section()) {
465 /* if torn off, make this a normal window
466 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
468 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
470 _tearoff->tearoff_window().set_title (X_("Monitor"));
471 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
473 update_output_display ();
474 update_processor_box ();
475 _ui_initialized = true;
477 /* catch changes that affect us */
478 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
479 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
481 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
484 MonitorSection::~MonitorSection ()
486 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
490 _channel_buttons.clear ();
491 _output_changed_connection.disconnect ();
494 delete output_button;
499 delete solo_boost_control;
500 delete solo_boost_display;
501 delete solo_cut_control;
502 delete solo_cut_display;
504 delete _output_selector;
505 _output_selector = 0;
510 MonitorSection::update_processor_box ()
512 bool show_processor_box = proctoggle->get_active ();
514 if (count_processors () > 0 && !show_processor_box) {
515 toggle_processorbox_button.set_name (X_("monitor section processors present"));
517 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
520 if (insert_box->is_visible() == show_processor_box) {
524 if (show_processor_box) {
525 if (master_packer.get_parent()) {
526 master_packer.get_parent()->remove (master_packer);
529 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
531 if (master_packer.get_parent()) {
532 master_packer.get_parent()->remove (master_packer);
535 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
540 MonitorSection::set_session (Session* s)
542 AxisView::set_session (s);
543 _plugin_selector->set_session (_session);
547 _route = _session->monitor_out ();
550 /* session with monitor section */
551 _monitor = _route->monitor_control ();
552 assign_controllables ();
553 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
554 boost::bind (&MonitorSection::update_output_display, this),
556 insert_box->set_route (_route);
557 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
558 if (_ui_initialized) {
559 update_processor_box ();
562 /* session with no monitor section */
563 _output_changed_connection.disconnect();
566 delete _output_selector;
567 _output_selector = 0;
570 if (channel_table_scroller.get_parent()) {
571 /* scroller is packed, so remove it */
572 channel_table_packer.remove (channel_table_scroller);
575 if (table_hpacker.get_parent () == &channel_table_packer) {
576 /* this occurs when the table hpacker is directly
577 packed, so remove it.
579 channel_table_packer.remove (table_hpacker);
580 } else if (table_hpacker.get_parent()) {
581 channel_table_viewport.remove ();
584 if (_monitor->output_streams().n_audio() > 7) {
585 /* put the table into a scrolled window, and then put
586 * that into the channel vpacker, after the table header
588 channel_table_viewport.add (table_hpacker);
589 channel_table_packer.pack_start (channel_table_scroller, true, true);
590 channel_table_viewport.show ();
591 channel_table_scroller.show ();
594 /* just put the channel table itself into the channel
595 * vpacker, after the table header
598 channel_table_packer.pack_start (table_hpacker, true, true);
599 channel_table_scroller.hide ();
602 table_hpacker.show ();
603 channel_table.show ();
608 _output_changed_connection.disconnect();
611 control_connections.drop_connections ();
612 rude_iso_button.unset_active_state ();
613 rude_solo_button.unset_active_state ();
614 delete _output_selector;
615 _output_selector = 0;
617 assign_controllables ();
621 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
623 cut.set_name (X_("mute button"));
624 dim.set_name (X_("monitor section dim"));
625 solo.set_name (X_("solo button"));
626 invert.set_name (X_("invert button"));
628 cut.unset_flags (Gtk::CAN_FOCUS);
629 dim.unset_flags (Gtk::CAN_FOCUS);
630 solo.unset_flags (Gtk::CAN_FOCUS);
631 invert.unset_flags (Gtk::CAN_FOCUS);
635 MonitorSection::populate_buttons ()
641 Glib::RefPtr<Action> act;
642 uint32_t nchans = _monitor->output_streams().n_audio();
644 channel_table.resize (nchans, 5);
645 channel_table.set_col_spacings (6);
646 channel_table.set_row_spacings (6);
647 channel_table.set_homogeneous (true);
649 const uint32_t row_offset = 0;
651 for (uint32_t i = 0; i < nchans; ++i) {
664 snprintf (buf, sizeof (buf), "%d", i+1);
668 Label* label = manage (new Label (l));
669 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
671 ChannelButtonSet* cbs = new ChannelButtonSet;
673 _channel_buttons.push_back (cbs);
675 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
676 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
677 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
678 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
680 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
681 act = ActionManager::get_action (X_("Monitor"), buf);
683 cbs->cut.set_related_action (act);
686 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
687 act = ActionManager::get_action (X_("Monitor"), buf);
689 cbs->dim.set_related_action (act);
692 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
693 act = ActionManager::get_action (X_("Monitor"), buf);
695 cbs->solo.set_related_action (act);
698 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
699 act = ActionManager::get_action (X_("Monitor"), buf);
701 cbs->invert.set_related_action (act);
705 channel_table.show_all ();
709 MonitorSection::toggle_exclusive_solo ()
715 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
717 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
718 Config->set_exclusive_solo (tact->get_active());
724 MonitorSection::toggle_mute_overrides_solo ()
730 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
732 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
733 Config->set_solo_mute_override (tact->get_active());
738 MonitorSection::dim_all ()
744 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
746 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
747 _monitor->set_dim_all (tact->get_active());
753 MonitorSection::cut_all ()
759 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
761 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
762 _monitor->set_cut_all (tact->get_active());
767 MonitorSection::mono ()
773 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
775 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
776 _monitor->set_mono (tact->get_active());
781 MonitorSection::cut_channel (uint32_t chn)
788 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
790 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
792 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
793 _monitor->set_cut (chn, tact->get_active());
798 MonitorSection::dim_channel (uint32_t chn)
805 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
807 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
809 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
810 _monitor->set_dim (chn, tact->get_active());
816 MonitorSection::solo_channel (uint32_t chn)
823 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
825 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
827 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
828 _monitor->set_solo (chn, tact->get_active());
834 MonitorSection::invert_channel (uint32_t chn)
841 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
843 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
845 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
846 _monitor->set_polarity (chn, tact->get_active());
851 MonitorSection::register_actions ()
855 Glib::RefPtr<Action> act;
857 monitor_actions = ActionGroup::create (X_("Monitor"));
858 ActionManager::add_action_group (monitor_actions);
860 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
861 sigc::mem_fun (*this, &MonitorSection::mono));
863 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
864 sigc::mem_fun (*this, &MonitorSection::cut_all));
866 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
867 sigc::mem_fun (*this, &MonitorSection::dim_all));
869 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
870 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
872 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
873 tact->set_active (Config->get_exclusive_solo());
875 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
876 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
878 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
879 tact->set_active (Config->get_solo_mute_override());
882 for (uint32_t chn = 0; chn < 16; ++chn) {
884 action_name = string_compose (X_("monitor-cut-%1"), chn);
885 action_descr = string_compose (_("Cut monitor channel %1"), chn);
886 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
887 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
889 action_name = string_compose (X_("monitor-dim-%1"), chn);
890 action_descr = string_compose (_("Dim monitor channel %1"), chn);
891 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
892 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
894 action_name = string_compose (X_("monitor-solo-%1"), chn);
895 action_descr = string_compose (_("Solo monitor channel %1"), chn);
896 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
897 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
899 action_name = string_compose (X_("monitor-invert-%1"), chn);
900 action_descr = string_compose (_("Invert monitor channel %1"), chn);
901 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
902 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
907 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
908 RadioAction::Group solo_group;
910 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
911 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
912 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
913 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
914 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
915 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
917 ActionManager::add_action_group (solo_actions);
921 MonitorSection::connect_actions ()
923 Glib::RefPtr<Action> act;
924 Glib::RefPtr<ToggleAction> tact;
926 #define MON_TOG(NAME, FUNC) \
927 act = ActionManager::get_action (X_("Monitor"), NAME); \
928 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
930 tact->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
932 MON_TOG("monitor-mono", mono);
933 MON_TOG("monitor-cut-all", cut_all);
934 MON_TOG("monitor-dim-all", dim_all);
936 MON_TOG("toggle-exclusive-solo", toggle_exclusive_solo);
937 tact->set_active (Config->get_exclusive_solo());
939 MON_TOG("toggle-mute-overrides-solo", toggle_mute_overrides_solo);
940 tact->set_active (Config->get_solo_mute_override());
943 #define MON_BIND(NAME, FUNC, ARG) \
944 act = ActionManager::get_action (X_("Monitor"), NAME); \
945 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
947 tact->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::FUNC), ARG));
949 for (uint32_t chn = 0; chn < 16; ++chn) {
950 std::string action_name = string_compose (X_("monitor-cut-%1"), chn);
951 MON_BIND(action_name.c_str(), cut_channel, chn);
952 action_name = string_compose (X_("monitor-dim-%1"), chn);
953 MON_BIND(action_name.c_str(), dim_channel, chn);
954 action_name = string_compose (X_("monitor-solo-%1"), chn);
955 MON_BIND(action_name.c_str(), solo_channel, chn);
956 action_name = string_compose (X_("monitor-invert-%1"), chn);
957 MON_BIND(action_name.c_str(), invert_channel, chn);
961 #define SOLO_RADIO(NAME, FUNC) \
962 act = ActionManager::get_action (X_("Solo"), NAME); \
963 ract = Glib::RefPtr<RadioAction>::cast_dynamic (act); \
965 ract->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
967 Glib::RefPtr<RadioAction> ract;
968 SOLO_RADIO ("solo-use-in-place", solo_use_in_place);
969 SOLO_RADIO ("solo-use-afl", solo_use_afl);
970 SOLO_RADIO ("solo-use-pfl", solo_use_pfl);
975 MonitorSection::solo_use_in_place ()
977 /* this is driven by a toggle on a radio group, and so is invoked twice,
978 once for the item that became inactive and once for the one that became
982 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
985 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
987 if (!ract->get_active ()) {
988 /* We are turning SiP off, which means that AFL or PFL will be turned on
989 shortly; don't update the solo model in the mean time, as if the currently
990 configured listen position is not the one that is about to be turned on,
991 things will go wrong.
993 _inhibit_solo_model_update = true;
995 Config->set_solo_control_is_listen_control (!ract->get_active());
996 _inhibit_solo_model_update = false;
1002 MonitorSection::solo_use_afl ()
1004 /* this is driven by a toggle on a radio group, and so is invoked twice,
1005 once for the item that became inactive and once for the one that became
1009 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1011 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1013 if (ract->get_active()) {
1014 Config->set_solo_control_is_listen_control (true);
1015 Config->set_listen_position (AfterFaderListen);
1022 MonitorSection::solo_use_pfl ()
1024 /* this is driven by a toggle on a radio group, and so is invoked twice,
1025 once for the item that became inactive and once for the one that became
1029 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1031 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1033 if (ract->get_active()) {
1034 Config->set_solo_control_is_listen_control (true);
1035 Config->set_listen_position (PreFaderListen);
1042 MonitorSection::update_solo_model ()
1044 if (_inhibit_solo_model_update) {
1048 const char* action_name = 0;
1049 Glib::RefPtr<Action> act;
1051 if (Config->get_solo_control_is_listen_control()) {
1052 switch (Config->get_listen_position()) {
1053 case AfterFaderListen:
1054 action_name = X_("solo-use-afl");
1056 case PreFaderListen:
1057 action_name = X_("solo-use-pfl");
1061 action_name = X_("solo-use-in-place");
1064 act = ActionManager::get_action (X_("Solo"), action_name);
1067 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1069 /* because these are radio buttons, one of them will be
1070 active no matter what. to trigger a change in the
1071 action so that the view picks it up, toggle it.
1073 if (ract->get_active()) {
1074 ract->set_active (false);
1076 ract->set_active (true);
1083 MonitorSection::map_state ()
1085 if (!_route || !_monitor) {
1089 Glib::RefPtr<Action> act;
1091 update_solo_model ();
1093 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1095 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1097 tact->set_active (_monitor->cut_all());
1101 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1103 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1105 tact->set_active (_monitor->dim_all());
1109 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1111 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1113 tact->set_active (_monitor->mono());
1117 uint32_t nchans = _monitor->output_streams().n_audio();
1119 assert (nchans == _channel_buttons.size ());
1121 for (uint32_t n = 0; n < nchans; ++n) {
1123 char action_name[32];
1125 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1126 act = ActionManager::get_action (X_("Monitor"), action_name);
1128 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1130 tact->set_active (_monitor->cut (n));
1134 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1135 act = ActionManager::get_action (X_("Monitor"), action_name);
1137 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1139 tact->set_active (_monitor->dimmed (n));
1143 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1144 act = ActionManager::get_action (X_("Monitor"), action_name);
1146 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1148 tact->set_active (_monitor->soloed (n));
1152 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1153 act = ActionManager::get_action (X_("Monitor"), action_name);
1155 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1157 tact->set_active (_monitor->inverted (n));
1164 MonitorSection::do_blink (bool onoff)
1167 audition_blink (onoff);
1171 MonitorSection::audition_blink (bool onoff)
1173 if (_session == 0) {
1177 if (_session->is_auditioning()) {
1178 rude_audition_button.set_active (onoff);
1180 rude_audition_button.set_active (false);
1185 MonitorSection::solo_blink (bool onoff)
1187 if (_session == 0) {
1191 if (_session->soloing() || _session->listening()) {
1192 rude_solo_button.set_active (onoff);
1194 if (_session->soloing()) {
1195 if (_session->solo_isolated()) {
1196 rude_iso_button.set_active (onoff);
1198 rude_iso_button.set_active (false);
1203 rude_solo_button.set_active (false);
1204 rude_iso_button.set_active (false);
1209 MonitorSection::cancel_isolate (GdkEventButton*)
1212 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1213 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1220 MonitorSection::cancel_audition (GdkEventButton*)
1223 _session->cancel_audition();
1228 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1230 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1231 if (tact && tact->get_active() != value) { \
1232 tact->set_active(value); \
1237 MonitorSection::parameter_changed (std::string name)
1239 if (name == "solo-control-is-listen-control") {
1240 update_solo_model ();
1241 } else if (name == "listen-position") {
1242 update_solo_model ();
1243 } else if (name == "solo-mute-override") {
1244 SYNCHRONIZE_TOGGLE_ACTION(
1245 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1246 Config->get_solo_mute_override ())
1247 } else if (name == "exclusive-solo") {
1248 SYNCHRONIZE_TOGGLE_ACTION(
1249 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1250 Config->get_exclusive_solo ())
1255 MonitorSection::assign_controllables ()
1257 boost::shared_ptr<Controllable> none;
1259 if (!gain_control) {
1260 /* too early - GUI controls not set up yet */
1265 solo_cut_control->set_controllable (_session->solo_cut_control());
1266 solo_cut_display->set_controllable (_session->solo_cut_control());
1268 solo_cut_control->set_controllable (none);
1269 solo_cut_display->set_controllable (none);
1273 gain_control->set_controllable (_route->gain_control());
1274 gain_display->set_controllable (_route->gain_control());
1276 gain_control->set_controllable (none);
1281 cut_all_button.set_controllable (_monitor->cut_control());
1282 cut_all_button.watch ();
1283 dim_all_button.set_controllable (_monitor->dim_control());
1284 dim_all_button.watch ();
1285 mono_button.set_controllable (_monitor->mono_control());
1286 mono_button.watch ();
1288 dim_control->set_controllable (_monitor->dim_level_control ());
1289 dim_display->set_controllable (_monitor->dim_level_control ());
1290 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1291 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1295 cut_all_button.set_controllable (none);
1296 dim_all_button.set_controllable (none);
1297 mono_button.set_controllable (none);
1299 dim_control->set_controllable (none);
1300 dim_display->set_controllable (none);
1301 solo_boost_control->set_controllable (none);
1302 solo_boost_display->set_controllable (none);
1307 MonitorSection::state_id() const
1309 return "monitor-section";
1313 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1315 using namespace Menu_Helpers;
1317 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1321 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1322 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1326 if (i != output_menu_bundles.end()) {
1330 output_menu_bundles.push_back (b);
1332 MenuList& citems = output_menu.items();
1334 std::string n = b->name ();
1335 replace_all (n, "_", " ");
1337 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1341 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1344 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1346 if (std::find (current.begin(), current.end(), c) == current.end()) {
1347 _route->output()->connect_ports_to_bundle (c, true, this);
1349 _route->output()->disconnect_ports_from_bundle (c, this);
1354 MonitorSection::output_release (GdkEventButton *ev)
1356 switch (ev->button) {
1358 edit_output_configuration ();
1365 struct RouteCompareByName {
1366 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1367 return a->name().compare (b->name()) < 0;
1372 MonitorSection::output_press (GdkEventButton *ev)
1374 using namespace Menu_Helpers;
1376 MessageDialog msg (_("No session - no I/O changes are possible"));
1381 MenuList& citems = output_menu.items();
1382 switch (ev->button) {
1385 return false; //wait for the mouse-up to pop the dialog
1389 output_menu.set_name ("ArdourContextMenu");
1391 output_menu_bundles.clear ();
1393 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1395 citems.push_back (SeparatorElem());
1396 uint32_t const n_with_separator = citems.size ();
1398 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1400 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1402 /* give user bundles first chance at being in the menu */
1404 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1405 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1406 maybe_add_bundle_to_output_menu (*i, current);
1410 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1411 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1412 maybe_add_bundle_to_output_menu (*i, current);
1416 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1417 RouteList copy = *routes;
1418 copy.sort (RouteCompareByName ());
1419 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1420 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1423 if (citems.size() == n_with_separator) {
1424 /* no routes added; remove the separator */
1428 citems.push_back (SeparatorElem());
1429 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1431 output_menu.popup (1, ev->time);
1442 MonitorSection::update_output_display ()
1444 if (!_route || !_monitor || _session->deletion_in_progress()) {
1450 boost::shared_ptr<Port> port;
1451 vector<string> port_connections;
1453 uint32_t total_connection_count = 0;
1454 uint32_t io_connection_count = 0;
1455 uint32_t ardour_connection_count = 0;
1456 uint32_t system_connection_count = 0;
1457 uint32_t other_connection_count = 0;
1459 ostringstream label;
1461 bool have_label = false;
1462 bool each_io_has_one_connection = true;
1464 string connection_name;
1465 string ardour_track_name;
1466 string other_connection_type;
1467 string system_ports;
1470 ostringstream tooltip;
1471 char * tooltip_cstr;
1473 io_count = _route->n_outputs().n_total();
1474 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1477 for (io_index = 0; io_index < io_count; ++io_index) {
1479 port = _route->output()->nth (io_index);
1481 //ignore any port connections that don't match our DataType
1482 if (port->type() != DataType::AUDIO) {
1486 port_connections.clear ();
1487 port->get_connections(port_connections);
1488 io_connection_count = 0;
1490 if (!port_connections.empty()) {
1491 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1493 string& connection_name (*i);
1495 if (connection_name.find("system:") == 0) {
1496 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1499 if (io_connection_count == 0) {
1500 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1502 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1505 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1508 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1509 if (ardour_track_name.empty()) {
1510 // "ardour:Master/in 1" -> "ardour:Master/"
1511 string::size_type slash = connection_name.find("/");
1512 if (slash != string::npos) {
1513 ardour_track_name = connection_name.substr(0, slash + 1);
1517 if (connection_name.find(ardour_track_name) == 0) {
1518 ++ardour_connection_count;
1520 } else if (!pn.empty()) {
1521 if (system_ports.empty()) {
1524 system_ports += "/" + pn;
1526 if (connection_name.find("system:") == 0) {
1527 ++system_connection_count;
1529 } else if (connection_name.find("system:") == 0) {
1530 // "system:playback_123" -> "123"
1531 system_port = connection_name.substr(16);
1532 if (system_ports.empty()) {
1533 system_ports += system_port;
1535 system_ports += "/" + system_port;
1538 ++system_connection_count;
1540 if (other_connection_type.empty()) {
1541 // "jamin:in 1" -> "jamin:"
1542 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1545 if (connection_name.find(other_connection_type) == 0) {
1546 ++other_connection_count;
1550 ++total_connection_count;
1551 ++io_connection_count;
1555 if (io_connection_count != 1) {
1556 each_io_has_one_connection = false;
1560 if (total_connection_count == 0) {
1561 tooltip << endl << _("Disconnected");
1564 tooltip_cstr = new char[tooltip.str().size() + 1];
1565 strcpy(tooltip_cstr, tooltip.str().c_str());
1567 set_tooltip (output_button, tooltip_cstr, "");
1569 if (each_io_has_one_connection) {
1570 if (total_connection_count == ardour_connection_count) {
1571 // all connections are to the same track in ardour
1572 // "ardour:Master/" -> "Master"
1573 string::size_type slash = ardour_track_name.find("/");
1574 if (slash != string::npos) {
1575 label << ardour_track_name.substr(7, slash - 7);
1578 } else if (total_connection_count == system_connection_count) {
1579 // all connections are to system ports
1580 label << system_ports;
1582 } else if (total_connection_count == other_connection_count) {
1583 // all connections are to the same external program eg jamin
1584 // "jamin:" -> "jamin"
1585 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1591 if (total_connection_count == 0) {
1595 // Odd configuration
1596 label << "*" << total_connection_count << "*";
1600 output_button->set_text (label.str());
1604 MonitorSection::disconnect_output ()
1607 _route->output()->disconnect(this);
1612 MonitorSection::edit_output_configuration ()
1614 if (_output_selector == 0) {
1615 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1617 _output_selector->present ();
1621 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1626 boost::shared_ptr<Port> a = wa.lock ();
1627 boost::shared_ptr<Port> b = wb.lock ();
1628 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1629 update_output_display ();
1634 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1636 boost::shared_ptr<Processor> processor (p.lock ());
1637 if (!processor || !processor->display_to_user()) {
1640 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1647 MonitorSection::count_processors ()
1649 uint32_t processor_count = 0;
1651 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1653 return processor_count;
1657 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1659 update_processor_box ();