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.
20 #include <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/stop_signal.h>
22 #include <gtkmm2ext/choice.h>
23 #include <gtkmm2ext/doi.h>
24 #include <gtkmm2ext/bindable_button.h>
25 #include <gtkmm2ext/barcontroller.h>
26 #include <gtkmm2ext/gtk_ui.h>
28 #include "ardour/route_group.h"
29 #include "ardour/dB.h"
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/shiva.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour_ui.h"
42 #include "gui_thread.h"
43 #include "ardour_dialog.h"
44 #include "latency_gui.h"
45 #include "mixer_strip.h"
46 #include "automation_time_axis.h"
47 #include "route_time_axis.h"
49 #include "ardour/route.h"
50 #include "ardour/event_type_map.h"
51 #include "ardour/session.h"
52 #include "ardour/audioengine.h"
53 #include "ardour/audio_track.h"
54 #include "ardour/audio_diskstream.h"
55 #include "ardour/midi_track.h"
56 #include "ardour/midi_diskstream.h"
57 #include "ardour/template_utils.h"
58 #include "ardour/filename_extensions.h"
59 #include "ardour/directory_names.h"
60 #include "ardour/profile.h"
65 using namespace Gtkmm2ext;
66 using namespace ARDOUR;
69 RouteUI::RouteUI (ARDOUR::Session& sess)
75 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess)
84 /* derived classes should emit GoingAway so that they receive the signal
85 when the object is still a legal derived instance.
101 pre_fader_mute_check = 0;
102 post_fader_mute_check = 0;
103 listen_mute_check = 0;
105 ignore_toggle = false;
106 wait_for_release = false;
107 route_active_menu_item = 0;
108 polarity_menu_item = 0;
109 denormal_menu_item = 0;
110 multiple_mute_change = false;
111 multiple_solo_change = false;
113 mute_button = manage (new BindableToggleButton ());
114 mute_button->set_self_managed (true);
115 mute_button->set_name ("MuteButton");
116 mute_button->add (mute_button_label);
117 mute_button_label.show ();
118 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
120 solo_button = manage (new BindableToggleButton ());
121 solo_button->set_self_managed (true);
122 solo_button->set_name ("SoloButton");
123 solo_button->add (solo_button_label);
124 solo_button_label.show ();
125 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
126 solo_button->set_no_show_all (true);
128 rec_enable_button = manage (new BindableToggleButton ());
129 rec_enable_button->set_name ("RecordEnableButton");
130 rec_enable_button->set_self_managed (true);
131 rec_enable_button->add (rec_enable_button_label);
132 rec_enable_button_label.show ();
133 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
135 show_sends_button = manage (new BindableToggleButton (""));
136 show_sends_button->set_name ("SendAlert");
137 show_sends_button->set_self_managed (true);
138 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
140 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
141 _session.TransportStateChange.connect (mem_fun (*this, &RouteUI::check_rec_enable_sensitivity));
143 Config->ParameterChanged.connect (mem_fun (*this, &RouteUI::parameter_changed));
149 //Remove route connections associated with us.
150 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
154 connections.clear ();
163 /* do not delete the node - its owned by the route */
167 route_active_menu_item = 0;
168 polarity_menu_item = 0;
169 denormal_menu_item = 0;
173 RouteUI::set_route (boost::shared_ptr<Route> rp)
179 if (set_color_from_route()) {
180 set_color (unique_random_color());
183 /* no, there is no memory leak here. This object cleans itself (and other stuff)
184 up when the route is destroyed.
188 new PairedShiva<Route,RouteUI> (*_route, *this);
191 mute_button->set_controllable (_route->mute_control());
192 solo_button->set_controllable (_route->solo_control());
194 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
195 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
196 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
197 connections.push_back (_route->listen_changed.connect (mem_fun(*this, &RouteUI::listen_changed)));
198 connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
200 if (_session.writable() && is_track()) {
201 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
203 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
204 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
206 rec_enable_button->show();
207 rec_enable_button->set_controllable (t->rec_enable_control());
209 update_rec_display ();
212 mute_button->unset_flags (Gtk::CAN_FOCUS);
213 solo_button->unset_flags (Gtk::CAN_FOCUS);
217 if (_route->is_control()) {
218 solo_button->hide ();
223 /* map the current state */
232 RouteUI::mute_press(GdkEventButton* ev)
234 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
237 multiple_mute_change = false;
238 if (!ignore_toggle) {
240 if (Keyboard::is_context_menu_event (ev)) {
246 mute_menu->popup(0,ev->time);
250 if (Keyboard::is_button2_event (ev)) {
251 // Primary-button2 click is the midi binding click
252 // button2-click is "momentary"
254 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
255 wait_for_release = true;
261 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
263 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
266 /* Primary-Tertiary-click applies change to all routes */
268 _session.begin_reversible_command (_("mute change"));
269 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
270 _session.set_mute (!_route->muted());
272 _session.add_command(cmd);
273 _session.commit_reversible_command ();
274 multiple_mute_change = true;
277 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
280 /* Primary-button1 applies change to the mix group.
281 NOTE: Primary-button2 is MIDI learn.
284 if (ev->button == 1) {
285 set_route_group_mute (_route, !_route->muted());
292 /* plain click applies change to this route */
293 if (wait_for_release) {
294 _route->set_mute (!_route->muted(), this);
296 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
309 RouteUI::mute_release(GdkEventButton*)
311 if (!ignore_toggle) {
312 if (wait_for_release){
313 wait_for_release = false;
314 if (multiple_mute_change) {
315 multiple_mute_change = false;
317 // because the press was the last undoable thing we did
320 _route->set_mute (!_route->muted(), this);
328 RouteUI::post_solo_cleanup (SessionEvent* ev, bool was_not_latched)
330 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_solo_cleanup), ev, was_not_latched));
334 if (was_not_latched) {
335 Config->set_solo_latched (false);
340 RouteUI::solo_press(GdkEventButton* ev)
342 /* ignore double/triple clicks */
344 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
348 if (Config->get_solo_control_is_listen_control()) {
350 _route->set_listen (!_route->listening(), this);
354 multiple_solo_change = false;
355 if (!ignore_toggle) {
357 if (Keyboard::is_context_menu_event (ev)) {
359 if (solo_menu == 0) {
363 solo_menu->popup (1, ev->time);
367 if (Keyboard::is_button2_event (ev)) {
369 // Primary-button2 click is the midi binding click
370 // button2-click is "momentary"
372 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
373 wait_for_release = true;
379 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
381 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
383 /* Primary-Tertiary-click applies change to all routes */
384 bool was_not_latched = false;
386 if (!Config->get_solo_latched ()) {
387 was_not_latched = true;
389 XXX it makes no sense to solo all tracks if we're
390 not in latched mode, but doing nothing feels like a bug,
393 Config->set_solo_latched (true);
396 SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
397 ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_solo), _session.get_routes(), !_route->soloed());
398 ev->rt_return = bind (sigc::mem_fun (*this, &RouteUI::post_solo_cleanup), was_not_latched);
400 _session.queue_event (ev);
402 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
404 // Primary-Secondary-click: exclusively solo this track, not a toggle */
406 //boost::shared_ptr<RouteList> rl (new RouteList);
407 //rl->push_back (route());
409 //SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
410 // ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_just_one_solo), rl, true);
411 //ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
413 //_session.queue_event (ev);
415 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
417 // shift-click: toggle solo isolated status
419 _route->set_solo_isolated (!_route->solo_isolated(), this);
420 wait_for_release = false;
422 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
425 /* Primary-button1: solo mix group.
426 NOTE: Primary-button2 is MIDI learn.
429 if (ev->button == 1) {
430 queue_route_group_op (RouteGroup::Solo, &Session::set_all_solo, !_route->soloed());
437 /* click: solo this route */
439 boost::shared_ptr<RouteList> rl (new RouteList);
440 rl->push_back (route());
442 SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
443 ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_solo), rl, !rec_enable_button->get_active());
444 ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
446 _session.queue_event (ev);
457 RouteUI::solo_release(GdkEventButton*)
459 if (!ignore_toggle) {
460 if (wait_for_release) {
461 wait_for_release = false;
462 if (multiple_solo_change) {
463 multiple_solo_change = false;
465 // because the press was the last undoable thing we did
468 // we don't use "undo the last op"
469 // here because its expensive for the GUI
470 _route->set_solo (!_route->soloed(), this);
479 RouteUI::post_rtop_cleanup (SessionEvent* ev)
481 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_rtop_cleanup), ev));
486 RouteUI::post_group_rtop_cleanup (SessionEvent* ev, RouteGroup* rg, RouteGroup::Property prop)
488 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_group_rtop_cleanup), ev, rg, prop));
490 rg->set_property (prop, false);
494 RouteUI::queue_route_group_op (RouteGroup::Property prop, void (Session::*session_method)(boost::shared_ptr<RouteList>, bool), bool yn)
496 RouteGroup* rg = _route->route_group();
497 bool prop_was_active;
500 prop_was_active = rg->active_property (prop);
501 rg->set_property (prop, true);
503 prop_was_active = false;
506 /* we will queue the op for just this route, but because its route group now has the relevant property marked active,
507 the operation will apply to the whole group (if there is a group)
510 boost::shared_ptr<RouteList> rl (new RouteList);
511 rl->push_back (route());
513 SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
514 ev->rt_slot = bind (sigc::mem_fun (_session, session_method), rl, yn);
515 if (rg && !prop_was_active) {
516 ev->rt_return = bind (sigc::mem_fun (*this, &RouteUI::post_group_rtop_cleanup), rg, prop);
518 ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
521 _session.queue_event (ev);
525 RouteUI::rec_enable_press(GdkEventButton* ev)
527 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
531 if (!_session.engine().connected()) {
532 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
537 if (!ignore_toggle && is_track() && rec_enable_button) {
539 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
541 // do nothing on midi bind event
544 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
547 _session.set_record_enable (_session.get_route(), !rec_enable_button->get_active(), sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup));
550 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
552 /* Primary-button1 applies change to the route group (even if it is not active)
553 NOTE: Primary-button2 is MIDI learn.
556 if (ev->button == 1 && _route->route_group()) {
557 _session.set_record_enable (_route->route_group(), !rec_enable_button->get_active(),
558 queue_route_group_op (RouteGroup::RecEnable, &Session::set_record_enable,
562 } else if (Keyboard::is_context_menu_event (ev)) {
564 /* do this on release */
569 boost::shared_ptr<RouteList> rl (new RouteList);
570 rl->push_back (route());
571 _session.set_record_enable (rl, !rec_enable_button->get_active(), sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup));
580 RouteUI::rec_enable_release (GdkEventButton*)
586 RouteUI::build_sends_menu ()
588 using namespace Menu_Helpers;
590 sends_menu = new Menu;
591 sends_menu->set_name ("ArdourContextMenu");
592 MenuList& items = sends_menu->items();
594 items.push_back (MenuElem(_("Assign all tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_sends), PreFader)));
595 items.push_back (MenuElem(_("Assign all tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_sends), PostFader)));
596 items.push_back (MenuElem(_("Assign selected tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PreFader)));
597 items.push_back (MenuElem(_("Assign selected tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PostFader)));
598 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
599 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
600 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
605 RouteUI::create_sends (Placement p)
607 _session.globally_add_internal_sends (_route, p);
611 RouteUI::create_selected_sends (Placement p)
613 boost::shared_ptr<RouteList> rlist (new RouteList);
614 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
616 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
617 RouteTimeAxisView* rtv;
619 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
620 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
621 if (boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
622 rlist->push_back (rui->route());
628 _session.add_internal_sends (_route, p, rlist);
632 RouteUI::set_sends_gain_from_track ()
634 _session.globally_set_send_gains_from_track (_route);
638 RouteUI::set_sends_gain_to_zero ()
640 _session.globally_set_send_gains_to_zero (_route);
644 RouteUI::set_sends_gain_to_unity ()
646 _session.globally_set_send_gains_to_unity (_route);
650 RouteUI::show_sends_press(GdkEventButton* ev)
652 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
656 if (!ignore_toggle && !is_track() && show_sends_button) {
658 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
660 // do nothing on midi bind event
663 } else if (Keyboard::is_context_menu_event (ev)) {
665 if (sends_menu == 0) {
669 sends_menu->popup (0, ev->time);
673 /* change button state */
675 show_sends_button->set_active (!show_sends_button->get_active());
679 if (show_sends_button->get_active()) {
680 /* show sends to this bus */
681 MixerStrip::SwitchIO (_route);
682 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
684 /* everybody back to normal */
685 send_blink_connection.disconnect ();
686 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
696 RouteUI::show_sends_release (GdkEventButton*)
702 RouteUI::send_blink (bool onoff)
704 if (!show_sends_button) {
709 show_sends_button->set_state (STATE_ACTIVE);
711 show_sends_button->set_state (STATE_NORMAL);
716 RouteUI::solo_changed(void* /*src*/)
718 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
723 RouteUI::listen_changed(void* /*src*/)
725 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
729 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
731 if (Config->get_solo_control_is_listen_control()) {
733 if (r->listening()) {
741 if (r->solo_isolated()) {
743 } else if (r->soloed()) {
754 RouteUI::update_solo_display ()
758 if (Config->get_solo_control_is_listen_control()) {
760 if (solo_button->get_active() != (x = _route->listening())) {
761 ignore_toggle = true;
762 solo_button->set_active(x);
763 ignore_toggle = false;
768 if (solo_button->get_active() != (x = _route->soloed())) {
769 ignore_toggle = true;
770 solo_button->set_active (x);
771 ignore_toggle = false;
776 solo_button->set_visual_state (solo_visual_state (_route));
780 RouteUI::solo_changed_so_update_mute ()
782 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
786 RouteUI::mute_changed(void* /*src*/)
788 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
792 RouteUI::mute_visual_state (Session& s, boost::shared_ptr<Route> r)
794 if (Config->get_show_solo_mutes()) {
799 } else if (s.soloing() && !r->soloed() && !r->solo_isolated()) {
800 /* mute-because-not-soloed */
822 RouteUI::update_mute_display ()
824 bool model = _route->muted();
825 bool view = mute_button->get_active();
827 /* first make sure the button's "depressed" visual
832 ignore_toggle = true;
833 mute_button->set_active (model);
834 ignore_toggle = false;
837 mute_button->set_visual_state (mute_visual_state (_session, _route));
841 RouteUI::route_rec_enable_changed ()
843 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
847 RouteUI::session_rec_enable_changed ()
849 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
853 RouteUI::update_rec_display ()
855 bool model = _route->record_enabled();
856 bool view = rec_enable_button->get_active();
858 /* first make sure the button's "depressed" visual
863 ignore_toggle = true;
864 rec_enable_button->set_active (model);
865 ignore_toggle = false;
868 /* now make sure its color state is correct */
872 switch (_session.record_status ()) {
873 case Session::Recording:
874 rec_enable_button->set_visual_state (1);
877 case Session::Disabled:
878 case Session::Enabled:
879 rec_enable_button->set_visual_state (2);
885 rec_enable_button->set_visual_state (0);
888 check_rec_enable_sensitivity ();
892 RouteUI::build_solo_menu (void)
894 using namespace Menu_Helpers;
896 solo_menu = new Menu;
897 solo_menu->set_name ("ArdourContextMenu");
898 MenuList& items = solo_menu->items();
899 CheckMenuItem* check;
901 check = new CheckMenuItem(_("Solo Isolate"));
902 check->set_active (_route->solo_isolated());
903 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
904 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
905 items.push_back (CheckMenuElem(*check));
908 check = new CheckMenuItem(_("Solo Safe"));
909 check->set_active (_route->solo_safe());
910 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
911 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
912 items.push_back (CheckMenuElem(*check));
915 //items.push_back (SeparatorElem());
916 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
921 RouteUI::build_mute_menu(void)
923 using namespace Menu_Helpers;
925 mute_menu = new Menu;
926 mute_menu->set_name ("ArdourContextMenu");
928 MenuList& items = mute_menu->items();
930 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
931 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
932 pre_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
933 items.push_back (CheckMenuElem(*pre_fader_mute_check));
934 pre_fader_mute_check->show_all();
936 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
937 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
938 post_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
939 items.push_back (CheckMenuElem(*post_fader_mute_check));
940 post_fader_mute_check->show_all();
942 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
943 init_mute_menu(MuteMaster::Listen, listen_mute_check);
944 listen_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
945 items.push_back (CheckMenuElem(*listen_mute_check));
946 listen_mute_check->show_all();
948 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
949 init_mute_menu(MuteMaster::Main, main_mute_check);
950 main_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
951 items.push_back (CheckMenuElem(*main_mute_check));
952 main_mute_check->show_all();
954 //items.push_back (SeparatorElem());
955 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
957 _route->mute_points_changed.connect (mem_fun (*this, &RouteUI::muting_change));
961 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
963 check->set_active (_route->mute_points() & mp);
967 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
969 if (check->get_active()) {
970 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
972 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
977 RouteUI::muting_change ()
979 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::muting_change));
982 MuteMaster::MutePoint current = _route->mute_points ();
984 yn = (current & MuteMaster::PreFader);
986 if (pre_fader_mute_check->get_active() != yn) {
987 pre_fader_mute_check->set_active (yn);
990 yn = (current & MuteMaster::PostFader);
992 if (post_fader_mute_check->get_active() != yn) {
993 post_fader_mute_check->set_active (yn);
996 yn = (current & MuteMaster::Listen);
998 if (listen_mute_check->get_active() != yn) {
999 listen_mute_check->set_active (yn);
1002 yn = (current & MuteMaster::Main);
1004 if (main_mute_check->get_active() != yn) {
1005 main_mute_check->set_active (yn);
1010 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1012 _route->set_solo_isolated (check->get_active(), this);
1016 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1018 _route->set_solo_safe (check->get_active(), this);
1022 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
1024 RouteGroup* route_group;
1026 if((route_group = route->route_group()) != 0){
1027 _session.begin_reversible_command (_("mix group solo change"));
1028 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
1029 route_group->apply(&Route::set_solo, yn, this);
1031 _session.add_command (cmd);
1032 _session.commit_reversible_command ();
1034 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
1039 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
1041 _session.begin_reversible_command (name);
1042 XMLNode &before = _route->get_state();
1043 bind(mem_fun(*_route, func), yn, arg)();
1044 XMLNode &after = _route->get_state();
1045 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
1046 _session.commit_reversible_command ();
1050 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
1052 _session.begin_reversible_command (name);
1053 XMLNode &before = track()->get_state();
1054 bind (mem_fun (*track(), func), yn, arg)();
1055 XMLNode &after = track()->get_state();
1056 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
1057 _session.commit_reversible_command ();
1061 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
1063 RouteGroup* route_group;
1065 if((route_group = route->route_group()) != 0){
1066 _session.begin_reversible_command (_("mix group mute change"));
1067 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
1068 route_group->apply(&Route::set_mute, yn, this);
1070 _session.add_command(cmd);
1071 _session.commit_reversible_command ();
1073 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
1078 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
1080 RouteGroup* route_group;
1082 if((route_group = route->route_group()) != 0){
1083 _session.begin_reversible_command (_("mix group rec-enable change"));
1084 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
1085 route_group->apply (&Route::set_record_enable, yn, this);
1087 _session.add_command(cmd);
1088 _session.commit_reversible_command ();
1090 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
1096 RouteUI::choose_color()
1101 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
1111 RouteUI::set_color (const Gdk::Color & c)
1118 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1119 xml_node->add_property ("color", buf);
1121 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1126 RouteUI::ensure_xml_node ()
1128 if (xml_node == 0) {
1129 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1130 xml_node = new XMLNode ("GUI");
1131 _route->add_extra_xml (*xml_node);
1137 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1141 XMLNodeList kids = xml_node->children();
1142 XMLNodeConstIterator iter;
1144 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1146 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1147 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1148 XMLProperty* type = (*iter)->property("automation-id");
1149 if (type && type->value() == sym)
1154 // Didn't find it, make a new one
1155 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1156 child->add_property("automation-id", sym);
1157 xml_node->add_child_nocopy (*child);
1163 RouteUI::set_color_from_route ()
1167 RouteUI::ensure_xml_node ();
1169 if ((prop = xml_node->property ("color")) != 0) {
1171 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1173 _color.set_green(g);
1181 RouteUI::remove_this_route ()
1183 vector<string> choices;
1187 prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n(cannot be undone)"), _route->name());
1189 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1192 choices.push_back (_("No, do nothing."));
1193 choices.push_back (_("Yes, remove it."));
1195 Choice prompter (prompt, choices);
1197 if (prompter.run () == 1) {
1198 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1203 RouteUI::idle_remove_this_route (RouteUI *rui)
1205 rui->_session.remove_route (rui->_route);
1210 RouteUI::route_rename ()
1212 ArdourPrompter name_prompter (true);
1214 name_prompter.set_prompt (_("New Name: "));
1215 name_prompter.set_initial_text (_route->name());
1216 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1217 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1218 name_prompter.show_all ();
1220 switch (name_prompter.run ()) {
1222 case Gtk::RESPONSE_ACCEPT:
1223 name_prompter.get_result (result);
1224 if (result.length()) {
1225 _route->set_name (result);
1235 RouteUI::name_changed ()
1237 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1239 name_label.set_text (_route->name());
1243 RouteUI::toggle_route_active ()
1247 if (route_active_menu_item) {
1248 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1249 _route->set_active (!yn);
1255 RouteUI::route_active_changed ()
1257 if (route_active_menu_item) {
1258 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1263 RouteUI::toggle_polarity ()
1265 if (polarity_menu_item) {
1269 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1271 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1272 _route->set_phase_invert (x);
1274 name_label.set_text (X_("Ø ") + name_label.get_text());
1276 name_label.set_text (_route->name());
1283 RouteUI::polarity_changed ()
1285 if (_route->phase_invert()) {
1286 name_label.set_text (X_("Ø ") + name_label.get_text());
1288 name_label.set_text (_route->name());
1293 RouteUI::toggle_denormal_protection ()
1295 if (denormal_menu_item) {
1299 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1301 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1302 _route->set_denormal_protection (x);
1308 RouteUI::denormal_protection_changed ()
1310 if (denormal_menu_item) {
1311 denormal_menu_item->set_active (_route->denormal_protection());
1316 RouteUI::solo_isolated_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1318 bool yn = _route->solo_isolated ();
1320 if (check->get_active() != yn) {
1321 check->set_active (yn);
1327 RouteUI::solo_safe_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1329 bool yn = _route->solo_safe ();
1331 if (check->get_active() != yn) {
1332 check->set_active (yn);
1337 RouteUI::disconnect_input ()
1339 _route->input()->disconnect (this);
1343 RouteUI::disconnect_output ()
1345 _route->output()->disconnect (this);
1349 RouteUI::is_track () const
1351 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1354 boost::shared_ptr<Track>
1355 RouteUI::track() const
1357 return boost::dynamic_pointer_cast<Track>(_route);
1361 RouteUI::is_audio_track () const
1363 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1366 boost::shared_ptr<AudioTrack>
1367 RouteUI::audio_track() const
1369 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1373 RouteUI::is_midi_track () const
1375 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1378 boost::shared_ptr<MidiTrack>
1379 RouteUI::midi_track() const
1381 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1384 boost::shared_ptr<Diskstream>
1385 RouteUI::get_diskstream () const
1387 boost::shared_ptr<Track> t;
1389 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1390 return t->diskstream();
1392 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1397 RouteUI::name() const
1399 return _route->name();
1403 RouteUI::map_frozen ()
1405 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1407 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1410 switch (at->freeze_state()) {
1411 case AudioTrack::Frozen:
1412 rec_enable_button->set_sensitive (false);
1415 rec_enable_button->set_sensitive (true);
1422 RouteUI::adjust_latency ()
1424 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1428 RouteUI::save_as_template ()
1431 Glib::ustring safe_name;
1434 path = ARDOUR::user_route_template_directory ();
1436 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1437 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1441 Prompter p (true); // modal
1443 p.set_prompt (_("Template name:"));
1445 case RESPONSE_ACCEPT:
1452 p.get_result (name, true);
1454 safe_name = legalize_for_path (name);
1455 safe_name += template_suffix;
1459 _route->save_as_template (path.to_string(), name);
1463 RouteUI::check_rec_enable_sensitivity ()
1465 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1466 rec_enable_button->set_sensitive (false);
1468 rec_enable_button->set_sensitive (true);
1473 RouteUI::parameter_changed (string const & p)
1475 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1477 if (p == "disable-disarm-during-roll") {
1478 check_rec_enable_sensitivity ();
1479 } else if (p == "solo-control-is-listen-control") {
1480 set_button_names ();
1481 } else if (p == "listen-position") {
1482 set_button_names ();
1487 RouteUI::step_gain_up ()
1489 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1493 RouteUI::page_gain_up ()
1495 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1499 RouteUI::step_gain_down ()
1501 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1505 RouteUI::page_gain_down ()
1507 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1511 RouteUI::open_remote_control_id_dialog ()
1513 ArdourDialog dialog (_("Remote Control ID"));
1515 uint32_t const limit = _session.ntracks() + _session.nbusses () + 4;
1517 HBox* hbox = manage (new HBox);
1518 hbox->set_spacing (6);
1519 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1520 SpinButton* spin = manage (new SpinButton);
1521 spin->set_digits (0);
1522 spin->set_increments (1, 10);
1523 spin->set_range (0, limit);
1524 spin->set_value (_route->remote_control_id());
1525 hbox->pack_start (*spin);
1526 dialog.get_vbox()->pack_start (*hbox);
1528 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1529 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1532 int const r = dialog.run ();
1534 if (r == RESPONSE_ACCEPT) {
1535 _route->set_remote_control_id (spin->get_value_as_int ());