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))) {
265 /* Primary-Tertiary-click applies change to all routes */
267 _session.begin_reversible_command (_("mute change"));
268 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
269 _session.set_all_mute (!_route->muted());
271 _session.add_command(cmd);
272 _session.commit_reversible_command ();
273 multiple_mute_change = true;
275 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
277 /* Primary-button1 applies change to the mix group.
278 NOTE: Primary-button2 is MIDI learn.
281 if (ev->button == 1) {
282 set_route_group_mute (_route, !_route->muted());
287 /* plain click applies change to this route */
288 if (wait_for_release) {
289 _route->set_mute (!_route->muted(), this);
291 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
303 RouteUI::mute_release(GdkEventButton*)
305 if (!ignore_toggle) {
306 if (wait_for_release){
307 wait_for_release = false;
308 if (multiple_mute_change) {
309 multiple_mute_change = false;
311 // because the press was the last undoable thing we did
314 _route->set_mute (!_route->muted(), this);
322 RouteUI::solo_press(GdkEventButton* ev)
324 /* ignore double/triple clicks */
326 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
330 if (Config->get_solo_control_is_listen_control()) {
332 _route->set_listen (!_route->listening(), this);
336 multiple_solo_change = false;
337 if (!ignore_toggle) {
339 if (Keyboard::is_context_menu_event (ev)) {
341 if (solo_menu == 0) {
345 solo_menu->popup (1, ev->time);
349 if (Keyboard::is_button2_event (ev)) {
351 // Primary-button2 click is the midi binding click
352 // button2-click is "momentary"
354 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
355 wait_for_release = true;
361 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
363 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
365 /* Primary-Tertiary-click applies change to all routes */
366 bool was_not_latched = false;
367 if (!Config->get_solo_latched ()) {
368 was_not_latched = true;
370 XXX it makes no sense to solo all tracks if we're
371 not in latched mode, but doing nothing feels like a bug,
374 Config->set_solo_latched (true);
376 _session.begin_reversible_command (_("solo change"));
377 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
378 _session.set_all_solo (!_route->soloed());
380 _session.add_command (cmd);
381 _session.commit_reversible_command ();
382 multiple_solo_change = true;
383 if (was_not_latched) {
384 Config->set_solo_latched (false);
387 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
389 // Primary-Secondary-click: exclusively solo this track, not a toggle */
391 _session.begin_reversible_command (_("solo change"));
392 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
393 _session.set_all_solo (false);
394 _route->set_solo (true, this);
396 _session.add_command(cmd);
397 _session.commit_reversible_command ();
399 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
401 // shift-click: toggle solo isolated status
403 _route->set_solo_isolated (!_route->solo_isolated(), this);
404 wait_for_release = false;
406 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
408 /* Primary-button1: solo mix group.
409 NOTE: Primary-button2 is MIDI learn.
412 if (ev->button == 1) {
413 set_route_group_solo (_route, !_route->soloed());
418 /* click: solo this route */
419 if (wait_for_release) {
420 _route->set_solo (!_route->soloed(), this);
422 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
434 RouteUI::solo_release(GdkEventButton*)
436 if (!ignore_toggle) {
437 if (wait_for_release) {
438 wait_for_release = false;
439 if (multiple_solo_change) {
440 multiple_solo_change = false;
442 // because the press was the last undoable thing we did
445 // we don't use "undo the last op"
446 // here because its expensive for the GUI
447 _route->set_solo (!_route->soloed(), this);
456 RouteUI::post_rec_cleanup (SessionEvent* ev, UndoTransaction* undo, Session::GlobalRecordEnableStateCommand* cmd)
458 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_rec_cleanup), ev, undo, cmd));
462 check_rec_enable_sensitivity ();
465 undo->add_command(cmd);
467 _session.finish_reversible_command (*undo);
471 RouteUI::rec_enable_press(GdkEventButton* ev)
473 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
477 if (!_session.engine().connected()) {
478 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
483 if (!ignore_toggle && is_track() && rec_enable_button) {
485 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
487 // do nothing on midi bind event
490 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
492 UndoTransaction* undo = _session.start_reversible_command (_("rec-enable change"));
493 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
495 SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
496 ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_all_record_enable), _session.get_routes(), !rec_enable_button->get_active());
497 ev->rt_return = bind (sigc::mem_fun (*this, &RouteUI::post_rec_cleanup), undo, cmd);
499 _session.queue_event (ev);
501 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
503 /* Primary-button1 applies change to the mix group.
504 NOTE: Primary-button2 is MIDI learn.
507 set_route_group_rec_enable (_route, !_route->record_enabled());
509 } else if (Keyboard::is_context_menu_event (ev)) {
511 /* do this on release */
514 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
515 check_rec_enable_sensitivity ();
523 RouteUI::rec_enable_release (GdkEventButton*)
529 RouteUI::build_sends_menu ()
531 using namespace Menu_Helpers;
533 sends_menu = new Menu;
534 sends_menu->set_name ("ArdourContextMenu");
535 MenuList& items = sends_menu->items();
537 items.push_back (MenuElem(_("Assign all tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_sends), PreFader)));
538 items.push_back (MenuElem(_("Assign all tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_sends), PostFader)));
539 items.push_back (MenuElem(_("Assign selected tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PreFader)));
540 items.push_back (MenuElem(_("Assign selected tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PostFader)));
541 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
542 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
543 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
548 RouteUI::create_sends (Placement p)
550 _session.globally_add_internal_sends (_route, p);
554 RouteUI::create_selected_sends (Placement p)
556 boost::shared_ptr<RouteList> rlist (new RouteList);
557 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
559 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
560 RouteTimeAxisView* rtv;
562 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
563 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
564 if (boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
565 rlist->push_back (rui->route());
571 _session.add_internal_sends (_route, p, rlist);
575 RouteUI::set_sends_gain_from_track ()
577 _session.globally_set_send_gains_from_track (_route);
581 RouteUI::set_sends_gain_to_zero ()
583 _session.globally_set_send_gains_to_zero (_route);
587 RouteUI::set_sends_gain_to_unity ()
589 _session.globally_set_send_gains_to_unity (_route);
593 RouteUI::show_sends_press(GdkEventButton* ev)
595 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
599 if (!ignore_toggle && !is_track() && show_sends_button) {
601 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
603 // do nothing on midi bind event
606 } else if (Keyboard::is_context_menu_event (ev)) {
608 if (sends_menu == 0) {
612 sends_menu->popup (0, ev->time);
616 /* change button state */
618 show_sends_button->set_active (!show_sends_button->get_active());
622 if (show_sends_button->get_active()) {
623 /* show sends to this bus */
624 MixerStrip::SwitchIO (_route);
625 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
627 /* everybody back to normal */
628 send_blink_connection.disconnect ();
629 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
639 RouteUI::show_sends_release (GdkEventButton*)
645 RouteUI::send_blink (bool onoff)
647 if (!show_sends_button) {
652 show_sends_button->set_state (STATE_ACTIVE);
654 show_sends_button->set_state (STATE_NORMAL);
659 RouteUI::solo_changed(void* /*src*/)
661 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
666 RouteUI::listen_changed(void* /*src*/)
668 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
672 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
674 if (Config->get_solo_control_is_listen_control()) {
676 if (r->listening()) {
684 if (r->solo_isolated()) {
686 } else if (r->soloed()) {
697 RouteUI::update_solo_display ()
701 if (Config->get_solo_control_is_listen_control()) {
703 if (solo_button->get_active() != (x = _route->listening())) {
704 ignore_toggle = true;
705 solo_button->set_active(x);
706 ignore_toggle = false;
711 if (solo_button->get_active() != (x = _route->soloed())) {
712 ignore_toggle = true;
713 solo_button->set_active (x);
714 ignore_toggle = false;
719 solo_button->set_visual_state (solo_visual_state (_route));
723 RouteUI::solo_changed_so_update_mute ()
725 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
729 RouteUI::mute_changed(void* /*src*/)
731 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
735 RouteUI::mute_visual_state (Session& s, boost::shared_ptr<Route> r)
737 if (Config->get_show_solo_mutes()) {
742 } else if (s.soloing() && !r->soloed() && !r->solo_isolated()) {
743 /* mute-because-not-soloed */
765 RouteUI::update_mute_display ()
767 bool model = _route->muted();
768 bool view = mute_button->get_active();
770 /* first make sure the button's "depressed" visual
775 ignore_toggle = true;
776 mute_button->set_active (model);
777 ignore_toggle = false;
780 mute_button->set_visual_state (mute_visual_state (_session, _route));
784 RouteUI::route_rec_enable_changed ()
786 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
790 RouteUI::session_rec_enable_changed ()
792 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
796 RouteUI::update_rec_display ()
798 bool model = _route->record_enabled();
799 bool view = rec_enable_button->get_active();
801 /* first make sure the button's "depressed" visual
806 ignore_toggle = true;
807 rec_enable_button->set_active (model);
808 ignore_toggle = false;
811 /* now make sure its color state is correct */
815 switch (_session.record_status ()) {
816 case Session::Recording:
817 rec_enable_button->set_visual_state (1);
820 case Session::Disabled:
821 case Session::Enabled:
822 rec_enable_button->set_visual_state (2);
828 rec_enable_button->set_visual_state (0);
833 RouteUI::build_solo_menu (void)
835 using namespace Menu_Helpers;
837 solo_menu = new Menu;
838 solo_menu->set_name ("ArdourContextMenu");
839 MenuList& items = solo_menu->items();
840 CheckMenuItem* check;
842 check = new CheckMenuItem(_("Solo Isolate"));
843 check->set_active (_route->solo_isolated());
844 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
845 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
846 items.push_back (CheckMenuElem(*check));
849 check = new CheckMenuItem(_("Solo Safe"));
850 check->set_active (_route->solo_safe());
851 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
852 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
853 items.push_back (CheckMenuElem(*check));
856 //items.push_back (SeparatorElem());
857 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
862 RouteUI::build_mute_menu(void)
864 using namespace Menu_Helpers;
866 mute_menu = new Menu;
867 mute_menu->set_name ("ArdourContextMenu");
869 MenuList& items = mute_menu->items();
871 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
872 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
873 pre_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
874 items.push_back (CheckMenuElem(*pre_fader_mute_check));
875 pre_fader_mute_check->show_all();
877 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
878 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
879 post_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
880 items.push_back (CheckMenuElem(*post_fader_mute_check));
881 post_fader_mute_check->show_all();
883 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
884 init_mute_menu(MuteMaster::Listen, listen_mute_check);
885 listen_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
886 items.push_back (CheckMenuElem(*listen_mute_check));
887 listen_mute_check->show_all();
889 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
890 init_mute_menu(MuteMaster::Main, main_mute_check);
891 main_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
892 items.push_back (CheckMenuElem(*main_mute_check));
893 main_mute_check->show_all();
895 //items.push_back (SeparatorElem());
896 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
898 _route->mute_points_changed.connect (mem_fun (*this, &RouteUI::muting_change));
902 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
904 check->set_active (_route->mute_points() & mp);
908 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
910 if (check->get_active()) {
911 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
913 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
918 RouteUI::muting_change ()
920 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::muting_change));
923 MuteMaster::MutePoint current = _route->mute_points ();
925 yn = (current & MuteMaster::PreFader);
927 if (pre_fader_mute_check->get_active() != yn) {
928 pre_fader_mute_check->set_active (yn);
931 yn = (current & MuteMaster::PostFader);
933 if (post_fader_mute_check->get_active() != yn) {
934 post_fader_mute_check->set_active (yn);
937 yn = (current & MuteMaster::Listen);
939 if (listen_mute_check->get_active() != yn) {
940 listen_mute_check->set_active (yn);
943 yn = (current & MuteMaster::Main);
945 if (main_mute_check->get_active() != yn) {
946 main_mute_check->set_active (yn);
951 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
953 _route->set_solo_isolated (check->get_active(), this);
957 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
959 _route->set_solo_safe (check->get_active(), this);
963 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
965 RouteGroup* route_group;
967 if((route_group = route->route_group()) != 0){
968 _session.begin_reversible_command (_("mix group solo change"));
969 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
970 route_group->apply(&Route::set_solo, yn, this);
972 _session.add_command (cmd);
973 _session.commit_reversible_command ();
975 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
980 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
982 _session.begin_reversible_command (name);
983 XMLNode &before = _route->get_state();
984 bind(mem_fun(*_route, func), yn, arg)();
985 XMLNode &after = _route->get_state();
986 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
987 _session.commit_reversible_command ();
991 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
993 _session.begin_reversible_command (name);
994 XMLNode &before = track()->get_state();
995 bind (mem_fun (*track(), func), yn, arg)();
996 XMLNode &after = track()->get_state();
997 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
998 _session.commit_reversible_command ();
1002 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
1004 RouteGroup* route_group;
1006 if((route_group = route->route_group()) != 0){
1007 _session.begin_reversible_command (_("mix group mute change"));
1008 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
1009 route_group->apply(&Route::set_mute, yn, this);
1011 _session.add_command(cmd);
1012 _session.commit_reversible_command ();
1014 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
1019 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
1021 RouteGroup* route_group;
1023 if((route_group = route->route_group()) != 0){
1024 _session.begin_reversible_command (_("mix group rec-enable change"));
1025 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
1026 route_group->apply (&Route::set_record_enable, yn, this);
1028 _session.add_command(cmd);
1029 _session.commit_reversible_command ();
1031 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
1037 RouteUI::choose_color()
1042 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
1052 RouteUI::set_color (const Gdk::Color & c)
1059 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1060 xml_node->add_property ("color", buf);
1062 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1067 RouteUI::ensure_xml_node ()
1069 if (xml_node == 0) {
1070 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1071 xml_node = new XMLNode ("GUI");
1072 _route->add_extra_xml (*xml_node);
1078 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1082 XMLNodeList kids = xml_node->children();
1083 XMLNodeConstIterator iter;
1085 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1087 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1088 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1089 XMLProperty* type = (*iter)->property("automation-id");
1090 if (type && type->value() == sym)
1095 // Didn't find it, make a new one
1096 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1097 child->add_property("automation-id", sym);
1098 xml_node->add_child_nocopy (*child);
1104 RouteUI::set_color_from_route ()
1108 RouteUI::ensure_xml_node ();
1110 if ((prop = xml_node->property ("color")) != 0) {
1112 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1114 _color.set_green(g);
1122 RouteUI::remove_this_route ()
1124 vector<string> choices;
1128 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());
1130 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1133 choices.push_back (_("No, do nothing."));
1134 choices.push_back (_("Yes, remove it."));
1136 Choice prompter (prompt, choices);
1138 if (prompter.run () == 1) {
1139 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1144 RouteUI::idle_remove_this_route (RouteUI *rui)
1146 rui->_session.remove_route (rui->_route);
1151 RouteUI::route_rename ()
1153 ArdourPrompter name_prompter (true);
1155 name_prompter.set_prompt (_("New Name: "));
1156 name_prompter.set_initial_text (_route->name());
1157 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1158 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1159 name_prompter.show_all ();
1161 switch (name_prompter.run ()) {
1163 case Gtk::RESPONSE_ACCEPT:
1164 name_prompter.get_result (result);
1165 if (result.length()) {
1166 _route->set_name (result);
1176 RouteUI::name_changed ()
1178 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1180 name_label.set_text (_route->name());
1184 RouteUI::toggle_route_active ()
1188 if (route_active_menu_item) {
1189 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1190 _route->set_active (!yn);
1196 RouteUI::route_active_changed ()
1198 if (route_active_menu_item) {
1199 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1204 RouteUI::toggle_polarity ()
1206 if (polarity_menu_item) {
1210 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1212 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1213 _route->set_phase_invert (x);
1215 name_label.set_text (X_("Ø ") + name_label.get_text());
1217 name_label.set_text (_route->name());
1224 RouteUI::polarity_changed ()
1226 if (_route->phase_invert()) {
1227 name_label.set_text (X_("Ø ") + name_label.get_text());
1229 name_label.set_text (_route->name());
1234 RouteUI::toggle_denormal_protection ()
1236 if (denormal_menu_item) {
1240 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1242 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1243 _route->set_denormal_protection (x);
1249 RouteUI::denormal_protection_changed ()
1251 if (denormal_menu_item) {
1252 denormal_menu_item->set_active (_route->denormal_protection());
1257 RouteUI::solo_isolated_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1259 bool yn = _route->solo_isolated ();
1261 if (check->get_active() != yn) {
1262 check->set_active (yn);
1268 RouteUI::solo_safe_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1270 bool yn = _route->solo_safe ();
1272 if (check->get_active() != yn) {
1273 check->set_active (yn);
1278 RouteUI::disconnect_input ()
1280 _route->input()->disconnect (this);
1284 RouteUI::disconnect_output ()
1286 _route->output()->disconnect (this);
1290 RouteUI::is_track () const
1292 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1295 boost::shared_ptr<Track>
1296 RouteUI::track() const
1298 return boost::dynamic_pointer_cast<Track>(_route);
1302 RouteUI::is_audio_track () const
1304 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1307 boost::shared_ptr<AudioTrack>
1308 RouteUI::audio_track() const
1310 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1314 RouteUI::is_midi_track () const
1316 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1319 boost::shared_ptr<MidiTrack>
1320 RouteUI::midi_track() const
1322 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1325 boost::shared_ptr<Diskstream>
1326 RouteUI::get_diskstream () const
1328 boost::shared_ptr<Track> t;
1330 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1331 return t->diskstream();
1333 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1338 RouteUI::name() const
1340 return _route->name();
1344 RouteUI::map_frozen ()
1346 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1348 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1351 switch (at->freeze_state()) {
1352 case AudioTrack::Frozen:
1353 rec_enable_button->set_sensitive (false);
1356 rec_enable_button->set_sensitive (true);
1363 RouteUI::adjust_latency ()
1365 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1369 RouteUI::save_as_template ()
1372 Glib::ustring safe_name;
1375 path = ARDOUR::user_route_template_directory ();
1377 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1378 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1382 Prompter p (true); // modal
1384 p.set_prompt (_("Template name:"));
1386 case RESPONSE_ACCEPT:
1393 p.get_result (name, true);
1395 safe_name = legalize_for_path (name);
1396 safe_name += template_suffix;
1400 _route->save_as_template (path.to_string(), name);
1404 RouteUI::check_rec_enable_sensitivity ()
1406 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1407 rec_enable_button->set_sensitive (false);
1409 rec_enable_button->set_sensitive (true);
1414 RouteUI::parameter_changed (string const & p)
1416 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1418 if (p == "disable-disarm-during-roll") {
1419 check_rec_enable_sensitivity ();
1420 } else if (p == "solo-control-is-listen-control") {
1421 set_button_names ();
1422 } else if (p == "listen-position") {
1423 set_button_names ();
1428 RouteUI::step_gain_up ()
1430 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1434 RouteUI::page_gain_up ()
1436 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1440 RouteUI::step_gain_down ()
1442 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1446 RouteUI::page_gain_down ()
1448 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1452 RouteUI::open_remote_control_id_dialog ()
1454 ArdourDialog dialog (_("Remote Control ID"));
1456 uint32_t const limit = _session.ntracks() + _session.nbusses () + 4;
1458 HBox* hbox = manage (new HBox);
1459 hbox->set_spacing (6);
1460 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1461 SpinButton* spin = manage (new SpinButton);
1462 spin->set_digits (0);
1463 spin->set_increments (1, 10);
1464 spin->set_range (0, limit);
1465 spin->set_value (_route->remote_control_id());
1466 hbox->pack_start (*spin);
1467 dialog.get_vbox()->pack_start (*hbox);
1469 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1470 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1473 int const r = dialog.run ();
1475 if (r == RESPONSE_ACCEPT) {
1476 _route->set_remote_control_id (spin->get_value_as_int ());