2 Copyright (C) 2000-2006 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.
23 #include <sigc++/bind.h>
25 #include <gtkmm/messagedialog.h>
27 #include "pbd/convert.h"
28 #include "pbd/enumwriter.h"
29 #include "pbd/replace_all.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/unwind.h"
33 #include "ardour/amp.h"
34 #include "ardour/audio_track.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/internal_send.h"
37 #include "ardour/io.h"
38 #include "ardour/meter.h"
39 #include "ardour/midi_track.h"
40 #include "ardour/pannable.h"
41 #include "ardour/panner.h"
42 #include "ardour/panner_shell.h"
43 #include "ardour/panner_manager.h"
44 #include "ardour/port.h"
45 #include "ardour/profile.h"
46 #include "ardour/route.h"
47 #include "ardour/route_group.h"
48 #include "ardour/send.h"
49 #include "ardour/session.h"
50 #include "ardour/types.h"
51 #include "ardour/user_bundle.h"
52 #include "ardour/vca.h"
53 #include "ardour/vca_manager.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/menu_elems.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/doi.h"
60 #include "widgets/tooltips.h"
62 #include "ardour_window.h"
63 #include "context_menu_helper.h"
64 #include "enums_convert.h"
65 #include "mixer_strip.h"
68 #include "public_editor.h"
70 #include "io_selector.h"
72 #include "gui_thread.h"
73 #include "route_group_menu.h"
74 #include "meter_patterns.h"
75 #include "ui_config.h"
79 using namespace ARDOUR;
80 using namespace ArdourWidgets;
83 using namespace Gtkmm2ext;
85 using namespace ArdourMeter;
87 MixerStrip* MixerStrip::_entered_mixer_strip;
88 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
90 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
91 : SessionHandlePtr (sess)
94 , _mixer_owned (in_mixer)
95 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
98 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
99 , rec_mon_table (2, 2)
100 , solo_iso_table (1, 2)
101 , mute_solo_table (1, 2)
102 , bottom_button_table (1, 3)
103 , monitor_section_button (0)
104 , midi_input_enable_button (0)
105 , _plugin_insert_cnt (0)
106 , _comment_button (_("Comments"))
107 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
108 , _visibility (X_("mixer-element-visibility"))
109 , control_slave_ui (sess)
114 /* the editor mixer strip: don't destroy it every time
115 the underlying route goes away.
118 self_destruct = false;
122 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
123 : SessionHandlePtr (sess)
126 , _mixer_owned (in_mixer)
127 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
130 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
131 , rec_mon_table (2, 2)
132 , solo_iso_table (1, 2)
133 , mute_solo_table (1, 2)
134 , bottom_button_table (1, 3)
135 , monitor_section_button (0)
136 , midi_input_enable_button (0)
137 , _plugin_insert_cnt (0)
138 , _comment_button (_("Comments"))
139 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
140 , _visibility (X_("mixer-element-visibility"))
141 , control_slave_ui (sess)
150 _entered_mixer_strip= 0;
153 ignore_comment_edit = false;
154 ignore_toggle = false;
158 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
159 longest_label = "longest label";
161 string t = _("Click to toggle the width of this mixer strip.");
163 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
166 width_button.set_icon (ArdourIcon::StripWidth);
167 hide_button.set_tweaks (ArdourButton::Square);
168 set_tooltip (width_button, t);
170 hide_button.set_icon (ArdourIcon::CloseCross);
171 hide_button.set_tweaks (ArdourButton::Square);
172 set_tooltip (&hide_button, _("Hide this mixer strip"));
174 input_button_box.set_spacing(2);
176 input_button.set_text (_("Input"));
177 input_button.set_name ("mixer strip button");
178 input_button_box.pack_start (input_button, true, true);
180 output_button.set_text (_("Output"));
181 output_button.set_name ("mixer strip button");
183 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
185 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
187 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
188 solo_isolated_led->show ();
189 solo_isolated_led->set_no_show_all (true);
190 solo_isolated_led->set_name (X_("solo isolate"));
191 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
192 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
193 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
195 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
196 solo_safe_led->show ();
197 solo_safe_led->set_no_show_all (true);
198 solo_safe_led->set_name (X_("solo safe"));
199 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
200 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
201 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
203 solo_safe_led->set_text (S_("SoloLock|Lock"));
204 solo_isolated_led->set_text (_("Iso"));
206 solo_iso_table.set_homogeneous (true);
207 solo_iso_table.set_spacings (2);
208 if (!ARDOUR::Profile->get_trx()) {
209 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
210 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
212 solo_iso_table.show ();
214 rec_mon_table.set_homogeneous (true);
215 rec_mon_table.set_row_spacings (2);
216 rec_mon_table.set_col_spacings (2);
217 if (ARDOUR::Profile->get_mixbus()) {
218 rec_mon_table.resize (1, 3);
219 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
220 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
221 } else if (!ARDOUR::Profile->get_trx()) {
222 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
223 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
225 rec_mon_table.show ();
227 if (solo_isolated_led) {
228 button_size_group->add_widget (*solo_isolated_led);
231 button_size_group->add_widget (*solo_safe_led);
234 if (!ARDOUR::Profile->get_mixbus()) {
235 if (rec_enable_button) {
236 button_size_group->add_widget (*rec_enable_button);
238 if (monitor_disk_button) {
239 button_size_group->add_widget (*monitor_disk_button);
241 if (monitor_input_button) {
242 button_size_group->add_widget (*monitor_input_button);
246 mute_solo_table.set_homogeneous (true);
247 mute_solo_table.set_spacings (2);
249 bottom_button_table.set_spacings (2);
250 bottom_button_table.set_homogeneous (true);
251 bottom_button_table.attach (group_button, 1, 2, 0, 1);
252 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
254 name_button.set_name ("mixer strip button");
255 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
256 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
258 set_tooltip (&group_button, _("Mix group"));
259 group_button.set_name ("mixer strip button");
261 _comment_button.set_name (X_("mixer strip button"));
262 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
263 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
264 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
266 // TODO implement ArdourKnob::on_size_request properly
267 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
268 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
270 trim_control.set_tooltip_prefix (_("Trim: "));
271 trim_control.set_name ("trim knob");
272 trim_control.set_no_show_all (true);
273 trim_control.StartGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_start_touch));
274 trim_control.StopGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_end_touch));
275 input_button_box.pack_start (trim_control, false, false);
277 global_vpacker.set_border_width (1);
278 global_vpacker.set_spacing (0);
280 width_button.set_name ("mixer strip button");
281 hide_button.set_name ("mixer strip button");
283 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
284 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
286 width_hide_box.set_spacing (2);
287 width_hide_box.pack_start (width_button, false, true);
288 width_hide_box.pack_start (number_label, true, true);
289 width_hide_box.pack_end (hide_button, false, true);
291 number_label.set_text ("-");
292 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
293 number_label.set_no_show_all ();
294 number_label.set_name ("tracknumber label");
295 number_label.set_fixed_colors (0x80808080, 0x80808080);
296 number_label.set_alignment (.5, .5);
297 number_label.set_fallthrough_to_parent (true);
298 number_label.set_tweaks (ArdourButton::OccasionalText);
300 global_vpacker.set_spacing (2);
301 if (!ARDOUR::Profile->get_trx()) {
302 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
303 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
304 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (processor_box, true, true);
308 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
315 if (!ARDOUR::Profile->get_trx()) {
316 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
319 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
323 //add a spacer underneath the master bus;
324 //this fills the area that is taken up by the scrollbar on the tracks;
325 //and therefore keeps the faders "even" across the bottom
326 int scrollbar_height = 0;
328 Gtk::Window window (WINDOW_TOPLEVEL);
329 HScrollbar scrollbar;
330 window.add (scrollbar);
331 scrollbar.set_name ("MixerWindow");
332 scrollbar.ensure_style();
333 Gtk::Requisition requisition(scrollbar.size_request ());
334 scrollbar_height = requisition.height;
336 spacer.set_size_request (-1, scrollbar_height);
337 global_vpacker.pack_end (spacer, false, false);
340 global_frame.add (global_vpacker);
341 global_frame.set_shadow_type (Gtk::SHADOW_IN);
342 global_frame.set_name ("BaseFrame");
346 /* force setting of visible selected status */
349 set_selected (false);
354 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
355 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
357 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
358 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
359 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
361 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
362 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
364 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
365 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
366 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
368 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
370 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
372 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
376 /* start off as a passthru strip. we'll correct this, if necessary,
377 in update_diskstream_display().
380 /* start off as a passthru strip. we'll correct this, if necessary,
381 in update_diskstream_display().
384 if (is_midi_track()) {
385 set_name ("MidiTrackStripBase");
387 set_name ("AudioTrackStripBase");
390 add_events (Gdk::BUTTON_RELEASE_MASK|
391 Gdk::ENTER_NOTIFY_MASK|
392 Gdk::LEAVE_NOTIFY_MASK|
394 Gdk::KEY_RELEASE_MASK);
396 set_flags (get_flags() | Gtk::CAN_FOCUS);
398 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
399 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
402 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
403 must be the same as those used in RCOptionEditor so that the configuration changes
404 are recognised when they occur.
406 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
407 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
408 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
409 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
410 _visibility.add (&output_button, X_("Output"), _("Output"), false);
411 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
412 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
414 parameter_changed (X_("mixer-element-visibility"));
415 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
416 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
417 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
419 //watch for mouse enter/exit so we can do some stuff
420 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
421 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
423 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
426 MixerStrip::~MixerStrip ()
428 CatchDeletion (this);
430 if (this ==_entered_mixer_strip)
431 _entered_mixer_strip = NULL;
435 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
437 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
443 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
445 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
451 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
453 _entered_mixer_strip = this;
455 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
456 //because the mixerstrip control is a parent that encompasses the strip
457 deselect_all_processors();
463 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
465 //if we have moved outside our strip, but not into a child view, then deselect ourselves
466 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
467 _entered_mixer_strip= 0;
469 //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
470 gpm.gain_display.set_sensitive(false);
472 gpm.gain_display.set_sensitive(true);
474 //if we leave this mixer strip we need to clear out any selections
475 //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
482 MixerStrip::name() const
485 return _route->name();
491 MixerStrip::update_trim_control ()
493 if (route()->trim() && route()->trim()->active() &&
494 route()->n_inputs().n_audio() > 0) {
495 trim_control.show ();
496 trim_control.set_controllable (route()->trim()->gain_control());
498 trim_control.hide ();
499 boost::shared_ptr<Controllable> none;
500 trim_control.set_controllable (none);
505 MixerStrip::trim_start_touch ()
507 assert (_route && _session);
508 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
509 route()->trim()->gain_control ()->start_touch (_session->transport_sample());
514 MixerStrip::trim_end_touch ()
516 assert (_route && _session);
517 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
518 route()->trim()->gain_control ()->stop_touch (_session->transport_sample());
523 MixerStrip::set_route (boost::shared_ptr<Route> rt)
525 //the rec/monitor stuff only shows up for tracks.
526 //the show_sends only shows up for buses.
527 //remove them all here, and we may add them back later
528 if (show_sends_button->get_parent()) {
529 rec_mon_table.remove (*show_sends_button);
531 if (rec_enable_button->get_parent()) {
532 rec_mon_table.remove (*rec_enable_button);
534 if (monitor_input_button->get_parent()) {
535 rec_mon_table.remove (*monitor_input_button);
537 if (monitor_disk_button->get_parent()) {
538 rec_mon_table.remove (*monitor_disk_button);
540 if (group_button.get_parent()) {
541 bottom_button_table.remove (group_button);
544 RouteUI::set_route (rt);
546 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
548 /* ProcessorBox needs access to _route so that it can read
551 processor_box.set_route (rt);
553 revert_to_default_display ();
555 /* unpack these from the parent and stuff them into our own
559 if (gpm.peak_display.get_parent()) {
560 gpm.peak_display.get_parent()->remove (gpm.peak_display);
562 if (gpm.gain_display.get_parent()) {
563 gpm.gain_display.get_parent()->remove (gpm.gain_display);
566 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
567 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
569 if (solo_button->get_parent()) {
570 mute_solo_table.remove (*solo_button);
573 if (mute_button->get_parent()) {
574 mute_solo_table.remove (*mute_button);
577 if (route()->is_master()) {
578 solo_button->hide ();
579 mute_button->show ();
580 rec_mon_table.hide ();
581 solo_iso_table.set_sensitive(false);
582 control_slave_ui.set_sensitive(false);
583 if (monitor_section_button == 0) {
584 Glib::RefPtr<Action> act = ActionManager::get_action ("Mixer", "ToggleMonitorSection");
585 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
586 _session->MonitorBusAddedOrRemoved.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_section_added_or_removed, this), gui_context());
588 monitor_section_button = manage (new ArdourButton);
590 monitor_section_button->set_related_action (act);
591 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
592 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
593 monitor_section_button->show();
594 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
595 monitor_section_added_or_removed ();
598 bottom_button_table.attach (group_button, 1, 2, 0, 1);
599 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
600 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
601 mute_button->show ();
602 solo_button->show ();
603 rec_mon_table.show ();
604 solo_iso_table.set_sensitive(true);
605 control_slave_ui.set_sensitive(true);
608 if (_mixer_owned && route()->is_master() ) {
615 monitor_input_button->show ();
616 monitor_disk_button->show ();
618 monitor_input_button->hide();
619 monitor_disk_button->hide ();
622 update_trim_control();
624 if (is_midi_track()) {
625 if (midi_input_enable_button == 0) {
626 midi_input_enable_button = manage (new ArdourButton);
627 midi_input_enable_button->set_name ("midi input button");
628 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
629 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
630 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
631 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
632 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
634 input_button_box.remove (*midi_input_enable_button);
636 /* get current state */
637 midi_input_status_changed ();
638 input_button_box.pack_start (*midi_input_enable_button, false, false);
640 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
642 if (midi_input_enable_button) {
643 /* removal from the container will delete it */
644 input_button_box.remove (*midi_input_enable_button);
645 midi_input_enable_button = 0;
649 if (is_audio_track()) {
650 boost::shared_ptr<AudioTrack> at = audio_track();
651 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
656 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
657 rec_enable_button->show();
659 if (ARDOUR::Profile->get_mixbus()) {
660 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
661 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
662 } else if (ARDOUR::Profile->get_trx()) {
663 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
665 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
666 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
673 if (!_route->is_master()) {
674 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
675 show_sends_button->show();
679 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
681 delete route_ops_menu;
684 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
685 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
686 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
687 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
689 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
691 if (_route->panner_shell()) {
692 update_panner_choices();
693 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
696 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
698 set_stuff_from_route ();
700 /* now force an update of all the various elements */
702 update_mute_display ();
703 update_solo_display ();
706 route_group_changed ();
707 update_track_number_visibility ();
710 panners.setup_pan ();
712 if (has_audio_outputs ()) {
718 update_diskstream_display ();
719 update_input_display ();
720 update_output_display ();
722 add_events (Gdk::BUTTON_RELEASE_MASK);
724 processor_box.show ();
726 if (!route()->is_master() && !route()->is_monitor()) {
727 /* we don't allow master or control routes to be hidden */
732 gpm.reset_peak_display ();
733 gpm.gain_display.show ();
734 gpm.peak_display.show ();
737 width_hide_box.show();
739 global_vpacker.show();
740 mute_solo_table.show();
741 bottom_button_table.show();
743 gpm.meter_point_button.show();
744 input_button_box.show_all();
745 output_button.show();
747 _comment_button.show();
749 gpm.gain_automation_state_button.show();
751 parameter_changed ("mixer-element-visibility");
758 MixerStrip::set_stuff_from_route ()
760 /* if width is not set, it will be set by the MixerUI or editor */
763 if (get_gui_property ("strip-width", width)) {
764 set_width_enum (width, this);
769 MixerStrip::set_width_enum (Width w, void* owner)
771 /* always set the gpm width again, things may be hidden */
774 panners.set_width (w);
776 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
778 _width_owner = owner;
782 if (_width_owner == this) {
783 set_gui_property ("strip-width", _width);
788 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
793 if (show_sends_button) {
794 show_sends_button->set_text (_("Aux"));
797 gpm.gain_automation_state_button.set_text (
798 gpm.astate_string(gain_automation->automation_state()));
800 if (_route->panner()) {
801 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
802 panners.astate_string(_route->panner()->automation_state()));
806 // panners expect an even number of horiz. pixels
807 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
809 set_size_request (width, -1);
815 if (show_sends_button) {
816 show_sends_button->set_text (_("Snd"));
819 gpm.gain_automation_state_button.set_text (
820 gpm.short_astate_string(gain_automation->automation_state()));
821 gain_meter().setup_meters (); // recalc meter width
823 if (_route->panner()) {
824 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
825 panners.short_astate_string(_route->panner()->automation_state()));
829 // panners expect an even number of horiz. pixels
830 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
832 set_size_request (width, -1);
837 processor_box.set_width (w);
839 update_input_display ();
840 update_output_display ();
841 setup_comment_button ();
842 route_group_changed ();
848 MixerStrip::set_packed (bool yn)
851 set_gui_property ("visible", _packed);
855 struct RouteCompareByName {
856 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
857 return a->name().compare (b->name()) < 0;
862 MixerStrip::output_release (GdkEventButton *ev)
864 switch (ev->button) {
866 edit_output_configuration ();
874 MixerStrip::output_press (GdkEventButton *ev)
876 using namespace Menu_Helpers;
877 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
881 MenuList& citems = output_menu.items();
882 switch (ev->button) {
885 return false; //wait for the mouse-up to pop the dialog
889 output_menu.set_name ("ArdourContextMenu");
891 output_menu_bundles.clear ();
893 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
895 citems.push_back (SeparatorElem());
896 uint32_t const n_with_separator = citems.size ();
898 ARDOUR::BundleList current = _route->output()->bundles_connected ();
900 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
902 /* guess the user-intended main type of the route output */
903 DataType intended_type = guess_main_type(false);
905 /* try adding the master bus first */
906 boost::shared_ptr<Route> master = _session->master_out();
908 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
911 /* then other routes inputs */
912 RouteList copy = _session->get_routelist ();
913 copy.sort (RouteCompareByName ());
914 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
915 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
918 /* then try adding user bundles, often labeled/grouped physical inputs */
919 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
920 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
921 maybe_add_bundle_to_output_menu (*i, current, intended_type);
925 /* then all other bundles, including physical outs or other sofware */
926 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
927 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
928 maybe_add_bundle_to_output_menu (*i, current, intended_type);
932 if (citems.size() == n_with_separator) {
933 /* no routes added; remove the separator */
937 citems.push_back (SeparatorElem());
939 if (!ARDOUR::Profile->get_mixbus()) {
940 bool need_separator = false;
941 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
942 if (!_route->output()->can_add_port (*i)) {
945 need_separator = true;
948 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
949 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
953 if (need_separator) {
954 citems.push_back (SeparatorElem());
958 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
960 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
973 MixerStrip::input_release (GdkEventButton *ev)
975 switch (ev->button) {
978 edit_input_configuration ();
990 MixerStrip::input_press (GdkEventButton *ev)
992 using namespace Menu_Helpers;
994 MenuList& citems = input_menu.items();
995 input_menu.set_name ("ArdourContextMenu");
998 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
1002 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
1005 switch (ev->button) {
1008 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1012 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1014 citems.push_back (SeparatorElem());
1015 uint32_t const n_with_separator = citems.size ();
1017 input_menu_bundles.clear ();
1019 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1021 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1023 /* give user bundles first chance at being in the menu */
1025 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1026 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1027 maybe_add_bundle_to_input_menu (*i, current);
1031 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1032 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1033 maybe_add_bundle_to_input_menu (*i, current);
1037 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1038 RouteList copy = *routes;
1039 copy.sort (RouteCompareByName ());
1040 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1041 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1044 if (citems.size() == n_with_separator) {
1045 /* no routes added; remove the separator */
1049 citems.push_back (SeparatorElem());
1051 bool need_separator = false;
1052 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1053 if (!_route->input()->can_add_port (*i)) {
1056 need_separator = true;
1059 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1060 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1064 if (need_separator) {
1065 citems.push_back (SeparatorElem());
1068 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1070 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1082 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1084 if (ignore_toggle) {
1088 _route->input()->connect_ports_to_bundle (c, true, this);
1092 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1094 if (ignore_toggle) {
1098 _route->output()->connect_ports_to_bundle (c, true, true, this);
1102 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1104 using namespace Menu_Helpers;
1106 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1110 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1111 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1115 if (i != input_menu_bundles.end()) {
1119 input_menu_bundles.push_back (b);
1121 MenuList& citems = input_menu.items();
1122 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1126 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1129 using namespace Menu_Helpers;
1131 /* The bundle should be an input one, but not ours */
1132 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1136 /* Don't add the monitor input unless we are Master */
1137 boost::shared_ptr<Route> monitor = _session->monitor_out();
1138 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1141 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1142 * or have the same number of |type| channels than our outputs. */
1143 if (type == DataType::NIL) {
1144 if(b->nchannels() != _route->n_outputs())
1147 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1151 /* Avoid adding duplicates */
1152 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1153 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1156 if (i != output_menu_bundles.end()) {
1160 /* Now add the bundle to the menu */
1161 output_menu_bundles.push_back (b);
1163 MenuList& citems = output_menu.items();
1164 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1168 MixerStrip::update_diskstream_display ()
1170 if (is_track() && input_selector) {
1171 input_selector->hide_all ();
1174 route_color_changed ();
1178 MixerStrip::connect_to_pan ()
1180 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1182 panstate_connection.disconnect ();
1183 panstyle_connection.disconnect ();
1185 if (!_route->panner()) {
1189 boost::shared_ptr<Pannable> p = _route->pannable ();
1191 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1193 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1194 * However, that only works a panner was previously set.
1196 * PannerUI must remain subscribed to _panshell->Changed() in case
1197 * we switch the panner eg. AUX-Send and back
1198 * _route->panner_shell()->Changed() vs _panshell->Changed
1200 if (panners._panner == 0) {
1201 panners.panshell_changed ();
1203 update_panner_choices();
1207 MixerStrip::update_panner_choices ()
1209 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1210 if (!_route->panner_shell()) { return; }
1212 uint32_t in = _route->output()->n_ports().n_audio();
1214 if (_route->panner()) {
1215 in = _route->panner()->in().n_audio();
1218 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1222 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1224 /* The heuristic follows these principles:
1225 * A) If all ports that the user connected are of the same type, then he
1226 * very probably intends to use the IO with that type. A common subcase
1227 * is when the IO has only ports of the same type (connected or not).
1228 * B) If several types of ports are connected, then we should guess based
1229 * on the likeliness of the user wanting to use a given type.
1230 * We assume that the DataTypes are ordered from the most likely to the
1231 * least likely when iterating or comparing them with "<".
1232 * C) If no port is connected, the same logic can be applied with all ports
1233 * instead of connected ones. TODO: Try other ideas, for instance look at
1234 * the last plugin output when |for_input| is false (note: when StrictIO
1235 * the outs of the last plugin should be the same as the outs of the route
1236 * modulo the panner which forwards non-audio anyway).
1237 * All of these constraints are respected by the following algorithm that
1238 * just returns the most likely datatype found in connected ports if any, or
1239 * available ports if any (since if all ports are of the same type, the most
1240 * likely found will be that one obviously). */
1242 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1244 /* Find most likely type among connected ports */
1245 if (favor_connected) {
1246 DataType type = DataType::NIL; /* NIL is always last so least likely */
1247 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1248 if (p->connected() && p->type() < type)
1251 if (type != DataType::NIL) {
1252 /* There has been a connected port (necessarily non-NIL) */
1257 /* Find most likely type among available ports.
1258 * The iterator stops before NIL. */
1259 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1260 if (io->n_ports().n(*t) > 0)
1264 /* No port at all, return the most likely datatype by default */
1265 return DataType::front();
1269 * Output port labelling
1271 * Case 1: Each output has one connection, all connections are to system:playback_%i
1272 * out 1 -> system:playback_1
1273 * out 2 -> system:playback_2
1274 * out 3 -> system:playback_3
1277 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1278 * out 1 -> ardour:track_x/in 1
1279 * out 2 -> ardour:track_x/in 2
1280 * Display as: track_x
1282 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1283 * out 1 -> program x:foo
1284 * out 2 -> program x:foo
1285 * Display as: program x
1287 * Case 4: No connections (Disconnected)
1290 * Default case (unusual routing):
1291 * Display as: *number of connections*
1296 * .-----------------------------------------------.
1298 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1299 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1300 * '-----------------------------------------------'
1301 * .-----------------------------------------------.
1304 * '-----------------------------------------------'
1308 MixerStrip::update_io_button (bool for_input)
1310 ostringstream tooltip;
1311 ostringstream label;
1312 bool have_label = false;
1314 uint32_t total_connection_count = 0;
1315 uint32_t typed_connection_count = 0;
1316 bool each_typed_port_has_one_connection = true;
1318 DataType dt = guess_main_type(for_input);
1319 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1321 /* Fill in the tooltip. Also count:
1322 * - The total number of connections.
1323 * - The number of main-typed connections.
1324 * - Whether each main-typed port has exactly one connection. */
1326 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1327 Gtkmm2ext::markup_escape_text (_route->name()));
1329 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1330 Gtkmm2ext::markup_escape_text (_route->name()));
1333 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1334 vector<string> port_connections;
1335 for (PortSet::iterator port = io->ports().begin();
1336 port != io->ports().end();
1338 port_connections.clear();
1339 port->get_connections(port_connections);
1341 uint32_t port_connection_count = 0;
1343 for (vector<string>::iterator i = port_connections.begin();
1344 i != port_connections.end();
1346 ++port_connection_count;
1348 if (port_connection_count == 1) {
1349 tooltip << endl << Gtkmm2ext::markup_escape_text (
1350 port->name().substr(port->name().find("/") + 1));
1356 tooltip << Gtkmm2ext::markup_escape_text(*i);
1359 total_connection_count += port_connection_count;
1360 if (port->type() == dt) {
1361 typed_connection_count += port_connection_count;
1362 each_typed_port_has_one_connection &= (port_connection_count == 1);
1367 if (total_connection_count == 0) {
1368 tooltip << endl << _("Disconnected");
1371 if (typed_connection_count == 0) {
1376 /* Are all main-typed channels connected to the same route ? */
1378 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1379 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1380 route != routes->end();
1382 boost::shared_ptr<IO> dest_io =
1383 for_input ? (*route)->output() : (*route)->input();
1384 if (io->bundle()->connected_to(dest_io->bundle(),
1387 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1394 /* Are all main-typed channels connected to the same (user) bundle ? */
1396 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1397 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1398 bundle != bundles->end();
1400 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1402 if (io->bundle()->connected_to(*bundle, _session->engine(),
1404 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1411 /* Is each main-typed channel only connected to a physical output ? */
1412 if (!have_label && each_typed_port_has_one_connection) {
1413 ostringstream temp_label;
1414 vector<string> phys;
1415 string playorcapture;
1417 _session->engine().get_physical_inputs(dt, phys);
1418 playorcapture = "capture_";
1420 _session->engine().get_physical_outputs(dt, phys);
1421 playorcapture = "playback_";
1423 for (PortSet::iterator port = io->ports().begin(dt);
1424 port != io->ports().end(dt);
1427 for (vector<string>::iterator s = phys.begin();
1430 if (!port->connected_to(*s))
1432 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1434 string::size_type start = (*s).find(playorcapture);
1435 if (start != string::npos) {
1436 pn = (*s).substr(start + playorcapture.size());
1442 temp_label.str(""); /* erase the failed attempt */
1445 if (port != io->ports().begin(dt))
1450 if (!temp_label.str().empty()) {
1451 label << temp_label.str();
1456 /* Is each main-typed channel connected to a single and different port with
1457 * the same client name (e.g. another JACK client) ? */
1458 if (!have_label && each_typed_port_has_one_connection) {
1459 string maybe_client = "";
1460 vector<string> connections;
1461 for (PortSet::iterator port = io->ports().begin(dt);
1462 port != io->ports().end(dt);
1464 port_connections.clear();
1465 port->get_connections(port_connections);
1466 string connection = port_connections.front();
1468 vector<string>::iterator i = connections.begin();
1469 while (i != connections.end() && *i != connection) {
1472 if (i != connections.end())
1473 break; /* duplicate connection */
1474 connections.push_back(connection);
1476 connection = connection.substr(0, connection.find(":"));
1477 if (maybe_client.empty())
1478 maybe_client = connection;
1479 if (maybe_client != connection)
1482 if (connections.size() == io->n_ports().n(dt)) {
1483 label << maybe_client;
1488 /* Odd configuration */
1490 label << "*" << total_connection_count << "*";
1493 if (total_connection_count > typed_connection_count) {
1494 label << "\u2295"; /* circled plus */
1497 /* Actually set the properties of the button */
1498 char * cstr = new char[tooltip.str().size() + 1];
1499 strcpy(cstr, tooltip.str().c_str());
1502 input_button.set_text (label.str());
1503 set_tooltip (&input_button, cstr);
1505 output_button.set_text (label.str());
1506 set_tooltip (&output_button, cstr);
1513 MixerStrip::update_input_display ()
1515 update_io_button (true);
1516 panners.setup_pan ();
1518 if (has_audio_outputs ()) {
1519 panners.show_all ();
1521 panners.hide_all ();
1527 MixerStrip::update_output_display ()
1529 update_io_button (false);
1530 gpm.setup_meters ();
1531 panners.setup_pan ();
1533 if (has_audio_outputs ()) {
1534 panners.show_all ();
1536 panners.hide_all ();
1541 MixerStrip::fast_update ()
1543 gpm.update_meters ();
1547 MixerStrip::diskstream_changed ()
1549 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1553 MixerStrip::io_changed_proxy ()
1555 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1556 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1560 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1562 boost::shared_ptr<Port> a = wa.lock ();
1563 boost::shared_ptr<Port> b = wb.lock ();
1565 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1566 update_input_display ();
1567 set_width_enum (_width, this);
1570 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1571 update_output_display ();
1572 set_width_enum (_width, this);
1577 MixerStrip::setup_comment_button ()
1579 std::string comment = _route->comment();
1581 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1583 if (comment.empty ()) {
1584 _comment_button.set_name ("generic button");
1585 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1589 _comment_button.set_name ("comment button");
1591 string::size_type pos = comment.find_first_of (" \t\n");
1592 if (pos != string::npos) {
1593 comment = comment.substr (0, pos);
1595 if (comment.empty()) {
1596 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1598 _comment_button.set_text (comment);
1603 MixerStrip::select_route_group (GdkEventButton *ev)
1605 using namespace Menu_Helpers;
1607 if (ev->button == 1) {
1609 if (group_menu == 0) {
1611 PropertyList* plist = new PropertyList();
1613 plist->add (Properties::group_gain, true);
1614 plist->add (Properties::group_mute, true);
1615 plist->add (Properties::group_solo, true);
1617 group_menu = new RouteGroupMenu (_session, plist);
1621 r.push_back (route ());
1622 group_menu->build (r);
1624 RouteGroup *rg = _route->route_group();
1626 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1627 rg ? rg->name() : _("No Group"),
1635 MixerStrip::route_group_changed ()
1637 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1639 RouteGroup *rg = _route->route_group();
1642 group_button.set_text (PBD::short_version (rg->name(), 5));
1646 group_button.set_text (_("Grp"));
1649 group_button.set_text (_("~G"));
1656 MixerStrip::route_color_changed ()
1658 using namespace ARDOUR_UI_UTILS;
1659 name_button.modify_bg (STATE_NORMAL, color());
1660 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1661 reset_strip_style ();
1665 MixerStrip::show_passthru_color ()
1667 reset_strip_style ();
1672 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1674 boost::shared_ptr<Processor> processor (p.lock ());
1675 if (!processor || !processor->display_to_user()) {
1678 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1680 if (pi && pi->is_channelstrip ()) {
1685 ++_plugin_insert_cnt;
1689 MixerStrip::build_route_ops_menu ()
1691 using namespace Menu_Helpers;
1692 route_ops_menu = new Menu;
1693 route_ops_menu->set_name ("ArdourContextMenu");
1695 MenuList& items = route_ops_menu->items();
1697 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1699 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1701 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1703 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1705 if (!Profile->get_mixbus()) {
1706 items.push_back (SeparatorElem());
1709 if (!_route->is_master()
1711 && !_route->mixbus()
1714 if (Profile->get_mixbus()) {
1715 items.push_back (SeparatorElem());
1717 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1720 if (!Profile->get_mixbus()) {
1721 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1722 /* do not allow rename if the track is record-enabled */
1723 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1726 items.push_back (SeparatorElem());
1727 items.push_back (CheckMenuElem (_("Active")));
1728 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1729 i->set_active (_route->active());
1730 i->set_sensitive(! _session->transport_rolling());
1731 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1733 if (!Profile->get_mixbus ()) {
1734 items.push_back (SeparatorElem());
1735 items.push_back (CheckMenuElem (_("Strict I/O")));
1736 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1737 i->set_active (_route->strict_io());
1738 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1742 items.push_back (SeparatorElem());
1744 Gtk::Menu* dio_menu = new Menu;
1745 MenuList& dio_items = dio_menu->items();
1746 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1747 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1748 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1750 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1753 _plugin_insert_cnt = 0;
1754 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1755 if (_plugin_insert_cnt > 0) {
1756 items.push_back (SeparatorElem());
1757 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1760 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1761 items.push_back (MenuElem (_("Patch Selector..."),
1762 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1765 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1766 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1767 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1768 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1771 items.push_back (SeparatorElem());
1772 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1774 items.push_back (SeparatorElem());
1775 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1776 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1777 denormal_menu_item->set_active (_route->denormal_protection());
1780 /* note that this relies on selection being shared across editor and
1781 mixer (or global to the backend, in the future), which is the only
1782 sane thing for users anyway.
1785 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1787 Selection& selection (PublicEditor::instance().get_selection());
1788 if (!selection.selected (stav)) {
1789 selection.set (stav);
1792 if (!_route->is_master()) {
1793 items.push_back (SeparatorElem());
1794 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1797 items.push_back (SeparatorElem());
1798 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1804 MixerStrip::name_button_button_press (GdkEventButton* ev)
1806 if (ev->button == 1 || ev->button == 3) {
1807 list_route_operations ();
1809 if (ev->button == 1) {
1810 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1813 route_ops_menu->popup (3, ev->time);
1823 MixerStrip::number_button_button_press (GdkEventButton* ev)
1825 if ( ev->button == 3 ) {
1826 list_route_operations ();
1828 route_ops_menu->popup (1, ev->time);
1837 MixerStrip::list_route_operations ()
1839 delete route_ops_menu;
1840 build_route_ops_menu ();
1844 MixerStrip::set_selected (bool yn)
1846 AxisView::set_selected (yn);
1849 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1850 global_frame.set_name ("MixerStripSelectedFrame");
1852 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1853 global_frame.set_name ("MixerStripFrame");
1856 global_frame.queue_draw ();
1859 // processor_box.deselect_all_processors();
1863 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1865 if (what_changed.contains (ARDOUR::Properties::name)) {
1871 MixerStrip::name_changed ()
1875 name_button.set_text (_route->name());
1878 name_button.set_text (PBD::short_version (_route->name(), 5));
1882 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1884 if (_session->config.get_track_name_number()) {
1885 const int64_t track_number = _route->track_number ();
1886 if (track_number == 0) {
1887 number_label.set_text ("-");
1889 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1892 number_label.set_text ("");
1897 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1899 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1903 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1905 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1909 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1911 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1915 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1917 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1921 MixerStrip::width_button_pressed (GdkEventButton* ev)
1923 if (ev->button != 1) {
1927 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1930 _mixer.set_strip_width (Narrow, true);
1934 _mixer.set_strip_width (Wide, true);
1940 set_width_enum (Narrow, this);
1943 set_width_enum (Wide, this);
1952 MixerStrip::hide_clicked ()
1954 // LAME fix to reset the button status for when it is redisplayed (part 1)
1955 hide_button.set_sensitive(false);
1958 Hiding(); /* EMIT_SIGNAL */
1960 _mixer.hide_strip (this);
1964 hide_button.set_sensitive(true);
1968 MixerStrip::set_embedded (bool yn)
1974 MixerStrip::map_frozen ()
1976 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1978 boost::shared_ptr<AudioTrack> at = audio_track();
1981 switch (at->freeze_state()) {
1982 case AudioTrack::Frozen:
1983 processor_box.set_sensitive (false);
1984 hide_redirect_editors ();
1987 processor_box.set_sensitive (true);
1988 // XXX need some way, maybe, to retoggle redirect editors
1992 processor_box.set_sensitive (true);
1994 RouteUI::map_frozen ();
1998 MixerStrip::hide_redirect_editors ()
2000 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
2004 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
2006 boost::shared_ptr<Processor> processor (p.lock ());
2011 Gtk::Window* w = processor_box.get_processor_ui (processor);
2019 MixerStrip::reset_strip_style ()
2021 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2023 gpm.set_fader_name ("SendStripBase");
2027 if (is_midi_track()) {
2028 if (_route->active()) {
2029 set_name ("MidiTrackStripBase");
2031 set_name ("MidiTrackStripBaseInactive");
2033 gpm.set_fader_name ("MidiTrackFader");
2034 } else if (is_audio_track()) {
2035 if (_route->active()) {
2036 set_name ("AudioTrackStripBase");
2038 set_name ("AudioTrackStripBaseInactive");
2040 gpm.set_fader_name ("AudioTrackFader");
2042 if (_route->active()) {
2043 set_name ("AudioBusStripBase");
2045 set_name ("AudioBusStripBaseInactive");
2047 gpm.set_fader_name ("AudioBusFader");
2049 /* (no MIDI busses yet) */
2056 MixerStrip::engine_stopped ()
2061 MixerStrip::engine_running ()
2066 MixerStrip::meter_point_string (MeterPoint mp)
2079 case MeterPostFader:
2096 return S_("Meter|In");
2100 return S_("Meter|Pr");
2103 case MeterPostFader:
2104 return S_("Meter|Po");
2108 return S_("Meter|O");
2113 return S_("Meter|C");
2122 /** Called when the monitor-section state */
2124 MixerStrip::monitor_changed ()
2126 assert (monitor_section_button);
2127 if (_session->monitor_active()) {
2128 monitor_section_button->set_name ("master monitor section button active");
2130 monitor_section_button->set_name ("master monitor section button normal");
2135 MixerStrip::monitor_section_added_or_removed ()
2137 assert (monitor_section_button);
2138 if (mute_button->get_parent()) {
2139 mute_button->get_parent()->remove(*mute_button);
2141 if (monitor_section_button->get_parent()) {
2142 monitor_section_button->get_parent()->remove(*monitor_section_button);
2144 if (_session && _session->monitor_out ()) {
2145 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2146 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2147 mute_button->show();
2148 monitor_section_button->show();
2150 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2151 mute_button->show();
2155 /** Called when the metering point has changed */
2157 MixerStrip::meter_changed ()
2159 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2160 gpm.setup_meters ();
2161 // reset peak when meter point changes
2162 gpm.reset_peak_display();
2165 /** The bus that we are displaying sends to has changed, or been turned off.
2166 * @param send_to New bus that we are displaying sends to, or 0.
2169 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2171 RouteUI::bus_send_display_changed (send_to);
2174 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2179 revert_to_default_display ();
2182 revert_to_default_display ();
2187 MixerStrip::drop_send ()
2189 boost::shared_ptr<Send> current_send;
2191 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2192 current_send->set_metering (false);
2195 send_gone_connection.disconnect ();
2196 input_button.set_sensitive (true);
2197 output_button.set_sensitive (true);
2198 group_button.set_sensitive (true);
2199 set_invert_sensitive (true);
2200 gpm.meter_point_button.set_sensitive (true);
2201 mute_button->set_sensitive (true);
2202 solo_button->set_sensitive (true);
2203 solo_isolated_led->set_sensitive (true);
2204 solo_safe_led->set_sensitive (true);
2205 monitor_input_button->set_sensitive (true);
2206 monitor_disk_button->set_sensitive (true);
2207 _comment_button.set_sensitive (true);
2208 trim_control.set_sensitive (true);
2209 if (midi_input_enable_button) {
2210 midi_input_enable_button->set_sensitive (true);
2212 control_slave_ui.set_sensitive (true);
2213 RouteUI::check_rec_enable_sensitivity ();
2214 set_button_names (); // update solo button visual state
2218 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2220 _current_delivery = d;
2221 DeliveryChanged (_current_delivery);
2225 MixerStrip::show_send (boost::shared_ptr<Send> send)
2231 set_current_delivery (send);
2233 send->meter()->set_meter_type (_route->meter_type ());
2234 send->set_metering (true);
2235 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2237 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2238 gain_meter().setup_meters ();
2240 uint32_t const in = _current_delivery->pans_required();
2241 uint32_t const out = _current_delivery->pan_outs();
2243 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2244 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2245 panner_ui().setup_pan ();
2246 panner_ui().set_send_drawing_mode (true);
2247 panner_ui().show_all ();
2249 input_button.set_sensitive (false);
2250 group_button.set_sensitive (false);
2251 set_invert_sensitive (false);
2252 gpm.meter_point_button.set_sensitive (false);
2253 mute_button->set_sensitive (false);
2254 solo_button->set_sensitive (false);
2255 rec_enable_button->set_sensitive (false);
2256 solo_isolated_led->set_sensitive (false);
2257 solo_safe_led->set_sensitive (false);
2258 monitor_input_button->set_sensitive (false);
2259 monitor_disk_button->set_sensitive (false);
2260 _comment_button.set_sensitive (false);
2261 trim_control.set_sensitive (false);
2262 if (midi_input_enable_button) {
2263 midi_input_enable_button->set_sensitive (false);
2265 control_slave_ui.set_sensitive (false);
2267 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2268 output_button.set_sensitive (false);
2271 reset_strip_style ();
2275 MixerStrip::revert_to_default_display ()
2279 set_current_delivery (_route->main_outs ());
2281 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2282 gain_meter().setup_meters ();
2284 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2285 update_panner_choices();
2286 panner_ui().setup_pan ();
2287 panner_ui().set_send_drawing_mode (false);
2289 if (has_audio_outputs ()) {
2290 panners.show_all ();
2292 panners.hide_all ();
2295 reset_strip_style ();
2299 MixerStrip::set_button_names ()
2303 mute_button->set_text (_("Mute"));
2304 monitor_input_button->set_text (_("In"));
2305 monitor_disk_button->set_text (_("Disk"));
2306 if (monitor_section_button) {
2307 monitor_section_button->set_text (_("Mon"));
2310 if (_route && _route->solo_safe_control()->solo_safe()) {
2311 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2313 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2315 if (!Config->get_solo_control_is_listen_control()) {
2316 solo_button->set_text (_("Solo"));
2318 switch (Config->get_listen_position()) {
2319 case AfterFaderListen:
2320 solo_button->set_text (_("AFL"));
2322 case PreFaderListen:
2323 solo_button->set_text (_("PFL"));
2327 solo_isolated_led->set_text (_("Iso"));
2328 solo_safe_led->set_text (S_("SoloLock|Lock"));
2332 mute_button->set_text (S_("Mute|M"));
2333 monitor_input_button->set_text (S_("MonitorInput|I"));
2334 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2335 if (monitor_section_button) {
2336 monitor_section_button->set_text (S_("Mon|O"));
2339 if (_route && _route->solo_safe_control()->solo_safe()) {
2340 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2342 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2344 if (!Config->get_solo_control_is_listen_control()) {
2345 solo_button->set_text (S_("Solo|S"));
2347 switch (Config->get_listen_position()) {
2348 case AfterFaderListen:
2349 solo_button->set_text (S_("AfterFader|A"));
2351 case PreFaderListen:
2352 solo_button->set_text (S_("Prefader|P"));
2357 solo_isolated_led->set_text (S_("SoloIso|I"));
2358 solo_safe_led->set_text (S_("SoloLock|L"));
2363 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2365 gpm.meter_point_button.set_text ("");
2370 MixerStrip::plugin_selector()
2372 return _mixer.plugin_selector();
2376 MixerStrip::hide_things ()
2378 processor_box.hide_things ();
2382 MixerStrip::input_active_button_press (GdkEventButton*)
2384 /* nothing happens on press */
2389 MixerStrip::input_active_button_release (GdkEventButton* ev)
2391 boost::shared_ptr<MidiTrack> mt = midi_track ();
2397 boost::shared_ptr<RouteList> rl (new RouteList);
2399 rl->push_back (route());
2401 _session->set_exclusive_input_active (rl, !mt->input_active(),
2402 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2408 MixerStrip::midi_input_status_changed ()
2410 if (midi_input_enable_button) {
2411 boost::shared_ptr<MidiTrack> mt = midi_track ();
2413 midi_input_enable_button->set_active (mt->input_active ());
2418 MixerStrip::state_id () const
2420 return string_compose ("strip %1", _route->id().to_s());
2424 MixerStrip::parameter_changed (string p)
2426 if (p == _visibility.get_state_name()) {
2427 /* The user has made changes to the mixer strip visibility, so get
2428 our VisibilityGroup to reflect these changes in our widgets.
2430 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2431 } else if (p == "track-name-number") {
2433 update_track_number_visibility();
2437 /** Called to decide whether the solo isolate / solo lock button visibility should
2438 * be overridden from that configured by the user. We do this for the master bus.
2440 * @return optional value that is present if visibility state should be overridden.
2442 boost::optional<bool>
2443 MixerStrip::override_solo_visibility () const
2445 if (_route && _route->is_master ()) {
2446 return boost::optional<bool> (false);
2449 return boost::optional<bool> ();
2453 MixerStrip::add_input_port (DataType t)
2455 _route->input()->add_port ("", this, t);
2459 MixerStrip::add_output_port (DataType t)
2461 _route->output()->add_port ("", this, t);
2465 MixerStrip::route_active_changed ()
2467 reset_strip_style ();
2471 MixerStrip::copy_processors ()
2473 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2477 MixerStrip::cut_processors ()
2479 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2483 MixerStrip::paste_processors ()
2485 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2489 MixerStrip::select_all_processors ()
2491 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2495 MixerStrip::deselect_all_processors ()
2497 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2501 MixerStrip::delete_processors ()
2503 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2507 MixerStrip::toggle_processors ()
2509 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2513 MixerStrip::ab_plugins ()
2515 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2519 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2521 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2524 if (ev->button == 3) {
2525 popup_level_meter_menu (ev);
2533 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2535 using namespace Gtk::Menu_Helpers;
2537 Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
2538 MenuList& items = m->items ();
2540 RadioMenuItem::Group group;
2542 PBD::Unwinder<bool> (_suspend_menu_callbacks, true);
2543 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2544 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2545 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2546 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2547 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2549 if (gpm.meter_channels().n_audio() == 0) {
2550 m->popup (ev->button, ev->time);
2554 RadioMenuItem::Group tgroup;
2555 items.push_back (SeparatorElem());
2557 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2558 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2559 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2560 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2561 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2562 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2563 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2564 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2565 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2566 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2567 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2570 if (_route->is_master()) {
2573 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2574 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2575 /* non-master bus */
2578 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2585 MeterType cmt = _route->meter_type();
2586 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2588 items.push_back (SeparatorElem());
2589 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2590 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2591 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2592 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2593 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2594 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2596 m->popup (ev->button, ev->time);
2600 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2601 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2603 using namespace Menu_Helpers;
2605 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2606 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2607 i->set_active (_route->meter_point() == point);
2611 MixerStrip::set_meter_point (MeterPoint p)
2613 if (_suspend_menu_callbacks) return;
2614 _route->set_meter_point (p);
2618 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2619 RadioMenuItem::Group& group, string const & name, MeterType type)
2621 using namespace Menu_Helpers;
2623 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2624 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2625 i->set_active (_route->meter_type() == type);
2629 MixerStrip::set_meter_type (MeterType t)
2631 if (_suspend_menu_callbacks) return;
2632 _route->set_meter_type (t);
2636 MixerStrip::update_track_number_visibility ()
2638 DisplaySuspender ds;
2639 bool show_label = _session->config.get_track_name_number();
2641 if (_route && _route->is_master()) {
2646 number_label.show ();
2647 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2648 // except the width of the number label is subtracted from the name-hbox, so we
2649 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2650 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2652 number_label.set_size_request(tnw, -1);
2653 number_label.show ();
2655 number_label.hide ();
2660 MixerStrip::color () const
2662 return route_color ();
2666 MixerStrip::marked_for_display () const
2668 return !_route->presentation_info().hidden();
2672 MixerStrip::set_marked_for_display (bool yn)
2674 return RouteUI::mark_hidden (!yn);