From b130dc032ec9f1b962cb5ae8e70980c8b0f3bb05 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 22 Jun 2014 23:16:32 +0200 Subject: [PATCH] Do not allow to de/activate a track while the transport is rolling. roll_delay and latency are only re-calculated when the transport is stopped. de/activating a track is also not RT-safe. Conflicts: gtk2_ardour/mixer_strip.cc gtk2_ardour/route_time_axis.cc --- gtk2_ardour/mixer_strip.cc | 44 +++++ gtk2_ardour/route_time_axis.cc | 313 +++++++++++++++++++++++++++++++-- libs/ardour/route.cc | 4 + 3 files changed, 350 insertions(+), 11 deletions(-) diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 9ae906e887..d62f1cbe27 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -1200,6 +1200,50 @@ MixerStrip::show_passthru_color () reset_strip_style (); } +<<<<<<< HEAD +======= +void +MixerStrip::build_route_ops_menu () +{ + using namespace Menu_Helpers; + route_ops_menu = new Menu; + route_ops_menu->set_name ("ArdourContextMenu"); + + MenuList& items = route_ops_menu->items(); + + items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &MixerStrip::open_comment_editor))); + if (!_route->is_master()) { + items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template))); + } + items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename))); + rename_menu_item = &items.back(); + + items.push_back (SeparatorElem()); + items.push_back (CheckMenuElem (_("Active"))); + Gtk::CheckMenuItem* i = dynamic_cast (&items.back()); + i->set_active (_route->active()); + i->set_sensitive(! _session->transport_rolling()); + i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false)); + + items.push_back (SeparatorElem()); + + items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency))); + + items.push_back (SeparatorElem()); + items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection))); + denormal_menu_item = dynamic_cast (&items.back()); + denormal_menu_item->set_active (_route->denormal_protection()); + + if (!Profile->get_sae()) { + items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog))); + } + + items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Remove"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), false))); +} + +>>>>>>> 14c6dfa... Do not allow to de/activate a track while the transport is rolling. gboolean MixerStrip::name_button_button_press (GdkEventButton* ev) { diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 0edf78e144..c0919e3adc 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -388,18 +388,309 @@ RouteTimeAxisView::build_display_menu () build_size_menu (); items.push_back (MenuElem (_("Height"), *_size_menu)); - AudioTrack* atr = dynamic_cast(route().get() ); - if (! (atr && atr->is_master_track() ) ) { - - items.push_back (SeparatorElem()); - - if (!Profile->get_sae()) { - items.push_back (MenuElem (_("Remove"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true))); - } else { - items.push_front (SeparatorElem()); - items.push_front (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true))); + boost::shared_ptr atr = audio_track (); + + if (!(atr && atr->is_master_track())) { + + items.push_back (SeparatorElem()); + + if (!Profile->get_sae()) { + items.push_back (MenuElem (_("Remove"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true))); + } else { + items.push_front (SeparatorElem()); + items.push_front (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true))); + } } - } + + if (Profile->get_trx()) { + /* no more stuff in the menu for Tracks but retain code for easier merging with Ardour */ + return; + } + + items.push_back (SeparatorElem()); + + if (!Profile->get_sae()) { + items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog))); + items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1); + items.push_back (SeparatorElem()); + } + + // Hook for derived classes to add type specific stuff + append_extra_display_menu_items (); + + if (is_track()) { + + Menu* layers_menu = manage (new Menu); + MenuList &layers_items = layers_menu->items(); + layers_menu->set_name("ArdourContextMenu"); + + RadioMenuItem::Group layers_group; + + /* Find out how many overlaid/stacked tracks we have in the selection */ + + int overlaid = 0; + int stacked = 0; + TrackSelection const & s = _editor.get_selection().tracks; + for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) { + StreamView* v = (*i)->view (); + if (!v) { + continue; + } + + switch (v->layer_display ()) { + case Overlaid: + ++overlaid; + break; + case Stacked: + case Expanded: + ++stacked; + break; + } + } + + /* We're not connecting to signal_toggled() here; in the case where these two items are + set to be in the `inconsistent' state, it seems that one or other will end up active + as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you + select the active one, no toggled signal is emitted so nothing happens. + */ + + _ignore_set_layer_display = true; + + layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid"))); + RadioMenuItem* i = dynamic_cast (&layers_items.back ()); + i->set_active (overlaid != 0 && stacked == 0); + i->set_inconsistent (overlaid != 0 && stacked != 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true)); + + layers_items.push_back (RadioMenuElem (layers_group, _("Stacked"))); + i = dynamic_cast (&layers_items.back ()); + i->set_active (overlaid == 0 && stacked != 0); + i->set_inconsistent (overlaid != 0 && stacked != 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true)); + + _ignore_set_layer_display = false; + + items.push_back (MenuElem (_("Layers"), *layers_menu)); + + if (!Profile->get_sae()) { + + Menu* alignment_menu = manage (new Menu); + MenuList& alignment_items = alignment_menu->items(); + alignment_menu->set_name ("ArdourContextMenu"); + + RadioMenuItem::Group align_group; + + /* Same verbose hacks as for the layering options above */ + + int existing = 0; + int capture = 0; + int automatic = 0; + int styles = 0; + boost::shared_ptr first_track; + + TrackSelection const & s = _editor.get_selection().tracks; + for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) { + RouteTimeAxisView* r = dynamic_cast (*i); + if (!r || !r->is_track ()) { + continue; + } + + if (!first_track) { + first_track = r->track(); + } + + switch (r->track()->alignment_choice()) { + case Automatic: + ++automatic; + styles |= 0x1; + switch (r->track()->alignment_style()) { + case ExistingMaterial: + ++existing; + break; + case CaptureTime: + ++capture; + break; + } + break; + case UseExistingMaterial: + ++existing; + styles |= 0x2; + break; + case UseCaptureTime: + ++capture; + styles |= 0x4; + break; + } + } + + bool inconsistent; + switch (styles) { + case 1: + case 2: + case 4: + inconsistent = false; + break; + default: + inconsistent = true; + break; + } + + RadioMenuItem* i; + + if (!inconsistent && first_track) { + + alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)"))); + i = dynamic_cast (&alignment_items.back()); + i->set_active (automatic != 0 && existing == 0 && capture == 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true)); + + switch (first_track->alignment_choice()) { + case Automatic: + switch (first_track->alignment_style()) { + case ExistingMaterial: + alignment_items.push_back (MenuElem (_("(Currently: Existing Material)"))); + break; + case CaptureTime: + alignment_items.push_back (MenuElem (_("(Currently: Capture Time)"))); + break; + } + break; + default: + break; + } + + alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material"))); + i = dynamic_cast (&alignment_items.back()); + i->set_active (existing != 0 && capture == 0 && automatic == 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true)); + + alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time"))); + i = dynamic_cast (&alignment_items.back()); + i->set_active (existing == 0 && capture != 0 && automatic == 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true)); + + items.push_back (MenuElem (_("Alignment"), *alignment_menu)); + + } else { + /* show nothing */ + } + + Menu* mode_menu = manage (new Menu); + MenuList& mode_items = mode_menu->items (); + mode_menu->set_name ("ArdourContextMenu"); + + RadioMenuItem::Group mode_group; + + int normal = 0; + int tape = 0; + int non_layered = 0; + + for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) { + RouteTimeAxisView* r = dynamic_cast (*i); + if (!r || !r->is_track ()) { + continue; + } + + switch (r->track()->mode()) { + case Normal: + ++normal; + break; + case Destructive: + ++tape; + break; + case NonLayered: + ++non_layered; + break; + } + } + + mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode"))); + i = dynamic_cast (&mode_items.back ()); + i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true)); + i->set_active (normal != 0 && tape == 0 && non_layered == 0); + i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0)); + + mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode"))); + i = dynamic_cast (&mode_items.back ()); + i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true)); + i->set_active (normal == 0 && tape != 0 && non_layered == 0); + i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0)); + + mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode"))); + i = dynamic_cast (&mode_items.back ()); + i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true)); + i->set_active (normal == 0 && tape == 0 && non_layered != 0); + i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0)); + + items.push_back (MenuElem (_("Mode"), *mode_menu)); + } + + + items.push_back (SeparatorElem()); + + build_playlist_menu (); + items.push_back (MenuElem (_("Playlist"), *playlist_action_menu)); + items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1); + } + + route_group_menu->detach (); + + WeakRouteList r; + for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) { + RouteTimeAxisView* rtv = dynamic_cast (*i); + if (rtv) { + r.push_back (rtv->route ()); + } + } + + if (r.empty ()) { + r.push_back (route ()); + } + + route_group_menu->build (r); + items.push_back (MenuElem (_("Group"), *route_group_menu->menu ())); + + build_automation_action_menu (true); + items.push_back (MenuElem (_("Automation"), *automation_action_menu)); + + items.push_back (SeparatorElem()); + + int active = 0; + int inactive = 0; + TrackSelection const & s = _editor.get_selection().tracks; + for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) { + RouteTimeAxisView* r = dynamic_cast (*i); + if (!r) { + continue; + } + + if (r->route()->active()) { + ++active; + } else { + ++inactive; + } + } + + items.push_back (CheckMenuElem (_("Active"))); + Gtk::CheckMenuItem* i = dynamic_cast (&items.back()); + bool click_sets_active = true; + if (active > 0 && inactive == 0) { + i->set_active (true); + click_sets_active = false; + } else if (active > 0 && inactive > 0) { + i->set_inconsistent (true); + } + i->set_sensitive(! _session->transport_rolling()); + i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true)); + + items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true))); + if (!Profile->get_sae()) { + items.push_back (MenuElem (_("Remove"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true))); + } else { + items.push_front (SeparatorElem()); + items.push_front (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true))); + } } void diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index d56379b3e8..4e0403071c 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -3691,6 +3691,10 @@ Route::denormal_protection () const void Route::set_active (bool yn, void* src) { + if (_session.transport_rolling()) { + return; + } + if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_route_active()) { _route_group->foreach_route (boost::bind (&Route::set_active, _1, yn, _route_group)); return;