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"
32 #include "ardour/amp.h"
33 #include "ardour/audio_track.h"
34 #include "ardour/audioengine.h"
35 #include "ardour/internal_send.h"
36 #include "ardour/io.h"
37 #include "ardour/meter.h"
38 #include "ardour/midi_track.h"
39 #include "ardour/pannable.h"
40 #include "ardour/panner.h"
41 #include "ardour/panner_shell.h"
42 #include "ardour/panner_manager.h"
43 #include "ardour/port.h"
44 #include "ardour/profile.h"
45 #include "ardour/route.h"
46 #include "ardour/route_group.h"
47 #include "ardour/send.h"
48 #include "ardour/session.h"
49 #include "ardour/types.h"
50 #include "ardour/user_bundle.h"
51 #include "ardour/vca.h"
52 #include "ardour/vca_manager.h"
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/menu_elems.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/doi.h"
59 #include "widgets/tooltips.h"
61 #include "ardour_window.h"
62 #include "enums_convert.h"
63 #include "mixer_strip.h"
66 #include "public_editor.h"
68 #include "io_selector.h"
70 #include "gui_thread.h"
71 #include "route_group_menu.h"
72 #include "meter_patterns.h"
73 #include "ui_config.h"
77 using namespace ARDOUR;
78 using namespace ArdourWidgets;
81 using namespace Gtkmm2ext;
83 using namespace ArdourMeter;
85 MixerStrip* MixerStrip::_entered_mixer_strip;
86 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
88 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
89 : SessionHandlePtr (sess)
92 , _mixer_owned (in_mixer)
93 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
96 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
97 , rec_mon_table (2, 2)
98 , solo_iso_table (1, 2)
99 , mute_solo_table (1, 2)
100 , bottom_button_table (1, 3)
101 , monitor_section_button (0)
102 , midi_input_enable_button (0)
103 , _plugin_insert_cnt (0)
104 , _comment_button (_("Comments"))
105 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
106 , _visibility (X_("mixer-element-visibility"))
107 , control_slave_ui (sess)
112 /* the editor mixer strip: don't destroy it every time
113 the underlying route goes away.
116 self_destruct = false;
120 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
121 : SessionHandlePtr (sess)
124 , _mixer_owned (in_mixer)
125 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
128 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
129 , rec_mon_table (2, 2)
130 , solo_iso_table (1, 2)
131 , mute_solo_table (1, 2)
132 , bottom_button_table (1, 3)
133 , monitor_section_button (0)
134 , midi_input_enable_button (0)
135 , _plugin_insert_cnt (0)
136 , _comment_button (_("Comments"))
137 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
138 , _visibility (X_("mixer-element-visibility"))
139 , control_slave_ui (sess)
148 _entered_mixer_strip= 0;
151 ignore_comment_edit = false;
152 ignore_toggle = false;
156 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
157 longest_label = "longest label";
159 string t = _("Click to toggle the width of this mixer strip.");
161 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
164 width_button.set_icon (ArdourIcon::StripWidth);
165 hide_button.set_tweaks (ArdourButton::Square);
166 set_tooltip (width_button, t);
168 hide_button.set_icon (ArdourIcon::CloseCross);
169 hide_button.set_tweaks (ArdourButton::Square);
170 set_tooltip (&hide_button, _("Hide this mixer strip"));
172 input_button_box.set_spacing(2);
174 input_button.set_text (_("Input"));
175 input_button.set_name ("mixer strip button");
176 input_button_box.pack_start (input_button, true, true);
178 output_button.set_text (_("Output"));
179 output_button.set_name ("mixer strip button");
181 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
183 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
185 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
186 solo_isolated_led->show ();
187 solo_isolated_led->set_no_show_all (true);
188 solo_isolated_led->set_name (X_("solo isolate"));
189 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
190 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
191 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
193 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
194 solo_safe_led->show ();
195 solo_safe_led->set_no_show_all (true);
196 solo_safe_led->set_name (X_("solo safe"));
197 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
198 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
199 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
201 solo_safe_led->set_text (S_("SoloLock|Lock"));
202 solo_isolated_led->set_text (_("Iso"));
204 solo_iso_table.set_homogeneous (true);
205 solo_iso_table.set_spacings (2);
206 if (!ARDOUR::Profile->get_trx()) {
207 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
208 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
210 solo_iso_table.show ();
212 rec_mon_table.set_homogeneous (true);
213 rec_mon_table.set_row_spacings (2);
214 rec_mon_table.set_col_spacings (2);
215 if (ARDOUR::Profile->get_mixbus()) {
216 rec_mon_table.resize (1, 3);
217 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
218 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
219 } else if (!ARDOUR::Profile->get_trx()) {
220 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
221 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
223 rec_mon_table.show ();
225 if (solo_isolated_led) {
226 button_size_group->add_widget (*solo_isolated_led);
229 button_size_group->add_widget (*solo_safe_led);
232 if (!ARDOUR::Profile->get_mixbus()) {
233 if (rec_enable_button) {
234 button_size_group->add_widget (*rec_enable_button);
236 if (monitor_disk_button) {
237 button_size_group->add_widget (*monitor_disk_button);
239 if (monitor_input_button) {
240 button_size_group->add_widget (*monitor_input_button);
244 mute_solo_table.set_homogeneous (true);
245 mute_solo_table.set_spacings (2);
247 bottom_button_table.set_spacings (2);
248 bottom_button_table.set_homogeneous (true);
249 bottom_button_table.attach (group_button, 1, 2, 0, 1);
250 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
252 name_button.set_name ("mixer strip button");
253 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
254 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
256 set_tooltip (&group_button, _("Mix group"));
257 group_button.set_name ("mixer strip button");
259 _comment_button.set_name (X_("mixer strip button"));
260 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
261 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
262 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
264 // TODO implement ArdourKnob::on_size_request properly
265 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
266 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
268 trim_control.set_tooltip_prefix (_("Trim: "));
269 trim_control.set_name ("trim knob");
270 trim_control.set_no_show_all (true);
271 trim_control.StartGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_start_touch));
272 trim_control.StopGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_end_touch));
273 input_button_box.pack_start (trim_control, false, false);
275 global_vpacker.set_border_width (1);
276 global_vpacker.set_spacing (0);
278 width_button.set_name ("mixer strip button");
279 hide_button.set_name ("mixer strip button");
281 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
282 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
284 width_hide_box.set_spacing (2);
285 width_hide_box.pack_start (width_button, false, true);
286 width_hide_box.pack_start (number_label, true, true);
287 width_hide_box.pack_end (hide_button, false, true);
289 number_label.set_text ("-");
290 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
291 number_label.set_no_show_all ();
292 number_label.set_name ("tracknumber label");
293 number_label.set_fixed_colors (0x80808080, 0x80808080);
294 number_label.set_alignment (.5, .5);
295 number_label.set_fallthrough_to_parent (true);
296 number_label.set_tweaks (ArdourButton::OccasionalText);
298 global_vpacker.set_spacing (2);
299 if (!ARDOUR::Profile->get_trx()) {
300 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
301 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
302 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
303 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
304 global_vpacker.pack_start (processor_box, true, true);
306 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
313 if (!ARDOUR::Profile->get_trx()) {
314 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
321 //add a spacer underneath the master bus;
322 //this fills the area that is taken up by the scrollbar on the tracks;
323 //and therefore keeps the faders "even" across the bottom
324 int scrollbar_height = 0;
326 Gtk::Window window (WINDOW_TOPLEVEL);
327 HScrollbar scrollbar;
328 window.add (scrollbar);
329 scrollbar.set_name ("MixerWindow");
330 scrollbar.ensure_style();
331 Gtk::Requisition requisition(scrollbar.size_request ());
332 scrollbar_height = requisition.height;
334 spacer.set_size_request (-1, scrollbar_height);
335 global_vpacker.pack_end (spacer, false, false);
338 global_frame.add (global_vpacker);
339 global_frame.set_shadow_type (Gtk::SHADOW_IN);
340 global_frame.set_name ("BaseFrame");
344 /* force setting of visible selected status */
347 set_selected (false);
352 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
353 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
355 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
356 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
357 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
359 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
360 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
362 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
363 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
364 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
366 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
368 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
370 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
374 /* start off as a passthru strip. we'll correct this, if necessary,
375 in update_diskstream_display().
378 /* start off as a passthru strip. we'll correct this, if necessary,
379 in update_diskstream_display().
382 if (is_midi_track()) {
383 set_name ("MidiTrackStripBase");
385 set_name ("AudioTrackStripBase");
388 add_events (Gdk::BUTTON_RELEASE_MASK|
389 Gdk::ENTER_NOTIFY_MASK|
390 Gdk::LEAVE_NOTIFY_MASK|
392 Gdk::KEY_RELEASE_MASK);
394 set_flags (get_flags() | Gtk::CAN_FOCUS);
396 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
397 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
400 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
401 must be the same as those used in RCOptionEditor so that the configuration changes
402 are recognised when they occur.
404 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
405 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
406 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
407 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
408 _visibility.add (&output_button, X_("Output"), _("Output"), false);
409 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
410 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
412 parameter_changed (X_("mixer-element-visibility"));
413 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
414 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
415 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
417 //watch for mouse enter/exit so we can do some stuff
418 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
419 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
421 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
424 MixerStrip::~MixerStrip ()
426 CatchDeletion (this);
428 if (this ==_entered_mixer_strip)
429 _entered_mixer_strip = NULL;
433 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
435 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
441 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
443 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
449 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
451 _entered_mixer_strip = this;
453 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
454 //because the mixerstrip control is a parent that encompasses the strip
455 deselect_all_processors();
461 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
463 //if we have moved outside our strip, but not into a child view, then deselect ourselves
464 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
465 _entered_mixer_strip= 0;
467 //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
468 gpm.gain_display.set_sensitive(false);
470 gpm.gain_display.set_sensitive(true);
472 //if we leave this mixer strip we need to clear out any selections
473 //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
480 MixerStrip::name() const
483 return _route->name();
489 MixerStrip::update_trim_control ()
491 if (route()->trim() && route()->trim()->active() &&
492 route()->n_inputs().n_audio() > 0) {
493 trim_control.show ();
494 trim_control.set_controllable (route()->trim()->gain_control());
496 trim_control.hide ();
497 boost::shared_ptr<Controllable> none;
498 trim_control.set_controllable (none);
503 MixerStrip::trim_start_touch ()
505 assert (_route && _session);
506 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
507 route()->trim()->gain_control ()->start_touch (_session->transport_frame());
512 MixerStrip::trim_end_touch ()
514 assert (_route && _session);
515 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
516 route()->trim()->gain_control ()->stop_touch (_session->transport_frame());
521 MixerStrip::set_route (boost::shared_ptr<Route> rt)
523 //the rec/monitor stuff only shows up for tracks.
524 //the show_sends only shows up for buses.
525 //remove them all here, and we may add them back later
526 if (show_sends_button->get_parent()) {
527 rec_mon_table.remove (*show_sends_button);
529 if (rec_enable_button->get_parent()) {
530 rec_mon_table.remove (*rec_enable_button);
532 if (monitor_input_button->get_parent()) {
533 rec_mon_table.remove (*monitor_input_button);
535 if (monitor_disk_button->get_parent()) {
536 rec_mon_table.remove (*monitor_disk_button);
538 if (group_button.get_parent()) {
539 bottom_button_table.remove (group_button);
542 RouteUI::set_route (rt);
544 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
546 /* ProcessorBox needs access to _route so that it can read
549 processor_box.set_route (rt);
551 revert_to_default_display ();
553 /* unpack these from the parent and stuff them into our own
557 if (gpm.peak_display.get_parent()) {
558 gpm.peak_display.get_parent()->remove (gpm.peak_display);
560 if (gpm.gain_display.get_parent()) {
561 gpm.gain_display.get_parent()->remove (gpm.gain_display);
564 gpm.set_type (rt->meter_type());
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 ("Common", "ToggleMonitorSection");
585 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
587 monitor_section_button = manage (new ArdourButton);
589 monitor_section_button->set_related_action (act);
590 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
591 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
592 monitor_section_button->show();
593 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
595 parameter_changed ("use-monitor-bus");
597 bottom_button_table.attach (group_button, 1, 2, 0, 1);
598 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
599 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
600 mute_button->show ();
601 solo_button->show ();
602 rec_mon_table.show ();
603 solo_iso_table.set_sensitive(true);
604 control_slave_ui.set_sensitive(true);
607 if (_mixer_owned && route()->is_master() ) {
614 monitor_input_button->show ();
615 monitor_disk_button->show ();
617 monitor_input_button->hide();
618 monitor_disk_button->hide ();
621 update_trim_control();
623 if (is_midi_track()) {
624 if (midi_input_enable_button == 0) {
625 midi_input_enable_button = manage (new ArdourButton);
626 midi_input_enable_button->set_name ("midi input button");
627 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
628 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
629 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
630 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
631 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
633 input_button_box.remove (*midi_input_enable_button);
635 /* get current state */
636 midi_input_status_changed ();
637 input_button_box.pack_start (*midi_input_enable_button, false, false);
639 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
641 if (midi_input_enable_button) {
642 /* removal from the container will delete it */
643 input_button_box.remove (*midi_input_enable_button);
644 midi_input_enable_button = 0;
648 if (is_audio_track()) {
649 boost::shared_ptr<AudioTrack> at = audio_track();
650 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
655 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
656 rec_enable_button->show();
658 if (ARDOUR::Profile->get_mixbus()) {
659 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
660 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
661 } else if (ARDOUR::Profile->get_trx()) {
662 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
664 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
665 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
672 if (!_route->is_master()) {
673 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
674 show_sends_button->show();
678 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
680 delete route_ops_menu;
683 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
684 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
685 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
686 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
688 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
690 if (_route->panner_shell()) {
691 update_panner_choices();
692 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
695 if (is_audio_track()) {
696 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
699 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
701 set_stuff_from_route ();
703 /* now force an update of all the various elements */
705 update_mute_display ();
706 update_solo_display ();
709 route_group_changed ();
710 update_track_number_visibility ();
713 panners.setup_pan ();
715 if (has_audio_outputs ()) {
721 update_diskstream_display ();
722 update_input_display ();
723 update_output_display ();
725 add_events (Gdk::BUTTON_RELEASE_MASK);
727 processor_box.show ();
729 if (!route()->is_master() && !route()->is_monitor()) {
730 /* we don't allow master or control routes to be hidden */
735 gpm.reset_peak_display ();
736 gpm.gain_display.show ();
737 gpm.peak_display.show ();
740 width_hide_box.show();
742 global_vpacker.show();
743 mute_solo_table.show();
744 bottom_button_table.show();
746 gpm.meter_point_button.show();
747 input_button_box.show_all();
748 output_button.show();
750 _comment_button.show();
752 gpm.gain_automation_state_button.show();
754 parameter_changed ("mixer-element-visibility");
761 MixerStrip::set_stuff_from_route ()
763 /* if width is not set, it will be set by the MixerUI or editor */
766 if (get_gui_property ("strip-width", width)) {
767 set_width_enum (width, this);
772 MixerStrip::set_width_enum (Width w, void* owner)
774 /* always set the gpm width again, things may be hidden */
777 panners.set_width (w);
779 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
781 _width_owner = owner;
785 if (_width_owner == this) {
786 set_gui_property ("strip-width", _width);
791 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
796 if (show_sends_button) {
797 show_sends_button->set_text (_("Aux"));
800 gpm.gain_automation_state_button.set_text (
801 gpm.astate_string(gain_automation->automation_state()));
803 if (_route->panner()) {
804 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
805 panners.astate_string(_route->panner()->automation_state()));
809 // panners expect an even number of horiz. pixels
810 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
812 set_size_request (width, -1);
818 if (show_sends_button) {
819 show_sends_button->set_text (_("Snd"));
822 gpm.gain_automation_state_button.set_text (
823 gpm.short_astate_string(gain_automation->automation_state()));
824 gain_meter().setup_meters (); // recalc meter width
826 if (_route->panner()) {
827 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
828 panners.short_astate_string(_route->panner()->automation_state()));
832 // panners expect an even number of horiz. pixels
833 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
835 set_size_request (width, -1);
840 processor_box.set_width (w);
842 update_input_display ();
843 update_output_display ();
844 setup_comment_button ();
845 route_group_changed ();
851 MixerStrip::set_packed (bool yn)
854 set_gui_property ("visible", _packed);
858 struct RouteCompareByName {
859 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
860 return a->name().compare (b->name()) < 0;
865 MixerStrip::output_release (GdkEventButton *ev)
867 switch (ev->button) {
869 edit_output_configuration ();
877 MixerStrip::output_press (GdkEventButton *ev)
879 using namespace Menu_Helpers;
880 if (!_session->engine().connected()) {
881 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
886 MenuList& citems = output_menu.items();
887 switch (ev->button) {
890 return false; //wait for the mouse-up to pop the dialog
894 output_menu.set_name ("ArdourContextMenu");
896 output_menu_bundles.clear ();
898 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
900 citems.push_back (SeparatorElem());
901 uint32_t const n_with_separator = citems.size ();
903 ARDOUR::BundleList current = _route->output()->bundles_connected ();
905 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
907 /* guess the user-intended main type of the route output */
908 DataType intended_type = guess_main_type(false);
910 /* try adding the master bus first */
911 boost::shared_ptr<Route> master = _session->master_out();
913 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
916 /* then other routes inputs */
917 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
918 RouteList copy = *routes;
919 copy.sort (RouteCompareByName ());
920 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
921 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
924 /* then try adding user bundles, often labeled/grouped physical inputs */
925 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
926 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
927 maybe_add_bundle_to_output_menu (*i, current, intended_type);
931 /* then all other bundles, including physical outs or other sofware */
932 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
933 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
934 maybe_add_bundle_to_output_menu (*i, current, intended_type);
938 if (citems.size() == n_with_separator) {
939 /* no routes added; remove the separator */
943 if (!ARDOUR::Profile->get_mixbus()) {
944 citems.push_back (SeparatorElem());
946 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
949 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
950 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
956 citems.push_back (SeparatorElem());
957 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
959 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
972 MixerStrip::input_release (GdkEventButton *ev)
974 switch (ev->button) {
977 edit_input_configuration ();
989 MixerStrip::input_press (GdkEventButton *ev)
991 using namespace Menu_Helpers;
993 MenuList& citems = input_menu.items();
994 input_menu.set_name ("ArdourContextMenu");
997 if (!_session->engine().connected()) {
998 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
1003 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
1006 switch (ev->button) {
1009 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1013 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1015 citems.push_back (SeparatorElem());
1016 uint32_t const n_with_separator = citems.size ();
1018 input_menu_bundles.clear ();
1020 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1022 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1024 /* give user bundles first chance at being in the menu */
1026 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1027 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1028 maybe_add_bundle_to_input_menu (*i, current);
1032 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1033 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1034 maybe_add_bundle_to_input_menu (*i, current);
1038 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1039 RouteList copy = *routes;
1040 copy.sort (RouteCompareByName ());
1041 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1042 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1045 if (citems.size() == n_with_separator) {
1046 /* no routes added; remove the separator */
1050 citems.push_back (SeparatorElem());
1051 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1054 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1055 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1060 citems.push_back (SeparatorElem());
1061 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1063 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1075 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1077 if (ignore_toggle) {
1081 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1083 if (std::find (current.begin(), current.end(), c) == current.end()) {
1084 _route->input()->connect_ports_to_bundle (c, true, this);
1086 _route->input()->disconnect_ports_from_bundle (c, this);
1091 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1093 if (ignore_toggle) {
1097 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1099 if (std::find (current.begin(), current.end(), c) == current.end()) {
1100 _route->output()->connect_ports_to_bundle (c, true, this);
1102 _route->output()->disconnect_ports_from_bundle (c, this);
1107 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1109 using namespace Menu_Helpers;
1111 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1115 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1116 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1120 if (i != input_menu_bundles.end()) {
1124 input_menu_bundles.push_back (b);
1126 MenuList& citems = input_menu.items();
1127 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1131 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1134 using namespace Menu_Helpers;
1136 /* The bundle should be an input one, but not ours */
1137 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1141 /* Don't add the monitor input unless we are Master */
1142 boost::shared_ptr<Route> monitor = _session->monitor_out();
1143 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1146 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1147 * or have the same number of |type| channels than our outputs. */
1148 if (type == DataType::NIL) {
1149 if(b->nchannels() != _route->n_outputs())
1152 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1156 /* Avoid adding duplicates */
1157 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1158 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1161 if (i != output_menu_bundles.end()) {
1165 /* Now add the bundle to the menu */
1166 output_menu_bundles.push_back (b);
1168 MenuList& citems = output_menu.items();
1169 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1173 MixerStrip::update_diskstream_display ()
1175 if (is_track() && input_selector) {
1176 input_selector->hide_all ();
1179 route_color_changed ();
1183 MixerStrip::connect_to_pan ()
1185 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1187 panstate_connection.disconnect ();
1188 panstyle_connection.disconnect ();
1190 if (!_route->panner()) {
1194 boost::shared_ptr<Pannable> p = _route->pannable ();
1196 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1198 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1199 * However, that only works a panner was previously set.
1201 * PannerUI must remain subscribed to _panshell->Changed() in case
1202 * we switch the panner eg. AUX-Send and back
1203 * _route->panner_shell()->Changed() vs _panshell->Changed
1205 if (panners._panner == 0) {
1206 panners.panshell_changed ();
1208 update_panner_choices();
1212 MixerStrip::update_panner_choices ()
1214 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1215 if (!_route->panner_shell()) { return; }
1217 uint32_t in = _route->output()->n_ports().n_audio();
1219 if (_route->panner()) {
1220 in = _route->panner()->in().n_audio();
1223 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1227 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1229 /* The heuristic follows these principles:
1230 * A) If all ports that the user connected are of the same type, then he
1231 * very probably intends to use the IO with that type. A common subcase
1232 * is when the IO has only ports of the same type (connected or not).
1233 * B) If several types of ports are connected, then we should guess based
1234 * on the likeliness of the user wanting to use a given type.
1235 * We assume that the DataTypes are ordered from the most likely to the
1236 * least likely when iterating or comparing them with "<".
1237 * C) If no port is connected, the same logic can be applied with all ports
1238 * instead of connected ones. TODO: Try other ideas, for instance look at
1239 * the last plugin output when |for_input| is false (note: when StrictIO
1240 * the outs of the last plugin should be the same as the outs of the route
1241 * modulo the panner which forwards non-audio anyway).
1242 * All of these constraints are respected by the following algorithm that
1243 * just returns the most likely datatype found in connected ports if any, or
1244 * available ports if any (since if all ports are of the same type, the most
1245 * likely found will be that one obviously). */
1247 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1249 /* Find most likely type among connected ports */
1250 if (favor_connected) {
1251 DataType type = DataType::NIL; /* NIL is always last so least likely */
1252 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1253 if (p->connected() && p->type() < type)
1256 if (type != DataType::NIL) {
1257 /* There has been a connected port (necessarily non-NIL) */
1262 /* Find most likely type among available ports.
1263 * The iterator stops before NIL. */
1264 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1265 if (io->n_ports().n(*t) > 0)
1269 /* No port at all, return the most likely datatype by default */
1270 return DataType::front();
1274 * Output port labelling
1275 * =====================
1277 * Case 1: Each output has one connection, all connections are to system:playback_%i
1278 * out 1 -> system:playback_1
1279 * out 2 -> system:playback_2
1280 * out 3 -> system:playback_3
1283 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1284 * out 1 -> ardour:track_x/in 1
1285 * out 2 -> ardour:track_x/in 2
1286 * Display as: track_x
1288 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1289 * out 1 -> program x:foo
1290 * out 2 -> program x:foo
1291 * Display as: program x
1293 * Case 4: No connections (Disconnected)
1296 * Default case (unusual routing):
1297 * Display as: *number of connections*
1301 * .-----------------------------------------------.
1303 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1304 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1305 * '-----------------------------------------------'
1306 * .-----------------------------------------------.
1309 * '-----------------------------------------------'
1313 MixerStrip::update_io_button (bool for_input)
1315 vector<string> port_connections;
1317 uint32_t total_connection_count = 0;
1318 uint32_t io_connection_count = 0;
1319 uint32_t ardour_connection_count = 0;
1320 uint32_t system_connection_count = 0;
1321 uint32_t other_connection_count = 0;
1322 uint32_t typed_connection_count = 0;
1324 ostringstream label;
1326 bool have_label = false;
1327 bool each_io_has_one_connection = true;
1329 string connection_name;
1330 string ardour_track_name;
1331 string other_connection_type;
1332 string system_ports;
1335 ostringstream tooltip;
1336 char * tooltip_cstr;
1338 DataType dt = guess_main_type(for_input);
1340 if ( dt == DataType::MIDI ) {
1341 tooltip << _("MIDI ");
1345 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1347 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1350 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1351 for (PortSet::iterator port = io->ports().begin(); port != io->ports().end(); ++port) {
1352 port_connections.clear ();
1353 port->get_connections(port_connections);
1355 //ignore any port connections that don't match our DataType
1356 if (port->type() != dt) {
1357 if (!port_connections.empty()) {
1358 ++typed_connection_count;
1363 io_connection_count = 0;
1365 if (!port_connections.empty()) {
1366 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1368 string& connection_name (*i);
1370 if (connection_name.find("system:") == 0) {
1371 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1374 if (io_connection_count == 0) {
1375 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1377 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1380 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1383 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1384 if (ardour_track_name.empty()) {
1385 // "ardour:Master/in 1" -> "ardour:Master/"
1386 string::size_type slash = connection_name.find("/");
1387 if (slash != string::npos) {
1388 ardour_track_name = connection_name.substr(0, slash + 1);
1392 if (connection_name.find(ardour_track_name) == 0) {
1393 ++ardour_connection_count;
1395 } else if (!pn.empty()) {
1396 if (system_ports.empty()) {
1399 system_ports += "/" + pn;
1401 if (connection_name.find("system:") == 0) {
1402 ++system_connection_count;
1404 } else if (connection_name.find("system:midi_") == 0) {
1406 // "system:midi_capture_123" -> "123"
1407 system_port = "M " + connection_name.substr(20);
1409 // "system:midi_playback_123" -> "123"
1410 system_port = "M " + connection_name.substr(21);
1413 if (system_ports.empty()) {
1414 system_ports += system_port;
1416 system_ports += "/" + system_port;
1419 ++system_connection_count;
1421 } else if (connection_name.find("system:") == 0) {
1423 // "system:capture_123" -> "123"
1424 system_port = connection_name.substr(15);
1426 // "system:playback_123" -> "123"
1427 system_port = connection_name.substr(16);
1430 if (system_ports.empty()) {
1431 system_ports += system_port;
1433 system_ports += "/" + system_port;
1436 ++system_connection_count;
1438 if (other_connection_type.empty()) {
1439 // "jamin:in 1" -> "jamin:"
1440 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1443 if (connection_name.find(other_connection_type) == 0) {
1444 ++other_connection_count;
1448 ++total_connection_count;
1449 ++io_connection_count;
1453 if (io_connection_count != 1) {
1454 each_io_has_one_connection = false;
1458 if (total_connection_count == 0) {
1459 tooltip << endl << _("Disconnected");
1462 tooltip_cstr = new char[tooltip.str().size() + 1];
1463 strcpy(tooltip_cstr, tooltip.str().c_str());
1466 set_tooltip (&input_button, tooltip_cstr);
1468 set_tooltip (&output_button, tooltip_cstr);
1471 delete [] tooltip_cstr;
1473 if (each_io_has_one_connection) {
1474 if (total_connection_count == ardour_connection_count) {
1475 // all connections are to the same track in ardour
1476 // "ardour:Master/" -> "Master"
1477 string::size_type slash = ardour_track_name.find("/");
1478 if (slash != string::npos) {
1479 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1480 label << ardour_track_name.substr (ppps, slash - ppps);
1484 else if (total_connection_count == system_connection_count) {
1485 // all connections are to system ports
1486 label << system_ports;
1489 else if (total_connection_count == other_connection_count) {
1490 // all connections are to the same external program eg jamin
1491 // "jamin:" -> "jamin"
1492 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1498 if (total_connection_count == 0) {
1502 // Odd configuration
1503 label << "*" << total_connection_count << "*";
1505 if (typed_connection_count > 0) {
1506 label << "\u2295"; // circled plus
1511 input_button.set_text (label.str());
1513 output_button.set_text (label.str());
1518 MixerStrip::update_input_display ()
1520 update_io_button (true);
1521 panners.setup_pan ();
1523 if (has_audio_outputs ()) {
1524 panners.show_all ();
1526 panners.hide_all ();
1532 MixerStrip::update_output_display ()
1534 update_io_button (false);
1535 gpm.setup_meters ();
1536 panners.setup_pan ();
1538 if (has_audio_outputs ()) {
1539 panners.show_all ();
1541 panners.hide_all ();
1546 MixerStrip::fast_update ()
1548 gpm.update_meters ();
1552 MixerStrip::diskstream_changed ()
1554 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1558 MixerStrip::io_changed_proxy ()
1560 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1561 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1565 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1567 boost::shared_ptr<Port> a = wa.lock ();
1568 boost::shared_ptr<Port> b = wb.lock ();
1570 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1571 update_input_display ();
1572 set_width_enum (_width, this);
1575 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1576 update_output_display ();
1577 set_width_enum (_width, this);
1582 MixerStrip::setup_comment_button ()
1584 std::string comment = _route->comment();
1586 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1588 if (comment.empty ()) {
1589 _comment_button.set_name ("generic button");
1590 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1594 _comment_button.set_name ("comment button");
1596 string::size_type pos = comment.find_first_of (" \t\n");
1597 if (pos != string::npos) {
1598 comment = comment.substr (0, pos);
1600 if (comment.empty()) {
1601 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1603 _comment_button.set_text (comment);
1608 MixerStrip::select_route_group (GdkEventButton *ev)
1610 using namespace Menu_Helpers;
1612 if (ev->button == 1) {
1614 if (group_menu == 0) {
1616 PropertyList* plist = new PropertyList();
1618 plist->add (Properties::group_gain, true);
1619 plist->add (Properties::group_mute, true);
1620 plist->add (Properties::group_solo, true);
1622 group_menu = new RouteGroupMenu (_session, plist);
1626 r.push_back (route ());
1627 group_menu->build (r);
1629 RouteGroup *rg = _route->route_group();
1631 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1632 rg ? rg->name() : _("No Group"),
1640 MixerStrip::route_group_changed ()
1642 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1644 RouteGroup *rg = _route->route_group();
1647 group_button.set_text (PBD::short_version (rg->name(), 5));
1651 group_button.set_text (_("Grp"));
1654 group_button.set_text (_("~G"));
1661 MixerStrip::route_color_changed ()
1663 using namespace ARDOUR_UI_UTILS;
1664 name_button.modify_bg (STATE_NORMAL, color());
1665 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1666 reset_strip_style ();
1670 MixerStrip::show_passthru_color ()
1672 reset_strip_style ();
1677 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1679 boost::shared_ptr<Processor> processor (p.lock ());
1680 if (!processor || !processor->display_to_user()) {
1683 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1685 if (pi && pi->is_channelstrip ()) {
1690 ++_plugin_insert_cnt;
1694 MixerStrip::build_route_ops_menu ()
1696 using namespace Menu_Helpers;
1697 route_ops_menu = new Menu;
1698 route_ops_menu->set_name ("ArdourContextMenu");
1700 MenuList& items = route_ops_menu->items();
1702 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1704 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1706 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1708 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1710 if (!Profile->get_mixbus()) {
1711 items.push_back (SeparatorElem());
1714 if (!_route->is_master()
1716 && !_route->mixbus()
1719 if (Profile->get_mixbus()) {
1720 items.push_back (SeparatorElem());
1722 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1725 if (!Profile->get_mixbus()) {
1726 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1727 /* do not allow rename if the track is record-enabled */
1728 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1731 items.push_back (SeparatorElem());
1732 items.push_back (CheckMenuElem (_("Active")));
1733 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1734 i->set_active (_route->active());
1735 i->set_sensitive(! _session->transport_rolling());
1736 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1738 if (!Profile->get_mixbus ()) {
1739 items.push_back (SeparatorElem());
1740 items.push_back (CheckMenuElem (_("Strict I/O")));
1741 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1742 i->set_active (_route->strict_io());
1743 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1746 _plugin_insert_cnt = 0;
1747 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1748 if (_plugin_insert_cnt > 0) {
1749 items.push_back (SeparatorElem());
1750 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1753 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1754 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1755 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1756 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1759 items.push_back (SeparatorElem());
1760 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1762 items.push_back (SeparatorElem());
1763 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1764 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1765 denormal_menu_item->set_active (_route->denormal_protection());
1768 /* note that this relies on selection being shared across editor and
1769 mixer (or global to the backend, in the future), which is the only
1770 sane thing for users anyway.
1773 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1775 Selection& selection (PublicEditor::instance().get_selection());
1776 if (!selection.selected (stav)) {
1777 selection.set (stav);
1780 if (!_route->is_master()) {
1781 items.push_back (SeparatorElem());
1782 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1785 items.push_back (SeparatorElem());
1786 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1792 MixerStrip::name_button_button_press (GdkEventButton* ev)
1794 if (ev->button == 1 || ev->button == 3) {
1795 list_route_operations ();
1797 if (ev->button == 1) {
1798 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1801 route_ops_menu->popup (3, ev->time);
1811 MixerStrip::number_button_button_press (GdkEventButton* ev)
1813 if ( ev->button == 3 ) {
1814 list_route_operations ();
1816 route_ops_menu->popup (1, ev->time);
1825 MixerStrip::list_route_operations ()
1827 delete route_ops_menu;
1828 build_route_ops_menu ();
1832 MixerStrip::set_selected (bool yn)
1834 AxisView::set_selected (yn);
1837 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1838 global_frame.set_name ("MixerStripSelectedFrame");
1840 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1841 global_frame.set_name ("MixerStripFrame");
1844 global_frame.queue_draw ();
1847 // processor_box.deselect_all_processors();
1851 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1853 if (what_changed.contains (ARDOUR::Properties::name)) {
1859 MixerStrip::name_changed ()
1863 name_button.set_text (_route->name());
1866 name_button.set_text (PBD::short_version (_route->name(), 5));
1870 set_tooltip (name_button, _route->name());
1872 if (_session->config.get_track_name_number()) {
1873 const int64_t track_number = _route->track_number ();
1874 if (track_number == 0) {
1875 number_label.set_text ("-");
1877 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1880 number_label.set_text ("");
1885 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1887 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1891 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1893 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1897 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1899 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1903 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1905 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1909 MixerStrip::width_button_pressed (GdkEventButton* ev)
1911 if (ev->button != 1) {
1915 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1918 _mixer.set_strip_width (Narrow, true);
1922 _mixer.set_strip_width (Wide, true);
1928 set_width_enum (Narrow, this);
1931 set_width_enum (Wide, this);
1940 MixerStrip::hide_clicked ()
1942 // LAME fix to reset the button status for when it is redisplayed (part 1)
1943 hide_button.set_sensitive(false);
1946 Hiding(); /* EMIT_SIGNAL */
1948 _mixer.hide_strip (this);
1952 hide_button.set_sensitive(true);
1956 MixerStrip::set_embedded (bool yn)
1962 MixerStrip::map_frozen ()
1964 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1966 boost::shared_ptr<AudioTrack> at = audio_track();
1969 switch (at->freeze_state()) {
1970 case AudioTrack::Frozen:
1971 processor_box.set_sensitive (false);
1972 hide_redirect_editors ();
1975 processor_box.set_sensitive (true);
1976 // XXX need some way, maybe, to retoggle redirect editors
1980 processor_box.set_sensitive (true);
1982 RouteUI::map_frozen ();
1986 MixerStrip::hide_redirect_editors ()
1988 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1992 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1994 boost::shared_ptr<Processor> processor (p.lock ());
1999 Gtk::Window* w = processor_box.get_processor_ui (processor);
2007 MixerStrip::reset_strip_style ()
2009 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2011 gpm.set_fader_name ("SendStripBase");
2015 if (is_midi_track()) {
2016 if (_route->active()) {
2017 set_name ("MidiTrackStripBase");
2019 set_name ("MidiTrackStripBaseInactive");
2021 gpm.set_fader_name ("MidiTrackFader");
2022 } else if (is_audio_track()) {
2023 if (_route->active()) {
2024 set_name ("AudioTrackStripBase");
2026 set_name ("AudioTrackStripBaseInactive");
2028 gpm.set_fader_name ("AudioTrackFader");
2030 if (_route->active()) {
2031 set_name ("AudioBusStripBase");
2033 set_name ("AudioBusStripBaseInactive");
2035 gpm.set_fader_name ("AudioBusFader");
2037 /* (no MIDI busses yet) */
2044 MixerStrip::engine_stopped ()
2049 MixerStrip::engine_running ()
2054 MixerStrip::meter_point_string (MeterPoint mp)
2067 case MeterPostFader:
2084 return S_("Meter|In");
2088 return S_("Meter|Pr");
2091 case MeterPostFader:
2092 return S_("Meter|Po");
2096 return S_("Meter|O");
2101 return S_("Meter|C");
2110 /** Called when the monitor-section state */
2112 MixerStrip::monitor_changed ()
2114 assert (monitor_section_button);
2115 if (_session->monitor_active()) {
2116 monitor_section_button->set_name ("master monitor section button active");
2118 monitor_section_button->set_name ("master monitor section button normal");
2122 /** Called when the metering point has changed */
2124 MixerStrip::meter_changed ()
2126 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2127 gpm.setup_meters ();
2128 // reset peak when meter point changes
2129 gpm.reset_peak_display();
2132 /** The bus that we are displaying sends to has changed, or been turned off.
2133 * @param send_to New bus that we are displaying sends to, or 0.
2136 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2138 RouteUI::bus_send_display_changed (send_to);
2141 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2146 revert_to_default_display ();
2149 revert_to_default_display ();
2154 MixerStrip::drop_send ()
2156 boost::shared_ptr<Send> current_send;
2158 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2159 current_send->set_metering (false);
2162 send_gone_connection.disconnect ();
2163 input_button.set_sensitive (true);
2164 output_button.set_sensitive (true);
2165 group_button.set_sensitive (true);
2166 set_invert_sensitive (true);
2167 gpm.meter_point_button.set_sensitive (true);
2168 mute_button->set_sensitive (true);
2169 solo_button->set_sensitive (true);
2170 solo_isolated_led->set_sensitive (true);
2171 solo_safe_led->set_sensitive (true);
2172 monitor_input_button->set_sensitive (true);
2173 monitor_disk_button->set_sensitive (true);
2174 _comment_button.set_sensitive (true);
2175 RouteUI::check_rec_enable_sensitivity ();
2176 set_button_names (); // update solo button visual state
2180 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2182 _current_delivery = d;
2183 DeliveryChanged (_current_delivery);
2187 MixerStrip::show_send (boost::shared_ptr<Send> send)
2193 set_current_delivery (send);
2195 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2196 send->set_metering (true);
2197 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2199 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2200 gain_meter().setup_meters ();
2202 uint32_t const in = _current_delivery->pans_required();
2203 uint32_t const out = _current_delivery->pan_outs();
2205 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2206 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2207 panner_ui().setup_pan ();
2208 panner_ui().set_send_drawing_mode (true);
2209 panner_ui().show_all ();
2211 input_button.set_sensitive (false);
2212 group_button.set_sensitive (false);
2213 set_invert_sensitive (false);
2214 gpm.meter_point_button.set_sensitive (false);
2215 mute_button->set_sensitive (false);
2216 solo_button->set_sensitive (false);
2217 rec_enable_button->set_sensitive (false);
2218 solo_isolated_led->set_sensitive (false);
2219 solo_safe_led->set_sensitive (false);
2220 monitor_input_button->set_sensitive (false);
2221 monitor_disk_button->set_sensitive (false);
2222 _comment_button.set_sensitive (false);
2224 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2225 output_button.set_sensitive (false);
2228 reset_strip_style ();
2232 MixerStrip::revert_to_default_display ()
2236 set_current_delivery (_route->main_outs ());
2238 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2239 gain_meter().setup_meters ();
2241 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2242 update_panner_choices();
2243 panner_ui().setup_pan ();
2244 panner_ui().set_send_drawing_mode (false);
2246 if (has_audio_outputs ()) {
2247 panners.show_all ();
2249 panners.hide_all ();
2252 reset_strip_style ();
2256 MixerStrip::set_button_names ()
2260 mute_button->set_text (_("Mute"));
2261 monitor_input_button->set_text (_("In"));
2262 monitor_disk_button->set_text (_("Disk"));
2263 if (monitor_section_button) {
2264 monitor_section_button->set_text (_("Mon"));
2267 if (_route && _route->solo_safe_control()->solo_safe()) {
2268 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2270 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2272 if (!Config->get_solo_control_is_listen_control()) {
2273 solo_button->set_text (_("Solo"));
2275 switch (Config->get_listen_position()) {
2276 case AfterFaderListen:
2277 solo_button->set_text (_("AFL"));
2279 case PreFaderListen:
2280 solo_button->set_text (_("PFL"));
2284 solo_isolated_led->set_text (_("Iso"));
2285 solo_safe_led->set_text (S_("SoloLock|Lock"));
2289 mute_button->set_text (S_("Mute|M"));
2290 monitor_input_button->set_text (S_("MonitorInput|I"));
2291 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2292 if (monitor_section_button) {
2293 monitor_section_button->set_text (S_("Mon|O"));
2296 if (_route && _route->solo_safe_control()->solo_safe()) {
2297 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2299 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2301 if (!Config->get_solo_control_is_listen_control()) {
2302 solo_button->set_text (S_("Solo|S"));
2304 switch (Config->get_listen_position()) {
2305 case AfterFaderListen:
2306 solo_button->set_text (S_("AfterFader|A"));
2308 case PreFaderListen:
2309 solo_button->set_text (S_("Prefader|P"));
2314 solo_isolated_led->set_text (S_("SoloIso|I"));
2315 solo_safe_led->set_text (S_("SoloLock|L"));
2320 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2322 gpm.meter_point_button.set_text ("");
2327 MixerStrip::plugin_selector()
2329 return _mixer.plugin_selector();
2333 MixerStrip::hide_things ()
2335 processor_box.hide_things ();
2339 MixerStrip::input_active_button_press (GdkEventButton*)
2341 /* nothing happens on press */
2346 MixerStrip::input_active_button_release (GdkEventButton* ev)
2348 boost::shared_ptr<MidiTrack> mt = midi_track ();
2354 boost::shared_ptr<RouteList> rl (new RouteList);
2356 rl->push_back (route());
2358 _session->set_exclusive_input_active (rl, !mt->input_active(),
2359 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2365 MixerStrip::midi_input_status_changed ()
2367 if (midi_input_enable_button) {
2368 boost::shared_ptr<MidiTrack> mt = midi_track ();
2370 midi_input_enable_button->set_active (mt->input_active ());
2375 MixerStrip::state_id () const
2377 return string_compose ("strip %1", _route->id().to_s());
2381 MixerStrip::parameter_changed (string p)
2383 if (p == _visibility.get_state_name()) {
2384 /* The user has made changes to the mixer strip visibility, so get
2385 our VisibilityGroup to reflect these changes in our widgets.
2387 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2388 } else if (p == "track-name-number") {
2390 } else if (p == "use-monitor-bus") {
2391 if (monitor_section_button) {
2392 if (mute_button->get_parent()) {
2393 mute_button->get_parent()->remove(*mute_button);
2395 if (monitor_section_button->get_parent()) {
2396 monitor_section_button->get_parent()->remove(*monitor_section_button);
2398 if (Config->get_use_monitor_bus ()) {
2399 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2400 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2401 mute_button->show();
2402 monitor_section_button->show();
2404 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2405 mute_button->show();
2408 } else if (p == "track-name-number") {
2409 update_track_number_visibility();
2413 /** Called to decide whether the solo isolate / solo lock button visibility should
2414 * be overridden from that configured by the user. We do this for the master bus.
2416 * @return optional value that is present if visibility state should be overridden.
2418 boost::optional<bool>
2419 MixerStrip::override_solo_visibility () const
2421 if (_route && _route->is_master ()) {
2422 return boost::optional<bool> (false);
2425 return boost::optional<bool> ();
2429 MixerStrip::add_input_port (DataType t)
2431 _route->input()->add_port ("", this, t);
2435 MixerStrip::add_output_port (DataType t)
2437 _route->output()->add_port ("", this, t);
2441 MixerStrip::route_active_changed ()
2443 reset_strip_style ();
2447 MixerStrip::copy_processors ()
2449 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2453 MixerStrip::cut_processors ()
2455 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2459 MixerStrip::paste_processors ()
2461 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2465 MixerStrip::select_all_processors ()
2467 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2471 MixerStrip::deselect_all_processors ()
2473 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2477 MixerStrip::delete_processors ()
2479 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2483 MixerStrip::toggle_processors ()
2485 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2489 MixerStrip::ab_plugins ()
2491 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2495 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2497 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2500 if (ev->button == 3) {
2501 popup_level_meter_menu (ev);
2509 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2511 using namespace Gtk::Menu_Helpers;
2513 Gtk::Menu* m = manage (new Menu);
2514 MenuList& items = m->items ();
2516 RadioMenuItem::Group group;
2518 _suspend_menu_callbacks = true;
2519 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2520 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2521 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2522 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2523 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2525 if (gpm.meter_channels().n_audio() == 0) {
2526 m->popup (ev->button, ev->time);
2527 _suspend_menu_callbacks = false;
2531 RadioMenuItem::Group tgroup;
2532 items.push_back (SeparatorElem());
2534 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2535 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2536 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2537 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2538 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2539 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2540 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2541 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2542 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2543 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2544 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2547 if (_route->is_master()) {
2550 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2551 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2552 /* non-master bus */
2555 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2562 MeterType cmt = _route->meter_type();
2563 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2565 items.push_back (SeparatorElem());
2566 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2567 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2568 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2569 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2570 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2571 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2573 m->popup (ev->button, ev->time);
2574 _suspend_menu_callbacks = false;
2578 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2579 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2581 using namespace Menu_Helpers;
2583 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2584 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2585 i->set_active (_route->meter_point() == point);
2589 MixerStrip::set_meter_point (MeterPoint p)
2591 if (_suspend_menu_callbacks) return;
2592 _route->set_meter_point (p);
2596 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2597 RadioMenuItem::Group& group, string const & name, MeterType type)
2599 using namespace Menu_Helpers;
2601 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2602 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2603 i->set_active (_route->meter_type() == type);
2607 MixerStrip::set_meter_type (MeterType t)
2609 if (_suspend_menu_callbacks) return;
2614 MixerStrip::update_track_number_visibility ()
2616 DisplaySuspender ds;
2617 bool show_label = _session->config.get_track_name_number();
2619 if (_route && _route->is_master()) {
2624 number_label.show ();
2625 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2626 // except the width of the number label is subtracted from the name-hbox, so we
2627 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2628 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2630 number_label.set_size_request(tnw, -1);
2631 number_label.show ();
2633 number_label.hide ();
2638 MixerStrip::color () const
2640 return route_color ();
2644 MixerStrip::marked_for_display () const
2646 return !_route->presentation_info().hidden();
2650 MixerStrip::set_marked_for_display (bool yn)
2652 return RouteUI::mark_hidden (!yn);