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 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
697 set_stuff_from_route ();
699 /* now force an update of all the various elements */
701 update_mute_display ();
702 update_solo_display ();
705 route_group_changed ();
706 update_track_number_visibility ();
709 panners.setup_pan ();
711 if (has_audio_outputs ()) {
717 update_diskstream_display ();
718 update_input_display ();
719 update_output_display ();
721 add_events (Gdk::BUTTON_RELEASE_MASK);
723 processor_box.show ();
725 if (!route()->is_master() && !route()->is_monitor()) {
726 /* we don't allow master or control routes to be hidden */
731 gpm.reset_peak_display ();
732 gpm.gain_display.show ();
733 gpm.peak_display.show ();
736 width_hide_box.show();
738 global_vpacker.show();
739 mute_solo_table.show();
740 bottom_button_table.show();
742 gpm.meter_point_button.show();
743 input_button_box.show_all();
744 output_button.show();
746 _comment_button.show();
748 gpm.gain_automation_state_button.show();
750 parameter_changed ("mixer-element-visibility");
757 MixerStrip::set_stuff_from_route ()
759 /* if width is not set, it will be set by the MixerUI or editor */
762 if (get_gui_property ("strip-width", width)) {
763 set_width_enum (width, this);
768 MixerStrip::set_width_enum (Width w, void* owner)
770 /* always set the gpm width again, things may be hidden */
773 panners.set_width (w);
775 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
777 _width_owner = owner;
781 if (_width_owner == this) {
782 set_gui_property ("strip-width", _width);
787 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
792 if (show_sends_button) {
793 show_sends_button->set_text (_("Aux"));
796 gpm.gain_automation_state_button.set_text (
797 gpm.astate_string(gain_automation->automation_state()));
799 if (_route->panner()) {
800 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
801 panners.astate_string(_route->panner()->automation_state()));
805 // panners expect an even number of horiz. pixels
806 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
808 set_size_request (width, -1);
814 if (show_sends_button) {
815 show_sends_button->set_text (_("Snd"));
818 gpm.gain_automation_state_button.set_text (
819 gpm.short_astate_string(gain_automation->automation_state()));
820 gain_meter().setup_meters (); // recalc meter width
822 if (_route->panner()) {
823 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
824 panners.short_astate_string(_route->panner()->automation_state()));
828 // panners expect an even number of horiz. pixels
829 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
831 set_size_request (width, -1);
836 processor_box.set_width (w);
838 update_input_display ();
839 update_output_display ();
840 setup_comment_button ();
841 route_group_changed ();
847 MixerStrip::set_packed (bool yn)
850 set_gui_property ("visible", _packed);
854 struct RouteCompareByName {
855 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
856 return a->name().compare (b->name()) < 0;
861 MixerStrip::output_release (GdkEventButton *ev)
863 switch (ev->button) {
865 edit_output_configuration ();
873 MixerStrip::output_press (GdkEventButton *ev)
875 using namespace Menu_Helpers;
876 if (!_session->engine().connected()) {
877 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
882 MenuList& citems = output_menu.items();
883 switch (ev->button) {
886 return false; //wait for the mouse-up to pop the dialog
890 output_menu.set_name ("ArdourContextMenu");
892 output_menu_bundles.clear ();
894 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
896 citems.push_back (SeparatorElem());
897 uint32_t const n_with_separator = citems.size ();
899 ARDOUR::BundleList current = _route->output()->bundles_connected ();
901 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
903 /* guess the user-intended main type of the route output */
904 DataType intended_type = guess_main_type(false);
906 /* try adding the master bus first */
907 boost::shared_ptr<Route> master = _session->master_out();
909 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
912 /* then other routes inputs */
913 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
914 RouteList copy = *routes;
915 copy.sort (RouteCompareByName ());
916 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
917 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
920 /* then try adding user bundles, often labeled/grouped physical inputs */
921 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
922 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
923 maybe_add_bundle_to_output_menu (*i, current, intended_type);
927 /* then all other bundles, including physical outs or other sofware */
928 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
929 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
930 maybe_add_bundle_to_output_menu (*i, current, intended_type);
934 if (citems.size() == n_with_separator) {
935 /* no routes added; remove the separator */
939 if (!ARDOUR::Profile->get_mixbus()) {
940 citems.push_back (SeparatorElem());
942 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
945 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
946 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
952 citems.push_back (SeparatorElem());
953 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
955 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
968 MixerStrip::input_release (GdkEventButton *ev)
970 switch (ev->button) {
973 edit_input_configuration ();
985 MixerStrip::input_press (GdkEventButton *ev)
987 using namespace Menu_Helpers;
989 MenuList& citems = input_menu.items();
990 input_menu.set_name ("ArdourContextMenu");
993 if (!_session->engine().connected()) {
994 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
999 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
1002 switch (ev->button) {
1005 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1009 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1011 citems.push_back (SeparatorElem());
1012 uint32_t const n_with_separator = citems.size ();
1014 input_menu_bundles.clear ();
1016 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1018 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1020 /* give user bundles first chance at being in the menu */
1022 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1023 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1024 maybe_add_bundle_to_input_menu (*i, current);
1028 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1029 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1030 maybe_add_bundle_to_input_menu (*i, current);
1034 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1035 RouteList copy = *routes;
1036 copy.sort (RouteCompareByName ());
1037 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1038 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1041 if (citems.size() == n_with_separator) {
1042 /* no routes added; remove the separator */
1046 citems.push_back (SeparatorElem());
1047 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1050 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1051 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1056 citems.push_back (SeparatorElem());
1057 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1059 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1071 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1073 if (ignore_toggle) {
1077 _route->input()->connect_ports_to_bundle (c, true, this);
1081 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1083 if (ignore_toggle) {
1087 _route->output()->connect_ports_to_bundle (c, true, true, this);
1091 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1093 using namespace Menu_Helpers;
1095 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1099 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1100 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1104 if (i != input_menu_bundles.end()) {
1108 input_menu_bundles.push_back (b);
1110 MenuList& citems = input_menu.items();
1111 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1115 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1118 using namespace Menu_Helpers;
1120 /* The bundle should be an input one, but not ours */
1121 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1125 /* Don't add the monitor input unless we are Master */
1126 boost::shared_ptr<Route> monitor = _session->monitor_out();
1127 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1130 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1131 * or have the same number of |type| channels than our outputs. */
1132 if (type == DataType::NIL) {
1133 if(b->nchannels() != _route->n_outputs())
1136 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1140 /* Avoid adding duplicates */
1141 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1142 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1145 if (i != output_menu_bundles.end()) {
1149 /* Now add the bundle to the menu */
1150 output_menu_bundles.push_back (b);
1152 MenuList& citems = output_menu.items();
1153 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1157 MixerStrip::update_diskstream_display ()
1159 if (is_track() && input_selector) {
1160 input_selector->hide_all ();
1163 route_color_changed ();
1167 MixerStrip::connect_to_pan ()
1169 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1171 panstate_connection.disconnect ();
1172 panstyle_connection.disconnect ();
1174 if (!_route->panner()) {
1178 boost::shared_ptr<Pannable> p = _route->pannable ();
1180 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1182 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1183 * However, that only works a panner was previously set.
1185 * PannerUI must remain subscribed to _panshell->Changed() in case
1186 * we switch the panner eg. AUX-Send and back
1187 * _route->panner_shell()->Changed() vs _panshell->Changed
1189 if (panners._panner == 0) {
1190 panners.panshell_changed ();
1192 update_panner_choices();
1196 MixerStrip::update_panner_choices ()
1198 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1199 if (!_route->panner_shell()) { return; }
1201 uint32_t in = _route->output()->n_ports().n_audio();
1203 if (_route->panner()) {
1204 in = _route->panner()->in().n_audio();
1207 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1211 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1213 /* The heuristic follows these principles:
1214 * A) If all ports that the user connected are of the same type, then he
1215 * very probably intends to use the IO with that type. A common subcase
1216 * is when the IO has only ports of the same type (connected or not).
1217 * B) If several types of ports are connected, then we should guess based
1218 * on the likeliness of the user wanting to use a given type.
1219 * We assume that the DataTypes are ordered from the most likely to the
1220 * least likely when iterating or comparing them with "<".
1221 * C) If no port is connected, the same logic can be applied with all ports
1222 * instead of connected ones. TODO: Try other ideas, for instance look at
1223 * the last plugin output when |for_input| is false (note: when StrictIO
1224 * the outs of the last plugin should be the same as the outs of the route
1225 * modulo the panner which forwards non-audio anyway).
1226 * All of these constraints are respected by the following algorithm that
1227 * just returns the most likely datatype found in connected ports if any, or
1228 * available ports if any (since if all ports are of the same type, the most
1229 * likely found will be that one obviously). */
1231 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1233 /* Find most likely type among connected ports */
1234 if (favor_connected) {
1235 DataType type = DataType::NIL; /* NIL is always last so least likely */
1236 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1237 if (p->connected() && p->type() < type)
1240 if (type != DataType::NIL) {
1241 /* There has been a connected port (necessarily non-NIL) */
1246 /* Find most likely type among available ports.
1247 * The iterator stops before NIL. */
1248 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1249 if (io->n_ports().n(*t) > 0)
1253 /* No port at all, return the most likely datatype by default */
1254 return DataType::front();
1258 * Output port labelling
1259 * =====================
1261 * Case 1: Each output has one connection, all connections are to system:playback_%i
1262 * out 1 -> system:playback_1
1263 * out 2 -> system:playback_2
1264 * out 3 -> system:playback_3
1267 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1268 * out 1 -> ardour:track_x/in 1
1269 * out 2 -> ardour:track_x/in 2
1270 * Display as: track_x
1272 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1273 * out 1 -> program x:foo
1274 * out 2 -> program x:foo
1275 * Display as: program x
1277 * Case 4: No connections (Disconnected)
1280 * Default case (unusual routing):
1281 * Display as: *number of connections*
1285 * .-----------------------------------------------.
1287 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1288 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1289 * '-----------------------------------------------'
1290 * .-----------------------------------------------.
1293 * '-----------------------------------------------'
1297 MixerStrip::update_io_button (bool for_input)
1299 ostringstream tooltip;
1300 ostringstream label;
1301 bool have_label = false;
1303 uint32_t total_connection_count = 0;
1304 uint32_t typed_connection_count = 0;
1305 bool each_typed_port_has_one_connection = true;
1307 DataType dt = guess_main_type(for_input);
1308 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1310 /* Fill in the tooltip. Also count:
1311 * - The total number of connections.
1312 * - The number of main-typed connections.
1313 * - Whether each main-typed port has exactly one connection. */
1315 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1316 Gtkmm2ext::markup_escape_text (_route->name()));
1318 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1319 Gtkmm2ext::markup_escape_text (_route->name()));
1322 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1323 vector<string> port_connections;
1324 for (PortSet::iterator port = io->ports().begin();
1325 port != io->ports().end();
1327 port_connections.clear();
1328 port->get_connections(port_connections);
1330 uint32_t port_connection_count = 0;
1332 for (vector<string>::iterator i = port_connections.begin();
1333 i != port_connections.end();
1335 ++port_connection_count;
1337 if (port_connection_count == 1) {
1338 tooltip << endl << Gtkmm2ext::markup_escape_text (
1339 port->name().substr(port->name().find("/") + 1));
1345 tooltip << Gtkmm2ext::markup_escape_text(*i);
1348 total_connection_count += port_connection_count;
1349 if (port->type() == dt) {
1350 typed_connection_count += port_connection_count;
1351 each_typed_port_has_one_connection &= (port_connection_count == 1);
1356 if (total_connection_count == 0) {
1357 tooltip << endl << _("Disconnected");
1360 if (typed_connection_count == 0) {
1365 /* Are all main-typed channels connected to the same route ? */
1367 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1368 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1369 route != routes->end();
1371 boost::shared_ptr<IO> dest_io =
1372 for_input ? (*route)->output() : (*route)->input();
1373 if (io->bundle()->connected_to(dest_io->bundle(),
1376 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1383 /* Are all main-typed channels connected to the same (user) bundle ? */
1385 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1386 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1387 bundle != bundles->end();
1389 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1391 if (io->bundle()->connected_to(*bundle, _session->engine(),
1393 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1400 /* Is each main-typed channel only connected to a physical output ? */
1401 if (!have_label && each_typed_port_has_one_connection) {
1402 ostringstream temp_label;
1403 vector<string> phys;
1404 string playorcapture;
1406 _session->engine().get_physical_inputs(dt, phys);
1407 playorcapture = "capture_";
1409 _session->engine().get_physical_outputs(dt, phys);
1410 playorcapture = "playback_";
1412 for (PortSet::iterator port = io->ports().begin(dt);
1413 port != io->ports().end(dt);
1416 for (vector<string>::iterator s = phys.begin();
1419 if (!port->connected_to(*s))
1421 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1423 string::size_type start = (*s).find(playorcapture);
1424 if (start != string::npos) {
1425 pn = (*s).substr(start + playorcapture.size());
1431 temp_label.str(""); /* erase the failed attempt */
1434 if (port != io->ports().begin(dt))
1439 if (!temp_label.str().empty()) {
1440 label << temp_label.str();
1445 /* Is each main-typed channel connected to a single and different port with
1446 * the same client name (e.g. another JACK client) ? */
1447 if (!have_label && each_typed_port_has_one_connection) {
1448 string maybe_client = "";
1449 vector<string> connections;
1450 for (PortSet::iterator port = io->ports().begin(dt);
1451 port != io->ports().end(dt);
1453 port_connections.clear();
1454 port->get_connections(port_connections);
1455 string connection = port_connections.front();
1457 vector<string>::iterator i = connections.begin();
1458 while (i != connections.end() && *i != connection) {
1461 if (i != connections.end())
1462 break; /* duplicate connection */
1463 connections.push_back(connection);
1465 connection = connection.substr(0, connection.find(":"));
1466 if (maybe_client.empty())
1467 maybe_client = connection;
1468 if (maybe_client != connection)
1471 if (connections.size() == io->n_ports().n(dt)) {
1472 label << maybe_client;
1477 /* Odd configuration */
1479 label << "*" << total_connection_count << "*";
1482 if (total_connection_count > typed_connection_count) {
1483 label << "\u2295"; /* circled plus */
1486 /* Actually set the properties of the button */
1487 char * cstr = new char[tooltip.str().size() + 1];
1488 strcpy(cstr, tooltip.str().c_str());
1491 input_button.set_text (label.str());
1492 set_tooltip (&input_button, cstr);
1494 output_button.set_text (label.str());
1495 set_tooltip (&output_button, cstr);
1502 MixerStrip::update_input_display ()
1504 update_io_button (true);
1505 panners.setup_pan ();
1507 if (has_audio_outputs ()) {
1508 panners.show_all ();
1510 panners.hide_all ();
1516 MixerStrip::update_output_display ()
1518 update_io_button (false);
1519 gpm.setup_meters ();
1520 panners.setup_pan ();
1522 if (has_audio_outputs ()) {
1523 panners.show_all ();
1525 panners.hide_all ();
1530 MixerStrip::fast_update ()
1532 gpm.update_meters ();
1536 MixerStrip::diskstream_changed ()
1538 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1542 MixerStrip::io_changed_proxy ()
1544 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1545 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1549 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1551 boost::shared_ptr<Port> a = wa.lock ();
1552 boost::shared_ptr<Port> b = wb.lock ();
1554 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1555 update_input_display ();
1556 set_width_enum (_width, this);
1559 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1560 update_output_display ();
1561 set_width_enum (_width, this);
1566 MixerStrip::setup_comment_button ()
1568 std::string comment = _route->comment();
1570 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1572 if (comment.empty ()) {
1573 _comment_button.set_name ("generic button");
1574 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1578 _comment_button.set_name ("comment button");
1580 string::size_type pos = comment.find_first_of (" \t\n");
1581 if (pos != string::npos) {
1582 comment = comment.substr (0, pos);
1584 if (comment.empty()) {
1585 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1587 _comment_button.set_text (comment);
1592 MixerStrip::select_route_group (GdkEventButton *ev)
1594 using namespace Menu_Helpers;
1596 if (ev->button == 1) {
1598 if (group_menu == 0) {
1600 PropertyList* plist = new PropertyList();
1602 plist->add (Properties::group_gain, true);
1603 plist->add (Properties::group_mute, true);
1604 plist->add (Properties::group_solo, true);
1606 group_menu = new RouteGroupMenu (_session, plist);
1610 r.push_back (route ());
1611 group_menu->build (r);
1613 RouteGroup *rg = _route->route_group();
1615 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1616 rg ? rg->name() : _("No Group"),
1624 MixerStrip::route_group_changed ()
1626 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1628 RouteGroup *rg = _route->route_group();
1631 group_button.set_text (PBD::short_version (rg->name(), 5));
1635 group_button.set_text (_("Grp"));
1638 group_button.set_text (_("~G"));
1645 MixerStrip::route_color_changed ()
1647 using namespace ARDOUR_UI_UTILS;
1648 name_button.modify_bg (STATE_NORMAL, color());
1649 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1650 reset_strip_style ();
1654 MixerStrip::show_passthru_color ()
1656 reset_strip_style ();
1661 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1663 boost::shared_ptr<Processor> processor (p.lock ());
1664 if (!processor || !processor->display_to_user()) {
1667 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1669 if (pi && pi->is_channelstrip ()) {
1674 ++_plugin_insert_cnt;
1678 MixerStrip::build_route_ops_menu ()
1680 using namespace Menu_Helpers;
1681 route_ops_menu = new Menu;
1682 route_ops_menu->set_name ("ArdourContextMenu");
1684 MenuList& items = route_ops_menu->items();
1686 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1688 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1690 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1692 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1694 if (!Profile->get_mixbus()) {
1695 items.push_back (SeparatorElem());
1698 if (!_route->is_master()
1700 && !_route->mixbus()
1703 if (Profile->get_mixbus()) {
1704 items.push_back (SeparatorElem());
1706 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1709 if (!Profile->get_mixbus()) {
1710 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1711 /* do not allow rename if the track is record-enabled */
1712 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1715 items.push_back (SeparatorElem());
1716 items.push_back (CheckMenuElem (_("Active")));
1717 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1718 i->set_active (_route->active());
1719 i->set_sensitive(! _session->transport_rolling());
1720 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1722 if (!Profile->get_mixbus ()) {
1723 items.push_back (SeparatorElem());
1724 items.push_back (CheckMenuElem (_("Strict I/O")));
1725 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1726 i->set_active (_route->strict_io());
1727 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1731 items.push_back (SeparatorElem());
1733 Gtk::Menu* dio_menu = new Menu;
1734 MenuList& dio_items = dio_menu->items();
1735 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1736 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1737 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1739 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1742 _plugin_insert_cnt = 0;
1743 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1744 if (_plugin_insert_cnt > 0) {
1745 items.push_back (SeparatorElem());
1746 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1749 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1750 items.push_back (MenuElem (_("Patch Selector..."),
1751 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1754 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1755 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1756 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1757 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1760 items.push_back (SeparatorElem());
1761 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1763 items.push_back (SeparatorElem());
1764 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1765 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1766 denormal_menu_item->set_active (_route->denormal_protection());
1769 /* note that this relies on selection being shared across editor and
1770 mixer (or global to the backend, in the future), which is the only
1771 sane thing for users anyway.
1774 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1776 Selection& selection (PublicEditor::instance().get_selection());
1777 if (!selection.selected (stav)) {
1778 selection.set (stav);
1781 if (!_route->is_master()) {
1782 items.push_back (SeparatorElem());
1783 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1786 items.push_back (SeparatorElem());
1787 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1793 MixerStrip::name_button_button_press (GdkEventButton* ev)
1795 if (ev->button == 1 || ev->button == 3) {
1796 list_route_operations ();
1798 if (ev->button == 1) {
1799 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1802 route_ops_menu->popup (3, ev->time);
1812 MixerStrip::number_button_button_press (GdkEventButton* ev)
1814 if ( ev->button == 3 ) {
1815 list_route_operations ();
1817 route_ops_menu->popup (1, ev->time);
1826 MixerStrip::list_route_operations ()
1828 delete route_ops_menu;
1829 build_route_ops_menu ();
1833 MixerStrip::set_selected (bool yn)
1835 AxisView::set_selected (yn);
1838 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1839 global_frame.set_name ("MixerStripSelectedFrame");
1841 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1842 global_frame.set_name ("MixerStripFrame");
1845 global_frame.queue_draw ();
1848 // processor_box.deselect_all_processors();
1852 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1854 if (what_changed.contains (ARDOUR::Properties::name)) {
1860 MixerStrip::name_changed ()
1864 name_button.set_text (_route->name());
1867 name_button.set_text (PBD::short_version (_route->name(), 5));
1871 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1873 if (_session->config.get_track_name_number()) {
1874 const int64_t track_number = _route->track_number ();
1875 if (track_number == 0) {
1876 number_label.set_text ("-");
1878 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1881 number_label.set_text ("");
1886 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1888 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1892 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1894 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1898 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1900 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1904 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1906 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1910 MixerStrip::width_button_pressed (GdkEventButton* ev)
1912 if (ev->button != 1) {
1916 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1919 _mixer.set_strip_width (Narrow, true);
1923 _mixer.set_strip_width (Wide, true);
1929 set_width_enum (Narrow, this);
1932 set_width_enum (Wide, this);
1941 MixerStrip::hide_clicked ()
1943 // LAME fix to reset the button status for when it is redisplayed (part 1)
1944 hide_button.set_sensitive(false);
1947 Hiding(); /* EMIT_SIGNAL */
1949 _mixer.hide_strip (this);
1953 hide_button.set_sensitive(true);
1957 MixerStrip::set_embedded (bool yn)
1963 MixerStrip::map_frozen ()
1965 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1967 boost::shared_ptr<AudioTrack> at = audio_track();
1970 switch (at->freeze_state()) {
1971 case AudioTrack::Frozen:
1972 processor_box.set_sensitive (false);
1973 hide_redirect_editors ();
1976 processor_box.set_sensitive (true);
1977 // XXX need some way, maybe, to retoggle redirect editors
1981 processor_box.set_sensitive (true);
1983 RouteUI::map_frozen ();
1987 MixerStrip::hide_redirect_editors ()
1989 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1993 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1995 boost::shared_ptr<Processor> processor (p.lock ());
2000 Gtk::Window* w = processor_box.get_processor_ui (processor);
2008 MixerStrip::reset_strip_style ()
2010 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2012 gpm.set_fader_name ("SendStripBase");
2016 if (is_midi_track()) {
2017 if (_route->active()) {
2018 set_name ("MidiTrackStripBase");
2020 set_name ("MidiTrackStripBaseInactive");
2022 gpm.set_fader_name ("MidiTrackFader");
2023 } else if (is_audio_track()) {
2024 if (_route->active()) {
2025 set_name ("AudioTrackStripBase");
2027 set_name ("AudioTrackStripBaseInactive");
2029 gpm.set_fader_name ("AudioTrackFader");
2031 if (_route->active()) {
2032 set_name ("AudioBusStripBase");
2034 set_name ("AudioBusStripBaseInactive");
2036 gpm.set_fader_name ("AudioBusFader");
2038 /* (no MIDI busses yet) */
2045 MixerStrip::engine_stopped ()
2050 MixerStrip::engine_running ()
2055 MixerStrip::meter_point_string (MeterPoint mp)
2068 case MeterPostFader:
2085 return S_("Meter|In");
2089 return S_("Meter|Pr");
2092 case MeterPostFader:
2093 return S_("Meter|Po");
2097 return S_("Meter|O");
2102 return S_("Meter|C");
2111 /** Called when the monitor-section state */
2113 MixerStrip::monitor_changed ()
2115 assert (monitor_section_button);
2116 if (_session->monitor_active()) {
2117 monitor_section_button->set_name ("master monitor section button active");
2119 monitor_section_button->set_name ("master monitor section button normal");
2123 /** Called when the metering point has changed */
2125 MixerStrip::meter_changed ()
2127 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2128 gpm.setup_meters ();
2129 // reset peak when meter point changes
2130 gpm.reset_peak_display();
2133 /** The bus that we are displaying sends to has changed, or been turned off.
2134 * @param send_to New bus that we are displaying sends to, or 0.
2137 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2139 RouteUI::bus_send_display_changed (send_to);
2142 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2147 revert_to_default_display ();
2150 revert_to_default_display ();
2155 MixerStrip::drop_send ()
2157 boost::shared_ptr<Send> current_send;
2159 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2160 current_send->set_metering (false);
2163 send_gone_connection.disconnect ();
2164 input_button.set_sensitive (true);
2165 output_button.set_sensitive (true);
2166 group_button.set_sensitive (true);
2167 set_invert_sensitive (true);
2168 gpm.meter_point_button.set_sensitive (true);
2169 mute_button->set_sensitive (true);
2170 solo_button->set_sensitive (true);
2171 solo_isolated_led->set_sensitive (true);
2172 solo_safe_led->set_sensitive (true);
2173 monitor_input_button->set_sensitive (true);
2174 monitor_disk_button->set_sensitive (true);
2175 _comment_button.set_sensitive (true);
2176 RouteUI::check_rec_enable_sensitivity ();
2177 set_button_names (); // update solo button visual state
2181 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2183 _current_delivery = d;
2184 DeliveryChanged (_current_delivery);
2188 MixerStrip::show_send (boost::shared_ptr<Send> send)
2194 set_current_delivery (send);
2196 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2197 send->set_metering (true);
2198 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2200 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2201 gain_meter().setup_meters ();
2203 uint32_t const in = _current_delivery->pans_required();
2204 uint32_t const out = _current_delivery->pan_outs();
2206 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2207 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2208 panner_ui().setup_pan ();
2209 panner_ui().set_send_drawing_mode (true);
2210 panner_ui().show_all ();
2212 input_button.set_sensitive (false);
2213 group_button.set_sensitive (false);
2214 set_invert_sensitive (false);
2215 gpm.meter_point_button.set_sensitive (false);
2216 mute_button->set_sensitive (false);
2217 solo_button->set_sensitive (false);
2218 rec_enable_button->set_sensitive (false);
2219 solo_isolated_led->set_sensitive (false);
2220 solo_safe_led->set_sensitive (false);
2221 monitor_input_button->set_sensitive (false);
2222 monitor_disk_button->set_sensitive (false);
2223 _comment_button.set_sensitive (false);
2225 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2226 output_button.set_sensitive (false);
2229 reset_strip_style ();
2233 MixerStrip::revert_to_default_display ()
2237 set_current_delivery (_route->main_outs ());
2239 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2240 gain_meter().setup_meters ();
2242 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2243 update_panner_choices();
2244 panner_ui().setup_pan ();
2245 panner_ui().set_send_drawing_mode (false);
2247 if (has_audio_outputs ()) {
2248 panners.show_all ();
2250 panners.hide_all ();
2253 reset_strip_style ();
2257 MixerStrip::set_button_names ()
2261 mute_button->set_text (_("Mute"));
2262 monitor_input_button->set_text (_("In"));
2263 monitor_disk_button->set_text (_("Disk"));
2264 if (monitor_section_button) {
2265 monitor_section_button->set_text (_("Mon"));
2268 if (_route && _route->solo_safe_control()->solo_safe()) {
2269 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2271 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2273 if (!Config->get_solo_control_is_listen_control()) {
2274 solo_button->set_text (_("Solo"));
2276 switch (Config->get_listen_position()) {
2277 case AfterFaderListen:
2278 solo_button->set_text (_("AFL"));
2280 case PreFaderListen:
2281 solo_button->set_text (_("PFL"));
2285 solo_isolated_led->set_text (_("Iso"));
2286 solo_safe_led->set_text (S_("SoloLock|Lock"));
2290 mute_button->set_text (S_("Mute|M"));
2291 monitor_input_button->set_text (S_("MonitorInput|I"));
2292 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2293 if (monitor_section_button) {
2294 monitor_section_button->set_text (S_("Mon|O"));
2297 if (_route && _route->solo_safe_control()->solo_safe()) {
2298 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2300 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2302 if (!Config->get_solo_control_is_listen_control()) {
2303 solo_button->set_text (S_("Solo|S"));
2305 switch (Config->get_listen_position()) {
2306 case AfterFaderListen:
2307 solo_button->set_text (S_("AfterFader|A"));
2309 case PreFaderListen:
2310 solo_button->set_text (S_("Prefader|P"));
2315 solo_isolated_led->set_text (S_("SoloIso|I"));
2316 solo_safe_led->set_text (S_("SoloLock|L"));
2321 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2323 gpm.meter_point_button.set_text ("");
2328 MixerStrip::plugin_selector()
2330 return _mixer.plugin_selector();
2334 MixerStrip::hide_things ()
2336 processor_box.hide_things ();
2340 MixerStrip::input_active_button_press (GdkEventButton*)
2342 /* nothing happens on press */
2347 MixerStrip::input_active_button_release (GdkEventButton* ev)
2349 boost::shared_ptr<MidiTrack> mt = midi_track ();
2355 boost::shared_ptr<RouteList> rl (new RouteList);
2357 rl->push_back (route());
2359 _session->set_exclusive_input_active (rl, !mt->input_active(),
2360 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2366 MixerStrip::midi_input_status_changed ()
2368 if (midi_input_enable_button) {
2369 boost::shared_ptr<MidiTrack> mt = midi_track ();
2371 midi_input_enable_button->set_active (mt->input_active ());
2376 MixerStrip::state_id () const
2378 return string_compose ("strip %1", _route->id().to_s());
2382 MixerStrip::parameter_changed (string p)
2384 if (p == _visibility.get_state_name()) {
2385 /* The user has made changes to the mixer strip visibility, so get
2386 our VisibilityGroup to reflect these changes in our widgets.
2388 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2389 } else if (p == "track-name-number") {
2391 } else if (p == "use-monitor-bus") {
2392 if (monitor_section_button) {
2393 if (mute_button->get_parent()) {
2394 mute_button->get_parent()->remove(*mute_button);
2396 if (monitor_section_button->get_parent()) {
2397 monitor_section_button->get_parent()->remove(*monitor_section_button);
2399 if (Config->get_use_monitor_bus ()) {
2400 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2401 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2402 mute_button->show();
2403 monitor_section_button->show();
2405 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2406 mute_button->show();
2409 } else if (p == "track-name-number") {
2410 update_track_number_visibility();
2414 /** Called to decide whether the solo isolate / solo lock button visibility should
2415 * be overridden from that configured by the user. We do this for the master bus.
2417 * @return optional value that is present if visibility state should be overridden.
2419 boost::optional<bool>
2420 MixerStrip::override_solo_visibility () const
2422 if (_route && _route->is_master ()) {
2423 return boost::optional<bool> (false);
2426 return boost::optional<bool> ();
2430 MixerStrip::add_input_port (DataType t)
2432 _route->input()->add_port ("", this, t);
2436 MixerStrip::add_output_port (DataType t)
2438 _route->output()->add_port ("", this, t);
2442 MixerStrip::route_active_changed ()
2444 reset_strip_style ();
2448 MixerStrip::copy_processors ()
2450 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2454 MixerStrip::cut_processors ()
2456 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2460 MixerStrip::paste_processors ()
2462 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2466 MixerStrip::select_all_processors ()
2468 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2472 MixerStrip::deselect_all_processors ()
2474 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2478 MixerStrip::delete_processors ()
2480 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2484 MixerStrip::toggle_processors ()
2486 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2490 MixerStrip::ab_plugins ()
2492 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2496 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2498 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2501 if (ev->button == 3) {
2502 popup_level_meter_menu (ev);
2510 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2512 using namespace Gtk::Menu_Helpers;
2514 Gtk::Menu* m = manage (new Menu);
2515 MenuList& items = m->items ();
2517 RadioMenuItem::Group group;
2519 _suspend_menu_callbacks = true;
2520 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2521 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2522 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2523 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2524 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2526 if (gpm.meter_channels().n_audio() == 0) {
2527 m->popup (ev->button, ev->time);
2528 _suspend_menu_callbacks = false;
2532 RadioMenuItem::Group tgroup;
2533 items.push_back (SeparatorElem());
2535 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2536 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2537 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2538 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2539 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2540 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2541 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2542 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2543 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2544 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2545 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2548 if (_route->is_master()) {
2551 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2552 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2553 /* non-master bus */
2556 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2563 MeterType cmt = _route->meter_type();
2564 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2566 items.push_back (SeparatorElem());
2567 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2568 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2569 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2570 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2571 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2572 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2574 m->popup (ev->button, ev->time);
2575 _suspend_menu_callbacks = false;
2579 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2580 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2582 using namespace Menu_Helpers;
2584 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2585 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2586 i->set_active (_route->meter_point() == point);
2590 MixerStrip::set_meter_point (MeterPoint p)
2592 if (_suspend_menu_callbacks) return;
2593 _route->set_meter_point (p);
2597 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2598 RadioMenuItem::Group& group, string const & name, MeterType type)
2600 using namespace Menu_Helpers;
2602 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2603 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2604 i->set_active (_route->meter_type() == type);
2608 MixerStrip::set_meter_type (MeterType t)
2610 if (_suspend_menu_callbacks) return;
2615 MixerStrip::update_track_number_visibility ()
2617 DisplaySuspender ds;
2618 bool show_label = _session->config.get_track_name_number();
2620 if (_route && _route->is_master()) {
2625 number_label.show ();
2626 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2627 // except the width of the number label is subtracted from the name-hbox, so we
2628 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2629 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2631 number_label.set_size_request(tnw, -1);
2632 number_label.show ();
2634 number_label.hide ();
2639 MixerStrip::color () const
2641 return route_color ();
2645 MixerStrip::marked_for_display () const
2647 return !_route->presentation_info().hidden();
2651 MixerStrip::set_marked_for_display (bool yn)
2653 return RouteUI::mark_hidden (!yn);