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_sample());
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_sample());
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 ("Mixer", "ToggleMonitorSection");
585 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
586 _session->MonitorBusAddedOrRemoved.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_section_added_or_removed, this), gui_context());
588 monitor_section_button = manage (new ArdourButton);
590 monitor_section_button->set_related_action (act);
591 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
592 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
593 monitor_section_button->show();
594 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
595 monitor_section_added_or_removed ();
598 bottom_button_table.attach (group_button, 1, 2, 0, 1);
599 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
600 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
601 mute_button->show ();
602 solo_button->show ();
603 rec_mon_table.show ();
604 solo_iso_table.set_sensitive(true);
605 control_slave_ui.set_sensitive(true);
608 if (_mixer_owned && route()->is_master() ) {
615 monitor_input_button->show ();
616 monitor_disk_button->show ();
618 monitor_input_button->hide();
619 monitor_disk_button->hide ();
622 update_trim_control();
624 if (is_midi_track()) {
625 if (midi_input_enable_button == 0) {
626 midi_input_enable_button = manage (new ArdourButton);
627 midi_input_enable_button->set_name ("midi input button");
628 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
629 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
630 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
631 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
632 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
634 input_button_box.remove (*midi_input_enable_button);
636 /* get current state */
637 midi_input_status_changed ();
638 input_button_box.pack_start (*midi_input_enable_button, false, false);
640 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
642 if (midi_input_enable_button) {
643 /* removal from the container will delete it */
644 input_button_box.remove (*midi_input_enable_button);
645 midi_input_enable_button = 0;
649 if (is_audio_track()) {
650 boost::shared_ptr<AudioTrack> at = audio_track();
651 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
656 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
657 rec_enable_button->show();
659 if (ARDOUR::Profile->get_mixbus()) {
660 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
661 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
662 } else if (ARDOUR::Profile->get_trx()) {
663 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
665 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
666 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
673 if (!_route->is_master()) {
674 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
675 show_sends_button->show();
679 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
681 delete route_ops_menu;
684 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
685 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
686 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
687 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
689 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
691 if (_route->panner_shell()) {
692 update_panner_choices();
693 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
696 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
698 set_stuff_from_route ();
700 /* now force an update of all the various elements */
702 update_mute_display ();
703 update_solo_display ();
706 route_group_changed ();
707 update_track_number_visibility ();
710 panners.setup_pan ();
712 if (has_audio_outputs ()) {
718 update_diskstream_display ();
719 update_input_display ();
720 update_output_display ();
722 add_events (Gdk::BUTTON_RELEASE_MASK);
724 processor_box.show ();
726 if (!route()->is_master() && !route()->is_monitor()) {
727 /* we don't allow master or control routes to be hidden */
732 gpm.reset_peak_display ();
733 gpm.gain_display.show ();
734 gpm.peak_display.show ();
737 width_hide_box.show();
739 global_vpacker.show();
740 mute_solo_table.show();
741 bottom_button_table.show();
743 gpm.meter_point_button.show();
744 input_button_box.show_all();
745 output_button.show();
747 _comment_button.show();
749 gpm.gain_automation_state_button.show();
751 parameter_changed ("mixer-element-visibility");
758 MixerStrip::set_stuff_from_route ()
760 /* if width is not set, it will be set by the MixerUI or editor */
763 if (get_gui_property ("strip-width", width)) {
764 set_width_enum (width, this);
769 MixerStrip::set_width_enum (Width w, void* owner)
771 /* always set the gpm width again, things may be hidden */
774 panners.set_width (w);
776 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
778 _width_owner = owner;
782 if (_width_owner == this) {
783 set_gui_property ("strip-width", _width);
788 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
793 if (show_sends_button) {
794 show_sends_button->set_text (_("Aux"));
797 gpm.gain_automation_state_button.set_text (
798 gpm.astate_string(gain_automation->automation_state()));
800 if (_route->panner()) {
801 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
802 panners.astate_string(_route->panner()->automation_state()));
806 // panners expect an even number of horiz. pixels
807 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
809 set_size_request (width, -1);
815 if (show_sends_button) {
816 show_sends_button->set_text (_("Snd"));
819 gpm.gain_automation_state_button.set_text (
820 gpm.short_astate_string(gain_automation->automation_state()));
821 gain_meter().setup_meters (); // recalc meter width
823 if (_route->panner()) {
824 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
825 panners.short_astate_string(_route->panner()->automation_state()));
829 // panners expect an even number of horiz. pixels
830 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
832 set_size_request (width, -1);
837 processor_box.set_width (w);
839 update_input_display ();
840 update_output_display ();
841 setup_comment_button ();
842 route_group_changed ();
848 MixerStrip::set_packed (bool yn)
851 set_gui_property ("visible", _packed);
855 struct RouteCompareByName {
856 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
857 return a->name().compare (b->name()) < 0;
862 MixerStrip::output_release (GdkEventButton *ev)
864 switch (ev->button) {
866 edit_output_configuration ();
874 MixerStrip::output_press (GdkEventButton *ev)
876 using namespace Menu_Helpers;
877 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
881 MenuList& citems = output_menu.items();
882 switch (ev->button) {
885 return false; //wait for the mouse-up to pop the dialog
889 output_menu.set_name ("ArdourContextMenu");
891 output_menu_bundles.clear ();
893 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
895 citems.push_back (SeparatorElem());
896 uint32_t const n_with_separator = citems.size ();
898 ARDOUR::BundleList current = _route->output()->bundles_connected ();
900 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
902 /* guess the user-intended main type of the route output */
903 DataType intended_type = guess_main_type(false);
905 /* try adding the master bus first */
906 boost::shared_ptr<Route> master = _session->master_out();
908 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
911 /* then other routes inputs */
912 RouteList copy = _session->get_routelist ();
913 copy.sort (RouteCompareByName ());
914 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
915 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
918 /* then try adding user bundles, often labeled/grouped physical inputs */
919 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
920 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
921 maybe_add_bundle_to_output_menu (*i, current, intended_type);
925 /* then all other bundles, including physical outs or other sofware */
926 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
927 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
928 maybe_add_bundle_to_output_menu (*i, current, intended_type);
932 if (citems.size() == n_with_separator) {
933 /* no routes added; remove the separator */
937 if (!ARDOUR::Profile->get_mixbus()) {
938 citems.push_back (SeparatorElem());
940 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
943 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
944 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
950 citems.push_back (SeparatorElem());
951 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
953 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
966 MixerStrip::input_release (GdkEventButton *ev)
968 switch (ev->button) {
971 edit_input_configuration ();
983 MixerStrip::input_press (GdkEventButton *ev)
985 using namespace Menu_Helpers;
987 MenuList& citems = input_menu.items();
988 input_menu.set_name ("ArdourContextMenu");
991 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
995 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
998 switch (ev->button) {
1001 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1005 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1007 citems.push_back (SeparatorElem());
1008 uint32_t const n_with_separator = citems.size ();
1010 input_menu_bundles.clear ();
1012 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1014 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1016 /* give user bundles first chance at being in the menu */
1018 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1019 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1020 maybe_add_bundle_to_input_menu (*i, current);
1024 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1025 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1026 maybe_add_bundle_to_input_menu (*i, current);
1030 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1031 RouteList copy = *routes;
1032 copy.sort (RouteCompareByName ());
1033 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1034 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1037 if (citems.size() == n_with_separator) {
1038 /* no routes added; remove the separator */
1042 citems.push_back (SeparatorElem());
1043 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1046 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1047 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1052 citems.push_back (SeparatorElem());
1053 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1055 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1067 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1069 if (ignore_toggle) {
1073 _route->input()->connect_ports_to_bundle (c, true, this);
1077 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1079 if (ignore_toggle) {
1083 _route->output()->connect_ports_to_bundle (c, true, true, this);
1087 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1089 using namespace Menu_Helpers;
1091 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1095 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1096 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1100 if (i != input_menu_bundles.end()) {
1104 input_menu_bundles.push_back (b);
1106 MenuList& citems = input_menu.items();
1107 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1111 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1114 using namespace Menu_Helpers;
1116 /* The bundle should be an input one, but not ours */
1117 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1121 /* Don't add the monitor input unless we are Master */
1122 boost::shared_ptr<Route> monitor = _session->monitor_out();
1123 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1126 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1127 * or have the same number of |type| channels than our outputs. */
1128 if (type == DataType::NIL) {
1129 if(b->nchannels() != _route->n_outputs())
1132 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1136 /* Avoid adding duplicates */
1137 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1138 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1141 if (i != output_menu_bundles.end()) {
1145 /* Now add the bundle to the menu */
1146 output_menu_bundles.push_back (b);
1148 MenuList& citems = output_menu.items();
1149 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1153 MixerStrip::update_diskstream_display ()
1155 if (is_track() && input_selector) {
1156 input_selector->hide_all ();
1159 route_color_changed ();
1163 MixerStrip::connect_to_pan ()
1165 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1167 panstate_connection.disconnect ();
1168 panstyle_connection.disconnect ();
1170 if (!_route->panner()) {
1174 boost::shared_ptr<Pannable> p = _route->pannable ();
1176 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1178 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1179 * However, that only works a panner was previously set.
1181 * PannerUI must remain subscribed to _panshell->Changed() in case
1182 * we switch the panner eg. AUX-Send and back
1183 * _route->panner_shell()->Changed() vs _panshell->Changed
1185 if (panners._panner == 0) {
1186 panners.panshell_changed ();
1188 update_panner_choices();
1192 MixerStrip::update_panner_choices ()
1194 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1195 if (!_route->panner_shell()) { return; }
1197 uint32_t in = _route->output()->n_ports().n_audio();
1199 if (_route->panner()) {
1200 in = _route->panner()->in().n_audio();
1203 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1207 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1209 /* The heuristic follows these principles:
1210 * A) If all ports that the user connected are of the same type, then he
1211 * very probably intends to use the IO with that type. A common subcase
1212 * is when the IO has only ports of the same type (connected or not).
1213 * B) If several types of ports are connected, then we should guess based
1214 * on the likeliness of the user wanting to use a given type.
1215 * We assume that the DataTypes are ordered from the most likely to the
1216 * least likely when iterating or comparing them with "<".
1217 * C) If no port is connected, the same logic can be applied with all ports
1218 * instead of connected ones. TODO: Try other ideas, for instance look at
1219 * the last plugin output when |for_input| is false (note: when StrictIO
1220 * the outs of the last plugin should be the same as the outs of the route
1221 * modulo the panner which forwards non-audio anyway).
1222 * All of these constraints are respected by the following algorithm that
1223 * just returns the most likely datatype found in connected ports if any, or
1224 * available ports if any (since if all ports are of the same type, the most
1225 * likely found will be that one obviously). */
1227 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1229 /* Find most likely type among connected ports */
1230 if (favor_connected) {
1231 DataType type = DataType::NIL; /* NIL is always last so least likely */
1232 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1233 if (p->connected() && p->type() < type)
1236 if (type != DataType::NIL) {
1237 /* There has been a connected port (necessarily non-NIL) */
1242 /* Find most likely type among available ports.
1243 * The iterator stops before NIL. */
1244 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1245 if (io->n_ports().n(*t) > 0)
1249 /* No port at all, return the most likely datatype by default */
1250 return DataType::front();
1254 * Output port labelling
1256 * Case 1: Each output has one connection, all connections are to system:playback_%i
1257 * out 1 -> system:playback_1
1258 * out 2 -> system:playback_2
1259 * out 3 -> system:playback_3
1262 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1263 * out 1 -> ardour:track_x/in 1
1264 * out 2 -> ardour:track_x/in 2
1265 * Display as: track_x
1267 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1268 * out 1 -> program x:foo
1269 * out 2 -> program x:foo
1270 * Display as: program x
1272 * Case 4: No connections (Disconnected)
1275 * Default case (unusual routing):
1276 * Display as: *number of connections*
1281 * .-----------------------------------------------.
1283 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1284 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1285 * '-----------------------------------------------'
1286 * .-----------------------------------------------.
1289 * '-----------------------------------------------'
1293 MixerStrip::update_io_button (bool for_input)
1295 ostringstream tooltip;
1296 ostringstream label;
1297 bool have_label = false;
1299 uint32_t total_connection_count = 0;
1300 uint32_t typed_connection_count = 0;
1301 bool each_typed_port_has_one_connection = true;
1303 DataType dt = guess_main_type(for_input);
1304 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1306 /* Fill in the tooltip. Also count:
1307 * - The total number of connections.
1308 * - The number of main-typed connections.
1309 * - Whether each main-typed port has exactly one connection. */
1311 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1312 Gtkmm2ext::markup_escape_text (_route->name()));
1314 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1315 Gtkmm2ext::markup_escape_text (_route->name()));
1318 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1319 vector<string> port_connections;
1320 for (PortSet::iterator port = io->ports().begin();
1321 port != io->ports().end();
1323 port_connections.clear();
1324 port->get_connections(port_connections);
1326 uint32_t port_connection_count = 0;
1328 for (vector<string>::iterator i = port_connections.begin();
1329 i != port_connections.end();
1331 ++port_connection_count;
1333 if (port_connection_count == 1) {
1334 tooltip << endl << Gtkmm2ext::markup_escape_text (
1335 port->name().substr(port->name().find("/") + 1));
1341 tooltip << Gtkmm2ext::markup_escape_text(*i);
1344 total_connection_count += port_connection_count;
1345 if (port->type() == dt) {
1346 typed_connection_count += port_connection_count;
1347 each_typed_port_has_one_connection &= (port_connection_count == 1);
1352 if (total_connection_count == 0) {
1353 tooltip << endl << _("Disconnected");
1356 if (typed_connection_count == 0) {
1361 /* Are all main-typed channels connected to the same route ? */
1363 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1364 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1365 route != routes->end();
1367 boost::shared_ptr<IO> dest_io =
1368 for_input ? (*route)->output() : (*route)->input();
1369 if (io->bundle()->connected_to(dest_io->bundle(),
1372 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1379 /* Are all main-typed channels connected to the same (user) bundle ? */
1381 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1382 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1383 bundle != bundles->end();
1385 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1387 if (io->bundle()->connected_to(*bundle, _session->engine(),
1389 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1396 /* Is each main-typed channel only connected to a physical output ? */
1397 if (!have_label && each_typed_port_has_one_connection) {
1398 ostringstream temp_label;
1399 vector<string> phys;
1400 string playorcapture;
1402 _session->engine().get_physical_inputs(dt, phys);
1403 playorcapture = "capture_";
1405 _session->engine().get_physical_outputs(dt, phys);
1406 playorcapture = "playback_";
1408 for (PortSet::iterator port = io->ports().begin(dt);
1409 port != io->ports().end(dt);
1412 for (vector<string>::iterator s = phys.begin();
1415 if (!port->connected_to(*s))
1417 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1419 string::size_type start = (*s).find(playorcapture);
1420 if (start != string::npos) {
1421 pn = (*s).substr(start + playorcapture.size());
1427 temp_label.str(""); /* erase the failed attempt */
1430 if (port != io->ports().begin(dt))
1435 if (!temp_label.str().empty()) {
1436 label << temp_label.str();
1441 /* Is each main-typed channel connected to a single and different port with
1442 * the same client name (e.g. another JACK client) ? */
1443 if (!have_label && each_typed_port_has_one_connection) {
1444 string maybe_client = "";
1445 vector<string> connections;
1446 for (PortSet::iterator port = io->ports().begin(dt);
1447 port != io->ports().end(dt);
1449 port_connections.clear();
1450 port->get_connections(port_connections);
1451 string connection = port_connections.front();
1453 vector<string>::iterator i = connections.begin();
1454 while (i != connections.end() && *i != connection) {
1457 if (i != connections.end())
1458 break; /* duplicate connection */
1459 connections.push_back(connection);
1461 connection = connection.substr(0, connection.find(":"));
1462 if (maybe_client.empty())
1463 maybe_client = connection;
1464 if (maybe_client != connection)
1467 if (connections.size() == io->n_ports().n(dt)) {
1468 label << maybe_client;
1473 /* Odd configuration */
1475 label << "*" << total_connection_count << "*";
1478 if (total_connection_count > typed_connection_count) {
1479 label << "\u2295"; /* circled plus */
1482 /* Actually set the properties of the button */
1483 char * cstr = new char[tooltip.str().size() + 1];
1484 strcpy(cstr, tooltip.str().c_str());
1487 input_button.set_text (label.str());
1488 set_tooltip (&input_button, cstr);
1490 output_button.set_text (label.str());
1491 set_tooltip (&output_button, cstr);
1498 MixerStrip::update_input_display ()
1500 update_io_button (true);
1501 panners.setup_pan ();
1503 if (has_audio_outputs ()) {
1504 panners.show_all ();
1506 panners.hide_all ();
1512 MixerStrip::update_output_display ()
1514 update_io_button (false);
1515 gpm.setup_meters ();
1516 panners.setup_pan ();
1518 if (has_audio_outputs ()) {
1519 panners.show_all ();
1521 panners.hide_all ();
1526 MixerStrip::fast_update ()
1528 gpm.update_meters ();
1532 MixerStrip::diskstream_changed ()
1534 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1538 MixerStrip::io_changed_proxy ()
1540 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1541 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1545 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1547 boost::shared_ptr<Port> a = wa.lock ();
1548 boost::shared_ptr<Port> b = wb.lock ();
1550 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1551 update_input_display ();
1552 set_width_enum (_width, this);
1555 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1556 update_output_display ();
1557 set_width_enum (_width, this);
1562 MixerStrip::setup_comment_button ()
1564 std::string comment = _route->comment();
1566 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1568 if (comment.empty ()) {
1569 _comment_button.set_name ("generic button");
1570 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1574 _comment_button.set_name ("comment button");
1576 string::size_type pos = comment.find_first_of (" \t\n");
1577 if (pos != string::npos) {
1578 comment = comment.substr (0, pos);
1580 if (comment.empty()) {
1581 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1583 _comment_button.set_text (comment);
1588 MixerStrip::select_route_group (GdkEventButton *ev)
1590 using namespace Menu_Helpers;
1592 if (ev->button == 1) {
1594 if (group_menu == 0) {
1596 PropertyList* plist = new PropertyList();
1598 plist->add (Properties::group_gain, true);
1599 plist->add (Properties::group_mute, true);
1600 plist->add (Properties::group_solo, true);
1602 group_menu = new RouteGroupMenu (_session, plist);
1606 r.push_back (route ());
1607 group_menu->build (r);
1609 RouteGroup *rg = _route->route_group();
1611 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1612 rg ? rg->name() : _("No Group"),
1620 MixerStrip::route_group_changed ()
1622 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1624 RouteGroup *rg = _route->route_group();
1627 group_button.set_text (PBD::short_version (rg->name(), 5));
1631 group_button.set_text (_("Grp"));
1634 group_button.set_text (_("~G"));
1641 MixerStrip::route_color_changed ()
1643 using namespace ARDOUR_UI_UTILS;
1644 name_button.modify_bg (STATE_NORMAL, color());
1645 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1646 reset_strip_style ();
1650 MixerStrip::show_passthru_color ()
1652 reset_strip_style ();
1657 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1659 boost::shared_ptr<Processor> processor (p.lock ());
1660 if (!processor || !processor->display_to_user()) {
1663 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1665 if (pi && pi->is_channelstrip ()) {
1670 ++_plugin_insert_cnt;
1674 MixerStrip::build_route_ops_menu ()
1676 using namespace Menu_Helpers;
1677 route_ops_menu = new Menu;
1678 route_ops_menu->set_name ("ArdourContextMenu");
1680 MenuList& items = route_ops_menu->items();
1682 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1684 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1686 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1688 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1690 if (!Profile->get_mixbus()) {
1691 items.push_back (SeparatorElem());
1694 if (!_route->is_master()
1696 && !_route->mixbus()
1699 if (Profile->get_mixbus()) {
1700 items.push_back (SeparatorElem());
1702 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1705 if (!Profile->get_mixbus()) {
1706 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1707 /* do not allow rename if the track is record-enabled */
1708 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1711 items.push_back (SeparatorElem());
1712 items.push_back (CheckMenuElem (_("Active")));
1713 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1714 i->set_active (_route->active());
1715 i->set_sensitive(! _session->transport_rolling());
1716 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1718 if (!Profile->get_mixbus ()) {
1719 items.push_back (SeparatorElem());
1720 items.push_back (CheckMenuElem (_("Strict I/O")));
1721 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1722 i->set_active (_route->strict_io());
1723 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1727 items.push_back (SeparatorElem());
1729 Gtk::Menu* dio_menu = new Menu;
1730 MenuList& dio_items = dio_menu->items();
1731 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1732 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1733 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1735 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1738 _plugin_insert_cnt = 0;
1739 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1740 if (_plugin_insert_cnt > 0) {
1741 items.push_back (SeparatorElem());
1742 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1745 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1746 items.push_back (MenuElem (_("Patch Selector..."),
1747 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1750 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1751 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1752 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1753 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1756 items.push_back (SeparatorElem());
1757 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1759 items.push_back (SeparatorElem());
1760 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1761 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1762 denormal_menu_item->set_active (_route->denormal_protection());
1765 /* note that this relies on selection being shared across editor and
1766 mixer (or global to the backend, in the future), which is the only
1767 sane thing for users anyway.
1770 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1772 Selection& selection (PublicEditor::instance().get_selection());
1773 if (!selection.selected (stav)) {
1774 selection.set (stav);
1777 if (!_route->is_master()) {
1778 items.push_back (SeparatorElem());
1779 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1782 items.push_back (SeparatorElem());
1783 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1789 MixerStrip::name_button_button_press (GdkEventButton* ev)
1791 if (ev->button == 1 || ev->button == 3) {
1792 list_route_operations ();
1794 if (ev->button == 1) {
1795 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1798 route_ops_menu->popup (3, ev->time);
1808 MixerStrip::number_button_button_press (GdkEventButton* ev)
1810 if ( ev->button == 3 ) {
1811 list_route_operations ();
1813 route_ops_menu->popup (1, ev->time);
1822 MixerStrip::list_route_operations ()
1824 delete route_ops_menu;
1825 build_route_ops_menu ();
1829 MixerStrip::set_selected (bool yn)
1831 AxisView::set_selected (yn);
1834 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1835 global_frame.set_name ("MixerStripSelectedFrame");
1837 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1838 global_frame.set_name ("MixerStripFrame");
1841 global_frame.queue_draw ();
1844 // processor_box.deselect_all_processors();
1848 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1850 if (what_changed.contains (ARDOUR::Properties::name)) {
1856 MixerStrip::name_changed ()
1860 name_button.set_text (_route->name());
1863 name_button.set_text (PBD::short_version (_route->name(), 5));
1867 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1869 if (_session->config.get_track_name_number()) {
1870 const int64_t track_number = _route->track_number ();
1871 if (track_number == 0) {
1872 number_label.set_text ("-");
1874 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1877 number_label.set_text ("");
1882 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1884 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1888 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1890 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1894 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1896 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1900 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1902 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1906 MixerStrip::width_button_pressed (GdkEventButton* ev)
1908 if (ev->button != 1) {
1912 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1915 _mixer.set_strip_width (Narrow, true);
1919 _mixer.set_strip_width (Wide, true);
1925 set_width_enum (Narrow, this);
1928 set_width_enum (Wide, this);
1937 MixerStrip::hide_clicked ()
1939 // LAME fix to reset the button status for when it is redisplayed (part 1)
1940 hide_button.set_sensitive(false);
1943 Hiding(); /* EMIT_SIGNAL */
1945 _mixer.hide_strip (this);
1949 hide_button.set_sensitive(true);
1953 MixerStrip::set_embedded (bool yn)
1959 MixerStrip::map_frozen ()
1961 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1963 boost::shared_ptr<AudioTrack> at = audio_track();
1966 switch (at->freeze_state()) {
1967 case AudioTrack::Frozen:
1968 processor_box.set_sensitive (false);
1969 hide_redirect_editors ();
1972 processor_box.set_sensitive (true);
1973 // XXX need some way, maybe, to retoggle redirect editors
1977 processor_box.set_sensitive (true);
1979 RouteUI::map_frozen ();
1983 MixerStrip::hide_redirect_editors ()
1985 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1989 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1991 boost::shared_ptr<Processor> processor (p.lock ());
1996 Gtk::Window* w = processor_box.get_processor_ui (processor);
2004 MixerStrip::reset_strip_style ()
2006 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2008 gpm.set_fader_name ("SendStripBase");
2012 if (is_midi_track()) {
2013 if (_route->active()) {
2014 set_name ("MidiTrackStripBase");
2016 set_name ("MidiTrackStripBaseInactive");
2018 gpm.set_fader_name ("MidiTrackFader");
2019 } else if (is_audio_track()) {
2020 if (_route->active()) {
2021 set_name ("AudioTrackStripBase");
2023 set_name ("AudioTrackStripBaseInactive");
2025 gpm.set_fader_name ("AudioTrackFader");
2027 if (_route->active()) {
2028 set_name ("AudioBusStripBase");
2030 set_name ("AudioBusStripBaseInactive");
2032 gpm.set_fader_name ("AudioBusFader");
2034 /* (no MIDI busses yet) */
2041 MixerStrip::engine_stopped ()
2046 MixerStrip::engine_running ()
2051 MixerStrip::meter_point_string (MeterPoint mp)
2064 case MeterPostFader:
2081 return S_("Meter|In");
2085 return S_("Meter|Pr");
2088 case MeterPostFader:
2089 return S_("Meter|Po");
2093 return S_("Meter|O");
2098 return S_("Meter|C");
2107 /** Called when the monitor-section state */
2109 MixerStrip::monitor_changed ()
2111 assert (monitor_section_button);
2112 if (_session->monitor_active()) {
2113 monitor_section_button->set_name ("master monitor section button active");
2115 monitor_section_button->set_name ("master monitor section button normal");
2120 MixerStrip::monitor_section_added_or_removed ()
2122 assert (monitor_section_button);
2123 if (mute_button->get_parent()) {
2124 mute_button->get_parent()->remove(*mute_button);
2126 if (monitor_section_button->get_parent()) {
2127 monitor_section_button->get_parent()->remove(*monitor_section_button);
2129 if (_session && _session->monitor_out ()) {
2130 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2131 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2132 mute_button->show();
2133 monitor_section_button->show();
2135 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2136 mute_button->show();
2140 /** Called when the metering point has changed */
2142 MixerStrip::meter_changed ()
2144 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2145 gpm.setup_meters ();
2146 // reset peak when meter point changes
2147 gpm.reset_peak_display();
2150 /** The bus that we are displaying sends to has changed, or been turned off.
2151 * @param send_to New bus that we are displaying sends to, or 0.
2154 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2156 RouteUI::bus_send_display_changed (send_to);
2159 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2164 revert_to_default_display ();
2167 revert_to_default_display ();
2172 MixerStrip::drop_send ()
2174 boost::shared_ptr<Send> current_send;
2176 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2177 current_send->set_metering (false);
2180 send_gone_connection.disconnect ();
2181 input_button.set_sensitive (true);
2182 output_button.set_sensitive (true);
2183 group_button.set_sensitive (true);
2184 set_invert_sensitive (true);
2185 gpm.meter_point_button.set_sensitive (true);
2186 mute_button->set_sensitive (true);
2187 solo_button->set_sensitive (true);
2188 solo_isolated_led->set_sensitive (true);
2189 solo_safe_led->set_sensitive (true);
2190 monitor_input_button->set_sensitive (true);
2191 monitor_disk_button->set_sensitive (true);
2192 _comment_button.set_sensitive (true);
2193 trim_control.set_sensitive (true);
2194 if (midi_input_enable_button) {
2195 midi_input_enable_button->set_sensitive (true);
2197 control_slave_ui.set_sensitive (true);
2198 RouteUI::check_rec_enable_sensitivity ();
2199 set_button_names (); // update solo button visual state
2203 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2205 _current_delivery = d;
2206 DeliveryChanged (_current_delivery);
2210 MixerStrip::show_send (boost::shared_ptr<Send> send)
2216 set_current_delivery (send);
2218 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2219 send->set_metering (true);
2220 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2222 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2223 gain_meter().setup_meters ();
2225 uint32_t const in = _current_delivery->pans_required();
2226 uint32_t const out = _current_delivery->pan_outs();
2228 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2229 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2230 panner_ui().setup_pan ();
2231 panner_ui().set_send_drawing_mode (true);
2232 panner_ui().show_all ();
2234 input_button.set_sensitive (false);
2235 group_button.set_sensitive (false);
2236 set_invert_sensitive (false);
2237 gpm.meter_point_button.set_sensitive (false);
2238 mute_button->set_sensitive (false);
2239 solo_button->set_sensitive (false);
2240 rec_enable_button->set_sensitive (false);
2241 solo_isolated_led->set_sensitive (false);
2242 solo_safe_led->set_sensitive (false);
2243 monitor_input_button->set_sensitive (false);
2244 monitor_disk_button->set_sensitive (false);
2245 _comment_button.set_sensitive (false);
2246 trim_control.set_sensitive (false);
2247 if (midi_input_enable_button) {
2248 midi_input_enable_button->set_sensitive (false);
2250 control_slave_ui.set_sensitive (false);
2252 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2253 output_button.set_sensitive (false);
2256 reset_strip_style ();
2260 MixerStrip::revert_to_default_display ()
2264 set_current_delivery (_route->main_outs ());
2266 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2267 gain_meter().setup_meters ();
2269 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2270 update_panner_choices();
2271 panner_ui().setup_pan ();
2272 panner_ui().set_send_drawing_mode (false);
2274 if (has_audio_outputs ()) {
2275 panners.show_all ();
2277 panners.hide_all ();
2280 reset_strip_style ();
2284 MixerStrip::set_button_names ()
2288 mute_button->set_text (_("Mute"));
2289 monitor_input_button->set_text (_("In"));
2290 monitor_disk_button->set_text (_("Disk"));
2291 if (monitor_section_button) {
2292 monitor_section_button->set_text (_("Mon"));
2295 if (_route && _route->solo_safe_control()->solo_safe()) {
2296 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2298 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2300 if (!Config->get_solo_control_is_listen_control()) {
2301 solo_button->set_text (_("Solo"));
2303 switch (Config->get_listen_position()) {
2304 case AfterFaderListen:
2305 solo_button->set_text (_("AFL"));
2307 case PreFaderListen:
2308 solo_button->set_text (_("PFL"));
2312 solo_isolated_led->set_text (_("Iso"));
2313 solo_safe_led->set_text (S_("SoloLock|Lock"));
2317 mute_button->set_text (S_("Mute|M"));
2318 monitor_input_button->set_text (S_("MonitorInput|I"));
2319 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2320 if (monitor_section_button) {
2321 monitor_section_button->set_text (S_("Mon|O"));
2324 if (_route && _route->solo_safe_control()->solo_safe()) {
2325 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2327 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2329 if (!Config->get_solo_control_is_listen_control()) {
2330 solo_button->set_text (S_("Solo|S"));
2332 switch (Config->get_listen_position()) {
2333 case AfterFaderListen:
2334 solo_button->set_text (S_("AfterFader|A"));
2336 case PreFaderListen:
2337 solo_button->set_text (S_("Prefader|P"));
2342 solo_isolated_led->set_text (S_("SoloIso|I"));
2343 solo_safe_led->set_text (S_("SoloLock|L"));
2348 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2350 gpm.meter_point_button.set_text ("");
2355 MixerStrip::plugin_selector()
2357 return _mixer.plugin_selector();
2361 MixerStrip::hide_things ()
2363 processor_box.hide_things ();
2367 MixerStrip::input_active_button_press (GdkEventButton*)
2369 /* nothing happens on press */
2374 MixerStrip::input_active_button_release (GdkEventButton* ev)
2376 boost::shared_ptr<MidiTrack> mt = midi_track ();
2382 boost::shared_ptr<RouteList> rl (new RouteList);
2384 rl->push_back (route());
2386 _session->set_exclusive_input_active (rl, !mt->input_active(),
2387 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2393 MixerStrip::midi_input_status_changed ()
2395 if (midi_input_enable_button) {
2396 boost::shared_ptr<MidiTrack> mt = midi_track ();
2398 midi_input_enable_button->set_active (mt->input_active ());
2403 MixerStrip::state_id () const
2405 return string_compose ("strip %1", _route->id().to_s());
2409 MixerStrip::parameter_changed (string p)
2411 if (p == _visibility.get_state_name()) {
2412 /* The user has made changes to the mixer strip visibility, so get
2413 our VisibilityGroup to reflect these changes in our widgets.
2415 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2416 } else if (p == "track-name-number") {
2418 update_track_number_visibility();
2422 /** Called to decide whether the solo isolate / solo lock button visibility should
2423 * be overridden from that configured by the user. We do this for the master bus.
2425 * @return optional value that is present if visibility state should be overridden.
2427 boost::optional<bool>
2428 MixerStrip::override_solo_visibility () const
2430 if (_route && _route->is_master ()) {
2431 return boost::optional<bool> (false);
2434 return boost::optional<bool> ();
2438 MixerStrip::add_input_port (DataType t)
2440 _route->input()->add_port ("", this, t);
2444 MixerStrip::add_output_port (DataType t)
2446 _route->output()->add_port ("", this, t);
2450 MixerStrip::route_active_changed ()
2452 reset_strip_style ();
2456 MixerStrip::copy_processors ()
2458 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2462 MixerStrip::cut_processors ()
2464 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2468 MixerStrip::paste_processors ()
2470 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2474 MixerStrip::select_all_processors ()
2476 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2480 MixerStrip::deselect_all_processors ()
2482 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2486 MixerStrip::delete_processors ()
2488 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2492 MixerStrip::toggle_processors ()
2494 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2498 MixerStrip::ab_plugins ()
2500 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2504 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2506 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2509 if (ev->button == 3) {
2510 popup_level_meter_menu (ev);
2518 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2520 using namespace Gtk::Menu_Helpers;
2522 Gtk::Menu* m = manage (new Menu);
2523 MenuList& items = m->items ();
2525 RadioMenuItem::Group group;
2527 _suspend_menu_callbacks = true;
2528 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2529 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2530 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2531 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2532 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2534 if (gpm.meter_channels().n_audio() == 0) {
2535 m->popup (ev->button, ev->time);
2536 _suspend_menu_callbacks = false;
2540 RadioMenuItem::Group tgroup;
2541 items.push_back (SeparatorElem());
2543 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2544 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2545 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2546 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2547 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2548 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2549 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2550 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2551 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2552 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2553 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2556 if (_route->is_master()) {
2559 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2560 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2561 /* non-master bus */
2564 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2571 MeterType cmt = _route->meter_type();
2572 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2574 items.push_back (SeparatorElem());
2575 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2576 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2577 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2578 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2579 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2580 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2582 m->popup (ev->button, ev->time);
2583 _suspend_menu_callbacks = false;
2587 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2588 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2590 using namespace Menu_Helpers;
2592 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2593 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2594 i->set_active (_route->meter_point() == point);
2598 MixerStrip::set_meter_point (MeterPoint p)
2600 if (_suspend_menu_callbacks) return;
2601 _route->set_meter_point (p);
2605 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2606 RadioMenuItem::Group& group, string const & name, MeterType type)
2608 using namespace Menu_Helpers;
2610 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2611 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2612 i->set_active (_route->meter_type() == type);
2616 MixerStrip::set_meter_type (MeterType t)
2618 if (_suspend_menu_callbacks) return;
2623 MixerStrip::update_track_number_visibility ()
2625 DisplaySuspender ds;
2626 bool show_label = _session->config.get_track_name_number();
2628 if (_route && _route->is_master()) {
2633 number_label.show ();
2634 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2635 // except the width of the number label is subtracted from the name-hbox, so we
2636 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2637 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2639 number_label.set_size_request(tnw, -1);
2640 number_label.show ();
2642 number_label.hide ();
2647 MixerStrip::color () const
2649 return route_color ();
2653 MixerStrip::marked_for_display () const
2655 return !_route->presentation_info().hidden();
2659 MixerStrip::set_marked_for_display (bool yn)
2661 return RouteUI::mark_hidden (!yn);