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 _route->input()->connect_ports_to_bundle (c, true, this);
1085 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1087 if (ignore_toggle) {
1091 _route->output()->connect_ports_to_bundle (c, true, true, this);
1095 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1097 using namespace Menu_Helpers;
1099 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1103 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1104 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1108 if (i != input_menu_bundles.end()) {
1112 input_menu_bundles.push_back (b);
1114 MenuList& citems = input_menu.items();
1115 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1119 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1122 using namespace Menu_Helpers;
1124 /* The bundle should be an input one, but not ours */
1125 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1129 /* Don't add the monitor input unless we are Master */
1130 boost::shared_ptr<Route> monitor = _session->monitor_out();
1131 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1134 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1135 * or have the same number of |type| channels than our outputs. */
1136 if (type == DataType::NIL) {
1137 if(b->nchannels() != _route->n_outputs())
1140 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1144 /* Avoid adding duplicates */
1145 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1146 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1149 if (i != output_menu_bundles.end()) {
1153 /* Now add the bundle to the menu */
1154 output_menu_bundles.push_back (b);
1156 MenuList& citems = output_menu.items();
1157 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1161 MixerStrip::update_diskstream_display ()
1163 if (is_track() && input_selector) {
1164 input_selector->hide_all ();
1167 route_color_changed ();
1171 MixerStrip::connect_to_pan ()
1173 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1175 panstate_connection.disconnect ();
1176 panstyle_connection.disconnect ();
1178 if (!_route->panner()) {
1182 boost::shared_ptr<Pannable> p = _route->pannable ();
1184 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1186 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1187 * However, that only works a panner was previously set.
1189 * PannerUI must remain subscribed to _panshell->Changed() in case
1190 * we switch the panner eg. AUX-Send and back
1191 * _route->panner_shell()->Changed() vs _panshell->Changed
1193 if (panners._panner == 0) {
1194 panners.panshell_changed ();
1196 update_panner_choices();
1200 MixerStrip::update_panner_choices ()
1202 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1203 if (!_route->panner_shell()) { return; }
1205 uint32_t in = _route->output()->n_ports().n_audio();
1207 if (_route->panner()) {
1208 in = _route->panner()->in().n_audio();
1211 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1215 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1217 /* The heuristic follows these principles:
1218 * A) If all ports that the user connected are of the same type, then he
1219 * very probably intends to use the IO with that type. A common subcase
1220 * is when the IO has only ports of the same type (connected or not).
1221 * B) If several types of ports are connected, then we should guess based
1222 * on the likeliness of the user wanting to use a given type.
1223 * We assume that the DataTypes are ordered from the most likely to the
1224 * least likely when iterating or comparing them with "<".
1225 * C) If no port is connected, the same logic can be applied with all ports
1226 * instead of connected ones. TODO: Try other ideas, for instance look at
1227 * the last plugin output when |for_input| is false (note: when StrictIO
1228 * the outs of the last plugin should be the same as the outs of the route
1229 * modulo the panner which forwards non-audio anyway).
1230 * All of these constraints are respected by the following algorithm that
1231 * just returns the most likely datatype found in connected ports if any, or
1232 * available ports if any (since if all ports are of the same type, the most
1233 * likely found will be that one obviously). */
1235 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1237 /* Find most likely type among connected ports */
1238 if (favor_connected) {
1239 DataType type = DataType::NIL; /* NIL is always last so least likely */
1240 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1241 if (p->connected() && p->type() < type)
1244 if (type != DataType::NIL) {
1245 /* There has been a connected port (necessarily non-NIL) */
1250 /* Find most likely type among available ports.
1251 * The iterator stops before NIL. */
1252 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1253 if (io->n_ports().n(*t) > 0)
1257 /* No port at all, return the most likely datatype by default */
1258 return DataType::front();
1262 * Output port labelling
1263 * =====================
1265 * Case 1: Each output has one connection, all connections are to system:playback_%i
1266 * out 1 -> system:playback_1
1267 * out 2 -> system:playback_2
1268 * out 3 -> system:playback_3
1271 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1272 * out 1 -> ardour:track_x/in 1
1273 * out 2 -> ardour:track_x/in 2
1274 * Display as: track_x
1276 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1277 * out 1 -> program x:foo
1278 * out 2 -> program x:foo
1279 * Display as: program x
1281 * Case 4: No connections (Disconnected)
1284 * Default case (unusual routing):
1285 * Display as: *number of connections*
1289 * .-----------------------------------------------.
1291 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1292 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1293 * '-----------------------------------------------'
1294 * .-----------------------------------------------.
1297 * '-----------------------------------------------'
1301 MixerStrip::update_io_button (bool for_input)
1303 ostringstream tooltip;
1304 ostringstream label;
1305 bool have_label = false;
1307 uint32_t total_connection_count = 0;
1308 uint32_t typed_connection_count = 0;
1309 bool each_typed_port_has_one_connection = true;
1311 DataType dt = guess_main_type(for_input);
1312 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1314 /* Fill in the tooltip. Also count:
1315 * - The total number of connections.
1316 * - The number of main-typed connections.
1317 * - Whether each main-typed port has exactly one connection. */
1319 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1320 Gtkmm2ext::markup_escape_text (_route->name()));
1322 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1323 Gtkmm2ext::markup_escape_text (_route->name()));
1326 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1327 vector<string> port_connections;
1328 for (PortSet::iterator port = io->ports().begin();
1329 port != io->ports().end();
1331 port_connections.clear();
1332 port->get_connections(port_connections);
1334 uint32_t port_connection_count = 0;
1336 for (vector<string>::iterator i = port_connections.begin();
1337 i != port_connections.end();
1339 ++port_connection_count;
1341 if (port_connection_count == 1) {
1342 tooltip << endl << Gtkmm2ext::markup_escape_text (
1343 port->name().substr(port->name().find("/") + 1));
1349 tooltip << Gtkmm2ext::markup_escape_text(*i);
1352 total_connection_count += port_connection_count;
1353 if (port->type() == dt) {
1354 typed_connection_count += port_connection_count;
1355 each_typed_port_has_one_connection &= (port_connection_count == 1);
1360 if (total_connection_count == 0) {
1361 tooltip << endl << _("Disconnected");
1364 if (typed_connection_count == 0) {
1369 /* Are all main-typed channels connected to the same route ? */
1371 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1372 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1373 route != routes->end();
1375 boost::shared_ptr<IO> dest_io =
1376 for_input ? (*route)->output() : (*route)->input();
1377 if (io->bundle()->connected_to(dest_io->bundle(),
1380 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1387 /* Are all main-typed channels connected to the same (user) bundle ? */
1389 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1390 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1391 bundle != bundles->end();
1393 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1395 if (io->bundle()->connected_to(*bundle, _session->engine(),
1397 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1404 /* Is each main-typed channel only connected to a physical output ? */
1405 if (!have_label && each_typed_port_has_one_connection) {
1406 ostringstream temp_label;
1407 vector<string> phys;
1408 string playorcapture;
1410 _session->engine().get_physical_inputs(dt, phys);
1411 playorcapture = "capture_";
1413 _session->engine().get_physical_outputs(dt, phys);
1414 playorcapture = "playback_";
1416 for (PortSet::iterator port = io->ports().begin(dt);
1417 port != io->ports().end(dt);
1420 for (vector<string>::iterator s = phys.begin();
1423 if (!port->connected_to(*s))
1425 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1427 string::size_type start = (*s).find(playorcapture);
1428 if (start != string::npos) {
1429 pn = (*s).substr(start + playorcapture.size());
1435 temp_label.str(""); /* erase the failed attempt */
1438 if (port != io->ports().begin(dt))
1443 if (!temp_label.str().empty()) {
1444 label << temp_label.str();
1449 /* Is each main-typed channel connected to a single and different port with
1450 * the same client name (e.g. another JACK client) ? */
1451 if (!have_label && each_typed_port_has_one_connection) {
1452 string maybe_client = "";
1453 vector<string> connections;
1454 for (PortSet::iterator port = io->ports().begin(dt);
1455 port != io->ports().end(dt);
1457 port_connections.clear();
1458 port->get_connections(port_connections);
1459 string connection = port_connections.front();
1461 vector<string>::iterator i = connections.begin();
1462 while (i != connections.end() && *i != connection) {
1465 if (i != connections.end())
1466 break; /* duplicate connection */
1467 connections.push_back(connection);
1469 connection = connection.substr(0, connection.find(":"));
1470 if (maybe_client.empty())
1471 maybe_client = connection;
1472 if (maybe_client != connection)
1475 if (connections.size() == io->n_ports().n(dt)) {
1476 label << maybe_client;
1481 /* Odd configuration */
1483 label << "*" << total_connection_count << "*";
1486 if (total_connection_count > typed_connection_count) {
1487 label << "\u2295"; /* circled plus */
1490 /* Actually set the properties of the button */
1491 char * cstr = new char[tooltip.str().size() + 1];
1492 strcpy(cstr, tooltip.str().c_str());
1495 input_button.set_text (label.str());
1496 set_tooltip (&input_button, cstr);
1498 output_button.set_text (label.str());
1499 set_tooltip (&output_button, cstr);
1506 MixerStrip::update_input_display ()
1508 update_io_button (true);
1509 panners.setup_pan ();
1511 if (has_audio_outputs ()) {
1512 panners.show_all ();
1514 panners.hide_all ();
1520 MixerStrip::update_output_display ()
1522 update_io_button (false);
1523 gpm.setup_meters ();
1524 panners.setup_pan ();
1526 if (has_audio_outputs ()) {
1527 panners.show_all ();
1529 panners.hide_all ();
1534 MixerStrip::fast_update ()
1536 gpm.update_meters ();
1540 MixerStrip::diskstream_changed ()
1542 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1546 MixerStrip::io_changed_proxy ()
1548 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1549 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1553 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1555 boost::shared_ptr<Port> a = wa.lock ();
1556 boost::shared_ptr<Port> b = wb.lock ();
1558 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1559 update_input_display ();
1560 set_width_enum (_width, this);
1563 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1564 update_output_display ();
1565 set_width_enum (_width, this);
1570 MixerStrip::setup_comment_button ()
1572 std::string comment = _route->comment();
1574 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1576 if (comment.empty ()) {
1577 _comment_button.set_name ("generic button");
1578 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1582 _comment_button.set_name ("comment button");
1584 string::size_type pos = comment.find_first_of (" \t\n");
1585 if (pos != string::npos) {
1586 comment = comment.substr (0, pos);
1588 if (comment.empty()) {
1589 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1591 _comment_button.set_text (comment);
1596 MixerStrip::select_route_group (GdkEventButton *ev)
1598 using namespace Menu_Helpers;
1600 if (ev->button == 1) {
1602 if (group_menu == 0) {
1604 PropertyList* plist = new PropertyList();
1606 plist->add (Properties::group_gain, true);
1607 plist->add (Properties::group_mute, true);
1608 plist->add (Properties::group_solo, true);
1610 group_menu = new RouteGroupMenu (_session, plist);
1614 r.push_back (route ());
1615 group_menu->build (r);
1617 RouteGroup *rg = _route->route_group();
1619 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1620 rg ? rg->name() : _("No Group"),
1628 MixerStrip::route_group_changed ()
1630 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1632 RouteGroup *rg = _route->route_group();
1635 group_button.set_text (PBD::short_version (rg->name(), 5));
1639 group_button.set_text (_("Grp"));
1642 group_button.set_text (_("~G"));
1649 MixerStrip::route_color_changed ()
1651 using namespace ARDOUR_UI_UTILS;
1652 name_button.modify_bg (STATE_NORMAL, color());
1653 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1654 reset_strip_style ();
1658 MixerStrip::show_passthru_color ()
1660 reset_strip_style ();
1665 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1667 boost::shared_ptr<Processor> processor (p.lock ());
1668 if (!processor || !processor->display_to_user()) {
1671 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1673 if (pi && pi->is_channelstrip ()) {
1678 ++_plugin_insert_cnt;
1682 MixerStrip::build_route_ops_menu ()
1684 using namespace Menu_Helpers;
1685 route_ops_menu = new Menu;
1686 route_ops_menu->set_name ("ArdourContextMenu");
1688 MenuList& items = route_ops_menu->items();
1690 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1692 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1694 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1696 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1698 if (!Profile->get_mixbus()) {
1699 items.push_back (SeparatorElem());
1702 if (!_route->is_master()
1704 && !_route->mixbus()
1707 if (Profile->get_mixbus()) {
1708 items.push_back (SeparatorElem());
1710 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1713 if (!Profile->get_mixbus()) {
1714 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1715 /* do not allow rename if the track is record-enabled */
1716 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1719 items.push_back (SeparatorElem());
1720 items.push_back (CheckMenuElem (_("Active")));
1721 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1722 i->set_active (_route->active());
1723 i->set_sensitive(! _session->transport_rolling());
1724 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1726 if (!Profile->get_mixbus ()) {
1727 items.push_back (SeparatorElem());
1728 items.push_back (CheckMenuElem (_("Strict I/O")));
1729 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1730 i->set_active (_route->strict_io());
1731 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1734 _plugin_insert_cnt = 0;
1735 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1736 if (_plugin_insert_cnt > 0) {
1737 items.push_back (SeparatorElem());
1738 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1741 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1742 items.push_back (MenuElem (_("Patch Selector..."),
1743 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1746 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1747 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1748 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1749 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1752 items.push_back (SeparatorElem());
1753 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1755 items.push_back (SeparatorElem());
1756 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1757 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1758 denormal_menu_item->set_active (_route->denormal_protection());
1761 /* note that this relies on selection being shared across editor and
1762 mixer (or global to the backend, in the future), which is the only
1763 sane thing for users anyway.
1766 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1768 Selection& selection (PublicEditor::instance().get_selection());
1769 if (!selection.selected (stav)) {
1770 selection.set (stav);
1773 if (!_route->is_master()) {
1774 items.push_back (SeparatorElem());
1775 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1778 items.push_back (SeparatorElem());
1779 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1785 MixerStrip::name_button_button_press (GdkEventButton* ev)
1787 if (ev->button == 1 || ev->button == 3) {
1788 list_route_operations ();
1790 if (ev->button == 1) {
1791 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1794 route_ops_menu->popup (3, ev->time);
1804 MixerStrip::number_button_button_press (GdkEventButton* ev)
1806 if ( ev->button == 3 ) {
1807 list_route_operations ();
1809 route_ops_menu->popup (1, ev->time);
1818 MixerStrip::list_route_operations ()
1820 delete route_ops_menu;
1821 build_route_ops_menu ();
1825 MixerStrip::set_selected (bool yn)
1827 AxisView::set_selected (yn);
1830 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1831 global_frame.set_name ("MixerStripSelectedFrame");
1833 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1834 global_frame.set_name ("MixerStripFrame");
1837 global_frame.queue_draw ();
1840 // processor_box.deselect_all_processors();
1844 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1846 if (what_changed.contains (ARDOUR::Properties::name)) {
1852 MixerStrip::name_changed ()
1856 name_button.set_text (_route->name());
1859 name_button.set_text (PBD::short_version (_route->name(), 5));
1863 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1865 if (_session->config.get_track_name_number()) {
1866 const int64_t track_number = _route->track_number ();
1867 if (track_number == 0) {
1868 number_label.set_text ("-");
1870 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1873 number_label.set_text ("");
1878 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1880 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1884 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1886 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1890 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1892 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1896 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1898 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1902 MixerStrip::width_button_pressed (GdkEventButton* ev)
1904 if (ev->button != 1) {
1908 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1911 _mixer.set_strip_width (Narrow, true);
1915 _mixer.set_strip_width (Wide, true);
1921 set_width_enum (Narrow, this);
1924 set_width_enum (Wide, this);
1933 MixerStrip::hide_clicked ()
1935 // LAME fix to reset the button status for when it is redisplayed (part 1)
1936 hide_button.set_sensitive(false);
1939 Hiding(); /* EMIT_SIGNAL */
1941 _mixer.hide_strip (this);
1945 hide_button.set_sensitive(true);
1949 MixerStrip::set_embedded (bool yn)
1955 MixerStrip::map_frozen ()
1957 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1959 boost::shared_ptr<AudioTrack> at = audio_track();
1962 switch (at->freeze_state()) {
1963 case AudioTrack::Frozen:
1964 processor_box.set_sensitive (false);
1965 hide_redirect_editors ();
1968 processor_box.set_sensitive (true);
1969 // XXX need some way, maybe, to retoggle redirect editors
1973 processor_box.set_sensitive (true);
1975 RouteUI::map_frozen ();
1979 MixerStrip::hide_redirect_editors ()
1981 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1985 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1987 boost::shared_ptr<Processor> processor (p.lock ());
1992 Gtk::Window* w = processor_box.get_processor_ui (processor);
2000 MixerStrip::reset_strip_style ()
2002 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2004 gpm.set_fader_name ("SendStripBase");
2008 if (is_midi_track()) {
2009 if (_route->active()) {
2010 set_name ("MidiTrackStripBase");
2012 set_name ("MidiTrackStripBaseInactive");
2014 gpm.set_fader_name ("MidiTrackFader");
2015 } else if (is_audio_track()) {
2016 if (_route->active()) {
2017 set_name ("AudioTrackStripBase");
2019 set_name ("AudioTrackStripBaseInactive");
2021 gpm.set_fader_name ("AudioTrackFader");
2023 if (_route->active()) {
2024 set_name ("AudioBusStripBase");
2026 set_name ("AudioBusStripBaseInactive");
2028 gpm.set_fader_name ("AudioBusFader");
2030 /* (no MIDI busses yet) */
2037 MixerStrip::engine_stopped ()
2042 MixerStrip::engine_running ()
2047 MixerStrip::meter_point_string (MeterPoint mp)
2060 case MeterPostFader:
2077 return S_("Meter|In");
2081 return S_("Meter|Pr");
2084 case MeterPostFader:
2085 return S_("Meter|Po");
2089 return S_("Meter|O");
2094 return S_("Meter|C");
2103 /** Called when the monitor-section state */
2105 MixerStrip::monitor_changed ()
2107 assert (monitor_section_button);
2108 if (_session->monitor_active()) {
2109 monitor_section_button->set_name ("master monitor section button active");
2111 monitor_section_button->set_name ("master monitor section button normal");
2115 /** Called when the metering point has changed */
2117 MixerStrip::meter_changed ()
2119 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2120 gpm.setup_meters ();
2121 // reset peak when meter point changes
2122 gpm.reset_peak_display();
2125 /** The bus that we are displaying sends to has changed, or been turned off.
2126 * @param send_to New bus that we are displaying sends to, or 0.
2129 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2131 RouteUI::bus_send_display_changed (send_to);
2134 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2139 revert_to_default_display ();
2142 revert_to_default_display ();
2147 MixerStrip::drop_send ()
2149 boost::shared_ptr<Send> current_send;
2151 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2152 current_send->set_metering (false);
2155 send_gone_connection.disconnect ();
2156 input_button.set_sensitive (true);
2157 output_button.set_sensitive (true);
2158 group_button.set_sensitive (true);
2159 set_invert_sensitive (true);
2160 gpm.meter_point_button.set_sensitive (true);
2161 mute_button->set_sensitive (true);
2162 solo_button->set_sensitive (true);
2163 solo_isolated_led->set_sensitive (true);
2164 solo_safe_led->set_sensitive (true);
2165 monitor_input_button->set_sensitive (true);
2166 monitor_disk_button->set_sensitive (true);
2167 _comment_button.set_sensitive (true);
2168 RouteUI::check_rec_enable_sensitivity ();
2169 set_button_names (); // update solo button visual state
2173 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2175 _current_delivery = d;
2176 DeliveryChanged (_current_delivery);
2180 MixerStrip::show_send (boost::shared_ptr<Send> send)
2186 set_current_delivery (send);
2188 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2189 send->set_metering (true);
2190 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2192 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2193 gain_meter().setup_meters ();
2195 uint32_t const in = _current_delivery->pans_required();
2196 uint32_t const out = _current_delivery->pan_outs();
2198 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2199 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2200 panner_ui().setup_pan ();
2201 panner_ui().set_send_drawing_mode (true);
2202 panner_ui().show_all ();
2204 input_button.set_sensitive (false);
2205 group_button.set_sensitive (false);
2206 set_invert_sensitive (false);
2207 gpm.meter_point_button.set_sensitive (false);
2208 mute_button->set_sensitive (false);
2209 solo_button->set_sensitive (false);
2210 rec_enable_button->set_sensitive (false);
2211 solo_isolated_led->set_sensitive (false);
2212 solo_safe_led->set_sensitive (false);
2213 monitor_input_button->set_sensitive (false);
2214 monitor_disk_button->set_sensitive (false);
2215 _comment_button.set_sensitive (false);
2217 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2218 output_button.set_sensitive (false);
2221 reset_strip_style ();
2225 MixerStrip::revert_to_default_display ()
2229 set_current_delivery (_route->main_outs ());
2231 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2232 gain_meter().setup_meters ();
2234 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2235 update_panner_choices();
2236 panner_ui().setup_pan ();
2237 panner_ui().set_send_drawing_mode (false);
2239 if (has_audio_outputs ()) {
2240 panners.show_all ();
2242 panners.hide_all ();
2245 reset_strip_style ();
2249 MixerStrip::set_button_names ()
2253 mute_button->set_text (_("Mute"));
2254 monitor_input_button->set_text (_("In"));
2255 monitor_disk_button->set_text (_("Disk"));
2256 if (monitor_section_button) {
2257 monitor_section_button->set_text (_("Mon"));
2260 if (_route && _route->solo_safe_control()->solo_safe()) {
2261 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2263 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2265 if (!Config->get_solo_control_is_listen_control()) {
2266 solo_button->set_text (_("Solo"));
2268 switch (Config->get_listen_position()) {
2269 case AfterFaderListen:
2270 solo_button->set_text (_("AFL"));
2272 case PreFaderListen:
2273 solo_button->set_text (_("PFL"));
2277 solo_isolated_led->set_text (_("Iso"));
2278 solo_safe_led->set_text (S_("SoloLock|Lock"));
2282 mute_button->set_text (S_("Mute|M"));
2283 monitor_input_button->set_text (S_("MonitorInput|I"));
2284 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2285 if (monitor_section_button) {
2286 monitor_section_button->set_text (S_("Mon|O"));
2289 if (_route && _route->solo_safe_control()->solo_safe()) {
2290 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2292 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2294 if (!Config->get_solo_control_is_listen_control()) {
2295 solo_button->set_text (S_("Solo|S"));
2297 switch (Config->get_listen_position()) {
2298 case AfterFaderListen:
2299 solo_button->set_text (S_("AfterFader|A"));
2301 case PreFaderListen:
2302 solo_button->set_text (S_("Prefader|P"));
2307 solo_isolated_led->set_text (S_("SoloIso|I"));
2308 solo_safe_led->set_text (S_("SoloLock|L"));
2313 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2315 gpm.meter_point_button.set_text ("");
2320 MixerStrip::plugin_selector()
2322 return _mixer.plugin_selector();
2326 MixerStrip::hide_things ()
2328 processor_box.hide_things ();
2332 MixerStrip::input_active_button_press (GdkEventButton*)
2334 /* nothing happens on press */
2339 MixerStrip::input_active_button_release (GdkEventButton* ev)
2341 boost::shared_ptr<MidiTrack> mt = midi_track ();
2347 boost::shared_ptr<RouteList> rl (new RouteList);
2349 rl->push_back (route());
2351 _session->set_exclusive_input_active (rl, !mt->input_active(),
2352 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2358 MixerStrip::midi_input_status_changed ()
2360 if (midi_input_enable_button) {
2361 boost::shared_ptr<MidiTrack> mt = midi_track ();
2363 midi_input_enable_button->set_active (mt->input_active ());
2368 MixerStrip::state_id () const
2370 return string_compose ("strip %1", _route->id().to_s());
2374 MixerStrip::parameter_changed (string p)
2376 if (p == _visibility.get_state_name()) {
2377 /* The user has made changes to the mixer strip visibility, so get
2378 our VisibilityGroup to reflect these changes in our widgets.
2380 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2381 } else if (p == "track-name-number") {
2383 } else if (p == "use-monitor-bus") {
2384 if (monitor_section_button) {
2385 if (mute_button->get_parent()) {
2386 mute_button->get_parent()->remove(*mute_button);
2388 if (monitor_section_button->get_parent()) {
2389 monitor_section_button->get_parent()->remove(*monitor_section_button);
2391 if (Config->get_use_monitor_bus ()) {
2392 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2393 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2394 mute_button->show();
2395 monitor_section_button->show();
2397 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2398 mute_button->show();
2401 } else if (p == "track-name-number") {
2402 update_track_number_visibility();
2406 /** Called to decide whether the solo isolate / solo lock button visibility should
2407 * be overridden from that configured by the user. We do this for the master bus.
2409 * @return optional value that is present if visibility state should be overridden.
2411 boost::optional<bool>
2412 MixerStrip::override_solo_visibility () const
2414 if (_route && _route->is_master ()) {
2415 return boost::optional<bool> (false);
2418 return boost::optional<bool> ();
2422 MixerStrip::add_input_port (DataType t)
2424 _route->input()->add_port ("", this, t);
2428 MixerStrip::add_output_port (DataType t)
2430 _route->output()->add_port ("", this, t);
2434 MixerStrip::route_active_changed ()
2436 reset_strip_style ();
2440 MixerStrip::copy_processors ()
2442 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2446 MixerStrip::cut_processors ()
2448 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2452 MixerStrip::paste_processors ()
2454 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2458 MixerStrip::select_all_processors ()
2460 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2464 MixerStrip::deselect_all_processors ()
2466 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2470 MixerStrip::delete_processors ()
2472 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2476 MixerStrip::toggle_processors ()
2478 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2482 MixerStrip::ab_plugins ()
2484 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2488 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2490 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2493 if (ev->button == 3) {
2494 popup_level_meter_menu (ev);
2502 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2504 using namespace Gtk::Menu_Helpers;
2506 Gtk::Menu* m = manage (new Menu);
2507 MenuList& items = m->items ();
2509 RadioMenuItem::Group group;
2511 _suspend_menu_callbacks = true;
2512 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2513 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2514 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2515 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2516 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2518 if (gpm.meter_channels().n_audio() == 0) {
2519 m->popup (ev->button, ev->time);
2520 _suspend_menu_callbacks = false;
2524 RadioMenuItem::Group tgroup;
2525 items.push_back (SeparatorElem());
2527 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2528 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2529 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2530 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2531 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2532 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2533 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2534 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2535 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2536 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2537 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2540 if (_route->is_master()) {
2543 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2544 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2545 /* non-master bus */
2548 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2555 MeterType cmt = _route->meter_type();
2556 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2558 items.push_back (SeparatorElem());
2559 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2560 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2561 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2562 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2563 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2564 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2566 m->popup (ev->button, ev->time);
2567 _suspend_menu_callbacks = false;
2571 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2572 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2574 using namespace Menu_Helpers;
2576 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2577 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2578 i->set_active (_route->meter_point() == point);
2582 MixerStrip::set_meter_point (MeterPoint p)
2584 if (_suspend_menu_callbacks) return;
2585 _route->set_meter_point (p);
2589 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2590 RadioMenuItem::Group& group, string const & name, MeterType type)
2592 using namespace Menu_Helpers;
2594 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2595 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2596 i->set_active (_route->meter_type() == type);
2600 MixerStrip::set_meter_type (MeterType t)
2602 if (_suspend_menu_callbacks) return;
2607 MixerStrip::update_track_number_visibility ()
2609 DisplaySuspender ds;
2610 bool show_label = _session->config.get_track_name_number();
2612 if (_route && _route->is_master()) {
2617 number_label.show ();
2618 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2619 // except the width of the number label is subtracted from the name-hbox, so we
2620 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2621 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2623 number_label.set_size_request(tnw, -1);
2624 number_label.show ();
2626 number_label.hide ();
2631 MixerStrip::color () const
2633 return route_color ();
2637 MixerStrip::marked_for_display () const
2639 return !_route->presentation_info().hidden();
2643 MixerStrip::set_marked_for_display (bool yn)
2645 return RouteUI::mark_hidden (!yn);