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);
683 act = ActionManager::get_action (X_("Monitor"), buf);
685 cbs->cut.set_related_action (act);
688 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
689 act = ActionManager::get_action (X_("Monitor"), buf);
691 cbs->dim.set_related_action (act);
694 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
695 act = ActionManager::get_action (X_("Monitor"), buf);
697 cbs->solo.set_related_action (act);
700 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
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 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
794 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
795 _monitor->set_cut (chn, tact->get_active());
800 MonitorSection::dim_channel (uint32_t chn)
807 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
809 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
811 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
812 _monitor->set_dim (chn, tact->get_active());
818 MonitorSection::solo_channel (uint32_t chn)
825 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
827 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
829 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
830 _monitor->set_solo (chn, tact->get_active());
836 MonitorSection::invert_channel (uint32_t chn)
843 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
845 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
847 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
848 _monitor->set_polarity (chn, tact->get_active());
853 MonitorSection::register_actions ()
857 Glib::RefPtr<Action> act;
859 monitor_actions = ActionGroup::create (X_("Monitor"));
860 ActionManager::add_action_group (monitor_actions);
862 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
863 sigc::mem_fun (*this, &MonitorSection::mono));
865 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
866 sigc::mem_fun (*this, &MonitorSection::cut_all));
868 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
869 sigc::mem_fun (*this, &MonitorSection::dim_all));
871 act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
872 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
874 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
875 tact->set_active (Config->get_exclusive_solo());
877 act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
878 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
880 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
881 tact->set_active (Config->get_solo_mute_override());
884 for (uint32_t chn = 0; chn < 16; ++chn) {
886 action_name = string_compose (X_("monitor-cut-%1"), chn);
887 action_descr = string_compose (_("Cut monitor channel %1"), chn);
888 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
889 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
891 action_name = string_compose (X_("monitor-dim-%1"), chn);
892 action_descr = string_compose (_("Dim monitor channel %1"), chn);
893 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
894 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
896 action_name = string_compose (X_("monitor-solo-%1"), chn);
897 action_descr = string_compose (_("Solo 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::solo_channel), chn));
901 action_name = string_compose (X_("monitor-invert-%1"), chn);
902 action_descr = string_compose (_("Invert 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::invert_channel), chn));
909 Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
910 RadioAction::Group solo_group;
912 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
913 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
914 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
915 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
916 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
917 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
919 ActionManager::add_action_group (solo_actions);
923 MonitorSection::solo_use_in_place ()
925 /* this is driven by a toggle on a radio group, and so is invoked twice,
926 once for the item that became inactive and once for the one that became
930 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
933 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
935 if (!ract->get_active ()) {
936 /* We are turning SiP off, which means that AFL or PFL will be turned on
937 shortly; don't update the solo model in the mean time, as if the currently
938 configured listen position is not the one that is about to be turned on,
939 things will go wrong.
941 _inhibit_solo_model_update = true;
943 Config->set_solo_control_is_listen_control (!ract->get_active());
944 _inhibit_solo_model_update = false;
950 MonitorSection::solo_use_afl ()
952 /* this is driven by a toggle on a radio group, and so is invoked twice,
953 once for the item that became inactive and once for the one that became
957 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
959 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
961 if (ract->get_active()) {
962 Config->set_solo_control_is_listen_control (true);
963 Config->set_listen_position (AfterFaderListen);
970 MonitorSection::solo_use_pfl ()
972 /* this is driven by a toggle on a radio group, and so is invoked twice,
973 once for the item that became inactive and once for the one that became
977 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
979 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
981 if (ract->get_active()) {
982 Config->set_solo_control_is_listen_control (true);
983 Config->set_listen_position (PreFaderListen);
990 MonitorSection::update_solo_model ()
992 if (_inhibit_solo_model_update) {
996 const char* action_name = 0;
997 Glib::RefPtr<Action> act;
999 if (Config->get_solo_control_is_listen_control()) {
1000 switch (Config->get_listen_position()) {
1001 case AfterFaderListen:
1002 action_name = X_("solo-use-afl");
1004 case PreFaderListen:
1005 action_name = X_("solo-use-pfl");
1009 action_name = X_("solo-use-in-place");
1012 act = ActionManager::get_action (X_("Solo"), action_name);
1015 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1017 /* because these are radio buttons, one of them will be
1018 active no matter what. to trigger a change in the
1019 action so that the view picks it up, toggle it.
1021 if (ract->get_active()) {
1022 ract->set_active (false);
1024 ract->set_active (true);
1031 MonitorSection::map_state ()
1033 if (!_route || !_monitor) {
1037 Glib::RefPtr<Action> act;
1039 update_solo_model ();
1041 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1043 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1045 tact->set_active (_monitor->cut_all());
1049 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1051 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1053 tact->set_active (_monitor->dim_all());
1057 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1059 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1061 tact->set_active (_monitor->mono());
1065 uint32_t nchans = _monitor->output_streams().n_audio();
1067 assert (nchans == _channel_buttons.size ());
1069 for (uint32_t n = 0; n < nchans; ++n) {
1071 char action_name[32];
1073 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1074 act = ActionManager::get_action (X_("Monitor"), action_name);
1076 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1078 tact->set_active (_monitor->cut (n));
1082 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1083 act = ActionManager::get_action (X_("Monitor"), action_name);
1085 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1087 tact->set_active (_monitor->dimmed (n));
1091 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1092 act = ActionManager::get_action (X_("Monitor"), action_name);
1094 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1096 tact->set_active (_monitor->soloed (n));
1100 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1101 act = ActionManager::get_action (X_("Monitor"), action_name);
1103 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1105 tact->set_active (_monitor->inverted (n));
1112 MonitorSection::do_blink (bool onoff)
1115 audition_blink (onoff);
1119 MonitorSection::audition_blink (bool onoff)
1121 if (_session == 0) {
1125 if (_session->is_auditioning()) {
1126 rude_audition_button.set_active (onoff);
1128 rude_audition_button.set_active (false);
1133 MonitorSection::solo_blink (bool onoff)
1135 if (_session == 0) {
1139 if (_session->soloing() || _session->listening()) {
1140 rude_solo_button.set_active (onoff);
1142 if (_session->soloing()) {
1143 if (_session->solo_isolated()) {
1144 rude_iso_button.set_active (onoff);
1146 rude_iso_button.set_active (false);
1151 rude_solo_button.set_active (false);
1152 rude_iso_button.set_active (false);
1157 MonitorSection::cancel_isolate (GdkEventButton*)
1160 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1161 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1168 MonitorSection::cancel_audition (GdkEventButton*)
1171 _session->cancel_audition();
1176 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1178 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1179 if (tact && tact->get_active() != value) { \
1180 tact->set_active(value); \
1185 MonitorSection::parameter_changed (std::string name)
1187 if (name == "solo-control-is-listen-control") {
1188 update_solo_model ();
1189 } else if (name == "listen-position") {
1190 update_solo_model ();
1191 } else if (name == "solo-mute-override") {
1192 SYNCHRONIZE_TOGGLE_ACTION(
1193 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1194 Config->get_solo_mute_override ())
1195 } else if (name == "exclusive-solo") {
1196 SYNCHRONIZE_TOGGLE_ACTION(
1197 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1198 Config->get_exclusive_solo ())
1203 MonitorSection::assign_controllables ()
1205 boost::shared_ptr<Controllable> none;
1207 if (!gain_control) {
1208 /* too early - GUI controls not set up yet */
1213 solo_cut_control->set_controllable (_session->solo_cut_control());
1214 solo_cut_display->set_controllable (_session->solo_cut_control());
1216 solo_cut_control->set_controllable (none);
1217 solo_cut_display->set_controllable (none);
1221 gain_control->set_controllable (_route->gain_control());
1222 gain_display->set_controllable (_route->gain_control());
1224 gain_control->set_controllable (none);
1229 cut_all_button.set_controllable (_monitor->cut_control());
1230 cut_all_button.watch ();
1231 dim_all_button.set_controllable (_monitor->dim_control());
1232 dim_all_button.watch ();
1233 mono_button.set_controllable (_monitor->mono_control());
1234 mono_button.watch ();
1236 dim_control->set_controllable (_monitor->dim_level_control ());
1237 dim_display->set_controllable (_monitor->dim_level_control ());
1238 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1239 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1243 cut_all_button.set_controllable (none);
1244 dim_all_button.set_controllable (none);
1245 mono_button.set_controllable (none);
1247 dim_control->set_controllable (none);
1248 dim_display->set_controllable (none);
1249 solo_boost_control->set_controllable (none);
1250 solo_boost_display->set_controllable (none);
1255 MonitorSection::state_id() const
1257 return "monitor-section";
1261 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1263 using namespace Menu_Helpers;
1265 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1269 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1270 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1274 if (i != output_menu_bundles.end()) {
1278 output_menu_bundles.push_back (b);
1280 MenuList& citems = output_menu.items();
1282 std::string n = b->name ();
1283 replace_all (n, "_", " ");
1285 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1289 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1292 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1294 if (std::find (current.begin(), current.end(), c) == current.end()) {
1295 _route->output()->connect_ports_to_bundle (c, true, this);
1297 _route->output()->disconnect_ports_from_bundle (c, this);
1302 MonitorSection::output_release (GdkEventButton *ev)
1304 switch (ev->button) {
1306 edit_output_configuration ();
1313 struct RouteCompareByName {
1314 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1315 return a->name().compare (b->name()) < 0;
1320 MonitorSection::output_press (GdkEventButton *ev)
1322 using namespace Menu_Helpers;
1324 MessageDialog msg (_("No session - no I/O changes are possible"));
1329 MenuList& citems = output_menu.items();
1330 switch (ev->button) {
1333 return false; //wait for the mouse-up to pop the dialog
1337 output_menu.set_name ("ArdourContextMenu");
1339 output_menu_bundles.clear ();
1341 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1343 citems.push_back (SeparatorElem());
1344 uint32_t const n_with_separator = citems.size ();
1346 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1348 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1350 /* give user bundles first chance at being in the menu */
1352 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1353 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1354 maybe_add_bundle_to_output_menu (*i, current);
1358 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1359 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1360 maybe_add_bundle_to_output_menu (*i, current);
1364 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1365 RouteList copy = *routes;
1366 copy.sort (RouteCompareByName ());
1367 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1368 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1371 if (citems.size() == n_with_separator) {
1372 /* no routes added; remove the separator */
1376 citems.push_back (SeparatorElem());
1377 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1379 output_menu.popup (1, ev->time);
1390 MonitorSection::update_output_display ()
1392 if (!_route || !_monitor || _session->deletion_in_progress()) {
1398 boost::shared_ptr<Port> port;
1399 vector<string> port_connections;
1401 uint32_t total_connection_count = 0;
1402 uint32_t io_connection_count = 0;
1403 uint32_t ardour_connection_count = 0;
1404 uint32_t system_connection_count = 0;
1405 uint32_t other_connection_count = 0;
1407 ostringstream label;
1409 bool have_label = false;
1410 bool each_io_has_one_connection = true;
1412 string connection_name;
1413 string ardour_track_name;
1414 string other_connection_type;
1415 string system_ports;
1418 ostringstream tooltip;
1419 char * tooltip_cstr;
1421 io_count = _route->n_outputs().n_total();
1422 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1425 for (io_index = 0; io_index < io_count; ++io_index) {
1427 port = _route->output()->nth (io_index);
1429 //ignore any port connections that don't match our DataType
1430 if (port->type() != DataType::AUDIO) {
1434 port_connections.clear ();
1435 port->get_connections(port_connections);
1436 io_connection_count = 0;
1438 if (!port_connections.empty()) {
1439 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1441 string& connection_name (*i);
1443 if (connection_name.find("system:") == 0) {
1444 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1447 if (io_connection_count == 0) {
1448 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1450 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1453 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1456 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1457 if (ardour_track_name.empty()) {
1458 // "ardour:Master/in 1" -> "ardour:Master/"
1459 string::size_type slash = connection_name.find("/");
1460 if (slash != string::npos) {
1461 ardour_track_name = connection_name.substr(0, slash + 1);
1465 if (connection_name.find(ardour_track_name) == 0) {
1466 ++ardour_connection_count;
1468 } else if (!pn.empty()) {
1469 if (system_ports.empty()) {
1472 system_ports += "/" + pn;
1474 if (connection_name.find("system:") == 0) {
1475 ++system_connection_count;
1477 } else if (connection_name.find("system:") == 0) {
1478 // "system:playback_123" -> "123"
1479 system_port = connection_name.substr(16);
1480 if (system_ports.empty()) {
1481 system_ports += system_port;
1483 system_ports += "/" + system_port;
1486 ++system_connection_count;
1488 if (other_connection_type.empty()) {
1489 // "jamin:in 1" -> "jamin:"
1490 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1493 if (connection_name.find(other_connection_type) == 0) {
1494 ++other_connection_count;
1498 ++total_connection_count;
1499 ++io_connection_count;
1503 if (io_connection_count != 1) {
1504 each_io_has_one_connection = false;
1508 if (total_connection_count == 0) {
1509 tooltip << endl << _("Disconnected");
1512 tooltip_cstr = new char[tooltip.str().size() + 1];
1513 strcpy(tooltip_cstr, tooltip.str().c_str());
1515 set_tooltip (output_button, tooltip_cstr, "");
1517 if (each_io_has_one_connection) {
1518 if (total_connection_count == ardour_connection_count) {
1519 // all connections are to the same track in ardour
1520 // "ardour:Master/" -> "Master"
1521 string::size_type slash = ardour_track_name.find("/");
1522 if (slash != string::npos) {
1523 label << ardour_track_name.substr(7, slash - 7);
1526 } else if (total_connection_count == system_connection_count) {
1527 // all connections are to system ports
1528 label << system_ports;
1530 } else if (total_connection_count == other_connection_count) {
1531 // all connections are to the same external program eg jamin
1532 // "jamin:" -> "jamin"
1533 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1539 if (total_connection_count == 0) {
1543 // Odd configuration
1544 label << "*" << total_connection_count << "*";
1548 output_button->set_text (label.str());
1552 MonitorSection::disconnect_output ()
1555 _route->output()->disconnect(this);
1560 MonitorSection::edit_output_configuration ()
1562 if (_output_selector == 0) {
1563 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1565 _output_selector->present ();
1569 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1574 boost::shared_ptr<Port> a = wa.lock ();
1575 boost::shared_ptr<Port> b = wb.lock ();
1576 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1577 update_output_display ();
1582 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1584 boost::shared_ptr<Processor> processor (p.lock ());
1585 if (!processor || !processor->display_to_user()) {
1588 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1595 MonitorSection::count_processors ()
1597 uint32_t processor_count = 0;
1599 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1601 return processor_count;
1605 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1607 update_processor_box ();