2 * Copyright (C) 2005-2006 Nick Mainsbridge <mainsbridge@gmail.com>
3 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
5 * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
6 * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
7 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8 * Copyright (C) 2008 Hans Baier <hansfbaier@googlemail.com>
9 * Copyright (C) 2009-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
10 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
11 * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
12 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
13 * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
14 * Copyright (C) 2016-2017 Julien "_FrnchFrgg_" RIVAUD <frnchfrgg@free.fr>
15 * Copyright (C) 2018 Len Ovens <len@ovenwerks.net>
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36 #include <sigc++/bind.h>
38 #include <gtkmm/messagedialog.h>
40 #include "pbd/convert.h"
41 #include "pbd/enumwriter.h"
42 #include "pbd/replace_all.h"
43 #include "pbd/stacktrace.h"
44 #include "pbd/unwind.h"
46 #include "ardour/amp.h"
47 #include "ardour/audio_track.h"
48 #include "ardour/audioengine.h"
49 #include "ardour/internal_send.h"
50 #include "ardour/io.h"
51 #include "ardour/meter.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/pannable.h"
54 #include "ardour/panner.h"
55 #include "ardour/panner_shell.h"
56 #include "ardour/panner_manager.h"
57 #include "ardour/port.h"
58 #include "ardour/profile.h"
59 #include "ardour/route.h"
60 #include "ardour/route_group.h"
61 #include "ardour/send.h"
62 #include "ardour/session.h"
63 #include "ardour/types.h"
64 #include "ardour/user_bundle.h"
65 #include "ardour/vca.h"
66 #include "ardour/vca_manager.h"
68 #include "gtkmm2ext/gtk_ui.h"
69 #include "gtkmm2ext/menu_elems.h"
70 #include "gtkmm2ext/utils.h"
71 #include "gtkmm2ext/doi.h"
73 #include "widgets/tooltips.h"
75 #include "ardour_window.h"
76 #include "context_menu_helper.h"
77 #include "enums_convert.h"
78 #include "mixer_strip.h"
81 #include "public_editor.h"
83 #include "io_selector.h"
85 #include "gui_thread.h"
86 #include "route_group_menu.h"
87 #include "meter_patterns.h"
88 #include "ui_config.h"
92 using namespace ARDOUR;
93 using namespace ArdourWidgets;
96 using namespace Gtkmm2ext;
98 using namespace ArdourMeter;
100 MixerStrip* MixerStrip::_entered_mixer_strip;
101 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
103 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
104 : SessionHandlePtr (sess)
107 , _mixer_owned (in_mixer)
108 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
111 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
112 , rec_mon_table (2, 2)
113 , solo_iso_table (1, 2)
114 , mute_solo_table (1, 2)
115 , bottom_button_table (1, 3)
116 , monitor_section_button (0)
117 , midi_input_enable_button (0)
118 , _plugin_insert_cnt (0)
119 , _comment_button (_("Comments"))
120 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
121 , _visibility (X_("mixer-element-visibility"))
122 , _suspend_menu_callbacks (false)
123 , control_slave_ui (sess)
128 /* the editor mixer strip: don't destroy it every time
129 the underlying route goes away.
132 self_destruct = false;
136 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
137 : SessionHandlePtr (sess)
140 , _mixer_owned (in_mixer)
141 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
144 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
145 , rec_mon_table (2, 2)
146 , solo_iso_table (1, 2)
147 , mute_solo_table (1, 2)
148 , bottom_button_table (1, 3)
149 , monitor_section_button (0)
150 , midi_input_enable_button (0)
151 , _plugin_insert_cnt (0)
152 , _comment_button (_("Comments"))
153 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
154 , _visibility (X_("mixer-element-visibility"))
155 , _suspend_menu_callbacks (false)
156 , control_slave_ui (sess)
165 _entered_mixer_strip= 0;
168 ignore_comment_edit = false;
169 ignore_toggle = false;
173 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
174 longest_label = "longest label";
176 string t = _("Click to toggle the width of this mixer strip.");
178 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
181 width_button.set_icon (ArdourIcon::StripWidth);
182 hide_button.set_tweaks (ArdourButton::Square);
183 set_tooltip (width_button, t);
185 hide_button.set_icon (ArdourIcon::HideEye);
186 hide_button.set_tweaks (ArdourButton::Square);
187 set_tooltip (&hide_button, _("Hide this mixer strip"));
189 input_button_box.set_spacing(2);
191 input_button.set_text (_("Input"));
192 input_button.set_name ("mixer strip button");
193 input_button_box.pack_start (input_button, true, true);
195 output_button.set_text (_("Output"));
196 output_button.set_name ("mixer strip button");
198 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
200 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
202 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
203 solo_isolated_led->show ();
204 solo_isolated_led->set_no_show_all (true);
205 solo_isolated_led->set_name (X_("solo isolate"));
206 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
207 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
208 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
210 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
211 solo_safe_led->show ();
212 solo_safe_led->set_no_show_all (true);
213 solo_safe_led->set_name (X_("solo safe"));
214 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
215 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
216 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
218 solo_safe_led->set_text (S_("SoloLock|Lock"));
219 solo_isolated_led->set_text (_("Iso"));
221 solo_iso_table.set_homogeneous (true);
222 solo_iso_table.set_spacings (2);
223 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
224 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
225 solo_iso_table.show ();
227 rec_mon_table.set_homogeneous (true);
228 rec_mon_table.set_row_spacings (2);
229 rec_mon_table.set_col_spacings (2);
230 if (ARDOUR::Profile->get_mixbus()) {
231 rec_mon_table.resize (1, 3);
232 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
233 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
235 rec_mon_table.show ();
237 if (solo_isolated_led) {
238 button_size_group->add_widget (*solo_isolated_led);
241 button_size_group->add_widget (*solo_safe_led);
244 if (!ARDOUR::Profile->get_mixbus()) {
245 if (rec_enable_button) {
246 button_size_group->add_widget (*rec_enable_button);
248 if (monitor_disk_button) {
249 button_size_group->add_widget (*monitor_disk_button);
251 if (monitor_input_button) {
252 button_size_group->add_widget (*monitor_input_button);
256 mute_solo_table.set_homogeneous (true);
257 mute_solo_table.set_spacings (2);
259 bottom_button_table.set_spacings (2);
260 bottom_button_table.set_homogeneous (true);
261 bottom_button_table.attach (group_button, 1, 2, 0, 1);
262 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
264 name_button.set_name ("mixer strip button");
265 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
266 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
268 set_tooltip (&group_button, _("Mix group"));
269 group_button.set_name ("mixer strip button");
271 _comment_button.set_name (X_("mixer strip button"));
272 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
273 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
274 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
276 // TODO implement ArdourKnob::on_size_request properly
277 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
278 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
280 trim_control.set_tooltip_prefix (_("Trim: "));
281 trim_control.set_name ("trim knob");
282 trim_control.set_no_show_all (true);
283 trim_control.StartGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_start_touch));
284 trim_control.StopGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_end_touch));
285 input_button_box.pack_start (trim_control, false, false);
287 global_vpacker.set_border_width (1);
288 global_vpacker.set_spacing (0);
290 width_button.set_name ("mixer strip button");
291 hide_button.set_name ("mixer strip button");
293 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
294 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
296 width_hide_box.set_spacing (2);
297 width_hide_box.pack_start (width_button, false, true);
298 width_hide_box.pack_start (number_label, true, true);
299 width_hide_box.pack_end (hide_button, false, true);
301 number_label.set_text ("-");
302 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
303 number_label.set_no_show_all ();
304 number_label.set_name ("tracknumber label");
305 number_label.set_fixed_colors (0x80808080, 0x80808080);
306 number_label.set_alignment (.5, .5);
307 number_label.set_fallthrough_to_parent (true);
308 number_label.set_tweaks (ArdourButton::OccasionalText);
310 global_vpacker.set_spacing (2);
311 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (processor_box, true, true);
316 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
318 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
319 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
320 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
321 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
322 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
323 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
324 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
327 //add a spacer underneath the master bus;
328 //this fills the area that is taken up by the scrollbar on the tracks;
329 //and therefore keeps the faders "even" across the bottom
330 int scrollbar_height = 0;
332 Gtk::Window window (WINDOW_TOPLEVEL);
333 HScrollbar scrollbar;
334 window.add (scrollbar);
335 scrollbar.set_name ("MixerWindow");
336 scrollbar.ensure_style();
337 Gtk::Requisition requisition(scrollbar.size_request ());
338 scrollbar_height = requisition.height;
340 spacer.set_size_request (-1, scrollbar_height);
341 global_vpacker.pack_end (spacer, false, false);
344 global_frame.add (global_vpacker);
345 global_frame.set_shadow_type (Gtk::SHADOW_IN);
346 global_frame.set_name ("BaseFrame");
350 /* force setting of visible selected status */
353 set_selected (false);
358 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
359 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
360 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
362 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
363 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
365 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
366 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
367 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
369 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
371 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
373 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
377 /* start off as a passthru strip. we'll correct this, if necessary,
378 in update_diskstream_display().
381 /* start off as a passthru strip. we'll correct this, if necessary,
382 in update_diskstream_display().
385 if (is_midi_track()) {
386 set_name ("MidiTrackStripBase");
388 set_name ("AudioTrackStripBase");
391 add_events (Gdk::BUTTON_RELEASE_MASK|
392 Gdk::ENTER_NOTIFY_MASK|
393 Gdk::LEAVE_NOTIFY_MASK|
395 Gdk::KEY_RELEASE_MASK);
397 set_flags (get_flags() | Gtk::CAN_FOCUS);
399 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
400 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
403 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
404 must be the same as those used in RCOptionEditor so that the configuration changes
405 are recognised when they occur.
407 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
408 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
409 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
410 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
411 _visibility.add (&output_button, X_("Output"), _("Output"), false);
412 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
413 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
415 parameter_changed (X_("mixer-element-visibility"));
416 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
417 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
418 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
420 //watch for mouse enter/exit so we can do some stuff
421 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
422 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
424 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
427 MixerStrip::~MixerStrip ()
429 CatchDeletion (this);
431 if (this ==_entered_mixer_strip)
432 _entered_mixer_strip = NULL;
436 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
438 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
444 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
446 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
452 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
454 _entered_mixer_strip = this;
456 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
457 //because the mixerstrip control is a parent that encompasses the strip
458 deselect_all_processors();
464 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
466 //if we have moved outside our strip, but not into a child view, then deselect ourselves
467 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
468 _entered_mixer_strip= 0;
470 //clear keyboard focus in the gain display. this is cheesy but fixes a longstanding "bug" where the user starts typing in the gain entry, and leaves it active, thereby prohibiting other keybindings from working
471 gpm.gain_display.set_sensitive(false);
473 gpm.gain_display.set_sensitive(true);
475 //if we leave this mixer strip we need to clear out any selections
476 //processor_box.processor_display.select_none(); //but this doesn't work, because it gets triggered when (for example) you open the menu or start a drag
483 MixerStrip::name() const
486 return _route->name();
492 MixerStrip::update_trim_control ()
494 if (route()->trim() && route()->trim()->active() &&
495 route()->n_inputs().n_audio() > 0) {
496 trim_control.show ();
497 trim_control.set_controllable (route()->trim()->gain_control());
499 trim_control.hide ();
500 boost::shared_ptr<Controllable> none;
501 trim_control.set_controllable (none);
506 MixerStrip::trim_start_touch ()
508 assert (_route && _session);
509 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
510 route()->trim()->gain_control ()->start_touch (_session->transport_sample());
515 MixerStrip::trim_end_touch ()
517 assert (_route && _session);
518 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
519 route()->trim()->gain_control ()->stop_touch (_session->transport_sample());
524 MixerStrip::set_route (boost::shared_ptr<Route> rt)
526 //the rec/monitor stuff only shows up for tracks.
527 //the show_sends only shows up for buses.
528 //remove them all here, and we may add them back later
529 if (show_sends_button->get_parent()) {
530 rec_mon_table.remove (*show_sends_button);
532 if (rec_enable_button->get_parent()) {
533 rec_mon_table.remove (*rec_enable_button);
535 if (monitor_input_button->get_parent()) {
536 rec_mon_table.remove (*monitor_input_button);
538 if (monitor_disk_button->get_parent()) {
539 rec_mon_table.remove (*monitor_disk_button);
541 if (group_button.get_parent()) {
542 bottom_button_table.remove (group_button);
545 RouteUI::set_route (rt);
547 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
549 /* ProcessorBox needs access to _route so that it can read
552 processor_box.set_route (rt);
554 revert_to_default_display ();
556 /* unpack these from the parent and stuff them into our own
560 if (gpm.peak_display.get_parent()) {
561 gpm.peak_display.get_parent()->remove (gpm.peak_display);
563 if (gpm.gain_display.get_parent()) {
564 gpm.gain_display.get_parent()->remove (gpm.gain_display);
567 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
568 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
570 if (solo_button->get_parent()) {
571 mute_solo_table.remove (*solo_button);
574 if (mute_button->get_parent()) {
575 mute_solo_table.remove (*mute_button);
578 if (route()->is_master()) {
579 solo_button->hide ();
580 mute_button->show ();
581 rec_mon_table.hide ();
582 solo_iso_table.set_sensitive(false);
583 control_slave_ui.set_sensitive(false);
584 if (monitor_section_button == 0) {
585 Glib::RefPtr<Action> act = ActionManager::get_action ("Mixer", "ToggleMonitorSection");
586 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
587 _session->MonitorBusAddedOrRemoved.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_section_added_or_removed, this), gui_context());
589 monitor_section_button = manage (new ArdourButton);
591 monitor_section_button->set_related_action (act);
592 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
593 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
594 monitor_section_button->show();
595 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
596 monitor_section_added_or_removed ();
599 bottom_button_table.attach (group_button, 1, 2, 0, 1);
600 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
601 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
602 mute_button->show ();
603 solo_button->show ();
604 rec_mon_table.show ();
605 solo_iso_table.set_sensitive(true);
606 control_slave_ui.set_sensitive(true);
609 hide_master_spacer (false);
612 monitor_input_button->show ();
613 monitor_disk_button->show ();
615 monitor_input_button->hide();
616 monitor_disk_button->hide ();
619 update_trim_control();
621 if (is_midi_track()) {
622 if (midi_input_enable_button == 0) {
623 midi_input_enable_button = manage (new ArdourButton);
624 midi_input_enable_button->set_name ("midi input button");
625 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
626 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
627 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
628 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
629 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
631 input_button_box.remove (*midi_input_enable_button);
633 /* get current state */
634 midi_input_status_changed ();
635 input_button_box.pack_start (*midi_input_enable_button, false, false);
637 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
639 if (midi_input_enable_button) {
640 /* removal from the container will delete it */
641 input_button_box.remove (*midi_input_enable_button);
642 midi_input_enable_button = 0;
646 if (is_audio_track()) {
647 boost::shared_ptr<AudioTrack> at = audio_track();
648 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
653 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
654 rec_enable_button->show();
656 if (ARDOUR::Profile->get_mixbus()) {
657 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
658 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
660 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
661 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
668 if (!_route->is_master()) {
669 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
670 show_sends_button->show();
674 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
676 delete route_ops_menu;
679 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
680 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
681 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
682 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
684 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
686 if (_route->panner_shell()) {
687 update_panner_choices();
688 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
691 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
693 set_stuff_from_route ();
695 /* now force an update of all the various elements */
697 update_mute_display ();
698 update_solo_display ();
701 route_group_changed ();
702 update_track_number_visibility ();
705 panners.setup_pan ();
707 if (has_audio_outputs ()) {
713 update_diskstream_display ();
714 update_input_display ();
715 update_output_display ();
717 add_events (Gdk::BUTTON_RELEASE_MASK);
719 processor_box.show ();
721 if (!route()->is_master() && !route()->is_monitor()) {
722 /* we don't allow master or control routes to be hidden */
727 gpm.reset_peak_display ();
728 gpm.gain_display.show ();
729 gpm.peak_display.show ();
732 width_hide_box.show();
734 global_vpacker.show();
735 mute_solo_table.show();
736 bottom_button_table.show();
738 gpm.meter_point_button.show();
739 input_button_box.show_all();
740 output_button.show();
742 _comment_button.show();
744 gpm.gain_automation_state_button.show();
746 parameter_changed ("mixer-element-visibility");
753 MixerStrip::set_stuff_from_route ()
755 /* if width is not set, it will be set by the MixerUI or editor */
758 if (get_gui_property ("strip-width", width)) {
759 set_width_enum (width, this);
764 MixerStrip::set_width_enum (Width w, void* owner)
766 /* always set the gpm width again, things may be hidden */
769 panners.set_width (w);
771 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
773 _width_owner = owner;
777 if (_width_owner == this) {
778 set_gui_property ("strip-width", _width);
783 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
785 gpm.gain_automation_state_button.set_text (GainMeterBase::short_astate_string (gain_automation->automation_state()));
787 if (_route->panner()) {
788 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (GainMeterBase::short_astate_string (_route->panner()->automation_state()));
794 if (show_sends_button) {
795 show_sends_button->set_text (_("Aux"));
799 // panners expect an even number of horiz. pixels
800 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
802 set_size_request (width, -1);
808 if (show_sends_button) {
809 show_sends_button->set_text (_("Snd"));
812 gain_meter().setup_meters (); // recalc meter width
815 // panners expect an even number of horiz. pixels
816 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
818 set_size_request (width, -1);
823 processor_box.set_width (w);
825 update_input_display ();
826 update_output_display ();
827 setup_comment_button ();
828 route_group_changed ();
834 MixerStrip::set_packed (bool yn)
837 set_gui_property ("visible", _packed);
841 struct RouteCompareByName {
842 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
843 return a->name().compare (b->name()) < 0;
848 MixerStrip::output_release (GdkEventButton *ev)
850 switch (ev->button) {
852 edit_output_configuration ();
860 MixerStrip::output_press (GdkEventButton *ev)
862 using namespace Menu_Helpers;
863 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
867 MenuList& citems = output_menu.items();
868 switch (ev->button) {
871 return false; //wait for the mouse-up to pop the dialog
875 output_menu.set_name ("ArdourContextMenu");
877 output_menu_bundles.clear ();
879 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
881 citems.push_back (SeparatorElem());
882 uint32_t const n_with_separator = citems.size ();
884 ARDOUR::BundleList current = _route->output()->bundles_connected ();
886 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
888 /* guess the user-intended main type of the route output */
889 DataType intended_type = guess_main_type(false);
891 /* try adding the master bus first */
892 boost::shared_ptr<Route> master = _session->master_out();
894 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
897 /* then other routes inputs */
898 RouteList copy = _session->get_routelist ();
899 copy.sort (RouteCompareByName ());
900 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
901 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
904 /* then try adding user bundles, often labeled/grouped physical inputs */
905 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
906 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
907 maybe_add_bundle_to_output_menu (*i, current, intended_type);
911 /* then all other bundles, including physical outs or other sofware */
912 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
913 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
914 maybe_add_bundle_to_output_menu (*i, current, intended_type);
918 if (citems.size() == n_with_separator) {
919 /* no routes added; remove the separator */
923 citems.push_back (SeparatorElem());
925 if (!ARDOUR::Profile->get_mixbus()) {
926 bool need_separator = false;
927 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
928 if (!_route->output()->can_add_port (*i)) {
931 need_separator = true;
934 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
935 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
939 if (need_separator) {
940 citems.push_back (SeparatorElem());
944 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
946 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
959 MixerStrip::input_release (GdkEventButton *ev)
961 switch (ev->button) {
964 edit_input_configuration ();
976 MixerStrip::input_press (GdkEventButton *ev)
978 using namespace Menu_Helpers;
980 MenuList& citems = input_menu.items();
981 input_menu.set_name ("ArdourContextMenu");
984 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
988 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
991 switch (ev->button) {
994 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
998 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1000 citems.push_back (SeparatorElem());
1001 uint32_t const n_with_separator = citems.size ();
1003 input_menu_bundles.clear ();
1005 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1007 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1009 /* give user bundles first chance at being in the menu */
1011 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1012 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1013 maybe_add_bundle_to_input_menu (*i, current);
1017 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1018 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1019 maybe_add_bundle_to_input_menu (*i, current);
1023 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1024 RouteList copy = *routes;
1025 copy.sort (RouteCompareByName ());
1026 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1027 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1030 if (citems.size() == n_with_separator) {
1031 /* no routes added; remove the separator */
1035 citems.push_back (SeparatorElem());
1037 bool need_separator = false;
1038 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1039 if (!_route->input()->can_add_port (*i)) {
1042 need_separator = true;
1045 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1046 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1050 if (need_separator) {
1051 citems.push_back (SeparatorElem());
1054 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1056 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1068 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1070 if (ignore_toggle) {
1074 _route->input()->connect_ports_to_bundle (c, true, this);
1078 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1080 if (ignore_toggle) {
1084 _route->output()->connect_ports_to_bundle (c, true, true, this);
1088 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1090 using namespace Menu_Helpers;
1092 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1096 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1097 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1101 if (i != input_menu_bundles.end()) {
1105 input_menu_bundles.push_back (b);
1107 MenuList& citems = input_menu.items();
1108 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1112 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1115 using namespace Menu_Helpers;
1117 /* The bundle should be an input one, but not ours */
1118 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1122 /* Don't add the monitor input unless we are Master */
1123 boost::shared_ptr<Route> monitor = _session->monitor_out();
1124 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1127 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1128 * or have the same number of |type| channels than our outputs. */
1129 if (type == DataType::NIL) {
1130 if(b->nchannels() != _route->n_outputs())
1133 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1137 /* Avoid adding duplicates */
1138 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1139 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1142 if (i != output_menu_bundles.end()) {
1146 /* Now add the bundle to the menu */
1147 output_menu_bundles.push_back (b);
1149 MenuList& citems = output_menu.items();
1150 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1154 MixerStrip::update_diskstream_display ()
1156 if (is_track() && input_selector) {
1157 input_selector->hide_all ();
1160 route_color_changed ();
1164 MixerStrip::connect_to_pan ()
1166 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1168 panstate_connection.disconnect ();
1169 panstyle_connection.disconnect ();
1171 if (!_route->panner()) {
1175 boost::shared_ptr<Pannable> p = _route->pannable ();
1177 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1179 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1180 * However, that only works a panner was previously set.
1182 * PannerUI must remain subscribed to _panshell->Changed() in case
1183 * we switch the panner eg. AUX-Send and back
1184 * _route->panner_shell()->Changed() vs _panshell->Changed
1186 if (panners._panner == 0) {
1187 panners.panshell_changed ();
1189 update_panner_choices();
1193 MixerStrip::update_panner_choices ()
1195 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1196 if (!_route->panner_shell()) { return; }
1198 uint32_t in = _route->output()->n_ports().n_audio();
1200 if (_route->panner()) {
1201 in = _route->panner()->in().n_audio();
1204 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1208 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1210 /* The heuristic follows these principles:
1211 * A) If all ports that the user connected are of the same type, then he
1212 * very probably intends to use the IO with that type. A common subcase
1213 * is when the IO has only ports of the same type (connected or not).
1214 * B) If several types of ports are connected, then we should guess based
1215 * on the likeliness of the user wanting to use a given type.
1216 * We assume that the DataTypes are ordered from the most likely to the
1217 * least likely when iterating or comparing them with "<".
1218 * C) If no port is connected, the same logic can be applied with all ports
1219 * instead of connected ones. TODO: Try other ideas, for instance look at
1220 * the last plugin output when |for_input| is false (note: when StrictIO
1221 * the outs of the last plugin should be the same as the outs of the route
1222 * modulo the panner which forwards non-audio anyway).
1223 * All of these constraints are respected by the following algorithm that
1224 * just returns the most likely datatype found in connected ports if any, or
1225 * available ports if any (since if all ports are of the same type, the most
1226 * likely found will be that one obviously). */
1228 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1230 /* Find most likely type among connected ports */
1231 if (favor_connected) {
1232 DataType type = DataType::NIL; /* NIL is always last so least likely */
1233 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1234 if (p->connected() && p->type() < type)
1237 if (type != DataType::NIL) {
1238 /* There has been a connected port (necessarily non-NIL) */
1243 /* Find most likely type among available ports.
1244 * The iterator stops before NIL. */
1245 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1246 if (io->n_ports().n(*t) > 0)
1250 /* No port at all, return the most likely datatype by default */
1251 return DataType::front();
1255 * Output port labelling
1257 * Case 1: Each output has one connection, all connections are to system:playback_%i
1258 * out 1 -> system:playback_1
1259 * out 2 -> system:playback_2
1260 * out 3 -> system:playback_3
1263 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1264 * out 1 -> ardour:track_x/in 1
1265 * out 2 -> ardour:track_x/in 2
1266 * Display as: track_x
1268 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1269 * out 1 -> program x:foo
1270 * out 2 -> program x:foo
1271 * Display as: program x
1273 * Case 4: No connections (Disconnected)
1276 * Default case (unusual routing):
1277 * Display as: *number of connections*
1282 * .-----------------------------------------------.
1284 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1285 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1286 * '-----------------------------------------------'
1287 * .-----------------------------------------------.
1290 * '-----------------------------------------------'
1294 MixerStrip::update_io_button (bool for_input)
1296 ostringstream tooltip;
1297 ostringstream label;
1298 bool have_label = false;
1300 uint32_t total_connection_count = 0;
1301 uint32_t typed_connection_count = 0;
1302 bool each_typed_port_has_one_connection = true;
1304 DataType dt = guess_main_type(for_input);
1305 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1307 /* Fill in the tooltip. Also count:
1308 * - The total number of connections.
1309 * - The number of main-typed connections.
1310 * - Whether each main-typed port has exactly one connection. */
1312 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1313 Gtkmm2ext::markup_escape_text (_route->name()));
1315 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1316 Gtkmm2ext::markup_escape_text (_route->name()));
1319 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1320 vector<string> port_connections;
1321 for (PortSet::iterator port = io->ports().begin();
1322 port != io->ports().end();
1324 port_connections.clear();
1325 port->get_connections(port_connections);
1327 uint32_t port_connection_count = 0;
1329 for (vector<string>::iterator i = port_connections.begin();
1330 i != port_connections.end();
1332 ++port_connection_count;
1334 if (port_connection_count == 1) {
1335 tooltip << endl << Gtkmm2ext::markup_escape_text (
1336 port->name().substr(port->name().find("/") + 1));
1342 tooltip << Gtkmm2ext::markup_escape_text(*i);
1345 total_connection_count += port_connection_count;
1346 if (port->type() == dt) {
1347 typed_connection_count += port_connection_count;
1348 each_typed_port_has_one_connection &= (port_connection_count == 1);
1353 if (total_connection_count == 0) {
1354 tooltip << endl << _("Disconnected");
1357 if (typed_connection_count == 0) {
1362 /* Are all main-typed channels connected to the same route ? */
1364 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1365 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1366 route != routes->end();
1368 boost::shared_ptr<IO> dest_io =
1369 for_input ? (*route)->output() : (*route)->input();
1370 if (io->bundle()->connected_to(dest_io->bundle(),
1373 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1380 /* Are all main-typed channels connected to the same (user) bundle ? */
1382 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1383 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1384 bundle != bundles->end();
1386 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1388 if (io->bundle()->connected_to(*bundle, _session->engine(),
1390 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1397 /* Is each main-typed channel only connected to a physical output ? */
1398 if (!have_label && each_typed_port_has_one_connection) {
1399 ostringstream temp_label;
1400 vector<string> phys;
1401 string playorcapture;
1403 _session->engine().get_physical_inputs(dt, phys);
1404 playorcapture = "capture_";
1406 _session->engine().get_physical_outputs(dt, phys);
1407 playorcapture = "playback_";
1409 for (PortSet::iterator port = io->ports().begin(dt);
1410 port != io->ports().end(dt);
1413 for (vector<string>::iterator s = phys.begin();
1416 if (!port->connected_to(*s))
1418 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1420 string::size_type start = (*s).find(playorcapture);
1421 if (start != string::npos) {
1422 pn = (*s).substr(start + playorcapture.size());
1428 temp_label.str(""); /* erase the failed attempt */
1431 if (port != io->ports().begin(dt))
1436 if (!temp_label.str().empty()) {
1437 label << temp_label.str();
1442 /* Is each main-typed channel connected to a single and different port with
1443 * the same client name (e.g. another JACK client) ? */
1444 if (!have_label && each_typed_port_has_one_connection) {
1445 string maybe_client = "";
1446 vector<string> connections;
1447 for (PortSet::iterator port = io->ports().begin(dt);
1448 port != io->ports().end(dt);
1450 port_connections.clear();
1451 port->get_connections(port_connections);
1452 string connection = port_connections.front();
1454 vector<string>::iterator i = connections.begin();
1455 while (i != connections.end() && *i != connection) {
1458 if (i != connections.end())
1459 break; /* duplicate connection */
1460 connections.push_back(connection);
1462 connection = connection.substr(0, connection.find(":"));
1463 if (maybe_client.empty())
1464 maybe_client = connection;
1465 if (maybe_client != connection)
1468 if (connections.size() == io->n_ports().n(dt)) {
1469 label << maybe_client;
1474 /* Odd configuration */
1476 label << "*" << total_connection_count << "*";
1479 if (total_connection_count > typed_connection_count) {
1480 label << "\u2295"; /* circled plus */
1483 /* Actually set the properties of the button */
1484 char * cstr = new char[tooltip.str().size() + 1];
1485 strcpy(cstr, tooltip.str().c_str());
1488 input_button.set_text (label.str());
1489 set_tooltip (&input_button, cstr);
1491 output_button.set_text (label.str());
1492 set_tooltip (&output_button, cstr);
1499 MixerStrip::update_input_display ()
1501 update_io_button (true);
1502 panners.setup_pan ();
1504 if (has_audio_outputs ()) {
1505 panners.show_all ();
1507 panners.hide_all ();
1513 MixerStrip::update_output_display ()
1515 update_io_button (false);
1516 gpm.setup_meters ();
1517 panners.setup_pan ();
1519 if (has_audio_outputs ()) {
1520 panners.show_all ();
1522 panners.hide_all ();
1527 MixerStrip::fast_update ()
1529 gpm.update_meters ();
1533 MixerStrip::diskstream_changed ()
1535 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1539 MixerStrip::io_changed_proxy ()
1541 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1542 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1546 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1548 boost::shared_ptr<Port> a = wa.lock ();
1549 boost::shared_ptr<Port> b = wb.lock ();
1551 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1552 update_input_display ();
1553 set_width_enum (_width, this);
1556 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1557 update_output_display ();
1558 set_width_enum (_width, this);
1563 MixerStrip::setup_comment_button ()
1565 std::string comment = _route->comment();
1567 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1569 if (comment.empty ()) {
1570 _comment_button.set_name ("generic button");
1571 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1575 _comment_button.set_name ("comment button");
1577 string::size_type pos = comment.find_first_of (" \t\n");
1578 if (pos != string::npos) {
1579 comment = comment.substr (0, pos);
1581 if (comment.empty()) {
1582 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1584 _comment_button.set_text (comment);
1589 MixerStrip::select_route_group (GdkEventButton *ev)
1591 using namespace Menu_Helpers;
1593 if (ev->button == 1) {
1595 if (group_menu == 0) {
1597 PropertyList* plist = new PropertyList();
1599 plist->add (Properties::group_gain, true);
1600 plist->add (Properties::group_mute, true);
1601 plist->add (Properties::group_solo, true);
1603 group_menu = new RouteGroupMenu (_session, plist);
1607 r.push_back (route ());
1608 group_menu->build (r);
1610 RouteGroup *rg = _route->route_group();
1612 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1613 rg ? rg->name() : _("No Group"),
1621 MixerStrip::route_group_changed ()
1623 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1625 RouteGroup *rg = _route->route_group();
1628 group_button.set_text (PBD::short_version (rg->name(), 5));
1632 group_button.set_text (_("Grp"));
1635 group_button.set_text (_("~G"));
1642 MixerStrip::route_color_changed ()
1644 using namespace ARDOUR_UI_UTILS;
1645 name_button.modify_bg (STATE_NORMAL, color());
1646 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1647 reset_strip_style ();
1651 MixerStrip::show_passthru_color ()
1653 reset_strip_style ();
1658 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1660 boost::shared_ptr<Processor> processor (p.lock ());
1661 if (!processor || !processor->display_to_user()) {
1664 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1666 if (pi && pi->is_channelstrip ()) {
1671 ++_plugin_insert_cnt;
1675 MixerStrip::build_route_ops_menu ()
1677 using namespace Menu_Helpers;
1678 route_ops_menu = new Menu;
1679 route_ops_menu->set_name ("ArdourContextMenu");
1681 MenuList& items = route_ops_menu->items();
1683 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1685 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1687 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1689 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1691 if (!Profile->get_mixbus()) {
1692 items.push_back (SeparatorElem());
1695 if (!_route->is_master()
1697 && !_route->mixbus()
1700 if (Profile->get_mixbus()) {
1701 items.push_back (SeparatorElem());
1703 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1706 if (!Profile->get_mixbus()) {
1707 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1708 /* do not allow rename if the track is record-enabled */
1709 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1712 items.push_back (SeparatorElem());
1713 items.push_back (CheckMenuElem (_("Active")));
1714 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1715 i->set_active (_route->active());
1716 i->set_sensitive(! _session->transport_rolling());
1717 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1719 if (!Profile->get_mixbus ()) {
1720 items.push_back (SeparatorElem());
1721 items.push_back (CheckMenuElem (_("Strict I/O")));
1722 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1723 i->set_active (_route->strict_io());
1724 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1728 items.push_back (SeparatorElem());
1730 Gtk::Menu* dio_menu = new Menu;
1731 MenuList& dio_items = dio_menu->items();
1732 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1733 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1734 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1736 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1739 _plugin_insert_cnt = 0;
1740 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1741 if (_plugin_insert_cnt > 0) {
1742 items.push_back (SeparatorElem());
1743 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1746 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1747 items.push_back (MenuElem (_("Patch Selector..."),
1748 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1751 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1752 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1753 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1754 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1757 items.push_back (SeparatorElem());
1758 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1759 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1760 denormal_menu_item->set_active (_route->denormal_protection());
1763 /* note that this relies on selection being shared across editor and
1764 mixer (or global to the backend, in the future), which is the only
1765 sane thing for users anyway.
1768 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1770 Selection& selection (PublicEditor::instance().get_selection());
1771 if (!selection.selected (stav)) {
1772 selection.set (stav);
1775 if (!_route->is_master()) {
1776 items.push_back (SeparatorElem());
1777 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1780 items.push_back (SeparatorElem());
1781 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1787 MixerStrip::name_button_button_press (GdkEventButton* ev)
1789 if (ev->button == 1 || ev->button == 3) {
1790 list_route_operations ();
1792 if (ev->button == 1) {
1793 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1796 route_ops_menu->popup (3, ev->time);
1806 MixerStrip::number_button_button_press (GdkEventButton* ev)
1808 if ( ev->button == 3 ) {
1809 list_route_operations ();
1811 route_ops_menu->popup (1, ev->time);
1820 MixerStrip::list_route_operations ()
1822 delete route_ops_menu;
1823 build_route_ops_menu ();
1827 MixerStrip::set_selected (bool yn)
1829 AxisView::set_selected (yn);
1832 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1833 global_frame.set_name ("MixerStripSelectedFrame");
1835 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1836 global_frame.set_name ("MixerStripFrame");
1839 global_frame.queue_draw ();
1842 // processor_box.deselect_all_processors();
1846 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1848 if (what_changed.contains (ARDOUR::Properties::name)) {
1854 MixerStrip::name_changed ()
1858 name_button.set_text (_route->name());
1861 name_button.set_text (PBD::short_version (_route->name(), 5));
1865 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1867 if (_session->config.get_track_name_number()) {
1868 const int64_t track_number = _route->track_number ();
1869 if (track_number == 0) {
1870 number_label.set_text ("-");
1872 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1875 number_label.set_text ("");
1880 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1882 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1886 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1888 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1892 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1894 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1898 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1900 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1904 MixerStrip::width_button_pressed (GdkEventButton* ev)
1906 if (ev->button != 1) {
1910 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1913 _mixer.set_strip_width (Narrow, true);
1917 _mixer.set_strip_width (Wide, true);
1923 set_width_enum (Narrow, this);
1926 set_width_enum (Wide, this);
1935 MixerStrip::hide_clicked ()
1937 // LAME fix to reset the button status for when it is redisplayed (part 1)
1938 hide_button.set_sensitive(false);
1941 Hiding(); /* EMIT_SIGNAL */
1943 _mixer.hide_strip (this);
1947 hide_button.set_sensitive(true);
1951 MixerStrip::set_embedded (bool yn)
1957 MixerStrip::map_frozen ()
1959 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1961 boost::shared_ptr<AudioTrack> at = audio_track();
1964 switch (at->freeze_state()) {
1965 case AudioTrack::Frozen:
1966 processor_box.set_sensitive (false);
1967 hide_redirect_editors ();
1970 processor_box.set_sensitive (true);
1971 // XXX need some way, maybe, to retoggle redirect editors
1975 processor_box.set_sensitive (true);
1977 RouteUI::map_frozen ();
1981 MixerStrip::hide_redirect_editors ()
1983 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1987 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1989 boost::shared_ptr<Processor> processor (p.lock ());
1994 Gtk::Window* w = processor_box.get_processor_ui (processor);
2002 MixerStrip::reset_strip_style ()
2004 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2006 gpm.set_fader_name ("SendStripBase");
2010 if (is_midi_track()) {
2011 if (_route->active()) {
2012 set_name ("MidiTrackStripBase");
2014 set_name ("MidiTrackStripBaseInactive");
2016 gpm.set_fader_name ("MidiTrackFader");
2017 } else if (is_audio_track()) {
2018 if (_route->active()) {
2019 set_name ("AudioTrackStripBase");
2021 set_name ("AudioTrackStripBaseInactive");
2023 gpm.set_fader_name ("AudioTrackFader");
2025 if (_route->active()) {
2026 set_name ("AudioBusStripBase");
2028 set_name ("AudioBusStripBaseInactive");
2030 gpm.set_fader_name ("AudioBusFader");
2032 /* (no MIDI busses yet) */
2039 MixerStrip::meter_point_string (MeterPoint mp)
2052 case MeterPostFader:
2069 return S_("Meter|In");
2073 return S_("Meter|Pr");
2076 case MeterPostFader:
2077 return S_("Meter|Po");
2081 return S_("Meter|O");
2086 return S_("Meter|C");
2095 /** Called when the monitor-section state */
2097 MixerStrip::monitor_changed ()
2099 assert (monitor_section_button);
2100 if (_session->monitor_active()) {
2101 monitor_section_button->set_name ("master monitor section button active");
2103 monitor_section_button->set_name ("master monitor section button normal");
2108 MixerStrip::monitor_section_added_or_removed ()
2110 assert (monitor_section_button);
2111 if (mute_button->get_parent()) {
2112 mute_button->get_parent()->remove(*mute_button);
2114 if (monitor_section_button->get_parent()) {
2115 monitor_section_button->get_parent()->remove(*monitor_section_button);
2117 if (_session && _session->monitor_out ()) {
2118 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2119 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2120 mute_button->show();
2121 monitor_section_button->show();
2123 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2124 mute_button->show();
2128 /** Called when the metering point has changed */
2130 MixerStrip::meter_changed ()
2132 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2133 gpm.setup_meters ();
2134 // reset peak when meter point changes
2135 gpm.reset_peak_display();
2138 /** The bus that we are displaying sends to has changed, or been turned off.
2139 * @param send_to New bus that we are displaying sends to, or 0.
2142 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2144 RouteUI::bus_send_display_changed (send_to);
2147 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2152 revert_to_default_display ();
2155 revert_to_default_display ();
2160 MixerStrip::drop_send ()
2162 boost::shared_ptr<Send> current_send;
2164 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2165 current_send->set_metering (false);
2168 send_gone_connection.disconnect ();
2169 input_button.set_sensitive (true);
2170 output_button.set_sensitive (true);
2171 group_button.set_sensitive (true);
2172 set_invert_sensitive (true);
2173 gpm.meter_point_button.set_sensitive (true);
2174 mute_button->set_sensitive (true);
2175 solo_button->set_sensitive (true);
2176 solo_isolated_led->set_sensitive (true);
2177 solo_safe_led->set_sensitive (true);
2178 monitor_input_button->set_sensitive (true);
2179 monitor_disk_button->set_sensitive (true);
2180 _comment_button.set_sensitive (true);
2181 trim_control.set_sensitive (true);
2182 if (midi_input_enable_button) {
2183 midi_input_enable_button->set_sensitive (true);
2185 control_slave_ui.set_sensitive (true);
2186 RouteUI::check_rec_enable_sensitivity ();
2187 set_button_names (); // update solo button visual state
2191 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2193 _current_delivery = d;
2194 DeliveryChanged (_current_delivery);
2198 MixerStrip::show_send (boost::shared_ptr<Send> send)
2204 set_current_delivery (send);
2206 send->meter()->set_meter_type (_route->meter_type ());
2207 send->set_metering (true);
2208 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2210 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2211 gain_meter().setup_meters ();
2213 uint32_t const in = _current_delivery->pans_required();
2214 uint32_t const out = _current_delivery->pan_outs();
2216 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2217 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2218 panner_ui().setup_pan ();
2219 panner_ui().set_send_drawing_mode (true);
2220 panner_ui().show_all ();
2222 input_button.set_sensitive (false);
2223 group_button.set_sensitive (false);
2224 set_invert_sensitive (false);
2225 gpm.meter_point_button.set_sensitive (false);
2226 mute_button->set_sensitive (false);
2227 solo_button->set_sensitive (false);
2228 rec_enable_button->set_sensitive (false);
2229 solo_isolated_led->set_sensitive (false);
2230 solo_safe_led->set_sensitive (false);
2231 monitor_input_button->set_sensitive (false);
2232 monitor_disk_button->set_sensitive (false);
2233 _comment_button.set_sensitive (false);
2234 trim_control.set_sensitive (false);
2235 if (midi_input_enable_button) {
2236 midi_input_enable_button->set_sensitive (false);
2238 control_slave_ui.set_sensitive (false);
2240 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2241 output_button.set_sensitive (false);
2244 reset_strip_style ();
2248 MixerStrip::revert_to_default_display ()
2252 set_current_delivery (_route->main_outs ());
2254 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2255 gain_meter().setup_meters ();
2257 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2258 update_panner_choices();
2259 panner_ui().setup_pan ();
2260 panner_ui().set_send_drawing_mode (false);
2262 if (has_audio_outputs ()) {
2263 panners.show_all ();
2265 panners.hide_all ();
2268 reset_strip_style ();
2272 MixerStrip::set_button_names ()
2276 mute_button->set_text (_("Mute"));
2277 monitor_input_button->set_text (_("In"));
2278 monitor_disk_button->set_text (_("Disk"));
2279 if (monitor_section_button) {
2280 monitor_section_button->set_text (_("Mon"));
2283 if (_route && _route->solo_safe_control()->solo_safe()) {
2284 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2286 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2288 if (!Config->get_solo_control_is_listen_control()) {
2289 solo_button->set_text (_("Solo"));
2291 switch (Config->get_listen_position()) {
2292 case AfterFaderListen:
2293 solo_button->set_text (_("AFL"));
2295 case PreFaderListen:
2296 solo_button->set_text (_("PFL"));
2300 solo_isolated_led->set_text (_("Iso"));
2301 solo_safe_led->set_text (S_("SoloLock|Lock"));
2305 mute_button->set_text (S_("Mute|M"));
2306 monitor_input_button->set_text (S_("MonitorInput|I"));
2307 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2308 if (monitor_section_button) {
2309 monitor_section_button->set_text (S_("Mon|O"));
2312 if (_route && _route->solo_safe_control()->solo_safe()) {
2313 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2315 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2317 if (!Config->get_solo_control_is_listen_control()) {
2318 solo_button->set_text (S_("Solo|S"));
2320 switch (Config->get_listen_position()) {
2321 case AfterFaderListen:
2322 solo_button->set_text (S_("AfterFader|A"));
2324 case PreFaderListen:
2325 solo_button->set_text (S_("Prefader|P"));
2330 solo_isolated_led->set_text (S_("SoloIso|I"));
2331 solo_safe_led->set_text (S_("SoloLock|L"));
2336 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2338 gpm.meter_point_button.set_text ("");
2343 MixerStrip::plugin_selector()
2345 return _mixer.plugin_selector();
2349 MixerStrip::hide_things ()
2351 processor_box.hide_things ();
2355 MixerStrip::input_active_button_press (GdkEventButton*)
2357 /* nothing happens on press */
2362 MixerStrip::input_active_button_release (GdkEventButton* ev)
2364 boost::shared_ptr<MidiTrack> mt = midi_track ();
2370 boost::shared_ptr<RouteList> rl (new RouteList);
2372 rl->push_back (route());
2374 _session->set_exclusive_input_active (rl, !mt->input_active(),
2375 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2381 MixerStrip::midi_input_status_changed ()
2383 if (midi_input_enable_button) {
2384 boost::shared_ptr<MidiTrack> mt = midi_track ();
2386 midi_input_enable_button->set_active (mt->input_active ());
2391 MixerStrip::state_id () const
2393 return string_compose ("strip %1", _route->id().to_s());
2397 MixerStrip::parameter_changed (string p)
2399 if (p == _visibility.get_state_name()) {
2400 /* The user has made changes to the mixer strip visibility, so get
2401 our VisibilityGroup to reflect these changes in our widgets.
2403 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2404 } else if (p == "track-name-number") {
2406 update_track_number_visibility();
2410 /** Called to decide whether the solo isolate / solo lock button visibility should
2411 * be overridden from that configured by the user. We do this for the master bus.
2413 * @return optional value that is present if visibility state should be overridden.
2415 boost::optional<bool>
2416 MixerStrip::override_solo_visibility () const
2418 if (_route && _route->is_master ()) {
2419 return boost::optional<bool> (false);
2422 return boost::optional<bool> ();
2426 MixerStrip::add_input_port (DataType t)
2428 _route->input()->add_port ("", this, t);
2432 MixerStrip::add_output_port (DataType t)
2434 _route->output()->add_port ("", this, t);
2438 MixerStrip::route_active_changed ()
2440 reset_strip_style ();
2444 MixerStrip::copy_processors ()
2446 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2450 MixerStrip::cut_processors ()
2452 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2456 MixerStrip::paste_processors ()
2458 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2462 MixerStrip::select_all_processors ()
2464 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2468 MixerStrip::deselect_all_processors ()
2470 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2474 MixerStrip::delete_processors ()
2476 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2480 MixerStrip::toggle_processors ()
2482 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2486 MixerStrip::ab_plugins ()
2488 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2492 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2494 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2497 if (ev->button == 3) {
2498 popup_level_meter_menu (ev);
2506 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2508 using namespace Gtk::Menu_Helpers;
2510 Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
2511 MenuList& items = m->items ();
2513 RadioMenuItem::Group group;
2515 PBD::Unwinder<bool> uw (_suspend_menu_callbacks, true);
2516 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2517 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2518 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2519 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2520 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2522 if (gpm.meter_channels().n_audio() == 0) {
2523 m->popup (ev->button, ev->time);
2527 RadioMenuItem::Group tgroup;
2528 items.push_back (SeparatorElem());
2530 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2531 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2532 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2533 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2534 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2535 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2536 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2537 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2538 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2539 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2540 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2543 if (_route->is_master()) {
2546 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2547 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2548 /* non-master bus */
2551 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2558 MeterType cmt = _route->meter_type();
2559 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2561 items.push_back (SeparatorElem());
2562 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2563 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2564 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2565 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2566 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2567 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2569 m->popup (ev->button, ev->time);
2573 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2574 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2576 using namespace Menu_Helpers;
2578 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2579 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2580 i->set_active (_route->meter_point() == point);
2584 MixerStrip::set_meter_point (MeterPoint p)
2586 if (_suspend_menu_callbacks) return;
2587 _route->set_meter_point (p);
2591 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2592 RadioMenuItem::Group& group, string const & name, MeterType type)
2594 using namespace Menu_Helpers;
2596 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2597 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2598 i->set_active (_route->meter_type() == type);
2602 MixerStrip::set_meter_type (MeterType t)
2604 if (_suspend_menu_callbacks) return;
2605 _route->set_meter_type (t);
2609 MixerStrip::update_track_number_visibility ()
2611 DisplaySuspender ds;
2612 bool show_label = _session->config.get_track_name_number();
2614 if (_route && _route->is_master()) {
2619 number_label.show ();
2620 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2621 // except the width of the number label is subtracted from the name-hbox, so we
2622 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2623 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2625 number_label.set_size_request(tnw, -1);
2626 number_label.show ();
2628 number_label.hide ();
2633 MixerStrip::color () const
2635 return route_color ();
2639 MixerStrip::marked_for_display () const
2641 return !_route->presentation_info().hidden();
2645 MixerStrip::set_marked_for_display (bool yn)
2647 return RouteUI::mark_hidden (!yn);
2651 MixerStrip::hide_master_spacer (bool yn)
2653 if (_mixer_owned && route()->is_master() && !yn) {