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) {
96 /* do some static stuff */
102 _plugin_selector = new PluginSelector (PluginManager::instance());
103 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
104 insert_box->set_no_show_all ();
106 // TODO allow keyboard shortcuts in ProcessorBox
110 /* Rude Solo & Solo Isolated */
111 rude_solo_button.set_text (_("Soloing"));
112 rude_solo_button.set_name ("rude solo");
113 rude_solo_button.show ();
115 rude_iso_button.set_text (_("Isolated"));
116 rude_iso_button.set_name ("rude isolate");
117 rude_iso_button.show ();
119 rude_audition_button.set_text (_("Auditioning"));
120 rude_audition_button.set_name ("rude audition");
121 rude_audition_button.show ();
123 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
125 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
126 rude_solo_button.set_related_action (act);
127 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
129 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
130 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
132 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
133 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
135 /* SIP, AFL, PFL radio */
137 solo_in_place_button.set_name ("monitor section solo model");
138 afl_button.set_name ("monitor section solo model");
139 pfl_button.set_name ("monitor section solo model");
141 solo_in_place_button.set_led_left (true);
142 afl_button.set_led_left (true);
143 pfl_button.set_led_left (true);
145 solo_in_place_button.show ();
149 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
150 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
152 solo_in_place_button.set_related_action (act);
155 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
156 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
158 afl_button.set_related_action (act);
161 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
162 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
164 pfl_button.set_related_action (act);
167 /* Solo option buttons */
168 exclusive_solo_button.set_text (_("Excl. Solo"));
169 exclusive_solo_button.set_name (X_("monitor section solo option"));
170 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
172 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
174 exclusive_solo_button.set_related_action (act);
177 solo_mute_override_button.set_text (_("Solo ยป Mute"));
178 solo_mute_override_button.set_name (X_("monitor section solo option"));
179 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
181 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
183 solo_mute_override_button.set_related_action (act);
186 /* Processor Box hide/shos */
187 toggle_processorbox_button.set_text (_("Processors"));
188 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
189 set_tooltip (&toggle_processorbox_button, _("Allow to add monitor effect processors"));
191 proctoggle = ToggleAction::create ();
192 toggle_processorbox_button.set_related_action (proctoggle);
193 proctoggle->signal_toggled().connect (sigc::mem_fun(*this, &MonitorSection::update_processor_box), false);
196 Label* solo_boost_label;
197 Label* solo_cut_label;
200 /* Solo Boost Knob */
202 solo_boost_control = new ArdourKnob ();
203 solo_boost_control->set_name("monitor section knob");
204 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
205 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
207 solo_boost_display = new ArdourDisplay ();
208 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
209 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
210 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
211 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
212 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
214 solo_boost_label = manage (new Label (_("Solo Boost")));
218 solo_cut_control = new ArdourKnob ();
219 solo_cut_control->set_name ("monitor section knob");
220 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
221 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
223 solo_cut_display = new ArdourDisplay ();
224 solo_cut_display->set_name("monitor section dropdown"); // XXX
225 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
226 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
227 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
228 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
229 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
230 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
232 solo_cut_label = manage (new Label (_("SiP Cut")));
236 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
237 dim_control->set_name ("monitor section knob");
238 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
239 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
241 dim_display = new ArdourDisplay ();
242 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
243 dim_display->add_controllable_preset(_("0 dB"), 0.0);
244 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
245 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
246 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
247 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
249 dim_label = manage (new Label (_("Dim")));
252 cut_all_button.set_text (_("Mute"));
253 cut_all_button.set_name ("mute button");
254 cut_all_button.set_size_request (-1, PX_SCALE(30));
255 cut_all_button.show ();
257 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
259 cut_all_button.set_related_action (act);
263 dim_all_button.set_text (_("Dim"));
264 dim_all_button.set_name ("monitor section dim");
265 dim_all_button.set_size_request (-1, PX_SCALE(25));
266 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
268 dim_all_button.set_related_action (act);
272 mono_button.set_text (_("Mono"));
273 mono_button.set_name ("monitor section mono");
274 mono_button.set_size_request (-1, PX_SCALE(25));
275 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
277 mono_button.set_related_action (act);
282 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
283 gain_control->set_name("monitor section knob");
284 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
286 gain_display = new ArdourDisplay ();
287 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
288 gain_display->add_controllable_preset(_("0 dB"), 0.0);
289 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
290 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
291 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
292 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
293 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
295 Label* output_label = manage (new Label (_("Output")));
296 output_label->set_name (X_("MonitorSectionLabel"));
298 output_button = new ArdourButton ();
299 output_button->set_text (_("Output"));
300 output_button->set_name (X_("monitor section cut")); // XXX
301 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
302 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
304 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
305 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
306 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
307 channel_table_scroller.show ();
308 channel_table_scroller.add (channel_table_viewport);
310 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
311 channel_size_group->add_widget (channel_table_header);
312 channel_size_group->add_widget (channel_table);
314 channel_table_header.resize (1, 5);
316 Label* l1 = manage (new Label (X_(" ")));
317 l1->set_name (X_("MonitorSectionLabel"));
318 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
320 l1 = manage (new Label (_("Mute")));
321 l1->set_name (X_("MonitorSectionLabel"));
322 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
324 l1 = manage (new Label (_("Dim")));
325 l1->set_name (X_("MonitorSectionLabel"));
326 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
328 l1 = manage (new Label (_("Solo")));
329 l1->set_name (X_("MonitorSectionLabel"));
330 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
332 l1 = manage (new Label (_("Inv")));
333 l1->set_name (X_("MonitorSectionLabel"));
334 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
336 channel_table_header.show ();
339 /****************************************************************************
340 * LAYOUT top to bottom
343 // solo, iso information
344 HBox* rude_box = manage (new HBox);
345 rude_box->set_spacing (PX_SCALE(4));
346 rude_box->set_homogeneous (true);
347 rude_box->pack_start (rude_solo_button, true, true);
348 rude_box->pack_start (rude_iso_button, true, true);
350 // solo options (right align)
351 HBox* tbx1 = manage (new HBox);
352 tbx1->pack_end (exclusive_solo_button, false, false);
354 HBox* tbx2 = manage (new HBox);
355 tbx2->pack_end (solo_mute_override_button, false, false);
357 HBox* tbx3 = manage (new HBox);
358 tbx3->pack_end (toggle_processorbox_button, false, false);
360 HBox* tbx0 = manage (new HBox); // space
362 // combined solo mode (Sip, AFL, PFL) & solo options
363 Table *solo_tbl = manage (new Table);
364 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
365 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
366 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
368 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
369 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
370 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
372 // boost, cut, dim volume control
373 Table *level_tbl = manage (new Table);
374 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
375 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
378 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
379 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
382 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
383 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
384 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
386 /* note that we don't pack the table_hpacker till later
387 * -> top level channel_table_packer */
388 table_hpacker.pack_start (channel_table, true, true);
391 HBox* mono_dim_box = manage (new HBox);
392 mono_dim_box->set_spacing (PX_SCALE(4));
393 mono_dim_box->set_homogeneous (true);
394 mono_dim_box->pack_start (mono_button, true, true);
395 mono_dim_box->pack_end (dim_all_button, true, true);
398 Label* spin_label = manage (new Label (_("Monitor")));
399 VBox* spin_packer = manage (new VBox);
400 spin_packer->set_spacing (PX_SCALE(2));
401 spin_packer->pack_start (*spin_label, false, false);
402 spin_packer->pack_start (*gain_control, false, false);
403 spin_packer->pack_start (*gain_display, false, false);
405 master_packer.pack_start (*spin_packer, true, false);
407 // combined gain section (channels, mute, dim)
408 VBox* lower_packer = manage (new VBox);
409 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
410 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
411 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
412 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
414 // output port select
415 VBox* out_packer = manage (new VBox);
416 out_packer->set_spacing (PX_SCALE(2));
417 out_packer->pack_start (*output_label, false, false);
418 out_packer->pack_start (*output_button, false, false);
420 /****************************************************************************
423 vpacker.set_border_width (PX_SCALE(3));
424 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
425 vpacker.pack_start (rude_audition_button, false, false, 0);
426 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
427 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
428 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
429 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
430 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
431 vpacker.pack_end (*out_packer, false, false, PX_SCALE(3));
433 hpacker.set_spacing (0);
434 hpacker.pack_start (vpacker, true, true);
436 gain_control->show_all ();
437 gain_display->show_all ();
438 dim_control->show_all ();
439 dim_display->show_all();
440 solo_boost_control->show_all ();
441 solo_boost_display->show_all();
443 mono_dim_box->show ();
444 spin_packer->show ();
445 master_packer.show ();
446 channel_table.show ();
449 solo_tbl->show_all();
451 lower_packer->show ();
459 assign_controllables ();
461 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
462 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
464 _tearoff = new TearOff (hpacker);
466 if (!UIConfiguration::instance().get_floating_monitor_section()) {
467 /* if torn off, make this a normal window
468 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
470 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
472 _tearoff->tearoff_window().set_title (X_("Monitor"));
473 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
475 update_output_display ();
476 update_processor_box ();
477 _ui_initialized = true;
479 /* catch changes that affect us */
480 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
481 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
483 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
486 MonitorSection::~MonitorSection ()
488 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
492 _channel_buttons.clear ();
493 _output_changed_connection.disconnect ();
496 delete output_button;
501 delete solo_boost_control;
502 delete solo_boost_display;
503 delete solo_cut_control;
504 delete solo_cut_display;
506 delete _output_selector;
507 _output_selector = 0;
512 MonitorSection::update_processor_box ()
514 bool show_processor_box = proctoggle->get_active ();
516 if (count_processors () > 0 && !show_processor_box) {
517 toggle_processorbox_button.set_name (X_("monitor section processors present"));
519 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
522 if (insert_box->is_visible() == show_processor_box) {
526 if (show_processor_box) {
527 if (master_packer.get_parent()) {
528 master_packer.get_parent()->remove (master_packer);
531 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
533 if (master_packer.get_parent()) {
534 master_packer.get_parent()->remove (master_packer);
537 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
542 MonitorSection::set_session (Session* s)
544 AxisView::set_session (s);
545 _plugin_selector->set_session (_session);
549 _route = _session->monitor_out ();
552 /* session with monitor section */
553 _monitor = _route->monitor_control ();
554 assign_controllables ();
555 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
556 boost::bind (&MonitorSection::update_output_display, this),
558 insert_box->set_route (_route);
559 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
560 if (_ui_initialized) {
561 update_processor_box ();
564 /* session with no monitor section */
565 _output_changed_connection.disconnect();
568 delete _output_selector;
569 _output_selector = 0;
572 if (channel_table_scroller.get_parent()) {
573 /* scroller is packed, so remove it */
574 channel_table_packer.remove (channel_table_scroller);
577 if (table_hpacker.get_parent () == &channel_table_packer) {
578 /* this occurs when the table hpacker is directly
579 packed, so remove it.
581 channel_table_packer.remove (table_hpacker);
582 } else if (table_hpacker.get_parent()) {
583 channel_table_viewport.remove ();
586 if (_monitor->output_streams().n_audio() > 7) {
587 /* put the table into a scrolled window, and then put
588 * that into the channel vpacker, after the table header
590 channel_table_viewport.add (table_hpacker);
591 channel_table_packer.pack_start (channel_table_scroller, true, true);
592 channel_table_viewport.show ();
593 channel_table_scroller.show ();
596 /* just put the channel table itself into the channel
597 * vpacker, after the table header
600 channel_table_packer.pack_start (table_hpacker, true, true);
601 channel_table_scroller.hide ();
604 table_hpacker.show ();
605 channel_table.show ();
610 _output_changed_connection.disconnect();
613 control_connections.drop_connections ();
614 rude_iso_button.unset_active_state ();
615 rude_solo_button.unset_active_state ();
616 delete _output_selector;
617 _output_selector = 0;
619 assign_controllables ();
623 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
625 cut.set_name (X_("mute button"));
626 dim.set_name (X_("monitor section dim"));
627 solo.set_name (X_("solo button"));
628 invert.set_name (X_("invert button"));
630 cut.unset_flags (Gtk::CAN_FOCUS);
631 dim.unset_flags (Gtk::CAN_FOCUS);
632 solo.unset_flags (Gtk::CAN_FOCUS);
633 invert.unset_flags (Gtk::CAN_FOCUS);
637 MonitorSection::populate_buttons ()
643 Glib::RefPtr<Action> act;
644 uint32_t nchans = _monitor->output_streams().n_audio();
646 channel_table.resize (nchans, 5);
647 channel_table.set_col_spacings (6);
648 channel_table.set_row_spacings (6);
649 channel_table.set_homogeneous (true);
651 const uint32_t row_offset = 0;
653 for (uint32_t i = 0; i < nchans; ++i) {
666 snprintf (buf, sizeof (buf), "%d", i+1);
670 Label* label = manage (new Label (l));
671 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
673 ChannelButtonSet* cbs = new ChannelButtonSet;
675 _channel_buttons.push_back (cbs);
677 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
678 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
679 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
680 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
682 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
683 act = ActionManager::get_action (X_("Monitor"), buf);
685 cbs->cut.set_related_action (act);
688 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
689 act = ActionManager::get_action (X_("Monitor"), buf);
691 cbs->dim.set_related_action (act);
694 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
695 act = ActionManager::get_action (X_("Monitor"), buf);
697 cbs->solo.set_related_action (act);
700 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
701 act = ActionManager::get_action (X_("Monitor"), buf);
703 cbs->invert.set_related_action (act);
707 channel_table.show_all ();
711 MonitorSection::toggle_exclusive_solo ()
717 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
719 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
720 Config->set_exclusive_solo (tact->get_active());
726 MonitorSection::toggle_mute_overrides_solo ()
732 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
734 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
735 Config->set_solo_mute_override (tact->get_active());
740 MonitorSection::dim_all ()
746 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
748 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
749 _monitor->set_dim_all (tact->get_active());
755 MonitorSection::cut_all ()
761 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
763 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
764 _monitor->set_cut_all (tact->get_active());
769 MonitorSection::mono ()
775 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
777 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
778 _monitor->set_mono (tact->get_active());
783 MonitorSection::cut_channel (uint32_t chn)
790 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
792 --chn; // 0-based in backend
794 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
796 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
797 _monitor->set_cut (chn, tact->get_active());
802 MonitorSection::dim_channel (uint32_t chn)
809 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
811 --chn; // 0-based in backend
813 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
815 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
816 _monitor->set_dim (chn, tact->get_active());
822 MonitorSection::solo_channel (uint32_t chn)
829 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
831 --chn; // 0-based in backend
833 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
835 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
836 _monitor->set_solo (chn, tact->get_active());
842 MonitorSection::invert_channel (uint32_t chn)
849 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
851 --chn; // 0-based in backend
853 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
855 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
856 _monitor->set_polarity (chn, tact->get_active());
861 MonitorSection::register_actions ()
865 Glib::RefPtr<Action> act;
867 monitor_actions = ActionGroup::create (X_("Monitor"));
868 ActionManager::add_action_group (monitor_actions);
870 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
871 sigc::mem_fun (*this, &MonitorSection::mono));
873 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
874 sigc::mem_fun (*this, &MonitorSection::cut_all));
876 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
877 sigc::mem_fun (*this, &MonitorSection::dim_all));
879 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
880 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
882 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
883 tact->set_active (Config->get_exclusive_solo());
885 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
886 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
888 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
889 tact->set_active (Config->get_solo_mute_override());
892 /* note the 1-based counting (for naming - backend uses 0-based) */
894 for (uint32_t chn = 1; chn <= 16; ++chn) {
896 action_name = string_compose (X_("monitor-cut-%1"), chn);
897 action_descr = string_compose (_("Cut monitor channel %1"), chn);
898 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
899 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
901 action_name = string_compose (X_("monitor-dim-%1"), chn);
902 action_descr = string_compose (_("Dim monitor channel %1"), chn);
903 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
904 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
906 action_name = string_compose (X_("monitor-solo-%1"), chn);
907 action_descr = string_compose (_("Solo monitor channel %1"), chn);
908 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
909 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
911 action_name = string_compose (X_("monitor-invert-%1"), chn);
912 action_descr = string_compose (_("Invert monitor channel %1"), chn);
913 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
914 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
919 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
920 RadioAction::Group solo_group;
922 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
923 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
924 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
925 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
926 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
927 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
929 ActionManager::add_action_group (solo_actions);
933 MonitorSection::solo_use_in_place ()
935 /* this is driven by a toggle on a radio group, and so is invoked twice,
936 once for the item that became inactive and once for the one that became
940 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
943 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
945 if (!ract->get_active ()) {
946 /* We are turning SiP off, which means that AFL or PFL will be turned on
947 shortly; don't update the solo model in the mean time, as if the currently
948 configured listen position is not the one that is about to be turned on,
949 things will go wrong.
951 _inhibit_solo_model_update = true;
953 Config->set_solo_control_is_listen_control (!ract->get_active());
954 _inhibit_solo_model_update = false;
960 MonitorSection::solo_use_afl ()
962 /* this is driven by a toggle on a radio group, and so is invoked twice,
963 once for the item that became inactive and once for the one that became
967 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
969 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
971 if (ract->get_active()) {
972 Config->set_solo_control_is_listen_control (true);
973 Config->set_listen_position (AfterFaderListen);
980 MonitorSection::solo_use_pfl ()
982 /* this is driven by a toggle on a radio group, and so is invoked twice,
983 once for the item that became inactive and once for the one that became
987 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
989 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
991 if (ract->get_active()) {
992 Config->set_solo_control_is_listen_control (true);
993 Config->set_listen_position (PreFaderListen);
1000 MonitorSection::update_solo_model ()
1002 if (_inhibit_solo_model_update) {
1006 const char* action_name = 0;
1007 Glib::RefPtr<Action> act;
1009 if (Config->get_solo_control_is_listen_control()) {
1010 switch (Config->get_listen_position()) {
1011 case AfterFaderListen:
1012 action_name = X_("solo-use-afl");
1014 case PreFaderListen:
1015 action_name = X_("solo-use-pfl");
1019 action_name = X_("solo-use-in-place");
1022 act = ActionManager::get_action (X_("Solo"), action_name);
1025 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1027 /* because these are radio buttons, one of them will be
1028 active no matter what. to trigger a change in the
1029 action so that the view picks it up, toggle it.
1031 if (ract->get_active()) {
1032 ract->set_active (false);
1034 ract->set_active (true);
1041 MonitorSection::map_state ()
1043 if (!_route || !_monitor) {
1047 Glib::RefPtr<Action> act;
1049 update_solo_model ();
1051 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1053 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1055 tact->set_active (_monitor->cut_all());
1059 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1061 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1063 tact->set_active (_monitor->dim_all());
1067 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1069 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1071 tact->set_active (_monitor->mono());
1075 uint32_t nchans = _monitor->output_streams().n_audio();
1077 assert (nchans == _channel_buttons.size ());
1079 for (uint32_t n = 0; n < nchans; ++n) {
1081 char action_name[32];
1083 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1084 act = ActionManager::get_action (X_("Monitor"), action_name);
1086 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1088 tact->set_active (_monitor->cut (n));
1092 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1093 act = ActionManager::get_action (X_("Monitor"), action_name);
1095 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1097 tact->set_active (_monitor->dimmed (n));
1101 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1102 act = ActionManager::get_action (X_("Monitor"), action_name);
1104 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1106 tact->set_active (_monitor->soloed (n));
1110 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1111 act = ActionManager::get_action (X_("Monitor"), action_name);
1113 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1115 tact->set_active (_monitor->inverted (n));
1122 MonitorSection::do_blink (bool onoff)
1125 audition_blink (onoff);
1129 MonitorSection::audition_blink (bool onoff)
1131 if (_session == 0) {
1135 if (_session->is_auditioning()) {
1136 rude_audition_button.set_active (onoff);
1138 rude_audition_button.set_active (false);
1143 MonitorSection::solo_blink (bool onoff)
1145 if (_session == 0) {
1149 if (_session->soloing() || _session->listening()) {
1150 rude_solo_button.set_active (onoff);
1152 if (_session->soloing()) {
1153 if (_session->solo_isolated()) {
1154 rude_iso_button.set_active (onoff);
1156 rude_iso_button.set_active (false);
1161 rude_solo_button.set_active (false);
1162 rude_iso_button.set_active (false);
1167 MonitorSection::cancel_isolate (GdkEventButton*)
1170 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1171 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1178 MonitorSection::cancel_audition (GdkEventButton*)
1181 _session->cancel_audition();
1186 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1188 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1189 if (tact && tact->get_active() != value) { \
1190 tact->set_active(value); \
1195 MonitorSection::parameter_changed (std::string name)
1197 if (name == "solo-control-is-listen-control") {
1198 update_solo_model ();
1199 } else if (name == "listen-position") {
1200 update_solo_model ();
1201 } else if (name == "solo-mute-override") {
1202 SYNCHRONIZE_TOGGLE_ACTION(
1203 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1204 Config->get_solo_mute_override ())
1205 } else if (name == "exclusive-solo") {
1206 SYNCHRONIZE_TOGGLE_ACTION(
1207 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1208 Config->get_exclusive_solo ())
1213 MonitorSection::assign_controllables ()
1215 boost::shared_ptr<Controllable> none;
1217 if (!gain_control) {
1218 /* too early - GUI controls not set up yet */
1223 solo_cut_control->set_controllable (_session->solo_cut_control());
1224 solo_cut_display->set_controllable (_session->solo_cut_control());
1226 solo_cut_control->set_controllable (none);
1227 solo_cut_display->set_controllable (none);
1231 gain_control->set_controllable (_route->gain_control());
1232 gain_display->set_controllable (_route->gain_control());
1234 gain_control->set_controllable (none);
1239 cut_all_button.set_controllable (_monitor->cut_control());
1240 cut_all_button.watch ();
1241 dim_all_button.set_controllable (_monitor->dim_control());
1242 dim_all_button.watch ();
1243 mono_button.set_controllable (_monitor->mono_control());
1244 mono_button.watch ();
1246 dim_control->set_controllable (_monitor->dim_level_control ());
1247 dim_display->set_controllable (_monitor->dim_level_control ());
1248 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1249 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1253 cut_all_button.set_controllable (none);
1254 dim_all_button.set_controllable (none);
1255 mono_button.set_controllable (none);
1257 dim_control->set_controllable (none);
1258 dim_display->set_controllable (none);
1259 solo_boost_control->set_controllable (none);
1260 solo_boost_display->set_controllable (none);
1265 MonitorSection::state_id() const
1267 return "monitor-section";
1271 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1273 using namespace Menu_Helpers;
1275 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1279 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1280 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1284 if (i != output_menu_bundles.end()) {
1288 output_menu_bundles.push_back (b);
1290 MenuList& citems = output_menu.items();
1292 std::string n = b->name ();
1293 replace_all (n, "_", " ");
1295 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1299 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1302 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1304 if (std::find (current.begin(), current.end(), c) == current.end()) {
1305 _route->output()->connect_ports_to_bundle (c, true, this);
1307 _route->output()->disconnect_ports_from_bundle (c, this);
1312 MonitorSection::output_release (GdkEventButton *ev)
1314 switch (ev->button) {
1316 edit_output_configuration ();
1323 struct RouteCompareByName {
1324 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1325 return a->name().compare (b->name()) < 0;
1330 MonitorSection::output_press (GdkEventButton *ev)
1332 using namespace Menu_Helpers;
1334 MessageDialog msg (_("No session - no I/O changes are possible"));
1339 MenuList& citems = output_menu.items();
1340 switch (ev->button) {
1343 return false; //wait for the mouse-up to pop the dialog
1347 output_menu.set_name ("ArdourContextMenu");
1349 output_menu_bundles.clear ();
1351 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1353 citems.push_back (SeparatorElem());
1354 uint32_t const n_with_separator = citems.size ();
1356 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1358 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1360 /* give user bundles first chance at being in the menu */
1362 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1363 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1364 maybe_add_bundle_to_output_menu (*i, current);
1368 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1369 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1370 maybe_add_bundle_to_output_menu (*i, current);
1374 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1375 RouteList copy = *routes;
1376 copy.sort (RouteCompareByName ());
1377 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1378 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1381 if (citems.size() == n_with_separator) {
1382 /* no routes added; remove the separator */
1386 citems.push_back (SeparatorElem());
1387 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1389 output_menu.popup (1, ev->time);
1400 MonitorSection::update_output_display ()
1402 if (!_route || !_monitor || _session->deletion_in_progress()) {
1408 boost::shared_ptr<Port> port;
1409 vector<string> port_connections;
1411 uint32_t total_connection_count = 0;
1412 uint32_t io_connection_count = 0;
1413 uint32_t ardour_connection_count = 0;
1414 uint32_t system_connection_count = 0;
1415 uint32_t other_connection_count = 0;
1417 ostringstream label;
1419 bool have_label = false;
1420 bool each_io_has_one_connection = true;
1422 string connection_name;
1423 string ardour_track_name;
1424 string other_connection_type;
1425 string system_ports;
1428 ostringstream tooltip;
1429 char * tooltip_cstr;
1431 io_count = _route->n_outputs().n_total();
1432 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1435 for (io_index = 0; io_index < io_count; ++io_index) {
1437 port = _route->output()->nth (io_index);
1439 //ignore any port connections that don't match our DataType
1440 if (port->type() != DataType::AUDIO) {
1444 port_connections.clear ();
1445 port->get_connections(port_connections);
1446 io_connection_count = 0;
1448 if (!port_connections.empty()) {
1449 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1451 string& connection_name (*i);
1453 if (connection_name.find("system:") == 0) {
1454 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1457 if (io_connection_count == 0) {
1458 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1460 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1463 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1466 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1467 if (ardour_track_name.empty()) {
1468 // "ardour:Master/in 1" -> "ardour:Master/"
1469 string::size_type slash = connection_name.find("/");
1470 if (slash != string::npos) {
1471 ardour_track_name = connection_name.substr(0, slash + 1);
1475 if (connection_name.find(ardour_track_name) == 0) {
1476 ++ardour_connection_count;
1478 } else if (!pn.empty()) {
1479 if (system_ports.empty()) {
1482 system_ports += "/" + pn;
1484 if (connection_name.find("system:") == 0) {
1485 ++system_connection_count;
1487 } else if (connection_name.find("system:") == 0) {
1488 // "system:playback_123" -> "123"
1489 system_port = connection_name.substr(16);
1490 if (system_ports.empty()) {
1491 system_ports += system_port;
1493 system_ports += "/" + system_port;
1496 ++system_connection_count;
1498 if (other_connection_type.empty()) {
1499 // "jamin:in 1" -> "jamin:"
1500 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1503 if (connection_name.find(other_connection_type) == 0) {
1504 ++other_connection_count;
1508 ++total_connection_count;
1509 ++io_connection_count;
1513 if (io_connection_count != 1) {
1514 each_io_has_one_connection = false;
1518 if (total_connection_count == 0) {
1519 tooltip << endl << _("Disconnected");
1522 tooltip_cstr = new char[tooltip.str().size() + 1];
1523 strcpy(tooltip_cstr, tooltip.str().c_str());
1525 set_tooltip (output_button, tooltip_cstr, "");
1527 if (each_io_has_one_connection) {
1528 if (total_connection_count == ardour_connection_count) {
1529 // all connections are to the same track in ardour
1530 // "ardour:Master/" -> "Master"
1531 string::size_type slash = ardour_track_name.find("/");
1532 if (slash != string::npos) {
1533 label << ardour_track_name.substr(7, slash - 7);
1536 } else if (total_connection_count == system_connection_count) {
1537 // all connections are to system ports
1538 label << system_ports;
1540 } else if (total_connection_count == other_connection_count) {
1541 // all connections are to the same external program eg jamin
1542 // "jamin:" -> "jamin"
1543 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1549 if (total_connection_count == 0) {
1553 // Odd configuration
1554 label << "*" << total_connection_count << "*";
1558 output_button->set_text (label.str());
1562 MonitorSection::disconnect_output ()
1565 _route->output()->disconnect(this);
1570 MonitorSection::edit_output_configuration ()
1572 if (_output_selector == 0) {
1573 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1575 _output_selector->present ();
1579 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1584 boost::shared_ptr<Port> a = wa.lock ();
1585 boost::shared_ptr<Port> b = wb.lock ();
1586 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1587 update_output_display ();
1592 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1594 boost::shared_ptr<Processor> processor (p.lock ());
1595 if (!processor || !processor->display_to_user()) {
1598 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1605 MonitorSection::count_processors ()
1607 uint32_t processor_count = 0;
1609 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1611 return processor_count;
1615 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1617 update_processor_box ();