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 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::ptr_fun (forward_key_press), 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 = ActionGroup::create (X_("Monitor"));
856 ActionManager::add_action_group (monitor_actions);
858 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
859 sigc::mem_fun (*this, &MonitorSection::mono));
861 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
862 sigc::mem_fun (*this, &MonitorSection::cut_all));
864 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
865 sigc::mem_fun (*this, &MonitorSection::dim_all));
867 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
868 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
870 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
871 tact->set_active (Config->get_exclusive_solo());
873 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
874 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
876 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
877 tact->set_active (Config->get_solo_mute_override());
880 for (uint32_t chn = 0; chn < 16; ++chn) {
882 action_name = string_compose (X_("monitor-cut-%1"), chn);
883 action_descr = string_compose (_("Cut monitor channel %1"), chn);
884 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
885 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
887 action_name = string_compose (X_("monitor-dim-%1"), chn);
888 action_descr = string_compose (_("Dim monitor channel %1"), chn);
889 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
890 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
892 action_name = string_compose (X_("monitor-solo-%1"), chn);
893 action_descr = string_compose (_("Solo monitor channel %1"), chn);
894 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
895 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
897 action_name = string_compose (X_("monitor-invert-%1"), chn);
898 action_descr = string_compose (_("Invert monitor channel %1"), chn);
899 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
900 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
905 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
906 RadioAction::Group solo_group;
908 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
909 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
910 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
911 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
912 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
913 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
915 ActionManager::add_action_group (solo_actions);
919 MonitorSection::connect_actions ()
921 Glib::RefPtr<Action> act;
922 Glib::RefPtr<ToggleAction> tact;
924 #define MON_TOG(NAME, FUNC) \
925 act = ActionManager::get_action (X_("Monitor"), NAME); \
926 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
928 tact->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
930 MON_TOG("monitor-mono", mono);
931 MON_TOG("monitor-cut-all", cut_all);
932 MON_TOG("monitor-dim-all", dim_all);
934 MON_TOG("toggle-exclusive-solo", toggle_exclusive_solo);
935 tact->set_active (Config->get_exclusive_solo());
937 MON_TOG("toggle-mute-overrides-solo", toggle_mute_overrides_solo);
938 tact->set_active (Config->get_solo_mute_override());
941 #define MON_BIND(NAME, FUNC, ARG) \
942 act = ActionManager::get_action (X_("Monitor"), NAME); \
943 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
945 tact->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::FUNC), ARG));
947 for (uint32_t chn = 0; chn < 16; ++chn) {
948 std::string action_name = string_compose (X_("monitor-cut-%1"), chn);
949 MON_BIND(action_name.c_str(), cut_channel, chn);
950 action_name = string_compose (X_("monitor-dim-%1"), chn);
951 MON_BIND(action_name.c_str(), dim_channel, chn);
952 action_name = string_compose (X_("monitor-solo-%1"), chn);
953 MON_BIND(action_name.c_str(), solo_channel, chn);
954 action_name = string_compose (X_("monitor-invert-%1"), chn);
955 MON_BIND(action_name.c_str(), invert_channel, chn);
959 #define SOLO_RADIO(NAME, FUNC) \
960 act = ActionManager::get_action (X_("Solo"), NAME); \
961 ract = Glib::RefPtr<RadioAction>::cast_dynamic (act); \
963 ract->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
965 Glib::RefPtr<RadioAction> ract;
966 SOLO_RADIO ("solo-use-in-place", solo_use_in_place);
967 SOLO_RADIO ("solo-use-afl", solo_use_afl);
968 SOLO_RADIO ("solo-use-pfl", solo_use_pfl);
973 MonitorSection::solo_use_in_place ()
975 /* this is driven by a toggle on a radio group, and so is invoked twice,
976 once for the item that became inactive and once for the one that became
980 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
983 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
985 if (!ract->get_active ()) {
986 /* We are turning SiP off, which means that AFL or PFL will be turned on
987 shortly; don't update the solo model in the mean time, as if the currently
988 configured listen position is not the one that is about to be turned on,
989 things will go wrong.
991 _inhibit_solo_model_update = true;
993 Config->set_solo_control_is_listen_control (!ract->get_active());
994 _inhibit_solo_model_update = false;
1000 MonitorSection::solo_use_afl ()
1002 /* this is driven by a toggle on a radio group, and so is invoked twice,
1003 once for the item that became inactive and once for the one that became
1007 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1009 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1011 if (ract->get_active()) {
1012 Config->set_solo_control_is_listen_control (true);
1013 Config->set_listen_position (AfterFaderListen);
1020 MonitorSection::solo_use_pfl ()
1022 /* this is driven by a toggle on a radio group, and so is invoked twice,
1023 once for the item that became inactive and once for the one that became
1027 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1029 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1031 if (ract->get_active()) {
1032 Config->set_solo_control_is_listen_control (true);
1033 Config->set_listen_position (PreFaderListen);
1040 MonitorSection::update_solo_model ()
1042 if (_inhibit_solo_model_update) {
1046 const char* action_name = 0;
1047 Glib::RefPtr<Action> act;
1049 if (Config->get_solo_control_is_listen_control()) {
1050 switch (Config->get_listen_position()) {
1051 case AfterFaderListen:
1052 action_name = X_("solo-use-afl");
1054 case PreFaderListen:
1055 action_name = X_("solo-use-pfl");
1059 action_name = X_("solo-use-in-place");
1062 act = ActionManager::get_action (X_("Solo"), action_name);
1065 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1067 /* because these are radio buttons, one of them will be
1068 active no matter what. to trigger a change in the
1069 action so that the view picks it up, toggle it.
1071 if (ract->get_active()) {
1072 ract->set_active (false);
1074 ract->set_active (true);
1081 MonitorSection::map_state ()
1083 if (!_route || !_monitor) {
1087 Glib::RefPtr<Action> act;
1089 update_solo_model ();
1091 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1093 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1095 tact->set_active (_monitor->cut_all());
1099 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1101 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1103 tact->set_active (_monitor->dim_all());
1107 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1109 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1111 tact->set_active (_monitor->mono());
1115 uint32_t nchans = _monitor->output_streams().n_audio();
1117 assert (nchans == _channel_buttons.size ());
1119 for (uint32_t n = 0; n < nchans; ++n) {
1121 char action_name[32];
1123 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1124 act = ActionManager::get_action (X_("Monitor"), action_name);
1126 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1128 tact->set_active (_monitor->cut (n));
1132 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1133 act = ActionManager::get_action (X_("Monitor"), action_name);
1135 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1137 tact->set_active (_monitor->dimmed (n));
1141 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1142 act = ActionManager::get_action (X_("Monitor"), action_name);
1144 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1146 tact->set_active (_monitor->soloed (n));
1150 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1151 act = ActionManager::get_action (X_("Monitor"), action_name);
1153 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1155 tact->set_active (_monitor->inverted (n));
1162 MonitorSection::do_blink (bool onoff)
1165 audition_blink (onoff);
1169 MonitorSection::audition_blink (bool onoff)
1171 if (_session == 0) {
1175 if (_session->is_auditioning()) {
1176 rude_audition_button.set_active (onoff);
1178 rude_audition_button.set_active (false);
1183 MonitorSection::solo_blink (bool onoff)
1185 if (_session == 0) {
1189 if (_session->soloing() || _session->listening()) {
1190 rude_solo_button.set_active (onoff);
1192 if (_session->soloing()) {
1193 if (_session->solo_isolated()) {
1194 rude_iso_button.set_active (onoff);
1196 rude_iso_button.set_active (false);
1201 rude_solo_button.set_active (false);
1202 rude_iso_button.set_active (false);
1207 MonitorSection::cancel_isolate (GdkEventButton*)
1210 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1211 _session->set_solo_isolated (rl, false, Session::rt_cleanup, Controllable::NoGroup);
1218 MonitorSection::cancel_audition (GdkEventButton*)
1221 _session->cancel_audition();
1226 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1228 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1229 if (tact && tact->get_active() != value) { \
1230 tact->set_active(value); \
1235 MonitorSection::parameter_changed (std::string name)
1237 if (name == "solo-control-is-listen-control") {
1238 update_solo_model ();
1239 } else if (name == "listen-position") {
1240 update_solo_model ();
1241 } else if (name == "solo-mute-override") {
1242 SYNCHRONIZE_TOGGLE_ACTION(
1243 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1244 Config->get_solo_mute_override ())
1245 } else if (name == "exclusive-solo") {
1246 SYNCHRONIZE_TOGGLE_ACTION(
1247 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1248 Config->get_exclusive_solo ())
1253 MonitorSection::assign_controllables ()
1255 boost::shared_ptr<Controllable> none;
1257 if (!gain_control) {
1258 /* too early - GUI controls not set up yet */
1263 solo_cut_control->set_controllable (_session->solo_cut_control());
1264 solo_cut_display->set_controllable (_session->solo_cut_control());
1266 solo_cut_control->set_controllable (none);
1267 solo_cut_display->set_controllable (none);
1271 gain_control->set_controllable (_route->gain_control());
1272 gain_display->set_controllable (_route->gain_control());
1274 gain_control->set_controllable (none);
1279 cut_all_button.set_controllable (_monitor->cut_control());
1280 cut_all_button.watch ();
1281 dim_all_button.set_controllable (_monitor->dim_control());
1282 dim_all_button.watch ();
1283 mono_button.set_controllable (_monitor->mono_control());
1284 mono_button.watch ();
1286 dim_control->set_controllable (_monitor->dim_level_control ());
1287 dim_display->set_controllable (_monitor->dim_level_control ());
1288 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1289 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1293 cut_all_button.set_controllable (none);
1294 dim_all_button.set_controllable (none);
1295 mono_button.set_controllable (none);
1297 dim_control->set_controllable (none);
1298 dim_display->set_controllable (none);
1299 solo_boost_control->set_controllable (none);
1300 solo_boost_display->set_controllable (none);
1305 MonitorSection::state_id() const
1307 return "monitor-section";
1311 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1313 using namespace Menu_Helpers;
1315 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1319 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1320 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1324 if (i != output_menu_bundles.end()) {
1328 output_menu_bundles.push_back (b);
1330 MenuList& citems = output_menu.items();
1332 std::string n = b->name ();
1333 replace_all (n, "_", " ");
1335 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1339 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1342 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1344 if (std::find (current.begin(), current.end(), c) == current.end()) {
1345 _route->output()->connect_ports_to_bundle (c, true, this);
1347 _route->output()->disconnect_ports_from_bundle (c, this);
1352 MonitorSection::output_release (GdkEventButton *ev)
1354 switch (ev->button) {
1356 edit_output_configuration ();
1363 struct RouteCompareByName {
1364 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1365 return a->name().compare (b->name()) < 0;
1370 MonitorSection::output_press (GdkEventButton *ev)
1372 using namespace Menu_Helpers;
1374 MessageDialog msg (_("No session - no I/O changes are possible"));
1379 MenuList& citems = output_menu.items();
1380 switch (ev->button) {
1383 return false; //wait for the mouse-up to pop the dialog
1387 output_menu.set_name ("ArdourContextMenu");
1389 output_menu_bundles.clear ();
1391 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1393 citems.push_back (SeparatorElem());
1394 uint32_t const n_with_separator = citems.size ();
1396 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1398 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1400 /* give user bundles first chance at being in the menu */
1402 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1403 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1404 maybe_add_bundle_to_output_menu (*i, current);
1408 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1409 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1410 maybe_add_bundle_to_output_menu (*i, current);
1414 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1415 RouteList copy = *routes;
1416 copy.sort (RouteCompareByName ());
1417 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1418 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1421 if (citems.size() == n_with_separator) {
1422 /* no routes added; remove the separator */
1426 citems.push_back (SeparatorElem());
1427 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1429 output_menu.popup (1, ev->time);
1440 MonitorSection::update_output_display ()
1442 if (!_route || !_monitor || _session->deletion_in_progress()) {
1448 boost::shared_ptr<Port> port;
1449 vector<string> port_connections;
1451 uint32_t total_connection_count = 0;
1452 uint32_t io_connection_count = 0;
1453 uint32_t ardour_connection_count = 0;
1454 uint32_t system_connection_count = 0;
1455 uint32_t other_connection_count = 0;
1457 ostringstream label;
1459 bool have_label = false;
1460 bool each_io_has_one_connection = true;
1462 string connection_name;
1463 string ardour_track_name;
1464 string other_connection_type;
1465 string system_ports;
1468 ostringstream tooltip;
1469 char * tooltip_cstr;
1471 io_count = _route->n_outputs().n_total();
1472 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1475 for (io_index = 0; io_index < io_count; ++io_index) {
1477 port = _route->output()->nth (io_index);
1479 //ignore any port connections that don't match our DataType
1480 if (port->type() != DataType::AUDIO) {
1484 port_connections.clear ();
1485 port->get_connections(port_connections);
1486 io_connection_count = 0;
1488 if (!port_connections.empty()) {
1489 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1491 string& connection_name (*i);
1493 if (connection_name.find("system:") == 0) {
1494 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1497 if (io_connection_count == 0) {
1498 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1500 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1503 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1506 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1507 if (ardour_track_name.empty()) {
1508 // "ardour:Master/in 1" -> "ardour:Master/"
1509 string::size_type slash = connection_name.find("/");
1510 if (slash != string::npos) {
1511 ardour_track_name = connection_name.substr(0, slash + 1);
1515 if (connection_name.find(ardour_track_name) == 0) {
1516 ++ardour_connection_count;
1518 } else if (!pn.empty()) {
1519 if (system_ports.empty()) {
1522 system_ports += "/" + pn;
1524 if (connection_name.find("system:") == 0) {
1525 ++system_connection_count;
1527 } else if (connection_name.find("system:") == 0) {
1528 // "system:playback_123" -> "123"
1529 system_port = connection_name.substr(16);
1530 if (system_ports.empty()) {
1531 system_ports += system_port;
1533 system_ports += "/" + system_port;
1536 ++system_connection_count;
1538 if (other_connection_type.empty()) {
1539 // "jamin:in 1" -> "jamin:"
1540 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1543 if (connection_name.find(other_connection_type) == 0) {
1544 ++other_connection_count;
1548 ++total_connection_count;
1549 ++io_connection_count;
1553 if (io_connection_count != 1) {
1554 each_io_has_one_connection = false;
1558 if (total_connection_count == 0) {
1559 tooltip << endl << _("Disconnected");
1562 tooltip_cstr = new char[tooltip.str().size() + 1];
1563 strcpy(tooltip_cstr, tooltip.str().c_str());
1565 set_tooltip (output_button, tooltip_cstr, "");
1567 if (each_io_has_one_connection) {
1568 if (total_connection_count == ardour_connection_count) {
1569 // all connections are to the same track in ardour
1570 // "ardour:Master/" -> "Master"
1571 string::size_type slash = ardour_track_name.find("/");
1572 if (slash != string::npos) {
1573 label << ardour_track_name.substr(7, slash - 7);
1576 } else if (total_connection_count == system_connection_count) {
1577 // all connections are to system ports
1578 label << system_ports;
1580 } else if (total_connection_count == other_connection_count) {
1581 // all connections are to the same external program eg jamin
1582 // "jamin:" -> "jamin"
1583 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1589 if (total_connection_count == 0) {
1593 // Odd configuration
1594 label << "*" << total_connection_count << "*";
1598 output_button->set_text (label.str());
1602 MonitorSection::disconnect_output ()
1605 _route->output()->disconnect(this);
1610 MonitorSection::edit_output_configuration ()
1612 if (_output_selector == 0) {
1613 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1615 _output_selector->present ();
1619 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1624 boost::shared_ptr<Port> a = wa.lock ();
1625 boost::shared_ptr<Port> b = wb.lock ();
1626 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1627 update_output_display ();
1632 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1634 boost::shared_ptr<Processor> processor (p.lock ());
1635 if (!processor || !processor->display_to_user()) {
1638 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1645 MonitorSection::count_processors ()
1647 uint32_t processor_count = 0;
1649 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1651 return processor_count;
1655 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1657 update_processor_box ();