2 Copyright (C) 2002-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.
21 #include <boost/algorithm/string.hpp>
23 #include <gtkmm2ext/gtk_ui.h>
24 #include <gtkmm2ext/choice.h>
25 #include <gtkmm2ext/doi.h>
26 #include <gtkmm2ext/bindable_button.h>
27 #include <gtkmm2ext/barcontroller.h>
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
31 #include "pbd/memento_command.h"
32 #include "pbd/stacktrace.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour/dB.h"
37 #include "ardour/route_group.h"
38 #include "ardour/solo_isolate_control.h"
39 #include "ardour/vca.h"
40 #include "ardour/vca_manager.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audio_port.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/filename_extensions.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/monitor_control.h"
47 #include "ardour/internal_send.h"
48 #include "ardour/panner_shell.h"
49 #include "ardour/profile.h"
50 #include "ardour/phase_control.h"
51 #include "ardour/send.h"
52 #include "ardour/route.h"
53 #include "ardour/session.h"
54 #include "ardour/template_utils.h"
56 #include "ardour_button.h"
57 #include "ardour_dialog.h"
58 #include "ardour_ui.h"
59 #include "automation_time_axis.h"
61 #include "group_tabs.h"
62 #include "gui_object.h"
63 #include "gui_thread.h"
65 #include "latency_gui.h"
66 #include "mixer_strip.h"
67 #include "plugin_pin_dialog.h"
69 #include "rgb_macros.h"
70 #include "route_time_axis.h"
73 #include "ui_config.h"
79 using namespace Gtkmm2ext;
80 using namespace ARDOUR;
81 using namespace ARDOUR_UI_UTILS;
85 uint32_t RouteUI::_max_invert_buttons = 3;
86 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
87 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
88 std::string RouteUI::program_port_prefix;
90 RouteUI::RouteUI (ARDOUR::Session* sess)
91 : monitor_input_button (0)
92 , monitor_disk_button (0)
100 , output_selector (0)
103 if (program_port_prefix.empty()) {
104 // compare to gtk2_ardour/port_group.cc
105 string lpn (PROGRAM_NAME);
106 boost::to_lower (lpn);
107 program_port_prefix = lpn + ":"; // e.g. "ardour:"
118 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
121 _route.reset (); /* drop reference to route, so that it can be cleaned up */
122 route_connections.drop_connections ();
128 delete comment_window;
129 delete input_selector;
130 delete output_selector;
131 delete monitor_input_button;
132 delete monitor_disk_button;
135 send_blink_connection.disconnect ();
136 rec_blink_connection.disconnect ();
142 self_destruct = true;
148 pre_fader_mute_check = 0;
149 post_fader_mute_check = 0;
150 listen_mute_check = 0;
153 solo_isolated_check = 0;
154 solo_isolated_led = 0;
158 denormal_menu_item = 0;
161 multiple_mute_change = false;
162 multiple_solo_change = false;
163 _i_am_the_modifier = 0;
168 setup_invert_buttons ();
170 mute_button = manage (new ArdourButton);
171 mute_button->set_name ("mute button");
172 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
174 solo_button = manage (new ArdourButton);
175 solo_button->set_name ("solo button");
176 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
177 solo_button->set_no_show_all (true);
179 rec_enable_button = manage (new ArdourButton);
180 rec_enable_button->set_name ("record enable button");
181 rec_enable_button->set_icon (ArdourIcon::RecButton);
182 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
184 if (UIConfiguration::instance().get_blink_rec_arm()) {
185 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
188 show_sends_button = manage (new ArdourButton);
189 show_sends_button->set_name ("send alert button");
190 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
192 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
193 monitor_input_button->set_name ("monitor button");
194 monitor_input_button->set_text (_("In"));
195 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
196 monitor_input_button->set_no_show_all (true);
198 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_disk_button->set_name ("monitor button");
200 monitor_disk_button->set_text (_("Disk"));
201 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
202 monitor_disk_button->set_no_show_all (true);
204 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
205 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
206 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
208 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
209 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
210 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
212 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
213 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
215 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
216 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
218 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
219 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
220 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
221 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
223 monitor_input_button->set_distinct_led_click (false);
224 monitor_disk_button->set_distinct_led_click (false);
226 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
227 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
229 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
230 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
232 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
238 route_connections.drop_connections ();
246 denormal_menu_item = 0;
250 RouteUI::self_delete ()
256 RouteUI::set_route (boost::shared_ptr<Route> rp)
262 if (set_color_from_route()) {
263 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
267 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
270 delete input_selector;
273 delete output_selector;
276 mute_button->set_controllable (_route->mute_control());
277 solo_button->set_controllable (_route->solo_control());
279 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
281 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
283 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
284 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
285 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
286 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
287 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
290 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
291 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
292 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
294 track_mode_changed();
298 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
299 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
301 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
303 if (_session->writable() && is_track()) {
304 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
306 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
307 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
309 rec_enable_button->show();
310 rec_enable_button->set_controllable (t->rec_enable_control());
312 if (is_midi_track()) {
313 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
314 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
319 /* this will work for busses and tracks, and needs to be called to
320 set up the name entry/name label display.
324 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
325 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
327 update_monitoring_display ();
330 mute_button->unset_flags (Gtk::CAN_FOCUS);
331 solo_button->unset_flags (Gtk::CAN_FOCUS);
335 if (_route->is_monitor() || _route->is_master()) {
336 solo_button->hide ();
343 setup_invert_buttons ();
344 set_invert_button_state ();
346 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
347 bus_send_display_changed (s);
349 update_mute_display ();
350 update_solo_display ();
352 if (!UIConfiguration::instance().get_blink_rec_arm()) {
353 blink_rec_display(true); // set initial rec-en button state
356 check_rec_enable_sensitivity ();
357 maybe_add_route_print_mgr ();
358 route_color_changed();
359 route_gui_changed (PropertyChange (Properties::selected));
363 RouteUI::polarity_changed ()
369 set_invert_button_state ();
373 RouteUI::mute_press (GdkEventButton* ev)
375 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
379 //if this is a binding action, let the ArdourButton handle it
380 if ( BindingProxy::is_bind_action(ev) )
383 multiple_mute_change = false;
385 if (Keyboard::is_context_menu_event (ev)) {
391 mute_menu->popup(0,ev->time);
397 if (Keyboard::is_button2_event (ev)) {
398 // button2-click is "momentary"
400 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
403 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
405 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
407 /* toggle mute on everything (but
408 * exclude the master and monitor)
410 * because we are going to erase
411 * elements of the list we need to work
415 boost::shared_ptr<RouteList> copy (new RouteList);
417 *copy = *_session->get_routes ();
419 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
420 if ((*i)->is_master() || (*i)->is_monitor()) {
428 _mute_release->routes = copy;
431 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
433 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
435 /* Primary-button1 inverts the implication of
436 the group being active. If the group is
437 active (for mute), then this modifier means
438 "do not apply to mute". If the group is
439 inactive (for mute), then this modifier
440 means "apply to route". This is all
441 accomplished by passing just the actual
442 route, along with the InverseGroup group
445 NOTE: Primary-button2 is MIDI learn.
448 boost::shared_ptr<RouteList> rl;
450 if (ev->button == 1) {
452 rl.reset (new RouteList);
453 rl->push_back (_route);
456 _mute_release->routes = rl;
459 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
464 /* plain click applies change to this route */
466 boost::shared_ptr<RouteList> rl (new RouteList);
467 rl->push_back (_route);
470 _mute_release->routes = rl;
473 _route->mute_control()->set_value (!_route->muted_by_self(), Controllable::UseGroup);
482 RouteUI::mute_release (GdkEventButton* /*ev*/)
485 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
486 delete _mute_release;
494 RouteUI::edit_output_configuration ()
496 if (output_selector == 0) {
498 boost::shared_ptr<Send> send;
499 boost::shared_ptr<IO> output;
501 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
502 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
503 output = send->output();
505 output = _route->output ();
508 output = _route->output ();
511 output_selector = new IOSelectorWindow (_session, output);
514 if (output_selector->is_visible()) {
515 output_selector->get_toplevel()->get_window()->raise();
517 output_selector->present ();
520 //output_selector->set_keep_above (true);
524 RouteUI::edit_input_configuration ()
526 if (input_selector == 0) {
527 input_selector = new IOSelectorWindow (_session, _route->input());
530 if (input_selector->is_visible()) {
531 input_selector->get_toplevel()->get_window()->raise();
533 input_selector->present ();
536 //input_selector->set_keep_above (true);
540 RouteUI::solo_press(GdkEventButton* ev)
542 /* ignore double/triple clicks */
544 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
548 //if this is a binding action, let the ArdourButton handle it
549 if ( BindingProxy::is_bind_action(ev) )
552 multiple_solo_change = false;
554 if (Keyboard::is_context_menu_event (ev)) {
556 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
557 ! (solo_safe_led && solo_safe_led->is_visible())) {
559 if (solo_menu == 0) {
563 solo_menu->popup (1, ev->time);
568 if (Keyboard::is_button2_event (ev)) {
570 // button2-click is "momentary"
571 _solo_release = new SoloMuteRelease (_route->self_soloed());
574 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
576 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
578 /* Primary-Tertiary-click applies change to all routes */
581 _solo_release->routes = _session->get_routes ();
584 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
586 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
588 // Primary-Secondary-click: exclusively solo this track
591 _solo_release->exclusive = true;
593 boost::shared_ptr<RouteList> routes = _session->get_routes();
595 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
596 if ((*i)->soloed ()) {
597 _solo_release->routes_on->push_back (*i);
599 _solo_release->routes_off->push_back (*i);
604 if (Config->get_solo_control_is_listen_control()) {
605 /* ??? we need a just_one_listen() method */
608 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
611 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
613 // shift-click: toggle solo isolated status
615 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
616 delete _solo_release;
619 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
621 /* Primary-button1: solo mix group.
622 NOTE: Primary-button2 is MIDI learn.
625 /* Primary-button1 applies change to the mix group even if it is not active
626 NOTE: Primary-button2 is MIDI learn.
629 boost::shared_ptr<RouteList> rl;
631 if (ev->button == 1) {
633 /* Primary-button1 inverts the implication of
634 the group being active. If the group is
635 active (for solo), then this modifier means
636 "do not apply to solo". If the group is
637 inactive (for mute), then this modifier
638 means "apply to route". This is all
639 accomplished by passing just the actual
640 route, along with the InverseGroup group
643 NOTE: Primary-button2 is MIDI learn.
646 rl.reset (new RouteList);
647 rl->push_back (_route);
650 _solo_release->routes = rl;
653 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
656 delete _solo_release;
661 /* click: solo this route */
663 boost::shared_ptr<RouteList> rl (new RouteList);
664 rl->push_back (route());
667 _solo_release->routes = rl;
670 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
679 RouteUI::solo_release (GdkEventButton* /*ev*/)
683 if (_solo_release->exclusive) {
686 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
689 delete _solo_release;
697 RouteUI::rec_enable_press(GdkEventButton* ev)
699 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
703 //if this is a binding action, let the ArdourButton handle it
704 if ( BindingProxy::is_bind_action(ev) )
707 if (!_session->engine().connected()) {
708 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
713 if (is_midi_track()) {
715 /* rec-enable button exits from step editing */
717 if (midi_track()->step_editing()) {
718 midi_track()->set_step_editing (false);
723 if (is_track() && rec_enable_button) {
725 if (Keyboard::is_button2_event (ev)) {
727 //rec arm does not have a momentary mode
730 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
732 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
734 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
736 /* Primary-button1 applies change to the route group (even if it is not active)
737 NOTE: Primary-button2 is MIDI learn.
740 if (ev->button == 1) {
742 boost::shared_ptr<RouteList> rl;
744 rl.reset (new RouteList);
745 rl->push_back (_route);
747 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
750 } else if (Keyboard::is_context_menu_event (ev)) {
752 /* do this on release */
756 boost::shared_ptr<Track> trk = track();
757 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
765 RouteUI::update_monitoring_display ()
771 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
777 MonitorState ms = t->monitoring_state();
779 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
780 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
782 if (ms & MonitoringInput) {
783 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
785 monitor_input_button->unset_active_state ();
789 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
790 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
792 if (ms & MonitoringDisk) {
793 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
795 monitor_disk_button->unset_active_state ();
801 RouteUI::monitor_input_press(GdkEventButton*)
807 RouteUI::monitor_input_release(GdkEventButton* ev)
809 return monitor_release (ev, MonitorInput);
813 RouteUI::monitor_disk_press (GdkEventButton*)
819 RouteUI::monitor_disk_release (GdkEventButton* ev)
821 return monitor_release (ev, MonitorDisk);
825 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
827 if (ev->button != 1) {
831 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
838 boost::shared_ptr<RouteList> rl;
840 /* XXX for now, monitoring choices are orthogonal. cue monitoring
841 will follow in 3.X but requires mixing the input and playback (disk)
842 signal together, which requires yet more buffers.
845 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
846 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
848 /* this line will change when the options are non-orthogonal */
849 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
853 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
854 rl = _session->get_routes ();
856 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
857 if (_route->route_group() && _route->route_group()->is_monitoring()) {
858 rl = _route->route_group()->route_list();
860 rl.reset (new RouteList);
861 rl->push_back (route());
864 rl.reset (new RouteList);
865 rl->push_back (route());
868 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
874 RouteUI::build_record_menu ()
877 record_menu = new Menu;
878 record_menu->set_name ("ArdourContextMenu");
879 using namespace Menu_Helpers;
880 MenuList& items = record_menu->items();
882 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
883 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
885 if (is_midi_track()) {
886 items.push_back (SeparatorElem());
887 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
888 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
892 if (step_edit_item) {
893 if (track()->rec_enable_control()->get_value()) {
894 step_edit_item->set_sensitive (false);
896 step_edit_item->set_active (midi_track()->step_editing());
899 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
900 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
905 RouteUI::toggle_step_edit ()
907 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
911 midi_track()->set_step_editing (step_edit_item->get_active());
915 RouteUI::toggle_rec_safe ()
917 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
923 /* This check is made inside the control too, but dong it here can't
927 if (_route->rec_enable_control()->get_value()) {
931 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
935 RouteUI::step_edit_changed (bool yn)
938 if (rec_enable_button) {
939 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
942 start_step_editing ();
944 if (step_edit_item) {
945 step_edit_item->set_active (true);
950 if (rec_enable_button) {
951 rec_enable_button->unset_active_state ();
954 stop_step_editing ();
956 if (step_edit_item) {
957 step_edit_item->set_active (false);
963 RouteUI::rec_enable_release (GdkEventButton* ev)
965 if (Keyboard::is_context_menu_event (ev)) {
966 build_record_menu ();
968 record_menu->popup (1, ev->time);
977 RouteUI::build_sends_menu ()
979 using namespace Menu_Helpers;
981 sends_menu = new Menu;
982 sends_menu->set_name ("ArdourContextMenu");
983 MenuList& items = sends_menu->items();
986 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
990 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
994 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
998 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1002 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1006 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1009 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1013 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1016 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1017 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1018 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1023 RouteUI::create_sends (Placement p, bool include_buses)
1025 _session->globally_add_internal_sends (_route, p, include_buses);
1029 RouteUI::create_selected_sends (Placement p, bool include_buses)
1031 boost::shared_ptr<RouteList> rlist (new RouteList);
1032 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1034 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1035 RouteTimeAxisView* rtv;
1037 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1038 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1039 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1040 rlist->push_back (rui->route());
1046 _session->add_internal_sends (_route, p, rlist);
1050 RouteUI::set_sends_gain_from_track ()
1052 _session->globally_set_send_gains_from_track (_route);
1056 RouteUI::set_sends_gain_to_zero ()
1058 _session->globally_set_send_gains_to_zero (_route);
1062 RouteUI::set_sends_gain_to_unity ()
1064 _session->globally_set_send_gains_to_unity (_route);
1068 RouteUI::show_sends_press(GdkEventButton* ev)
1070 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1074 if (!is_track() && show_sends_button) {
1076 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1078 // do nothing on midi sigc::bind event
1081 } else if (Keyboard::is_context_menu_event (ev)) {
1083 if (sends_menu == 0) {
1084 build_sends_menu ();
1087 sends_menu->popup (0, ev->time);
1091 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1094 set_showing_sends_to (boost::shared_ptr<Route> ());
1096 set_showing_sends_to (_route);
1105 RouteUI::show_sends_release (GdkEventButton*)
1111 RouteUI::send_blink (bool onoff)
1113 if (!show_sends_button) {
1118 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1120 show_sends_button->unset_active_state ();
1124 Gtkmm2ext::ActiveState
1125 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1127 boost::shared_ptr<SoloControl> sc = s->solo_control();
1130 return Gtkmm2ext::Off;
1133 if (!sc->can_solo()) {
1134 return Gtkmm2ext::Off;
1138 if (sc->self_soloed()) {
1139 return Gtkmm2ext::ExplicitActive;
1140 } else if (sc->soloed_by_others()) {
1141 return Gtkmm2ext::ImplicitActive;
1143 return Gtkmm2ext::Off;
1147 Gtkmm2ext::ActiveState
1148 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1150 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1153 return Gtkmm2ext::Off;
1156 if (s->is_master() || s->is_monitor()) {
1157 return Gtkmm2ext::Off;
1160 if (sc->solo_isolated()) {
1161 return Gtkmm2ext::ExplicitActive;
1163 return Gtkmm2ext::Off;
1167 Gtkmm2ext::ActiveState
1168 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1170 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1173 return Gtkmm2ext::Off;
1176 if (s->is_master() || s->is_monitor()) {
1177 return Gtkmm2ext::Off;
1180 if (sc->solo_safe()) {
1181 return Gtkmm2ext::ExplicitActive;
1183 return Gtkmm2ext::Off;
1188 RouteUI::update_solo_display ()
1190 bool yn = _route->solo_safe_control()->solo_safe ();
1192 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1193 solo_safe_check->set_active (yn);
1196 yn = _route->solo_isolate_control()->solo_isolated ();
1198 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1199 solo_isolated_check->set_active (yn);
1202 set_button_names ();
1204 if (solo_isolated_led) {
1205 if (_route->solo_isolate_control()->solo_isolated()) {
1206 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1208 solo_isolated_led->unset_active_state ();
1212 if (solo_safe_led) {
1213 if (_route->solo_safe_control()->solo_safe()) {
1214 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1216 solo_safe_led->unset_active_state ();
1220 solo_button->set_active_state (solo_active_state (_route));
1222 /* some changes to solo status can affect mute display, so catch up
1225 update_mute_display ();
1229 RouteUI::solo_changed_so_update_mute ()
1231 update_mute_display ();
1235 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1237 boost::shared_ptr<MuteControl> mc = s->mute_control();
1239 if (s->is_monitor()) {
1240 return Gtkmm2ext::Off;
1244 return Gtkmm2ext::Off;
1247 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1249 if (mc->muted_by_self ()) {
1251 return Gtkmm2ext::ExplicitActive;
1252 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1253 /* this will reflect both solo mutes AND master mutes */
1254 return Gtkmm2ext::ImplicitActive;
1256 /* no mute at all */
1257 return Gtkmm2ext::Off;
1262 if (mc->muted_by_self()) {
1264 return Gtkmm2ext::ExplicitActive;
1265 } else if (mc->muted_by_masters ()) {
1266 /* this shows only master mutes, not mute-by-others-soloing */
1267 return Gtkmm2ext::ImplicitActive;
1269 /* no mute at all */
1270 return Gtkmm2ext::Off;
1274 return ActiveState(0);
1278 RouteUI::update_mute_display ()
1284 mute_button->set_active_state (mute_active_state (_session, _route));
1289 RouteUI::route_rec_enable_changed ()
1291 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1295 RouteUI::session_rec_enable_changed ()
1297 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1301 RouteUI::blink_rec_display (bool blinkOn)
1303 if (!rec_enable_button || !_route) {
1307 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1315 if (track()->rec_enable_control()->get_value()) {
1316 switch (_session->record_status ()) {
1317 case Session::Recording:
1318 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1321 case Session::Disabled:
1322 case Session::Enabled:
1323 if (UIConfiguration::instance().get_blink_rec_arm()) {
1324 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1326 rec_enable_button->set_active_state ( ImplicitActive );
1331 if (step_edit_item) {
1332 step_edit_item->set_sensitive (false);
1336 rec_enable_button->unset_active_state ();
1338 if (step_edit_item) {
1339 step_edit_item->set_sensitive (true);
1343 check_rec_enable_sensitivity ();
1347 RouteUI::build_solo_menu (void)
1349 using namespace Menu_Helpers;
1351 solo_menu = new Menu;
1352 solo_menu->set_name ("ArdourContextMenu");
1353 MenuList& items = solo_menu->items();
1354 Gtk::CheckMenuItem* check;
1356 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1357 check->set_active (_route->solo_isolate_control()->solo_isolated());
1358 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1359 items.push_back (CheckMenuElem(*check));
1360 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1363 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1364 check->set_active (_route->solo_safe_control()->solo_safe());
1365 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1366 items.push_back (CheckMenuElem(*check));
1367 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1370 //items.push_back (SeparatorElem());
1371 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1376 RouteUI::build_mute_menu(void)
1378 using namespace Menu_Helpers;
1380 mute_menu = new Menu;
1381 mute_menu->set_name ("ArdourContextMenu");
1383 MenuList& items = mute_menu->items();
1385 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1386 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1387 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1388 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1389 pre_fader_mute_check->show_all();
1391 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1392 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1393 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1394 items.push_back (CheckMenuElem(*post_fader_mute_check));
1395 post_fader_mute_check->show_all();
1397 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1398 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1399 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1400 items.push_back (CheckMenuElem(*listen_mute_check));
1401 listen_mute_check->show_all();
1403 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1404 init_mute_menu(MuteMaster::Main, main_mute_check);
1405 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1406 items.push_back (CheckMenuElem(*main_mute_check));
1407 main_mute_check->show_all();
1409 //items.push_back (SeparatorElem());
1410 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1412 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1416 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1418 check->set_active (_route->mute_control()->mute_points() & mp);
1422 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1424 if (check->get_active()) {
1425 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1427 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1432 RouteUI::muting_change ()
1434 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1437 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1439 yn = (current & MuteMaster::PreFader);
1441 if (pre_fader_mute_check->get_active() != yn) {
1442 pre_fader_mute_check->set_active (yn);
1445 yn = (current & MuteMaster::PostFader);
1447 if (post_fader_mute_check->get_active() != yn) {
1448 post_fader_mute_check->set_active (yn);
1451 yn = (current & MuteMaster::Listen);
1453 if (listen_mute_check->get_active() != yn) {
1454 listen_mute_check->set_active (yn);
1457 yn = (current & MuteMaster::Main);
1459 if (main_mute_check->get_active() != yn) {
1460 main_mute_check->set_active (yn);
1465 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1467 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1471 bool view = solo_isolated_led->active_state();
1472 bool model = _route->solo_isolate_control()->solo_isolated();
1474 /* called BEFORE the view has changed */
1476 if (ev->button == 1) {
1477 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1480 /* disable isolate for all routes */
1481 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1483 /* enable isolate for all routes */
1484 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1489 if (model == view) {
1491 /* flip just this route */
1493 boost::shared_ptr<RouteList> rl (new RouteList);
1494 rl->push_back (_route);
1495 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1504 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1506 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1510 bool view = solo_safe_led->active_state();
1511 bool model = _route->solo_safe_control()->solo_safe();
1513 if (ev->button == 1) {
1514 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1515 boost::shared_ptr<RouteList> rl (_session->get_routes());
1517 /* disable solo safe for all routes */
1518 DisplaySuspender ds;
1519 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1520 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1523 /* enable solo safe for all routes */
1524 DisplaySuspender ds;
1525 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1526 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1531 if (model == view) {
1532 /* flip just this route */
1533 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1542 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1544 bool view = check->get_active();
1545 bool model = _route->solo_isolate_control()->solo_isolated();
1547 /* called AFTER the view has changed */
1549 if (model != view) {
1550 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1555 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1557 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1560 /** Ask the user to choose a colour, and then apply that color to my route
1563 RouteUI::choose_color ()
1566 Gdk::Color c (gdk_color_from_rgba (_route->presentation_info().color()));
1567 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1570 set_color (gdk_color_to_rgba (color));
1574 /** Set the route's own color. This may not be used for display if
1575 * the route is in a group which shares its color with its routes.
1578 RouteUI::set_color (uint32_t c)
1580 _route->presentation_info().set_color (c);
1583 /** @return GUI state ID for things that are common to the route in all its representations */
1585 RouteUI::route_state_id () const
1587 return string_compose (X_("route %1"), _route->id().to_s());
1591 RouteUI::set_color_from_route ()
1593 if (_route->presentation_info().color_set()) {
1594 return 0; /* nothing to do */
1597 return 1; /* pick a color */
1600 /** @return true if this name should be used for the route, otherwise false */
1602 RouteUI::verify_new_route_name (const std::string& name)
1604 if (name.find (':') == string::npos) {
1608 MessageDialog colon_msg (
1609 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1610 false, MESSAGE_QUESTION, BUTTONS_NONE
1613 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1614 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1616 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1620 RouteUI::route_rename ()
1622 ArdourPrompter name_prompter (true);
1627 name_prompter.set_title (_("Rename Track"));
1629 name_prompter.set_title (_("Rename Bus"));
1631 name_prompter.set_prompt (_("New name:"));
1632 name_prompter.set_initial_text (_route->name());
1633 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1634 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1635 name_prompter.show_all ();
1638 switch (name_prompter.run ()) {
1639 case Gtk::RESPONSE_ACCEPT:
1640 name_prompter.get_result (result);
1641 name_prompter.hide ();
1642 if (result.length()) {
1643 if (verify_new_route_name (result)) {
1644 _route->set_name (result);
1647 /* back to name prompter */
1651 /* nothing entered, just get out of here */
1666 RouteUI::toggle_comment_editor ()
1668 // if (ignore_toggle) {
1672 if (comment_window && comment_window->is_visible ()) {
1673 comment_window->hide ();
1675 open_comment_editor ();
1681 RouteUI::open_comment_editor ()
1683 if (comment_window == 0) {
1684 setup_comment_editor ();
1688 title = _route->name();
1689 title += _(": comment editor");
1691 comment_window->set_title (title);
1692 comment_window->present();
1696 RouteUI::setup_comment_editor ()
1698 comment_window = new ArdourWindow (""); // title will be reset to show route
1699 comment_window->set_skip_taskbar_hint (true);
1700 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1701 comment_window->set_default_size (400, 200);
1703 comment_area = manage (new TextView());
1704 comment_area->set_name ("MixerTrackCommentArea");
1705 comment_area->set_wrap_mode (WRAP_WORD);
1706 comment_area->set_editable (true);
1707 comment_area->get_buffer()->set_text (_route->comment());
1708 comment_area->show ();
1710 comment_window->add (*comment_area);
1714 RouteUI::comment_changed ()
1716 ignore_comment_edit = true;
1718 comment_area->get_buffer()->set_text (_route->comment());
1720 ignore_comment_edit = false;
1724 RouteUI::comment_editor_done_editing ()
1726 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1728 string const str = comment_area->get_buffer()->get_text();
1729 if (str == _route->comment ()) {
1733 _route->set_comment (str, this);
1737 RouteUI::set_route_active (bool a, bool apply_to_selection)
1739 if (apply_to_selection) {
1740 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1742 _route->set_active (a, this);
1747 RouteUI::duplicate_selected_routes ()
1749 ARDOUR_UI::instance()->start_duplicate_routes();
1753 RouteUI::toggle_denormal_protection ()
1755 if (denormal_menu_item) {
1759 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1761 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1762 _route->set_denormal_protection (x);
1768 RouteUI::denormal_protection_changed ()
1770 if (denormal_menu_item) {
1771 denormal_menu_item->set_active (_route->denormal_protection());
1776 RouteUI::disconnect_input ()
1778 _route->input()->disconnect (this);
1782 RouteUI::disconnect_output ()
1784 _route->output()->disconnect (this);
1788 RouteUI::is_track () const
1790 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1793 boost::shared_ptr<Track>
1794 RouteUI::track() const
1796 return boost::dynamic_pointer_cast<Track>(_route);
1800 RouteUI::is_audio_track () const
1802 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1805 boost::shared_ptr<AudioTrack>
1806 RouteUI::audio_track() const
1808 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1812 RouteUI::is_midi_track () const
1814 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1817 boost::shared_ptr<MidiTrack>
1818 RouteUI::midi_track() const
1820 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1824 RouteUI::has_audio_outputs () const
1826 return (_route->n_outputs().n_audio() > 0);
1830 RouteUI::map_frozen ()
1832 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1834 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1837 check_rec_enable_sensitivity ();
1842 RouteUI::adjust_latency ()
1844 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1848 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1851 std::string safe_name;
1854 prompter.get_result (name, true);
1856 safe_name = legalize_for_path (name);
1857 safe_name += template_suffix;
1859 path = Glib::build_filename (dir, safe_name);
1861 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1862 bool overwrite = overwrite_file_dialog (prompter,
1863 _("Confirm Template Overwrite"),
1864 _("A template already exists with that name. Do you want to overwrite it?"));
1871 _route->save_as_template (path, name);
1877 RouteUI::save_as_template ()
1881 dir = ARDOUR::user_route_template_directory ();
1883 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1884 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1888 ArdourPrompter prompter (true); // modal
1890 prompter.set_title (_("Save As Template"));
1891 prompter.set_prompt (_("Template name:"));
1892 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1894 bool finished = false;
1896 switch (prompter.run()) {
1897 case RESPONSE_ACCEPT:
1898 finished = process_save_template_prompter (prompter, dir);
1908 RouteUI::check_rec_enable_sensitivity ()
1910 if (!rec_enable_button) {
1911 assert (0); // This should not happen
1914 if (!_session->writable()) {
1915 rec_enable_button->set_sensitive (false);
1919 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1920 rec_enable_button->set_sensitive (false);
1921 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1922 rec_enable_button->set_sensitive (false);
1924 rec_enable_button->set_sensitive (true);
1926 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1927 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1929 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1931 update_monitoring_display ();
1935 RouteUI::parameter_changed (string const & p)
1937 /* this handles RC and per-session parameter changes */
1939 if (p == "disable-disarm-during-roll") {
1940 check_rec_enable_sensitivity ();
1941 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1942 set_button_names ();
1943 } else if (p == "session-monitoring") {
1944 update_monitoring_display ();
1945 } else if (p == "auto-input") {
1946 update_monitoring_display ();
1947 } else if (p == "blink-rec-arm") {
1948 if (UIConfiguration::instance().get_blink_rec_arm()) {
1949 rec_blink_connection.disconnect ();
1950 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1952 rec_blink_connection.disconnect ();
1953 RouteUI::blink_rec_display(false);
1959 RouteUI::step_gain_up ()
1961 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1965 RouteUI::page_gain_up ()
1967 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1971 RouteUI::step_gain_down ()
1973 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1977 RouteUI::page_gain_down ()
1979 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1983 RouteUI::setup_invert_buttons ()
1985 /* remove old invert buttons */
1986 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1987 _invert_button_box.remove (**i);
1990 _invert_buttons.clear ();
1992 if (!_route || !_route->input()) {
1996 uint32_t const N = _route->input()->n_ports().n_audio ();
1998 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2000 for (uint32_t i = 0; i < to_add; ++i) {
2001 ArdourButton* b = manage (new ArdourButton);
2002 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2003 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2005 b->set_name (X_("invert button"));
2008 b->set_text (string_compose (X_("Ø (%1)"), N));
2010 b->set_text (X_("Ø"));
2013 b->set_text (string_compose (X_("Ø%1"), i + 1));
2016 if (N <= _max_invert_buttons) {
2017 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert polarity of channel %1 of this track. Right-click to show menu."), i + 1));
2019 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2022 _invert_buttons.push_back (b);
2023 _invert_button_box.pack_start (*b);
2026 _invert_button_box.set_spacing (1);
2027 _invert_button_box.show_all ();
2031 RouteUI::set_invert_button_state ()
2033 uint32_t const N = _route->input()->n_ports().n_audio();
2034 if (N > _max_invert_buttons) {
2036 /* One button for many channels; explicit active if all channels are inverted,
2037 implicit active if some are, off if none are.
2040 ArdourButton* b = _invert_buttons.front ();
2042 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2043 b->set_active_state (Gtkmm2ext::ExplicitActive);
2044 } else if (_route->phase_control()->any()) {
2045 b->set_active_state (Gtkmm2ext::ImplicitActive);
2047 b->set_active_state (Gtkmm2ext::Off);
2052 /* One button per channel; just set active */
2055 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2056 (*i)->set_active (_route->phase_control()->inverted (j));
2063 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2065 if (ev->button == 1 && i < _invert_buttons.size()) {
2066 uint32_t const N = _route->input()->n_ports().n_audio ();
2067 if (N <= _max_invert_buttons) {
2068 /* left-click inverts phase so long as we have a button per channel */
2069 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2078 RouteUI::invert_press (GdkEventButton* ev)
2080 using namespace Menu_Helpers;
2082 uint32_t const N = _route->input()->n_ports().n_audio();
2083 if (N <= _max_invert_buttons && ev->button != 3) {
2084 /* If we have an invert button per channel, we only pop
2085 up a menu on right-click; left click is handled
2091 delete _invert_menu;
2092 _invert_menu = new Menu;
2093 _invert_menu->set_name ("ArdourContextMenu");
2094 MenuList& items = _invert_menu->items ();
2096 for (uint32_t i = 0; i < N; ++i) {
2097 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2098 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2099 ++_i_am_the_modifier;
2100 e->set_active (_route->phase_control()->inverted (i));
2101 --_i_am_the_modifier;
2104 _invert_menu->popup (0, ev->time);
2110 RouteUI::invert_menu_toggled (uint32_t c)
2112 if (_i_am_the_modifier) {
2117 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2121 RouteUI::set_invert_sensitive (bool yn)
2123 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2124 (*b)->set_sensitive (yn);
2129 RouteUI::request_redraw ()
2132 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2136 /** The Route's gui_changed signal has been emitted */
2138 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2140 if (what_changed.contains (Properties::color)) {
2141 if (set_color_from_route () == 0) {
2142 route_color_changed ();
2148 RouteUI::track_mode_changed (void)
2151 switch (track()->mode()) {
2152 case ARDOUR::NonLayered:
2153 case ARDOUR::Normal:
2154 rec_enable_button->set_icon (ArdourIcon::RecButton);
2156 case ARDOUR::Destructive:
2157 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2160 rec_enable_button->queue_draw();
2163 /** @return the color that this route should use; it maybe its own,
2164 or it maybe that of its route group.
2168 RouteUI::route_color () const
2171 RouteGroup* g = _route->route_group ();
2174 if (g && g->is_color()) {
2175 set_color_from_rgba (c, GroupTabs::group_color (g));
2178 /* deal with older 4.x color, which was stored in the GUI object state */
2180 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2184 /* old v4.x or earlier session. Use this information */
2186 int red, green, blue;
2189 stringstream ss (p);
2191 /* old color format version was:
2193 16bit value for red:16 bit value for green:16 bit value for blue
2208 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
2211 set_color_from_rgba (c, _route->presentation_info().color());
2218 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2220 _showing_sends_to = send_to;
2221 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2225 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2227 if (_route == send_to) {
2228 show_sends_button->set_active (true);
2229 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2231 show_sends_button->set_active (false);
2232 send_blink_connection.disconnect ();
2237 RouteUI::route_group() const
2239 return _route->route_group();
2243 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2244 : WM::ProxyBase (name, string())
2245 , _route (boost::weak_ptr<Route> (route))
2247 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2250 RoutePinWindowProxy::~RoutePinWindowProxy()
2255 ARDOUR::SessionHandlePtr*
2256 RoutePinWindowProxy::session_handle ()
2258 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2259 if (aw) { return aw; }
2264 RoutePinWindowProxy::get (bool create)
2266 boost::shared_ptr<Route> r = _route.lock ();
2275 _window = new PluginPinDialog (r);
2276 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2278 aw->set_session (_session);
2280 _window->show_all ();
2286 RoutePinWindowProxy::route_going_away ()
2290 WM::Manager::instance().remove (this);
2291 going_away_connection.disconnect();
2295 RouteUI::maybe_add_route_print_mgr ()
2297 if (_route->pinmgr_proxy ()) {
2300 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2301 string_compose ("RPM-%1", _route->id()), _route);
2302 wp->set_session (_session);
2304 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2306 wp->set_state (*ui_xml, 0);
2310 void* existing_ui = _route->pinmgr_proxy ();
2312 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2315 _route->set_pingmgr_proxy (wp);
2317 WM::Manager::instance().register_window (wp);
2321 RouteUI::manage_pins ()
2323 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2331 RouteUI::fan_out (bool to_busses, bool group)
2333 DisplaySuspender ds;
2334 boost::shared_ptr<ARDOUR::Route> route = _route;
2335 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2338 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2339 if (route->n_outputs ().n_audio () != n_outputs) {
2340 MessageDialog msg (string_compose (
2341 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2342 n_outputs, route->n_outputs ().n_audio ()));
2347 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2349 /* count busses and channels/bus */
2350 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2351 std::map<std::string, uint32_t> busnames;
2352 for (uint32_t p = 0; p < n_outputs; ++p) {
2353 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2354 std::string bn = BUSNAME;
2358 if (busnames.size () < 2) {
2359 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2364 uint32_t outputs = 2;
2365 if (_session->master_out ()) {
2366 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2369 route->output ()->disconnect (this);
2370 route->panner_shell ()->set_bypassed (true);
2373 for (uint32_t p = 0; p < n_outputs; ++p) {
2374 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2375 std::string bn = BUSNAME;
2376 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2379 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2383 list<boost::shared_ptr<AudioTrack> > tl =
2384 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2388 boost::shared_ptr<ControlList> cl (new ControlList);
2389 cl->push_back (r->monitoring_control ());
2390 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2392 r->input ()->disconnect (this);
2394 to_group.push_back (r);
2395 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2400 RouteGroup* rg = NULL;
2401 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2402 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2403 if ((*i)->name () == pi->name ()) {
2409 rg = new RouteGroup (*_session, pi->name ());
2410 _session->add_route_group (rg);
2411 rg->set_gain (false);
2414 GroupTabs::set_group_color (rg, route->presentation_info().color());
2415 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2422 RouteUI::mark_hidden (bool yn)
2424 if (yn != _route->presentation_info().hidden()) {
2425 _route->presentation_info().set_hidden (yn);
2426 return true; // things changed
2431 boost::shared_ptr<Stripable>
2432 RouteUI::stripable () const