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 gpm.set_type (rt->meter_type());
568 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
569 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
571 if (solo_button->get_parent()) {
572 mute_solo_table.remove (*solo_button);
575 if (mute_button->get_parent()) {
576 mute_solo_table.remove (*mute_button);
579 if (route()->is_master()) {
580 solo_button->hide ();
581 mute_button->show ();
582 rec_mon_table.hide ();
583 solo_iso_table.set_sensitive(false);
584 control_slave_ui.set_sensitive(false);
585 if (monitor_section_button == 0) {
586 Glib::RefPtr<Action> act = ActionManager::get_action ("Mixer", "ToggleMonitorSection");
587 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
588 _session->MonitorBusAddedOrRemoved.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_section_added_or_removed, this), gui_context());
590 monitor_section_button = manage (new ArdourButton);
592 monitor_section_button->set_related_action (act);
593 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
594 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
595 monitor_section_button->show();
596 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
597 monitor_section_added_or_removed ();
600 bottom_button_table.attach (group_button, 1, 2, 0, 1);
601 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
602 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
603 mute_button->show ();
604 solo_button->show ();
605 rec_mon_table.show ();
606 solo_iso_table.set_sensitive(true);
607 control_slave_ui.set_sensitive(true);
610 if (_mixer_owned && route()->is_master() ) {
617 monitor_input_button->show ();
618 monitor_disk_button->show ();
620 monitor_input_button->hide();
621 monitor_disk_button->hide ();
624 update_trim_control();
626 if (is_midi_track()) {
627 if (midi_input_enable_button == 0) {
628 midi_input_enable_button = manage (new ArdourButton);
629 midi_input_enable_button->set_name ("midi input button");
630 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
631 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
632 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
633 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
634 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
636 input_button_box.remove (*midi_input_enable_button);
638 /* get current state */
639 midi_input_status_changed ();
640 input_button_box.pack_start (*midi_input_enable_button, false, false);
642 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
644 if (midi_input_enable_button) {
645 /* removal from the container will delete it */
646 input_button_box.remove (*midi_input_enable_button);
647 midi_input_enable_button = 0;
651 if (is_audio_track()) {
652 boost::shared_ptr<AudioTrack> at = audio_track();
653 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
658 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
659 rec_enable_button->show();
661 if (ARDOUR::Profile->get_mixbus()) {
662 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
663 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
664 } else if (ARDOUR::Profile->get_trx()) {
665 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
667 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
668 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
675 if (!_route->is_master()) {
676 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
677 show_sends_button->show();
681 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
683 delete route_ops_menu;
686 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
687 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
688 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
689 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
691 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
693 if (_route->panner_shell()) {
694 update_panner_choices();
695 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
698 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
700 set_stuff_from_route ();
702 /* now force an update of all the various elements */
704 update_mute_display ();
705 update_solo_display ();
708 route_group_changed ();
709 update_track_number_visibility ();
712 panners.setup_pan ();
714 if (has_audio_outputs ()) {
720 update_diskstream_display ();
721 update_input_display ();
722 update_output_display ();
724 add_events (Gdk::BUTTON_RELEASE_MASK);
726 processor_box.show ();
728 if (!route()->is_master() && !route()->is_monitor()) {
729 /* we don't allow master or control routes to be hidden */
734 gpm.reset_peak_display ();
735 gpm.gain_display.show ();
736 gpm.peak_display.show ();
739 width_hide_box.show();
741 global_vpacker.show();
742 mute_solo_table.show();
743 bottom_button_table.show();
745 gpm.meter_point_button.show();
746 input_button_box.show_all();
747 output_button.show();
749 _comment_button.show();
751 gpm.gain_automation_state_button.show();
753 parameter_changed ("mixer-element-visibility");
760 MixerStrip::set_stuff_from_route ()
762 /* if width is not set, it will be set by the MixerUI or editor */
765 if (get_gui_property ("strip-width", width)) {
766 set_width_enum (width, this);
771 MixerStrip::set_width_enum (Width w, void* owner)
773 /* always set the gpm width again, things may be hidden */
776 panners.set_width (w);
778 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
780 _width_owner = owner;
784 if (_width_owner == this) {
785 set_gui_property ("strip-width", _width);
790 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
795 if (show_sends_button) {
796 show_sends_button->set_text (_("Aux"));
799 gpm.gain_automation_state_button.set_text (
800 gpm.astate_string(gain_automation->automation_state()));
802 if (_route->panner()) {
803 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
804 panners.astate_string(_route->panner()->automation_state()));
808 // panners expect an even number of horiz. pixels
809 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
811 set_size_request (width, -1);
817 if (show_sends_button) {
818 show_sends_button->set_text (_("Snd"));
821 gpm.gain_automation_state_button.set_text (
822 gpm.short_astate_string(gain_automation->automation_state()));
823 gain_meter().setup_meters (); // recalc meter width
825 if (_route->panner()) {
826 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
827 panners.short_astate_string(_route->panner()->automation_state()));
831 // panners expect an even number of horiz. pixels
832 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
834 set_size_request (width, -1);
839 processor_box.set_width (w);
841 update_input_display ();
842 update_output_display ();
843 setup_comment_button ();
844 route_group_changed ();
850 MixerStrip::set_packed (bool yn)
853 set_gui_property ("visible", _packed);
857 struct RouteCompareByName {
858 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
859 return a->name().compare (b->name()) < 0;
864 MixerStrip::output_release (GdkEventButton *ev)
866 switch (ev->button) {
868 edit_output_configuration ();
876 MixerStrip::output_press (GdkEventButton *ev)
878 using namespace Menu_Helpers;
879 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
883 MenuList& citems = output_menu.items();
884 switch (ev->button) {
887 return false; //wait for the mouse-up to pop the dialog
891 output_menu.set_name ("ArdourContextMenu");
893 output_menu_bundles.clear ();
895 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
897 citems.push_back (SeparatorElem());
898 uint32_t const n_with_separator = citems.size ();
900 ARDOUR::BundleList current = _route->output()->bundles_connected ();
902 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
904 /* guess the user-intended main type of the route output */
905 DataType intended_type = guess_main_type(false);
907 /* try adding the master bus first */
908 boost::shared_ptr<Route> master = _session->master_out();
910 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
913 /* then other routes inputs */
914 RouteList copy = _session->get_routelist ();
915 copy.sort (RouteCompareByName ());
916 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
917 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
920 /* then try adding user bundles, often labeled/grouped physical inputs */
921 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
922 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
923 maybe_add_bundle_to_output_menu (*i, current, intended_type);
927 /* then all other bundles, including physical outs or other sofware */
928 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
929 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
930 maybe_add_bundle_to_output_menu (*i, current, intended_type);
934 if (citems.size() == n_with_separator) {
935 /* no routes added; remove the separator */
939 if (!ARDOUR::Profile->get_mixbus()) {
940 citems.push_back (SeparatorElem());
942 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
945 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
946 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
952 citems.push_back (SeparatorElem());
953 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
955 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
968 MixerStrip::input_release (GdkEventButton *ev)
970 switch (ev->button) {
973 edit_input_configuration ();
985 MixerStrip::input_press (GdkEventButton *ev)
987 using namespace Menu_Helpers;
989 MenuList& citems = input_menu.items();
990 input_menu.set_name ("ArdourContextMenu");
993 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
997 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
1000 switch (ev->button) {
1003 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1007 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1009 citems.push_back (SeparatorElem());
1010 uint32_t const n_with_separator = citems.size ();
1012 input_menu_bundles.clear ();
1014 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1016 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1018 /* give user bundles first chance at being in the menu */
1020 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1021 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1022 maybe_add_bundle_to_input_menu (*i, current);
1026 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1027 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1028 maybe_add_bundle_to_input_menu (*i, current);
1032 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1033 RouteList copy = *routes;
1034 copy.sort (RouteCompareByName ());
1035 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1036 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1039 if (citems.size() == n_with_separator) {
1040 /* no routes added; remove the separator */
1044 citems.push_back (SeparatorElem());
1045 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1048 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1049 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1054 citems.push_back (SeparatorElem());
1055 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1057 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1069 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1071 if (ignore_toggle) {
1075 _route->input()->connect_ports_to_bundle (c, true, this);
1079 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1081 if (ignore_toggle) {
1085 _route->output()->connect_ports_to_bundle (c, true, true, this);
1089 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1091 using namespace Menu_Helpers;
1093 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1097 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1098 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1102 if (i != input_menu_bundles.end()) {
1106 input_menu_bundles.push_back (b);
1108 MenuList& citems = input_menu.items();
1109 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1113 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1116 using namespace Menu_Helpers;
1118 /* The bundle should be an input one, but not ours */
1119 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1123 /* Don't add the monitor input unless we are Master */
1124 boost::shared_ptr<Route> monitor = _session->monitor_out();
1125 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1128 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1129 * or have the same number of |type| channels than our outputs. */
1130 if (type == DataType::NIL) {
1131 if(b->nchannels() != _route->n_outputs())
1134 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1138 /* Avoid adding duplicates */
1139 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1140 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1143 if (i != output_menu_bundles.end()) {
1147 /* Now add the bundle to the menu */
1148 output_menu_bundles.push_back (b);
1150 MenuList& citems = output_menu.items();
1151 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1155 MixerStrip::update_diskstream_display ()
1157 if (is_track() && input_selector) {
1158 input_selector->hide_all ();
1161 route_color_changed ();
1165 MixerStrip::connect_to_pan ()
1167 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1169 panstate_connection.disconnect ();
1170 panstyle_connection.disconnect ();
1172 if (!_route->panner()) {
1176 boost::shared_ptr<Pannable> p = _route->pannable ();
1178 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1180 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1181 * However, that only works a panner was previously set.
1183 * PannerUI must remain subscribed to _panshell->Changed() in case
1184 * we switch the panner eg. AUX-Send and back
1185 * _route->panner_shell()->Changed() vs _panshell->Changed
1187 if (panners._panner == 0) {
1188 panners.panshell_changed ();
1190 update_panner_choices();
1194 MixerStrip::update_panner_choices ()
1196 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1197 if (!_route->panner_shell()) { return; }
1199 uint32_t in = _route->output()->n_ports().n_audio();
1201 if (_route->panner()) {
1202 in = _route->panner()->in().n_audio();
1205 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1209 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1211 /* The heuristic follows these principles:
1212 * A) If all ports that the user connected are of the same type, then he
1213 * very probably intends to use the IO with that type. A common subcase
1214 * is when the IO has only ports of the same type (connected or not).
1215 * B) If several types of ports are connected, then we should guess based
1216 * on the likeliness of the user wanting to use a given type.
1217 * We assume that the DataTypes are ordered from the most likely to the
1218 * least likely when iterating or comparing them with "<".
1219 * C) If no port is connected, the same logic can be applied with all ports
1220 * instead of connected ones. TODO: Try other ideas, for instance look at
1221 * the last plugin output when |for_input| is false (note: when StrictIO
1222 * the outs of the last plugin should be the same as the outs of the route
1223 * modulo the panner which forwards non-audio anyway).
1224 * All of these constraints are respected by the following algorithm that
1225 * just returns the most likely datatype found in connected ports if any, or
1226 * available ports if any (since if all ports are of the same type, the most
1227 * likely found will be that one obviously). */
1229 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1231 /* Find most likely type among connected ports */
1232 if (favor_connected) {
1233 DataType type = DataType::NIL; /* NIL is always last so least likely */
1234 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1235 if (p->connected() && p->type() < type)
1238 if (type != DataType::NIL) {
1239 /* There has been a connected port (necessarily non-NIL) */
1244 /* Find most likely type among available ports.
1245 * The iterator stops before NIL. */
1246 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1247 if (io->n_ports().n(*t) > 0)
1251 /* No port at all, return the most likely datatype by default */
1252 return DataType::front();
1256 * Output port labelling
1258 * Case 1: Each output has one connection, all connections are to system:playback_%i
1259 * out 1 -> system:playback_1
1260 * out 2 -> system:playback_2
1261 * out 3 -> system:playback_3
1264 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1265 * out 1 -> ardour:track_x/in 1
1266 * out 2 -> ardour:track_x/in 2
1267 * Display as: track_x
1269 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1270 * out 1 -> program x:foo
1271 * out 2 -> program x:foo
1272 * Display as: program x
1274 * Case 4: No connections (Disconnected)
1277 * Default case (unusual routing):
1278 * Display as: *number of connections*
1283 * .-----------------------------------------------.
1285 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1286 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1287 * '-----------------------------------------------'
1288 * .-----------------------------------------------.
1291 * '-----------------------------------------------'
1295 MixerStrip::update_io_button (bool for_input)
1297 ostringstream tooltip;
1298 ostringstream label;
1299 bool have_label = false;
1301 uint32_t total_connection_count = 0;
1302 uint32_t typed_connection_count = 0;
1303 bool each_typed_port_has_one_connection = true;
1305 DataType dt = guess_main_type(for_input);
1306 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1308 /* Fill in the tooltip. Also count:
1309 * - The total number of connections.
1310 * - The number of main-typed connections.
1311 * - Whether each main-typed port has exactly one connection. */
1313 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1314 Gtkmm2ext::markup_escape_text (_route->name()));
1316 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1317 Gtkmm2ext::markup_escape_text (_route->name()));
1320 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1321 vector<string> port_connections;
1322 for (PortSet::iterator port = io->ports().begin();
1323 port != io->ports().end();
1325 port_connections.clear();
1326 port->get_connections(port_connections);
1328 uint32_t port_connection_count = 0;
1330 for (vector<string>::iterator i = port_connections.begin();
1331 i != port_connections.end();
1333 ++port_connection_count;
1335 if (port_connection_count == 1) {
1336 tooltip << endl << Gtkmm2ext::markup_escape_text (
1337 port->name().substr(port->name().find("/") + 1));
1343 tooltip << Gtkmm2ext::markup_escape_text(*i);
1346 total_connection_count += port_connection_count;
1347 if (port->type() == dt) {
1348 typed_connection_count += port_connection_count;
1349 each_typed_port_has_one_connection &= (port_connection_count == 1);
1354 if (total_connection_count == 0) {
1355 tooltip << endl << _("Disconnected");
1358 if (typed_connection_count == 0) {
1363 /* Are all main-typed channels connected to the same route ? */
1365 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1366 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1367 route != routes->end();
1369 boost::shared_ptr<IO> dest_io =
1370 for_input ? (*route)->output() : (*route)->input();
1371 if (io->bundle()->connected_to(dest_io->bundle(),
1374 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1381 /* Are all main-typed channels connected to the same (user) bundle ? */
1383 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1384 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1385 bundle != bundles->end();
1387 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1389 if (io->bundle()->connected_to(*bundle, _session->engine(),
1391 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1398 /* Is each main-typed channel only connected to a physical output ? */
1399 if (!have_label && each_typed_port_has_one_connection) {
1400 ostringstream temp_label;
1401 vector<string> phys;
1402 string playorcapture;
1404 _session->engine().get_physical_inputs(dt, phys);
1405 playorcapture = "capture_";
1407 _session->engine().get_physical_outputs(dt, phys);
1408 playorcapture = "playback_";
1410 for (PortSet::iterator port = io->ports().begin(dt);
1411 port != io->ports().end(dt);
1414 for (vector<string>::iterator s = phys.begin();
1417 if (!port->connected_to(*s))
1419 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1421 string::size_type start = (*s).find(playorcapture);
1422 if (start != string::npos) {
1423 pn = (*s).substr(start + playorcapture.size());
1429 temp_label.str(""); /* erase the failed attempt */
1432 if (port != io->ports().begin(dt))
1437 if (!temp_label.str().empty()) {
1438 label << temp_label.str();
1443 /* Is each main-typed channel connected to a single and different port with
1444 * the same client name (e.g. another JACK client) ? */
1445 if (!have_label && each_typed_port_has_one_connection) {
1446 string maybe_client = "";
1447 vector<string> connections;
1448 for (PortSet::iterator port = io->ports().begin(dt);
1449 port != io->ports().end(dt);
1451 port_connections.clear();
1452 port->get_connections(port_connections);
1453 string connection = port_connections.front();
1455 vector<string>::iterator i = connections.begin();
1456 while (i != connections.end() && *i != connection) {
1459 if (i != connections.end())
1460 break; /* duplicate connection */
1461 connections.push_back(connection);
1463 connection = connection.substr(0, connection.find(":"));
1464 if (maybe_client.empty())
1465 maybe_client = connection;
1466 if (maybe_client != connection)
1469 if (connections.size() == io->n_ports().n(dt)) {
1470 label << maybe_client;
1475 /* Odd configuration */
1477 label << "*" << total_connection_count << "*";
1480 if (total_connection_count > typed_connection_count) {
1481 label << "\u2295"; /* circled plus */
1484 /* Actually set the properties of the button */
1485 char * cstr = new char[tooltip.str().size() + 1];
1486 strcpy(cstr, tooltip.str().c_str());
1489 input_button.set_text (label.str());
1490 set_tooltip (&input_button, cstr);
1492 output_button.set_text (label.str());
1493 set_tooltip (&output_button, cstr);
1500 MixerStrip::update_input_display ()
1502 update_io_button (true);
1503 panners.setup_pan ();
1505 if (has_audio_outputs ()) {
1506 panners.show_all ();
1508 panners.hide_all ();
1514 MixerStrip::update_output_display ()
1516 update_io_button (false);
1517 gpm.setup_meters ();
1518 panners.setup_pan ();
1520 if (has_audio_outputs ()) {
1521 panners.show_all ();
1523 panners.hide_all ();
1528 MixerStrip::fast_update ()
1530 gpm.update_meters ();
1534 MixerStrip::diskstream_changed ()
1536 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1540 MixerStrip::io_changed_proxy ()
1542 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1543 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1547 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1549 boost::shared_ptr<Port> a = wa.lock ();
1550 boost::shared_ptr<Port> b = wb.lock ();
1552 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1553 update_input_display ();
1554 set_width_enum (_width, this);
1557 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1558 update_output_display ();
1559 set_width_enum (_width, this);
1564 MixerStrip::setup_comment_button ()
1566 std::string comment = _route->comment();
1568 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1570 if (comment.empty ()) {
1571 _comment_button.set_name ("generic button");
1572 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1576 _comment_button.set_name ("comment button");
1578 string::size_type pos = comment.find_first_of (" \t\n");
1579 if (pos != string::npos) {
1580 comment = comment.substr (0, pos);
1582 if (comment.empty()) {
1583 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1585 _comment_button.set_text (comment);
1590 MixerStrip::select_route_group (GdkEventButton *ev)
1592 using namespace Menu_Helpers;
1594 if (ev->button == 1) {
1596 if (group_menu == 0) {
1598 PropertyList* plist = new PropertyList();
1600 plist->add (Properties::group_gain, true);
1601 plist->add (Properties::group_mute, true);
1602 plist->add (Properties::group_solo, true);
1604 group_menu = new RouteGroupMenu (_session, plist);
1608 r.push_back (route ());
1609 group_menu->build (r);
1611 RouteGroup *rg = _route->route_group();
1613 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1614 rg ? rg->name() : _("No Group"),
1622 MixerStrip::route_group_changed ()
1624 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1626 RouteGroup *rg = _route->route_group();
1629 group_button.set_text (PBD::short_version (rg->name(), 5));
1633 group_button.set_text (_("Grp"));
1636 group_button.set_text (_("~G"));
1643 MixerStrip::route_color_changed ()
1645 using namespace ARDOUR_UI_UTILS;
1646 name_button.modify_bg (STATE_NORMAL, color());
1647 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1648 reset_strip_style ();
1652 MixerStrip::show_passthru_color ()
1654 reset_strip_style ();
1659 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1661 boost::shared_ptr<Processor> processor (p.lock ());
1662 if (!processor || !processor->display_to_user()) {
1665 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1667 if (pi && pi->is_channelstrip ()) {
1672 ++_plugin_insert_cnt;
1676 MixerStrip::build_route_ops_menu ()
1678 using namespace Menu_Helpers;
1679 route_ops_menu = new Menu;
1680 route_ops_menu->set_name ("ArdourContextMenu");
1682 MenuList& items = route_ops_menu->items();
1684 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1686 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1688 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1690 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1692 if (!Profile->get_mixbus()) {
1693 items.push_back (SeparatorElem());
1696 if (!_route->is_master()
1698 && !_route->mixbus()
1701 if (Profile->get_mixbus()) {
1702 items.push_back (SeparatorElem());
1704 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1707 if (!Profile->get_mixbus()) {
1708 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1709 /* do not allow rename if the track is record-enabled */
1710 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1713 items.push_back (SeparatorElem());
1714 items.push_back (CheckMenuElem (_("Active")));
1715 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1716 i->set_active (_route->active());
1717 i->set_sensitive(! _session->transport_rolling());
1718 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1720 if (!Profile->get_mixbus ()) {
1721 items.push_back (SeparatorElem());
1722 items.push_back (CheckMenuElem (_("Strict I/O")));
1723 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1724 i->set_active (_route->strict_io());
1725 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1729 items.push_back (SeparatorElem());
1731 Gtk::Menu* dio_menu = new Menu;
1732 MenuList& dio_items = dio_menu->items();
1733 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1734 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1735 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1737 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1740 _plugin_insert_cnt = 0;
1741 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1742 if (_plugin_insert_cnt > 0) {
1743 items.push_back (SeparatorElem());
1744 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1747 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1748 items.push_back (MenuElem (_("Patch Selector..."),
1749 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1752 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1753 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1754 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1755 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1758 items.push_back (SeparatorElem());
1759 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1761 items.push_back (SeparatorElem());
1762 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1763 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1764 denormal_menu_item->set_active (_route->denormal_protection());
1767 /* note that this relies on selection being shared across editor and
1768 mixer (or global to the backend, in the future), which is the only
1769 sane thing for users anyway.
1772 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1774 Selection& selection (PublicEditor::instance().get_selection());
1775 if (!selection.selected (stav)) {
1776 selection.set (stav);
1779 if (!_route->is_master()) {
1780 items.push_back (SeparatorElem());
1781 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1784 items.push_back (SeparatorElem());
1785 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1791 MixerStrip::name_button_button_press (GdkEventButton* ev)
1793 if (ev->button == 1 || ev->button == 3) {
1794 list_route_operations ();
1796 if (ev->button == 1) {
1797 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1800 route_ops_menu->popup (3, ev->time);
1810 MixerStrip::number_button_button_press (GdkEventButton* ev)
1812 if ( ev->button == 3 ) {
1813 list_route_operations ();
1815 route_ops_menu->popup (1, ev->time);
1824 MixerStrip::list_route_operations ()
1826 delete route_ops_menu;
1827 build_route_ops_menu ();
1831 MixerStrip::set_selected (bool yn)
1833 AxisView::set_selected (yn);
1836 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1837 global_frame.set_name ("MixerStripSelectedFrame");
1839 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1840 global_frame.set_name ("MixerStripFrame");
1843 global_frame.queue_draw ();
1846 // processor_box.deselect_all_processors();
1850 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1852 if (what_changed.contains (ARDOUR::Properties::name)) {
1858 MixerStrip::name_changed ()
1862 name_button.set_text (_route->name());
1865 name_button.set_text (PBD::short_version (_route->name(), 5));
1869 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1871 if (_session->config.get_track_name_number()) {
1872 const int64_t track_number = _route->track_number ();
1873 if (track_number == 0) {
1874 number_label.set_text ("-");
1876 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1879 number_label.set_text ("");
1884 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1886 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1890 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1892 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1896 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1898 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1902 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1904 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1908 MixerStrip::width_button_pressed (GdkEventButton* ev)
1910 if (ev->button != 1) {
1914 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1917 _mixer.set_strip_width (Narrow, true);
1921 _mixer.set_strip_width (Wide, true);
1927 set_width_enum (Narrow, this);
1930 set_width_enum (Wide, this);
1939 MixerStrip::hide_clicked ()
1941 // LAME fix to reset the button status for when it is redisplayed (part 1)
1942 hide_button.set_sensitive(false);
1945 Hiding(); /* EMIT_SIGNAL */
1947 _mixer.hide_strip (this);
1951 hide_button.set_sensitive(true);
1955 MixerStrip::set_embedded (bool yn)
1961 MixerStrip::map_frozen ()
1963 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1965 boost::shared_ptr<AudioTrack> at = audio_track();
1968 switch (at->freeze_state()) {
1969 case AudioTrack::Frozen:
1970 processor_box.set_sensitive (false);
1971 hide_redirect_editors ();
1974 processor_box.set_sensitive (true);
1975 // XXX need some way, maybe, to retoggle redirect editors
1979 processor_box.set_sensitive (true);
1981 RouteUI::map_frozen ();
1985 MixerStrip::hide_redirect_editors ()
1987 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1991 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1993 boost::shared_ptr<Processor> processor (p.lock ());
1998 Gtk::Window* w = processor_box.get_processor_ui (processor);
2006 MixerStrip::reset_strip_style ()
2008 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2010 gpm.set_fader_name ("SendStripBase");
2014 if (is_midi_track()) {
2015 if (_route->active()) {
2016 set_name ("MidiTrackStripBase");
2018 set_name ("MidiTrackStripBaseInactive");
2020 gpm.set_fader_name ("MidiTrackFader");
2021 } else if (is_audio_track()) {
2022 if (_route->active()) {
2023 set_name ("AudioTrackStripBase");
2025 set_name ("AudioTrackStripBaseInactive");
2027 gpm.set_fader_name ("AudioTrackFader");
2029 if (_route->active()) {
2030 set_name ("AudioBusStripBase");
2032 set_name ("AudioBusStripBaseInactive");
2034 gpm.set_fader_name ("AudioBusFader");
2036 /* (no MIDI busses yet) */
2043 MixerStrip::engine_stopped ()
2048 MixerStrip::engine_running ()
2053 MixerStrip::meter_point_string (MeterPoint mp)
2066 case MeterPostFader:
2083 return S_("Meter|In");
2087 return S_("Meter|Pr");
2090 case MeterPostFader:
2091 return S_("Meter|Po");
2095 return S_("Meter|O");
2100 return S_("Meter|C");
2109 /** Called when the monitor-section state */
2111 MixerStrip::monitor_changed ()
2113 assert (monitor_section_button);
2114 if (_session->monitor_active()) {
2115 monitor_section_button->set_name ("master monitor section button active");
2117 monitor_section_button->set_name ("master monitor section button normal");
2122 MixerStrip::monitor_section_added_or_removed ()
2124 assert (monitor_section_button);
2125 if (mute_button->get_parent()) {
2126 mute_button->get_parent()->remove(*mute_button);
2128 if (monitor_section_button->get_parent()) {
2129 monitor_section_button->get_parent()->remove(*monitor_section_button);
2131 if (_session && _session->monitor_out ()) {
2132 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2133 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2134 mute_button->show();
2135 monitor_section_button->show();
2137 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2138 mute_button->show();
2142 /** Called when the metering point has changed */
2144 MixerStrip::meter_changed ()
2146 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2147 gpm.setup_meters ();
2148 // reset peak when meter point changes
2149 gpm.reset_peak_display();
2152 /** The bus that we are displaying sends to has changed, or been turned off.
2153 * @param send_to New bus that we are displaying sends to, or 0.
2156 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2158 RouteUI::bus_send_display_changed (send_to);
2161 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2166 revert_to_default_display ();
2169 revert_to_default_display ();
2174 MixerStrip::drop_send ()
2176 boost::shared_ptr<Send> current_send;
2178 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2179 current_send->set_metering (false);
2182 send_gone_connection.disconnect ();
2183 input_button.set_sensitive (true);
2184 output_button.set_sensitive (true);
2185 group_button.set_sensitive (true);
2186 set_invert_sensitive (true);
2187 gpm.meter_point_button.set_sensitive (true);
2188 mute_button->set_sensitive (true);
2189 solo_button->set_sensitive (true);
2190 solo_isolated_led->set_sensitive (true);
2191 solo_safe_led->set_sensitive (true);
2192 monitor_input_button->set_sensitive (true);
2193 monitor_disk_button->set_sensitive (true);
2194 _comment_button.set_sensitive (true);
2195 trim_control.set_sensitive (true);
2196 if (midi_input_enable_button) {
2197 midi_input_enable_button->set_sensitive (true);
2199 control_slave_ui.set_sensitive (true);
2200 RouteUI::check_rec_enable_sensitivity ();
2201 set_button_names (); // update solo button visual state
2205 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2207 _current_delivery = d;
2208 DeliveryChanged (_current_delivery);
2212 MixerStrip::show_send (boost::shared_ptr<Send> send)
2218 set_current_delivery (send);
2220 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2221 send->set_metering (true);
2222 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2224 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2225 gain_meter().setup_meters ();
2227 uint32_t const in = _current_delivery->pans_required();
2228 uint32_t const out = _current_delivery->pan_outs();
2230 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2231 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2232 panner_ui().setup_pan ();
2233 panner_ui().set_send_drawing_mode (true);
2234 panner_ui().show_all ();
2236 input_button.set_sensitive (false);
2237 group_button.set_sensitive (false);
2238 set_invert_sensitive (false);
2239 gpm.meter_point_button.set_sensitive (false);
2240 mute_button->set_sensitive (false);
2241 solo_button->set_sensitive (false);
2242 rec_enable_button->set_sensitive (false);
2243 solo_isolated_led->set_sensitive (false);
2244 solo_safe_led->set_sensitive (false);
2245 monitor_input_button->set_sensitive (false);
2246 monitor_disk_button->set_sensitive (false);
2247 _comment_button.set_sensitive (false);
2248 trim_control.set_sensitive (false);
2249 if (midi_input_enable_button) {
2250 midi_input_enable_button->set_sensitive (false);
2252 control_slave_ui.set_sensitive (false);
2254 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2255 output_button.set_sensitive (false);
2258 reset_strip_style ();
2262 MixerStrip::revert_to_default_display ()
2266 set_current_delivery (_route->main_outs ());
2268 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2269 gain_meter().setup_meters ();
2271 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2272 update_panner_choices();
2273 panner_ui().setup_pan ();
2274 panner_ui().set_send_drawing_mode (false);
2276 if (has_audio_outputs ()) {
2277 panners.show_all ();
2279 panners.hide_all ();
2282 reset_strip_style ();
2286 MixerStrip::set_button_names ()
2290 mute_button->set_text (_("Mute"));
2291 monitor_input_button->set_text (_("In"));
2292 monitor_disk_button->set_text (_("Disk"));
2293 if (monitor_section_button) {
2294 monitor_section_button->set_text (_("Mon"));
2297 if (_route && _route->solo_safe_control()->solo_safe()) {
2298 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2300 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2302 if (!Config->get_solo_control_is_listen_control()) {
2303 solo_button->set_text (_("Solo"));
2305 switch (Config->get_listen_position()) {
2306 case AfterFaderListen:
2307 solo_button->set_text (_("AFL"));
2309 case PreFaderListen:
2310 solo_button->set_text (_("PFL"));
2314 solo_isolated_led->set_text (_("Iso"));
2315 solo_safe_led->set_text (S_("SoloLock|Lock"));
2319 mute_button->set_text (S_("Mute|M"));
2320 monitor_input_button->set_text (S_("MonitorInput|I"));
2321 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2322 if (monitor_section_button) {
2323 monitor_section_button->set_text (S_("Mon|O"));
2326 if (_route && _route->solo_safe_control()->solo_safe()) {
2327 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2329 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2331 if (!Config->get_solo_control_is_listen_control()) {
2332 solo_button->set_text (S_("Solo|S"));
2334 switch (Config->get_listen_position()) {
2335 case AfterFaderListen:
2336 solo_button->set_text (S_("AfterFader|A"));
2338 case PreFaderListen:
2339 solo_button->set_text (S_("Prefader|P"));
2344 solo_isolated_led->set_text (S_("SoloIso|I"));
2345 solo_safe_led->set_text (S_("SoloLock|L"));
2350 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2352 gpm.meter_point_button.set_text ("");
2357 MixerStrip::plugin_selector()
2359 return _mixer.plugin_selector();
2363 MixerStrip::hide_things ()
2365 processor_box.hide_things ();
2369 MixerStrip::input_active_button_press (GdkEventButton*)
2371 /* nothing happens on press */
2376 MixerStrip::input_active_button_release (GdkEventButton* ev)
2378 boost::shared_ptr<MidiTrack> mt = midi_track ();
2384 boost::shared_ptr<RouteList> rl (new RouteList);
2386 rl->push_back (route());
2388 _session->set_exclusive_input_active (rl, !mt->input_active(),
2389 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2395 MixerStrip::midi_input_status_changed ()
2397 if (midi_input_enable_button) {
2398 boost::shared_ptr<MidiTrack> mt = midi_track ();
2400 midi_input_enable_button->set_active (mt->input_active ());
2405 MixerStrip::state_id () const
2407 return string_compose ("strip %1", _route->id().to_s());
2411 MixerStrip::parameter_changed (string p)
2413 if (p == _visibility.get_state_name()) {
2414 /* The user has made changes to the mixer strip visibility, so get
2415 our VisibilityGroup to reflect these changes in our widgets.
2417 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2418 } else if (p == "track-name-number") {
2420 update_track_number_visibility();
2424 /** Called to decide whether the solo isolate / solo lock button visibility should
2425 * be overridden from that configured by the user. We do this for the master bus.
2427 * @return optional value that is present if visibility state should be overridden.
2429 boost::optional<bool>
2430 MixerStrip::override_solo_visibility () const
2432 if (_route && _route->is_master ()) {
2433 return boost::optional<bool> (false);
2436 return boost::optional<bool> ();
2440 MixerStrip::add_input_port (DataType t)
2442 _route->input()->add_port ("", this, t);
2446 MixerStrip::add_output_port (DataType t)
2448 _route->output()->add_port ("", this, t);
2452 MixerStrip::route_active_changed ()
2454 reset_strip_style ();
2458 MixerStrip::copy_processors ()
2460 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2464 MixerStrip::cut_processors ()
2466 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2470 MixerStrip::paste_processors ()
2472 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2476 MixerStrip::select_all_processors ()
2478 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2482 MixerStrip::deselect_all_processors ()
2484 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2488 MixerStrip::delete_processors ()
2490 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2494 MixerStrip::toggle_processors ()
2496 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2500 MixerStrip::ab_plugins ()
2502 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2506 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2508 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2511 if (ev->button == 3) {
2512 popup_level_meter_menu (ev);
2520 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2522 using namespace Gtk::Menu_Helpers;
2524 Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
2525 MenuList& items = m->items ();
2527 RadioMenuItem::Group group;
2529 PBD::Unwinder<bool> (_suspend_menu_callbacks, true);
2530 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2531 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2532 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2533 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2534 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2536 if (gpm.meter_channels().n_audio() == 0) {
2537 m->popup (ev->button, ev->time);
2541 RadioMenuItem::Group tgroup;
2542 items.push_back (SeparatorElem());
2544 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2545 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2546 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2547 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2548 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2549 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2550 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2551 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2552 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2553 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2554 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2557 if (_route->is_master()) {
2560 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2561 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2562 /* non-master bus */
2565 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2572 MeterType cmt = _route->meter_type();
2573 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2575 items.push_back (SeparatorElem());
2576 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2577 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2578 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2579 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2580 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2581 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2583 m->popup (ev->button, ev->time);
2587 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2588 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2590 using namespace Menu_Helpers;
2592 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2593 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2594 i->set_active (_route->meter_point() == point);
2598 MixerStrip::set_meter_point (MeterPoint p)
2600 if (_suspend_menu_callbacks) return;
2601 _route->set_meter_point (p);
2605 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2606 RadioMenuItem::Group& group, string const & name, MeterType type)
2608 using namespace Menu_Helpers;
2610 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2611 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2612 i->set_active (_route->meter_type() == type);
2616 MixerStrip::set_meter_type (MeterType t)
2618 if (_suspend_menu_callbacks) return;
2623 MixerStrip::update_track_number_visibility ()
2625 DisplaySuspender ds;
2626 bool show_label = _session->config.get_track_name_number();
2628 if (_route && _route->is_master()) {
2633 number_label.show ();
2634 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2635 // except the width of the number label is subtracted from the name-hbox, so we
2636 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2637 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2639 number_label.set_size_request(tnw, -1);
2640 number_label.show ();
2642 number_label.hide ();
2647 MixerStrip::color () const
2649 return route_color ();
2653 MixerStrip::marked_for_display () const
2655 return !_route->presentation_info().hidden();
2659 MixerStrip::set_marked_for_display (bool yn)
2661 return RouteUI::mark_hidden (!yn);