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 "ardour_ui.h"
43 #include "gui_thread.h"
44 #include "monitor_section.h"
45 #include "public_editor.h"
48 #include "ui_config.h"
53 using namespace ARDOUR;
54 using namespace ARDOUR_UI_UTILS;
56 using namespace Gtkmm2ext;
60 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
62 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
64 MonitorSection::MonitorSection (Session* s)
68 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
69 , *channel_table_scroller.get_vadjustment ())
72 , solo_boost_control (0)
73 , solo_cut_control (0)
76 , solo_boost_display (0)
77 , solo_cut_display (0)
78 , _output_selector (0)
79 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
80 , afl_button (_("AFL"), ArdourButton::led_default_elements)
81 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
82 , exclusive_solo_button (ArdourButton::led_default_elements)
83 , solo_mute_override_button (ArdourButton::led_default_elements)
84 , toggle_processorbox_button (ArdourButton::default_elements)
85 , _inhibit_solo_model_update (false)
86 , _ui_initialized (false)
87 , myactions (X_("monitor section"))
91 using namespace Menu_Helpers;
93 Glib::RefPtr<Action> act;
95 if (!monitor_actions) {
99 set_data ("ardour-bindings", bindings);
103 _plugin_selector = new PluginSelector (PluginManager::instance());
104 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
105 insert_box->set_no_show_all ();
107 // TODO allow keyboard shortcuts in ProcessorBox
111 /* Rude Solo & Solo Isolated */
112 rude_solo_button.set_text (_("Soloing"));
113 rude_solo_button.set_name ("rude solo");
114 rude_solo_button.show ();
116 rude_iso_button.set_text (_("Isolated"));
117 rude_iso_button.set_name ("rude isolate");
118 rude_iso_button.show ();
120 rude_audition_button.set_text (_("Auditioning"));
121 rude_audition_button.set_name ("rude audition");
122 rude_audition_button.show ();
124 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
126 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
127 rude_solo_button.set_related_action (act);
128 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
130 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
131 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
133 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
134 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
136 /* SIP, AFL, PFL radio */
138 solo_in_place_button.set_name ("monitor section solo model");
139 afl_button.set_name ("monitor section solo model");
140 pfl_button.set_name ("monitor section solo model");
142 solo_in_place_button.set_led_left (true);
143 afl_button.set_led_left (true);
144 pfl_button.set_led_left (true);
146 solo_in_place_button.show ();
150 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
151 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
153 solo_in_place_button.set_related_action (act);
156 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
157 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
159 afl_button.set_related_action (act);
162 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
163 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
165 pfl_button.set_related_action (act);
168 /* Solo option buttons */
169 exclusive_solo_button.set_text (_("Excl. Solo"));
170 exclusive_solo_button.set_name (X_("monitor section solo option"));
171 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
173 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
175 exclusive_solo_button.set_related_action (act);
178 solo_mute_override_button.set_text (_("Solo ยป Mute"));
179 solo_mute_override_button.set_name (X_("monitor section solo option"));
180 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
182 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
184 solo_mute_override_button.set_related_action (act);
187 /* Processor Box hide/shos */
188 toggle_processorbox_button.set_text (_("Processors"));
189 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
190 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
192 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
193 toggle_processorbox_button.set_related_action (proctoggle);
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);
438 gain_control->show_all ();
439 gain_display->show_all ();
440 dim_control->show_all ();
441 dim_display->show_all();
442 solo_boost_control->show_all ();
443 solo_boost_display->show_all();
445 mono_dim_box->show ();
446 spin_packer->show ();
447 master_packer.show ();
448 channel_table.show ();
451 solo_tbl->show_all();
453 lower_packer->show ();
461 assign_controllables ();
463 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
464 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
466 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
467 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
468 set_flags (CAN_FOCUS);
470 _tearoff = new TearOff (*this);
472 if (!UIConfiguration::instance().get_floating_monitor_section()) {
473 /* if torn off, make this a normal window
474 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
476 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
478 _tearoff->tearoff_window().set_title (X_("Monitor"));
479 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
481 update_output_display ();
482 update_processor_box ();
483 _ui_initialized = true;
485 /* catch changes that affect us */
486 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
487 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
489 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
492 MonitorSection::~MonitorSection ()
494 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
498 _channel_buttons.clear ();
499 _output_changed_connection.disconnect ();
501 delete insert_box; insert_box = 0;
502 delete output_button; output_button = 0;
503 delete gain_control; gain_control = 0;
504 delete gain_display; gain_display = 0;
505 delete dim_control; dim_control = 0;
506 delete dim_display; dim_display = 0;
507 delete solo_boost_control; solo_boost_control = 0;
508 delete solo_boost_display; solo_boost_display = 0;
509 delete solo_cut_control; solo_cut_control = 0;
510 delete solo_cut_display; solo_cut_display = 0;
511 delete _tearoff; _tearoff = 0;
512 delete _output_selector; _output_selector = 0;
516 MonitorSection::enter_handler (GdkEventCrossing* ev)
523 MonitorSection::leave_handler (GdkEventCrossing* ev)
525 switch (ev->detail) {
526 case GDK_NOTIFY_INFERIOR:
532 /* cancel focus if we're not torn off. With X11 WM's that do
533 * focus-follows-mouse, focus will be taken from us anyway.
536 Widget* top = get_toplevel();
538 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
539 Window* win = dynamic_cast<Window*> (top);
540 gtk_window_set_focus (win->gobj(), 0);
547 MonitorSection::update_processor_box ()
549 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
551 if (count_processors () > 0 && !show_processor_box) {
552 toggle_processorbox_button.set_name (X_("monitor section processors present"));
554 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
557 if (insert_box->is_visible() == show_processor_box) {
561 if (show_processor_box) {
562 if (master_packer.get_parent()) {
563 master_packer.get_parent()->remove (master_packer);
566 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
568 if (master_packer.get_parent()) {
569 master_packer.get_parent()->remove (master_packer);
572 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
577 MonitorSection::set_session (Session* s)
579 AxisView::set_session (s);
580 _plugin_selector->set_session (_session);
584 _route = _session->monitor_out ();
587 /* session with monitor section */
588 _monitor = _route->monitor_control ();
589 assign_controllables ();
590 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
591 boost::bind (&MonitorSection::update_output_display, this),
593 insert_box->set_route (_route);
594 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
595 if (_ui_initialized) {
596 update_processor_box ();
599 /* session with no monitor section */
600 _output_changed_connection.disconnect();
603 delete _output_selector;
604 _output_selector = 0;
607 if (channel_table_scroller.get_parent()) {
608 /* scroller is packed, so remove it */
609 channel_table_packer.remove (channel_table_scroller);
612 if (table_hpacker.get_parent () == &channel_table_packer) {
613 /* this occurs when the table hpacker is directly
614 packed, so remove it.
616 channel_table_packer.remove (table_hpacker);
617 } else if (table_hpacker.get_parent()) {
618 channel_table_viewport.remove ();
621 if (_monitor->output_streams().n_audio() > 7) {
622 /* put the table into a scrolled window, and then put
623 * that into the channel vpacker, after the table header
625 channel_table_viewport.add (table_hpacker);
626 channel_table_packer.pack_start (channel_table_scroller, true, true);
627 channel_table_viewport.show ();
628 channel_table_scroller.show ();
631 /* just put the channel table itself into the channel
632 * vpacker, after the table header
635 channel_table_packer.pack_start (table_hpacker, true, true);
636 channel_table_scroller.hide ();
639 table_hpacker.show ();
640 channel_table.show ();
645 _output_changed_connection.disconnect();
648 control_connections.drop_connections ();
649 rude_iso_button.unset_active_state ();
650 rude_solo_button.unset_active_state ();
651 delete _output_selector;
652 _output_selector = 0;
654 assign_controllables ();
658 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
660 cut.set_name (X_("mute button"));
661 dim.set_name (X_("monitor section dim"));
662 solo.set_name (X_("solo button"));
663 invert.set_name (X_("invert button"));
665 cut.unset_flags (Gtk::CAN_FOCUS);
666 dim.unset_flags (Gtk::CAN_FOCUS);
667 solo.unset_flags (Gtk::CAN_FOCUS);
668 invert.unset_flags (Gtk::CAN_FOCUS);
672 MonitorSection::populate_buttons ()
678 Glib::RefPtr<Action> act;
679 uint32_t nchans = _monitor->output_streams().n_audio();
681 channel_table.resize (nchans, 5);
682 channel_table.set_col_spacings (6);
683 channel_table.set_row_spacings (6);
684 channel_table.set_homogeneous (true);
686 const uint32_t row_offset = 0;
688 for (uint32_t i = 0; i < nchans; ++i) {
701 snprintf (buf, sizeof (buf), "%d", i+1);
705 Label* label = manage (new Label (l));
706 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
708 ChannelButtonSet* cbs = new ChannelButtonSet;
710 _channel_buttons.push_back (cbs);
712 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
713 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
714 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
715 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
717 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
718 act = ActionManager::get_action (X_("Monitor"), buf);
720 cbs->cut.set_related_action (act);
723 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
724 act = ActionManager::get_action (X_("Monitor"), buf);
726 cbs->dim.set_related_action (act);
729 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
730 act = ActionManager::get_action (X_("Monitor"), buf);
732 cbs->solo.set_related_action (act);
735 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
736 act = ActionManager::get_action (X_("Monitor"), buf);
738 cbs->invert.set_related_action (act);
742 channel_table.show_all ();
746 MonitorSection::toggle_exclusive_solo ()
752 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
754 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
755 Config->set_exclusive_solo (tact->get_active());
761 MonitorSection::toggle_mute_overrides_solo ()
767 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
769 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
770 Config->set_solo_mute_override (tact->get_active());
775 MonitorSection::dim_all ()
781 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
783 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
784 _monitor->set_dim_all (tact->get_active());
790 MonitorSection::cut_all ()
796 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
798 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
799 _monitor->set_cut_all (tact->get_active());
804 MonitorSection::mono ()
810 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
812 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
813 _monitor->set_mono (tact->get_active());
818 MonitorSection::cut_channel (uint32_t chn)
825 snprintf (buf, sizeof (buf), "monitor-cut-%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_cut (chn, tact->get_active());
835 MonitorSection::dim_channel (uint32_t chn)
842 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
844 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
846 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
847 _monitor->set_dim (chn, tact->get_active());
853 MonitorSection::solo_channel (uint32_t chn)
860 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
862 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
864 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
865 _monitor->set_solo (chn, tact->get_active());
871 MonitorSection::invert_channel (uint32_t chn)
878 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
880 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
882 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
883 _monitor->set_polarity (chn, tact->get_active());
888 MonitorSection::register_actions ()
892 Glib::RefPtr<Action> act;
894 monitor_actions = myactions.create_action_group (X_("Monitor"));
896 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
897 sigc::mem_fun (*this, &MonitorSection::mono));
899 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
900 sigc::mem_fun (*this, &MonitorSection::cut_all));
902 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
903 sigc::mem_fun (*this, &MonitorSection::dim_all));
905 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
906 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
908 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
909 tact->set_active (Config->get_exclusive_solo());
911 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
912 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
914 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
915 tact->set_active (Config->get_solo_mute_override());
917 for (uint32_t chn = 0; chn < 16; ++chn) {
919 action_name = string_compose (X_("monitor-cut-%1"), chn);
920 action_descr = string_compose (_("Cut monitor channel %1"), chn);
921 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
922 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
924 action_name = string_compose (X_("monitor-dim-%1"), chn);
925 action_descr = string_compose (_("Dim monitor channel %1"), chn);
926 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
927 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
929 action_name = string_compose (X_("monitor-solo-%1"), chn);
930 action_descr = string_compose (_("Solo monitor channel %1"), chn);
931 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
932 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
934 action_name = string_compose (X_("monitor-invert-%1"), chn);
935 action_descr = string_compose (_("Invert monitor channel %1"), chn);
936 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
937 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
942 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
943 RadioAction::Group solo_group;
945 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
946 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
947 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
948 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
949 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
950 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
952 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
953 sigc::mem_fun(*this, &MonitorSection::update_processor_box));
957 MonitorSection::connect_actions ()
959 Glib::RefPtr<Action> act;
960 Glib::RefPtr<ToggleAction> tact;
962 #define MON_TOG(NAME, FUNC) \
963 act = ActionManager::get_action (X_("Monitor"), NAME); \
964 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
966 tact->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
968 MON_TOG("monitor-mono", mono);
969 MON_TOG("monitor-cut-all", cut_all);
970 MON_TOG("monitor-dim-all", dim_all);
972 MON_TOG("toggle-exclusive-solo", toggle_exclusive_solo);
973 tact->set_active (Config->get_exclusive_solo());
975 MON_TOG("toggle-mute-overrides-solo", toggle_mute_overrides_solo);
976 tact->set_active (Config->get_solo_mute_override());
979 #define MON_BIND(NAME, FUNC, ARG) \
980 act = ActionManager::get_action (X_("Monitor"), NAME); \
981 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
983 tact->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::FUNC), ARG));
985 for (uint32_t chn = 0; chn < 16; ++chn) {
986 std::string action_name = string_compose (X_("monitor-cut-%1"), chn);
987 MON_BIND(action_name.c_str(), cut_channel, chn);
988 action_name = string_compose (X_("monitor-dim-%1"), chn);
989 MON_BIND(action_name.c_str(), dim_channel, chn);
990 action_name = string_compose (X_("monitor-solo-%1"), chn);
991 MON_BIND(action_name.c_str(), solo_channel, chn);
992 action_name = string_compose (X_("monitor-invert-%1"), chn);
993 MON_BIND(action_name.c_str(), invert_channel, chn);
997 #define SOLO_RADIO(NAME, FUNC) \
998 act = ActionManager::get_action (X_("Solo"), NAME); \
999 ract = Glib::RefPtr<RadioAction>::cast_dynamic (act); \
1001 ract->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
1003 Glib::RefPtr<RadioAction> ract;
1004 SOLO_RADIO ("solo-use-in-place", solo_use_in_place);
1005 SOLO_RADIO ("solo-use-afl", solo_use_afl);
1006 SOLO_RADIO ("solo-use-pfl", solo_use_pfl);
1011 MonitorSection::solo_use_in_place ()
1013 /* this is driven by a toggle on a radio group, and so is invoked twice,
1014 once for the item that became inactive and once for the one that became
1018 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
1021 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1023 if (!ract->get_active ()) {
1024 /* We are turning SiP off, which means that AFL or PFL will be turned on
1025 shortly; don't update the solo model in the mean time, as if the currently
1026 configured listen position is not the one that is about to be turned on,
1027 things will go wrong.
1029 _inhibit_solo_model_update = true;
1031 Config->set_solo_control_is_listen_control (!ract->get_active());
1032 _inhibit_solo_model_update = false;
1038 MonitorSection::solo_use_afl ()
1040 /* this is driven by a toggle on a radio group, and so is invoked twice,
1041 once for the item that became inactive and once for the one that became
1045 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1047 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1049 if (ract->get_active()) {
1050 Config->set_solo_control_is_listen_control (true);
1051 Config->set_listen_position (AfterFaderListen);
1058 MonitorSection::solo_use_pfl ()
1060 /* this is driven by a toggle on a radio group, and so is invoked twice,
1061 once for the item that became inactive and once for the one that became
1065 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1067 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1069 if (ract->get_active()) {
1070 Config->set_solo_control_is_listen_control (true);
1071 Config->set_listen_position (PreFaderListen);
1078 MonitorSection::update_solo_model ()
1080 if (_inhibit_solo_model_update) {
1084 const char* action_name = 0;
1085 Glib::RefPtr<Action> act;
1087 if (Config->get_solo_control_is_listen_control()) {
1088 switch (Config->get_listen_position()) {
1089 case AfterFaderListen:
1090 action_name = X_("solo-use-afl");
1092 case PreFaderListen:
1093 action_name = X_("solo-use-pfl");
1097 action_name = X_("solo-use-in-place");
1100 act = ActionManager::get_action (X_("Solo"), action_name);
1103 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1105 /* because these are radio buttons, one of them will be
1106 active no matter what. to trigger a change in the
1107 action so that the view picks it up, toggle it.
1109 if (ract->get_active()) {
1110 ract->set_active (false);
1112 ract->set_active (true);
1119 MonitorSection::map_state ()
1121 if (!_route || !_monitor) {
1125 Glib::RefPtr<Action> act;
1127 update_solo_model ();
1129 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1131 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1133 tact->set_active (_monitor->cut_all());
1137 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1139 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1141 tact->set_active (_monitor->dim_all());
1145 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1147 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1149 tact->set_active (_monitor->mono());
1153 uint32_t nchans = _monitor->output_streams().n_audio();
1155 assert (nchans == _channel_buttons.size ());
1157 for (uint32_t n = 0; n < nchans; ++n) {
1159 char action_name[32];
1161 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1162 act = ActionManager::get_action (X_("Monitor"), action_name);
1164 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1166 tact->set_active (_monitor->cut (n));
1170 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1171 act = ActionManager::get_action (X_("Monitor"), action_name);
1173 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1175 tact->set_active (_monitor->dimmed (n));
1179 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1180 act = ActionManager::get_action (X_("Monitor"), action_name);
1182 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1184 tact->set_active (_monitor->soloed (n));
1188 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1189 act = ActionManager::get_action (X_("Monitor"), action_name);
1191 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1193 tact->set_active (_monitor->inverted (n));
1200 MonitorSection::do_blink (bool onoff)
1203 audition_blink (onoff);
1207 MonitorSection::audition_blink (bool onoff)
1209 if (_session == 0) {
1213 if (_session->is_auditioning()) {
1214 rude_audition_button.set_active (onoff);
1216 rude_audition_button.set_active (false);
1221 MonitorSection::solo_blink (bool onoff)
1223 if (_session == 0) {
1227 if (_session->soloing() || _session->listening()) {
1228 rude_solo_button.set_active (onoff);
1230 if (_session->soloing()) {
1231 if (_session->solo_isolated()) {
1232 rude_iso_button.set_active (onoff);
1234 rude_iso_button.set_active (false);
1239 rude_solo_button.set_active (false);
1240 rude_iso_button.set_active (false);
1245 MonitorSection::cancel_isolate (GdkEventButton*)
1248 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1249 _session->set_solo_isolated (rl, false, Session::rt_cleanup, Controllable::NoGroup);
1256 MonitorSection::cancel_audition (GdkEventButton*)
1259 _session->cancel_audition();
1264 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1266 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1267 if (tact && tact->get_active() != value) { \
1268 tact->set_active(value); \
1273 MonitorSection::parameter_changed (std::string name)
1275 if (name == "solo-control-is-listen-control") {
1276 update_solo_model ();
1277 } else if (name == "listen-position") {
1278 update_solo_model ();
1279 } else if (name == "solo-mute-override") {
1280 SYNCHRONIZE_TOGGLE_ACTION(
1281 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1282 Config->get_solo_mute_override ())
1283 } else if (name == "exclusive-solo") {
1284 SYNCHRONIZE_TOGGLE_ACTION(
1285 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1286 Config->get_exclusive_solo ())
1291 MonitorSection::assign_controllables ()
1293 boost::shared_ptr<Controllable> none;
1295 if (!gain_control) {
1296 /* too early - GUI controls not set up yet */
1301 solo_cut_control->set_controllable (_session->solo_cut_control());
1302 solo_cut_display->set_controllable (_session->solo_cut_control());
1304 solo_cut_control->set_controllable (none);
1305 solo_cut_display->set_controllable (none);
1309 gain_control->set_controllable (_route->gain_control());
1310 gain_display->set_controllable (_route->gain_control());
1312 gain_control->set_controllable (none);
1317 cut_all_button.set_controllable (_monitor->cut_control());
1318 cut_all_button.watch ();
1319 dim_all_button.set_controllable (_monitor->dim_control());
1320 dim_all_button.watch ();
1321 mono_button.set_controllable (_monitor->mono_control());
1322 mono_button.watch ();
1324 dim_control->set_controllable (_monitor->dim_level_control ());
1325 dim_display->set_controllable (_monitor->dim_level_control ());
1326 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1327 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1331 cut_all_button.set_controllable (none);
1332 dim_all_button.set_controllable (none);
1333 mono_button.set_controllable (none);
1335 dim_control->set_controllable (none);
1336 dim_display->set_controllable (none);
1337 solo_boost_control->set_controllable (none);
1338 solo_boost_display->set_controllable (none);
1343 MonitorSection::state_id() const
1345 return "monitor-section";
1349 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1351 using namespace Menu_Helpers;
1353 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1357 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1358 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1362 if (i != output_menu_bundles.end()) {
1366 output_menu_bundles.push_back (b);
1368 MenuList& citems = output_menu.items();
1370 std::string n = b->name ();
1371 replace_all (n, "_", " ");
1373 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1377 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1380 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1382 if (std::find (current.begin(), current.end(), c) == current.end()) {
1383 _route->output()->connect_ports_to_bundle (c, true, this);
1385 _route->output()->disconnect_ports_from_bundle (c, this);
1390 MonitorSection::output_release (GdkEventButton *ev)
1392 switch (ev->button) {
1394 edit_output_configuration ();
1401 struct RouteCompareByName {
1402 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1403 return a->name().compare (b->name()) < 0;
1408 MonitorSection::output_press (GdkEventButton *ev)
1410 using namespace Menu_Helpers;
1412 MessageDialog msg (_("No session - no I/O changes are possible"));
1417 MenuList& citems = output_menu.items();
1418 switch (ev->button) {
1421 return false; //wait for the mouse-up to pop the dialog
1425 output_menu.set_name ("ArdourContextMenu");
1427 output_menu_bundles.clear ();
1429 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1431 citems.push_back (SeparatorElem());
1432 uint32_t const n_with_separator = citems.size ();
1434 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1436 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1438 /* give user bundles first chance at being in the menu */
1440 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1441 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1442 maybe_add_bundle_to_output_menu (*i, current);
1446 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1447 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1448 maybe_add_bundle_to_output_menu (*i, current);
1452 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1453 RouteList copy = *routes;
1454 copy.sort (RouteCompareByName ());
1455 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1456 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1459 if (citems.size() == n_with_separator) {
1460 /* no routes added; remove the separator */
1464 citems.push_back (SeparatorElem());
1465 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1467 output_menu.popup (1, ev->time);
1478 MonitorSection::update_output_display ()
1480 if (!_route || !_monitor || _session->deletion_in_progress()) {
1486 boost::shared_ptr<Port> port;
1487 vector<string> port_connections;
1489 uint32_t total_connection_count = 0;
1490 uint32_t io_connection_count = 0;
1491 uint32_t ardour_connection_count = 0;
1492 uint32_t system_connection_count = 0;
1493 uint32_t other_connection_count = 0;
1495 ostringstream label;
1497 bool have_label = false;
1498 bool each_io_has_one_connection = true;
1500 string connection_name;
1501 string ardour_track_name;
1502 string other_connection_type;
1503 string system_ports;
1506 ostringstream tooltip;
1507 char * tooltip_cstr;
1509 io_count = _route->n_outputs().n_total();
1510 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1513 for (io_index = 0; io_index < io_count; ++io_index) {
1515 port = _route->output()->nth (io_index);
1517 //ignore any port connections that don't match our DataType
1518 if (port->type() != DataType::AUDIO) {
1522 port_connections.clear ();
1523 port->get_connections(port_connections);
1524 io_connection_count = 0;
1526 if (!port_connections.empty()) {
1527 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1529 string& connection_name (*i);
1531 if (connection_name.find("system:") == 0) {
1532 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1535 if (io_connection_count == 0) {
1536 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1538 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1541 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1544 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1545 if (ardour_track_name.empty()) {
1546 // "ardour:Master/in 1" -> "ardour:Master/"
1547 string::size_type slash = connection_name.find("/");
1548 if (slash != string::npos) {
1549 ardour_track_name = connection_name.substr(0, slash + 1);
1553 if (connection_name.find(ardour_track_name) == 0) {
1554 ++ardour_connection_count;
1556 } else if (!pn.empty()) {
1557 if (system_ports.empty()) {
1560 system_ports += "/" + pn;
1562 if (connection_name.find("system:") == 0) {
1563 ++system_connection_count;
1565 } else if (connection_name.find("system:") == 0) {
1566 // "system:playback_123" -> "123"
1567 system_port = connection_name.substr(16);
1568 if (system_ports.empty()) {
1569 system_ports += system_port;
1571 system_ports += "/" + system_port;
1574 ++system_connection_count;
1576 if (other_connection_type.empty()) {
1577 // "jamin:in 1" -> "jamin:"
1578 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1581 if (connection_name.find(other_connection_type) == 0) {
1582 ++other_connection_count;
1586 ++total_connection_count;
1587 ++io_connection_count;
1591 if (io_connection_count != 1) {
1592 each_io_has_one_connection = false;
1596 if (total_connection_count == 0) {
1597 tooltip << endl << _("Disconnected");
1600 tooltip_cstr = new char[tooltip.str().size() + 1];
1601 strcpy(tooltip_cstr, tooltip.str().c_str());
1603 set_tooltip (output_button, tooltip_cstr, "");
1605 if (each_io_has_one_connection) {
1606 if (total_connection_count == ardour_connection_count) {
1607 // all connections are to the same track in ardour
1608 // "ardour:Master/" -> "Master"
1609 string::size_type slash = ardour_track_name.find("/");
1610 if (slash != string::npos) {
1611 label << ardour_track_name.substr(7, slash - 7);
1614 } else if (total_connection_count == system_connection_count) {
1615 // all connections are to system ports
1616 label << system_ports;
1618 } else if (total_connection_count == other_connection_count) {
1619 // all connections are to the same external program eg jamin
1620 // "jamin:" -> "jamin"
1621 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1627 if (total_connection_count == 0) {
1631 // Odd configuration
1632 label << "*" << total_connection_count << "*";
1636 output_button->set_text (label.str());
1640 MonitorSection::disconnect_output ()
1643 _route->output()->disconnect(this);
1648 MonitorSection::edit_output_configuration ()
1650 if (_output_selector == 0) {
1651 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1653 _output_selector->present ();
1657 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1662 boost::shared_ptr<Port> a = wa.lock ();
1663 boost::shared_ptr<Port> b = wb.lock ();
1664 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1665 update_output_display ();
1670 MonitorSection::load_bindings ()
1672 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1676 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1678 boost::shared_ptr<Processor> processor (p.lock ());
1679 if (!processor || !processor->display_to_user()) {
1682 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1689 MonitorSection::count_processors ()
1691 uint32_t processor_count = 0;
1693 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1695 return processor_count;
1699 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1701 update_processor_box ();