X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_ops.cc;h=e140413e24ae3228255a484dc461e09ab8715fbc;hb=735d791e420c3e4944fdbc8ac7f6a26251d90d87;hp=643780a490ea4abd3559d7e111b656f099810a67;hpb=73f3e479d363ef35bb12a89b61d21609a7428e19;p=ardour.git diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 643780a490..e140413e24 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -28,6 +28,8 @@ #include #include +#include + #include "pbd/error.h" #include "pbd/basename.h" #include "pbd/pthread_utils.h" @@ -36,9 +38,11 @@ #include "pbd/whitespace.h" #include "pbd/stateful_diff_command.h" -#include -#include -#include +#include "gtkmm2ext/utils.h" + +#include "widgets/choice.h" +#include "widgets/popup.h" +#include "widgets/prompter.h" #include "ardour/audio_track.h" #include "ardour/audioregion.h" @@ -59,6 +63,7 @@ #include "ardour/strip_silence.h" #include "ardour/transient_detector.h" #include "ardour/transpose.h" +#include "ardour/vca_manager.h" #include "canvas/canvas.h" @@ -102,6 +107,7 @@ #include "transpose_dialog.h" #include "transform_dialog.h" #include "ui_config.h" +#include "vca_time_axis.h" #include "pbd/i18n.h" @@ -110,6 +116,7 @@ using namespace ARDOUR; using namespace PBD; using namespace Gtk; using namespace Gtkmm2ext; +using namespace ArdourWidgets; using namespace Editing; using Gtkmm2ext::Keyboard; @@ -166,8 +173,7 @@ Editor::redo (uint32_t n) } void -Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int32_t sub_num, - bool snap_frame) +Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame) { bool frozen = false; @@ -214,7 +220,7 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int3 have something to split. */ - if (!(*a)->region()->covers (where)) { + if (!(*a)->region()->covers (where.frame)) { ++a; continue; } @@ -246,7 +252,7 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int3 if (pl) { pl->clear_changes (); - pl->split_region ((*a)->region(), where, sub_num); + pl->split_region ((*a)->region(), where); _session->add_command (new StatefulDiffCommand (pl)); } @@ -278,7 +284,6 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int3 if (working_on_selection) { // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw. - _ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split(); /* There are three classes of regions that we might want selected after splitting selected regions: @@ -293,7 +298,7 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int3 } for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) { - if ((*ri)->region()->position() < where) { + if ((*ri)->region()->position() < where.frame) { // new regions created before the split if (rsas & NewlyCreatedLeft) { selection->add (*ri); @@ -305,13 +310,10 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int3 } } } - _ignore_follow_edits = false; } else { - _ignore_follow_edits = true; if( working_on_selection ) { selection->add (latest_regionviews); //these are the new regions created after the split } - _ignore_follow_edits = false; } commit_reversible_command (); @@ -424,6 +426,7 @@ Editor::nudge_forward (bool next, bool force_playhead) bool is_start; bool in_command = false; + const int32_t divisions = get_grid_music_divisions (0); for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) { @@ -439,9 +442,9 @@ Editor::nudge_forward (bool next, bool force_playhead) distance = next_distance; } if (max_framepos - distance > loc->start() + loc->length()) { - loc->set_start (loc->start() + distance); + loc->set_start (loc->start() + distance, false, true, divisions); } else { - loc->set_start (max_framepos - loc->length()); + loc->set_start (max_framepos - loc->length(), false, true, divisions); } } else { distance = get_nudge_distance (loc->end(), next_distance); @@ -449,9 +452,9 @@ Editor::nudge_forward (bool next, bool force_playhead) distance = next_distance; } if (max_framepos - distance > loc->end()) { - loc->set_end (loc->end() + distance); + loc->set_end (loc->end() + distance, false, true, divisions); } else { - loc->set_end (max_framepos); + loc->set_end (max_framepos, false, true, divisions); } if (loc->is_session_range()) { _session->set_end_is_free (false); @@ -531,9 +534,9 @@ Editor::nudge_backward (bool next, bool force_playhead) distance = next_distance; } if (distance < loc->start()) { - loc->set_start (loc->start() - distance); + loc->set_start (loc->start() - distance, false, true, get_grid_music_divisions(0)); } else { - loc->set_start (0); + loc->set_start (0, false, true, get_grid_music_divisions(0)); } } else { distance = get_nudge_distance (loc->end(), next_distance); @@ -543,9 +546,9 @@ Editor::nudge_backward (bool next, bool force_playhead) } if (distance < loc->end() - loc->length()) { - loc->set_end (loc->end() - distance); + loc->set_end (loc->end() - distance, false, true, get_grid_music_divisions(0)); } else { - loc->set_end (loc->length()); + loc->set_end (loc->length(), false, true, get_grid_music_divisions(0)); } if (loc->is_session_range()) { _session->set_end_is_free (false); @@ -629,9 +632,9 @@ Editor::nudge_backward_capture_offset () } struct RegionSelectionPositionSorter { - bool operator() (RegionView* a, RegionView* b) { - return a->region()->position() < b->region()->position(); - } + bool operator() (RegionView* a, RegionView* b) { + return a->region()->position() < b->region()->position(); + } }; void @@ -720,9 +723,12 @@ Editor::build_region_boundary_cache () return; } + bool maybe_first_frame = false; + switch (_snap_type) { case SnapToRegionStart: interesting_points.push_back (Start); + maybe_first_frame = true; break; case SnapToRegionEnd: interesting_points.push_back (End); @@ -733,6 +739,7 @@ Editor::build_region_boundary_cache () case SnapToRegionBoundary: interesting_points.push_back (Start); interesting_points.push_back (End); + maybe_first_frame = true; break; default: fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg; @@ -749,6 +756,17 @@ Editor::build_region_boundary_cache () tlist = track_views.filter_to_unique_playlists (); } + if (maybe_first_frame) { + TrackViewList::const_iterator i; + for (i = tlist.begin(); i != tlist.end(); ++i) { + boost::shared_ptr pl = (*i)->playlist(); + if (pl && pl->count_regions_at (0)) { + region_boundary_cache.push_back (0); + break; + } + } + } + while (pos < _session->current_end_frame() && !at_end) { framepos_t rpos; @@ -1159,7 +1177,7 @@ Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir) return; } - loc->move_to (target); + loc->move_to (target, 0); } void @@ -1236,7 +1254,7 @@ Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir) pos = track_frame_to_session_frame(pos, speed); - loc->move_to (pos); + loc->move_to (pos, 0); } void @@ -1283,7 +1301,7 @@ Editor::selected_marker_to_selection_start () return; } - loc->move_to (pos); + loc->move_to (pos, 0); } void @@ -1318,7 +1336,7 @@ Editor::selected_marker_to_selection_end () return; } - loc->move_to (pos); + loc->move_to (pos, 0); } void @@ -1370,6 +1388,7 @@ Editor::cursor_align (bool playhead_to_edit) _session->request_locate (selection->markers.front()->position(), _session->transport_rolling()); } else { + const int32_t divisions = get_grid_music_divisions (0); /* move selected markers to playhead */ for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) { @@ -1378,10 +1397,10 @@ Editor::cursor_align (bool playhead_to_edit) Location* loc = find_location_from_marker (*i, ignored); if (loc->is_mark()) { - loc->set_start (playhead_cursor->current_frame ()); + loc->set_start (playhead_cursor->current_frame (), false, true, divisions); } else { loc->set (playhead_cursor->current_frame (), - playhead_cursor->current_frame () + loc->length()); + playhead_cursor->current_frame () + loc->length(), true, divisions); } } } @@ -1454,6 +1473,22 @@ Editor::scroll_tracks_up_line () reset_y_origin (vertical_adjustment.get_value() - 60); } +void +Editor::select_topmost_track () +{ + const double top_of_trackviews = vertical_adjustment.get_value(); + for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) { + if ((*t)->hidden()) { + continue; + } + std::pair res = (*t)->covers_y_position (top_of_trackviews); + if (res.first) { + selection->set (*t); + break; + } + } +} + bool Editor::scroll_down_one_track (bool skip_child_views) { @@ -1754,6 +1789,50 @@ Editor::temporal_zoom_step_scale (bool zoom_out, double scale) } } + // ToDo: encapsulate all of this into something like editor::get_session_extents() or editor::leftmost(), rightmost() + { + //ToDo: also incorporate automation regions (in case the session has no audio/midi but is just used for automating plugins or the like) + + //calculate the extents of all regions in every playlist + framecnt_t session_extent_start = 0; + framecnt_t session_extent_end = 0; + { + boost::shared_ptr rl = _session->get_routes(); + for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) { + boost::shared_ptr tr = boost::dynamic_pointer_cast (*r); + if (tr) { + boost::shared_ptr pl = tr->playlist(); + if (pl) { + pair e; + e = pl->get_extent(); + if (e.first < session_extent_start) { + session_extent_start = e.first; + } + if (e.second > session_extent_end) { + session_extent_end = e.second; + } + } + } + } + } + framecnt_t session_extents = session_extent_end - session_extent_start; + + //in a session with no regions, use the start/end markers to set max zoom + framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame (); + if ( session_length > session_extents ) + session_extents = session_length; + + //in a session with no regions or start/end markers, use 2 minutes to set max zoom + framecnt_t const min_length = _session->nominal_frame_rate()*60*2; + if ( min_length > session_extents ) + session_extents = min_length; + + //convert to samples-per-pixel and limit our zoom to this value + framecnt_t session_extents_pp = session_extents / _visible_canvas_width; + if (nspp > session_extents_pp) + nspp = session_extents_pp; + } + temporal_zoom (nspp); } @@ -1922,53 +2001,6 @@ Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end) } } -void -Editor::temporal_zoom_region (bool both_axes) -{ - framepos_t start = max_framepos; - framepos_t end = 0; - set tracks; - - if ( !get_selection_extents(start, end) ) - return; - - calc_extra_zoom_edges (start, end); - - /* if we're zooming on both axes we need to save track heights etc. - */ - - undo_visual_stack.push_back (current_visual_state (both_axes)); - - PBD::Unwinder nsv (no_save_visual, true); - - temporal_zoom_by_frame (start, end); - - if (both_axes) { - uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size()); - - /* set visible track heights appropriately */ - - for (set::iterator t = tracks.begin(); t != tracks.end(); ++t) { - (*t)->set_height (per_track_height); - } - - /* hide irrelevant tracks */ - - DisplaySuspender ds; - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) { - hide_track_in_display (*i); - } - } - - vertical_adjustment.set_value (0.0); - } - - redo_visual_stack.push_back (current_visual_state (both_axes)); -} - - bool Editor::get_selection_extents (framepos_t &start, framepos_t &end) const { @@ -2010,7 +2042,7 @@ Editor::get_selection_extents (framepos_t &start, framepos_t &end) const void -Editor::temporal_zoom_selection (bool both_axes) +Editor::temporal_zoom_selection (Editing::ZoomAxis axes) { if (!selection) return; @@ -2018,23 +2050,18 @@ Editor::temporal_zoom_selection (bool both_axes) //ToDo: if control points are selected, zoom to that - //if region(s) are selected, zoom to that - if ( !selection->regions.empty() ) - temporal_zoom_region (both_axes); - - //if a range is selected, zoom to that - if (!selection->time.empty()) { + if (axes == Horizontal || axes == Both) { - framepos_t start, end; + framepos_t start, end; if (get_selection_extents (start, end)) { - calc_extra_zoom_edges(start, end); + calc_extra_zoom_edges (start, end); temporal_zoom_by_frame (start, end); } - - if (both_axes) - fit_selection(); } + if (axes == Vertical || axes == Both) { + fit_selection (); + } } void @@ -2156,7 +2183,7 @@ Editor::choose_new_marker_name(string &name) { return true; } - ArdourPrompter dialog (true); + Prompter dialog (true); dialog.set_prompt (_("New Name:")); @@ -2201,7 +2228,7 @@ Editor::add_location_from_selection () framepos_t end = selection->time[clicked_selection].end; _session->locations()->next_available_name(rangename,"selection"); - Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker); + Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0)); begin_reversible_command (_("add marker")); @@ -2224,7 +2251,7 @@ Editor::add_location_mark (framepos_t where) if (!choose_new_marker_name(markername)) { return; } - Location *location = new Location (*_session, where, where, markername, Location::IsMark); + Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0)); begin_reversible_command (_("add marker")); XMLNode &before = _session->locations()->get_state(); @@ -2353,7 +2380,7 @@ Editor::add_locations_from_region () boost::shared_ptr region = (*i)->region (); - Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker); + Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0); _session->locations()->add (location, true); commit = true; @@ -2394,7 +2421,7 @@ Editor::add_location_from_region () } // single range spanning all selected - Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker); + Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0); _session->locations()->add (location, true); begin_reversible_command (_("add marker")); @@ -2430,6 +2457,14 @@ Editor::jump_backward_to_mark () framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame()); + //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark... + if ( _session->transport_rolling() ) { + if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) { + framepos_t prior = _session->locations()->first_mark_before ( pos ); + pos = prior; + } + } + if (pos < 0) { return; } @@ -2449,7 +2484,7 @@ Editor::set_mark () return; } - _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true); + _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true); } void @@ -2652,24 +2687,19 @@ Editor::play_selection () _session->request_play_range (&lar, true); } -framepos_t -Editor::get_preroll () -{ - return Config->get_preroll_seconds() * _session->frame_rate(); -} - void -Editor::maybe_locate_with_edit_preroll ( framepos_t location ) +Editor::maybe_locate_with_edit_preroll (framepos_t location) { - if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() ) + if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() ) return; - location -= get_preroll(); + location -= _session->preroll_samples (location); //don't try to locate before the beginning of time - if ( location < 0 ) + if (location < 0) { location = 0; + } //if follow_playhead is on, keep the playhead on the screen if ( _follow_playhead ) @@ -2682,15 +2712,15 @@ Editor::maybe_locate_with_edit_preroll ( framepos_t location ) void Editor::play_with_preroll () { - { - framepos_t preroll = get_preroll(); + framepos_t start, end; + if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) { + const framepos_t preroll = _session->preroll_samples (start); - framepos_t start, end; - if (!get_selection_extents ( start, end)) - return; + framepos_t ret = start; - if (start > preroll) + if (start > preroll) { start = start - preroll; + } end = end + preroll; //"post-roll" @@ -2699,9 +2729,35 @@ Editor::play_with_preroll () lar.push_back (ar); _session->request_play_range (&lar, true); + _session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll + } else { + framepos_t ph = playhead_cursor->current_frame (); + const framepos_t preroll = _session->preroll_samples (ph); + framepos_t start; + if (ph > preroll) { + start = ph - preroll; + } else { + start = 0; + } + _session->request_locate (start, true); + _session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll } } +void +Editor::rec_with_preroll () +{ + framepos_t ph = playhead_cursor->current_frame (); + framepos_t preroll = _session->preroll_samples (ph); + _session->request_preroll_record_trim (ph, preroll); +} + +void +Editor::rec_with_count_in () +{ + _session->request_count_in_record (); +} + void Editor::play_location (Location& location) { @@ -3149,8 +3205,8 @@ Editor::separate_regions_between (const TimeSelection& ts) if (!latest_regionviews.empty()) { rtv->view()->foreach_regionview (sigc::bind ( - sigc::ptr_fun (add_if_covered), - &(*t), &new_selection)); + sigc::ptr_fun (add_if_covered), + &(*t), &new_selection)); if (!in_command) { begin_reversible_command (_("separate")); @@ -3180,8 +3236,8 @@ Editor::separate_regions_between (const TimeSelection& ts) } struct PlaylistState { - boost::shared_ptr playlist; - XMLNode* before; + boost::shared_ptr playlist; + XMLNode* before; }; /** Take tracks from get_tracks_for_range_action and cut any regions @@ -3284,10 +3340,10 @@ Editor::separate_under_selected_regions () boost::shared_ptr playlist = (*rl)->playlist(); - if (!playlist) { + if (!playlist) { // is this check necessary? continue; - } + } vector::iterator i; @@ -3303,7 +3359,7 @@ Editor::separate_under_selected_regions () PlaylistState before; before.playlist = playlist; before.before = &playlist->get_state(); - + playlist->clear_changes (); playlist->freeze (); playlists.push_back(before); } @@ -3330,15 +3386,22 @@ Editor::crop_region_to_selection () { if (!selection->time.empty()) { - crop_region_to (selection->time.start(), selection->time.end_frame()); - + begin_reversible_command (_("Crop Regions to Time Selection")); + for (std::list::iterator i = selection->time.begin(); i != selection->time.end(); ++i) { + crop_region_to ((*i).start, (*i).end); + } + commit_reversible_command(); } else { framepos_t start; framepos_t end; if (get_edit_op_range (start, end)) { + begin_reversible_command (_("Crop Regions to Edit Range")); + crop_region_to (start, end); + + commit_reversible_command(); } } @@ -3385,7 +3448,6 @@ Editor::crop_region_to (framepos_t start, framepos_t end) framepos_t new_start; framepos_t new_end; framecnt_t new_length; - bool in_command = false; for (vector >::iterator i = playlists.begin(); i != playlists.end(); ++i) { @@ -3415,19 +3477,11 @@ Editor::crop_region_to (framepos_t start, framepos_t end) new_end = min (end, new_end); new_length = new_end - new_start + 1; - if(!in_command) { - begin_reversible_command (_("trim to selection")); - in_command = true; - } (*i)->clear_changes (); (*i)->trim_to (new_start, new_length); _session->add_command (new StatefulDiffCommand (*i)); } } - - if (in_command) { - commit_reversible_command (); - } } void @@ -3579,9 +3633,9 @@ Editor::align_regions (RegionPoint what) } struct RegionSortByTime { - bool operator() (const RegionView* a, const RegionView* b) { - return a->region()->position() < b->region()->position(); - } + bool operator() (const RegionView* a, const RegionView* b) { + return a->region()->position() < b->region()->position(); + } }; void @@ -3735,10 +3789,8 @@ Editor::trim_region (bool front) if (front) { (*i)->region()->trim_front (where); - maybe_locate_with_edit_preroll ( where ); } else { (*i)->region()->trim_end (where); - maybe_locate_with_edit_preroll ( where ); } _session->add_command (new StatefulDiffCommand ((*i)->region())); @@ -3865,26 +3917,26 @@ Editor::trim_to_region(bool forward) if (forward) { - next_region = playlist->find_next_region (region->first_frame(), Start, 1); + next_region = playlist->find_next_region (region->first_frame(), Start, 1); - if (!next_region) { - continue; - } + if (!next_region) { + continue; + } - region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed)); - arv->region_changed (PropertyChange (ARDOUR::Properties::length)); + region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed)); + arv->region_changed (PropertyChange (ARDOUR::Properties::length)); } else { - next_region = playlist->find_next_region (region->first_frame(), Start, 0); + next_region = playlist->find_next_region (region->first_frame(), Start, 0); - if(!next_region){ - continue; - } + if(!next_region){ + continue; + } - region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed)); + region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed)); - arv->region_changed (ARDOUR::bounds_change); + arv->region_changed (ARDOUR::bounds_change); } if (!in_command) { @@ -3957,8 +4009,8 @@ Editor::freeze_route () if (clicked_routeview->track()->has_external_redirects()) { MessageDialog d (string_compose (_("%1\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n" - "Freezing will only process the signal as far as the first send/insert/return."), - clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true); + "Freezing will only process the signal as far as the first send/insert/return."), + clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true); d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK); d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL); @@ -4155,8 +4207,9 @@ Editor::cut_copy (CutCopyOp op) } } - if ( op != Delete ) //"Delete" doesn't change copy/paste buf + if ( op != Delete ) { //"Delete" doesn't change copy/paste buf cut_buffer->clear (); + } if (entered_marker) { @@ -4228,7 +4281,7 @@ Editor::cut_copy (CutCopyOp op) if (did_edit) { /* reset repeated paste state */ paste_count = 0; - last_paste_pos = 0; + last_paste_pos = -1; commit_reversible_command (); } @@ -4246,11 +4299,13 @@ struct AutomationRecord { const AutomationLine* line; ///< line this came from boost::shared_ptr copy; ///< copied events for the cut buffer }; + struct PointsSelectionPositionSorter { bool operator() (ControlPoint* a, ControlPoint* b) { return (*(a->model()))->when < (*(b->model()))->when; } }; + /** Cut, copy or clear selected automation points. * @param op Operation (Cut, Copy or Clear) */ @@ -4270,7 +4325,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid /* user could select points in any order */ selection->points.sort(PointsSelectionPositionSorter ()); - + /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */ for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) { const AutomationLine& line = (*sel_point)->line(); @@ -4292,7 +4347,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid } /* Add all selected points to the relevant copy ControlLists */ - framepos_t start = std::numeric_limits::max(); + MusicFrame start (std::numeric_limits::max(), 0); for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) { boost::shared_ptr al = (*sel_point)->line().the_list(); AutomationList::const_iterator ctrl_evt = (*sel_point)->model (); @@ -4303,7 +4358,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when)); } else { /* Update earliest session start time in frames */ - start = std::min(start, (*sel_point)->line().session_position(ctrl_evt)); + start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt)); } } @@ -4314,13 +4369,13 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid } earliest.round_down_to_beat(); } else { - if (start == std::numeric_limits::max()) { - start = 0; // Weird... don't offset + if (start.frame == std::numeric_limits::max()) { + start.frame = 0; // Weird... don't offset } snap_to(start, RoundDownMaybe); } - const double line_offset = midi ? earliest.to_double() : start; + const double line_offset = midi ? earliest.to_double() : start.frame; for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) { /* Correct this copy list so that it is relative to the earliest start time, so relative ordering between points is preserved @@ -4349,7 +4404,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid boost::shared_ptr al = line.the_list(); bool erase = true; - + if (dynamic_cast (&line)) { /* removing of first and last gain point in region gain lines is prohibited*/ if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) { @@ -4400,16 +4455,16 @@ Editor::cut_copy_midi (CutCopyOp op) } struct lt_playlist { - bool operator () (const PlaylistState& a, const PlaylistState& b) { - return a.playlist < b.playlist; - } + bool operator () (const PlaylistState& a, const PlaylistState& b) { + return a.playlist < b.playlist; + } }; struct PlaylistMapping { - TimeAxisView* tv; - boost::shared_ptr pl; + TimeAxisView* tv; + boost::shared_ptr pl; - PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {} + PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {} }; /** Remove `clicked_regionview' */ @@ -4473,10 +4528,10 @@ Editor::remove_selected_regions () boost::shared_ptr playlist = (*rl)->playlist(); - if (!playlist) { + if (!playlist) { // is this check necessary? continue; - } + } /* get_regions_from_selection_and_entered() guarantees that the playlists involved are unique, so there is no need @@ -4722,29 +4777,28 @@ Editor::cut_copy_ranges (CutCopyOp op) void Editor::paste (float times, bool from_context) { - DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n"); - - paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times, get_grid_music_divisions (0)); + DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n"); + MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0); + paste_internal (where.frame, times, 0); } void Editor::mouse_paste () { - framepos_t where; + MusicFrame where (0, 0); bool ignored; - - if (!mouse_frame (where, ignored)) { + if (!mouse_frame (where.frame, ignored)) { return; } snap_to (where); - paste_internal (where, 1, get_grid_music_divisions (0)); + paste_internal (where.frame, 1, where.division); } void Editor::paste_internal (framepos_t position, float times, const int32_t sub_num) { - DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position)); + DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position)); if (cut_buffer->empty(internal_editing())) { return; @@ -4752,7 +4806,7 @@ Editor::paste_internal (framepos_t position, float times, const int32_t sub_num) if (position == max_framepos) { position = get_preferred_edit_position(); - DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position)); + DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position)); } if (position == last_paste_pos) { @@ -4769,8 +4823,8 @@ Editor::paste_internal (framepos_t position, float times, const int32_t sub_num) TrackViewList ts; if (!selection->tracks.empty()) { /* If there is a track selection, paste into exactly those tracks and - only those tracks. This allows the user to be explicit and override - the below "do the reasonable thing" logic. */ + * only those tracks. This allows the user to be explicit and override + * the below "do the reasonable thing" logic. */ ts = selection->tracks.filter_to_unique_playlists (); sort_track_selection (ts); } else { @@ -4834,8 +4888,8 @@ Editor::paste_internal (framepos_t position, float times, const int32_t sub_num) /* Only one line copied, and one automation track selected. Do a "greedy" paste from one automation type to another. */ - PasteContext ctx(paste_count, times, ItemCounts(), true); - ts.front()->paste (position, *cut_buffer, ctx, sub_num); + PasteContext ctx(paste_count, times, ItemCounts(), true); + ts.front()->paste (position, *cut_buffer, ctx, sub_num); } else { @@ -4937,18 +4991,19 @@ Editor::duplicate_selection (float times) } if (in_command) { - // now "move" range selection to after the current range selection - framecnt_t distance = 0; - - if (clicked_selection) { - distance = selection->time[clicked_selection].end - - selection->time[clicked_selection].start; - } else { - distance = selection->time.end_frame() - selection->time.start(); - } + if (times == 1.0f) { + // now "move" range selection to after the current range selection + framecnt_t distance = 0; - selection->move_time (distance); + if (clicked_selection) { + distance = + selection->time[clicked_selection].end - selection->time[clicked_selection].start; + } else { + distance = selection->time.end_frame () - selection->time.start (); + } + selection->move_time (distance); + } commit_reversible_command (); } } @@ -4959,7 +5014,7 @@ Editor::reset_point_selection () { for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) { ARDOUR::AutomationList::iterator j = (*i)->model (); - (*j)->value = (*i)->line().the_list()->default_value (); + (*j)->value = (*i)->line().the_list()->descriptor ().normal; } } @@ -5051,12 +5106,12 @@ Editor::remove_last_capture () if (Config->get_verify_remove_last_capture()) { prompt = _("Do you really want to destroy the last capture?" - "\n(This is destructive and cannot be undone)"); + "\n(This is destructive and cannot be undone)"); choices.push_back (_("No, do nothing.")); choices.push_back (_("Yes, destroy it.")); - Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices); + Choice prompter (_("Destroy last capture"), prompt, choices); if (prompter.run () == 1) { _session->remove_last_capture (); @@ -5245,6 +5300,38 @@ Editor::adjust_region_gain (bool up) } } +void +Editor::reset_region_gain () +{ + RegionSelection rs = get_regions_from_selection_and_entered (); + + if (!_session || rs.empty()) { + return; + } + + bool in_command = false; + + for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { + AudioRegionView* const arv = dynamic_cast(*r); + if (!arv) { + continue; + } + + arv->region()->clear_changes (); + + arv->audio_region()->set_scale_amplitude (1.0f); + + if (!in_command) { + begin_reversible_command ("reset region gain"); + in_command = true; + } + _session->add_command (new StatefulDiffCommand (arv->region())); + } + + if (in_command) { + commit_reversible_command (); + } +} void Editor::reverse_region () @@ -5274,7 +5361,7 @@ Editor::strip_region_silence () for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { AudioRegionView* const arv = dynamic_cast (*i); - if (arv) { + if (arv) { audio_only.push_back (arv); } } @@ -5519,7 +5606,7 @@ Editor::insert_patch_change (bool from_context) MidiRegionView* first = dynamic_cast (rs.front ()); Evoral::PatchChange empty (Evoral::Beats(), 0, 0, 0); - PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD); + PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD); if (d.run() == RESPONSE_CANCEL) { return; @@ -5776,11 +5863,17 @@ Editor::toggle_region_lock_style () return; } - begin_reversible_command (_("region lock style")); + Glib::RefPtr a = Glib::RefPtr::cast_dynamic (_region_actions->get_action("toggle-region-lock-style")); + vector proxies = a->get_proxies(); + Gtk::CheckMenuItem* cmi = dynamic_cast (proxies.front()); + + assert (cmi); + + begin_reversible_command (_("toggle region lock style")); for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { (*i)->region()->clear_changes (); - PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime; + PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime; (*i)->region()->set_position_lock_style (ns); _session->add_command (new StatefulDiffCommand ((*i)->region())); } @@ -5841,18 +5934,18 @@ Editor::toggle_solo () boost::shared_ptr cl (new ControlList); for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - RouteTimeAxisView *rtav = dynamic_cast(*i); + StripableTimeAxisView *stav = dynamic_cast(*i); - if (!rtav) { + if (!stav || !stav->stripable()->solo_control()) { continue; } if (first) { - new_state = !rtav->route()->soloed (); + new_state = !stav->stripable()->solo_control()->soloed (); first = false; } - cl->push_back (rtav->route()->solo_control()); + cl->push_back (stav->stripable()->solo_control()); } _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup); @@ -5863,24 +5956,24 @@ Editor::toggle_mute () { bool new_state = false; bool first = true; - boost::shared_ptr rl (new RouteList); + boost::shared_ptr cl (new ControlList); for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - RouteTimeAxisView *rtav = dynamic_cast(*i); + StripableTimeAxisView *stav = dynamic_cast(*i); - if (!rtav) { + if (!stav || !stav->stripable()->mute_control()) { continue; } if (first) { - new_state = !rtav->route()->muted(); + new_state = !stav->stripable()->mute_control()->muted(); first = false; } - rl->push_back (rtav->route()); + cl->push_back (stav->stripable()->mute_control()); } - _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup); + _session->set_controls (cl, new_state, Controllable::UseGroup); } void @@ -6202,10 +6295,10 @@ Editor::update_region_fade_visibility () void Editor::set_edit_point () { - framepos_t where; bool ignored; + MusicFrame where (0, 0); - if (!mouse_frame (where, ignored)) { + if (!mouse_frame (where.frame, ignored)) { return; } @@ -6213,7 +6306,7 @@ Editor::set_edit_point () if (selection->markers.empty()) { - mouse_add_new_marker (where); + mouse_add_new_marker (where.frame); } else { bool ignored; @@ -6221,7 +6314,7 @@ Editor::set_edit_point () Location* loc = find_location_from_marker (selection->markers.front(), ignored); if (loc) { - loc->move_to (where); + loc->move_to (where.frame, where.division); } } } @@ -6232,23 +6325,25 @@ Editor::set_playhead_cursor () if (entered_marker) { _session->request_locate (entered_marker->position(), _session->transport_rolling()); } else { - framepos_t where; + MusicFrame where (0, 0); bool ignored; - if (!mouse_frame (where, ignored)) { + if (!mouse_frame (where.frame, ignored)) { return; } snap_to (where); if (_session) { - _session->request_locate (where, _session->transport_rolling()); + _session->request_locate (where.frame, _session->transport_rolling()); } } - if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) { - cancel_time_selection(); - } +//not sure what this was for; remove it for now. +// if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) { +// cancel_time_selection(); +// } + } void @@ -6268,23 +6363,21 @@ Editor::split_region () if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc. RegionSelection rs = get_regions_from_selection_and_edit_point (); - - framepos_t where = get_preferred_edit_position (); + const framepos_t pos = get_preferred_edit_position(); + const int32_t division = get_grid_music_divisions (0); + MusicFrame where (pos, division); if (rs.empty()) { return; } - if (snap_musical()) { - split_regions_at (where, rs, get_grid_music_divisions (0)); - } else { - split_regions_at (where, rs, 0); - } + split_regions_at (where, rs); + } } void -Editor::select_next_route() +Editor::select_next_stripable (bool routes_only) { if (selection->tracks.empty()) { selection->set (track_views.front()); @@ -6293,7 +6386,7 @@ Editor::select_next_route() TimeAxisView* current = selection->tracks.front(); - RouteUI *rui; + bool valid; do { for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { @@ -6309,9 +6402,14 @@ Editor::select_next_route() } } - rui = dynamic_cast(current); + if (routes_only) { + RouteUI* rui = dynamic_cast(current); + valid = rui && rui->route()->active(); + } else { + valid = 0 != current->stripable ().get(); + } - } while (current->hidden() || (rui == NULL) || !rui->route()->active()); + } while (current->hidden() || !valid); selection->set (current); @@ -6319,7 +6417,7 @@ Editor::select_next_route() } void -Editor::select_prev_route() +Editor::select_prev_stripable (bool routes_only) { if (selection->tracks.empty()) { selection->set (track_views.front()); @@ -6328,7 +6426,7 @@ Editor::select_prev_route() TimeAxisView* current = selection->tracks.front(); - RouteUI *rui; + bool valid; do { for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) { @@ -6342,9 +6440,14 @@ Editor::select_prev_route() break; } } - rui = dynamic_cast(current); + if (routes_only) { + RouteUI* rui = dynamic_cast(current); + valid = rui && rui->route()->active(); + } else { + valid = 0 != current->stripable ().get(); + } - } while (current->hidden() || (rui == NULL) || !rui->route()->active()); + } while (current->hidden() || !valid); selection->set (current); @@ -6433,7 +6536,7 @@ Editor::set_auto_punch_range () set_punch_range (tpl->start(), now, _("Auto Punch In/Out")); _session->config.set_punch_out(true); } - } else { + } else { if (_session->config.get_punch_out()) { _session->config.set_punch_out(false); } @@ -6487,7 +6590,7 @@ Editor::set_punch_start_from_edit_point () { if (_session) { - framepos_t start = 0; + MusicFrame start (0, 0); framepos_t end = max_framepos; //use the existing punch end, if any @@ -6497,20 +6600,20 @@ Editor::set_punch_start_from_edit_point () } if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) { - start = _session->audible_frame(); + start.frame = _session->audible_frame(); } else { - start = get_preferred_edit_position(); + start.frame = get_preferred_edit_position(); } //snap the selection start/end snap_to(start); //if there's not already a sensible selection endpoint, go "forever" - if ( start > end ) { + if (start.frame > end ) { end = max_framepos; } - set_punch_range (start, end, _("set punch start from EP")); + set_punch_range (start.frame, end, _("set punch start from EP")); } } @@ -6521,7 +6624,7 @@ Editor::set_punch_end_from_edit_point () if (_session) { framepos_t start = 0; - framepos_t end = max_framepos; + MusicFrame end (max_framepos, 0); //use the existing punch start, if any Location* tpl = transport_punch_location(); @@ -6530,15 +6633,15 @@ Editor::set_punch_end_from_edit_point () } if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) { - end = _session->audible_frame(); + end.frame = _session->audible_frame(); } else { - end = get_preferred_edit_position(); + end.frame = get_preferred_edit_position(); } //snap the selection start/end - snap_to(end); + snap_to (end); - set_punch_range (start, end, _("set punch end from EP")); + set_punch_range (start, end.frame, _("set punch end from EP")); } } @@ -6548,7 +6651,7 @@ Editor::set_loop_start_from_edit_point () { if (_session) { - framepos_t start = 0; + MusicFrame start (0, 0); framepos_t end = max_framepos; //use the existing loop end, if any @@ -6558,20 +6661,20 @@ Editor::set_loop_start_from_edit_point () } if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) { - start = _session->audible_frame(); + start.frame = _session->audible_frame(); } else { - start = get_preferred_edit_position(); + start.frame = get_preferred_edit_position(); } //snap the selection start/end - snap_to(start); + snap_to (start); //if there's not already a sensible selection endpoint, go "forever" - if ( start > end ) { + if (start.frame > end ) { end = max_framepos; } - set_loop_range (start, end, _("set loop start from EP")); + set_loop_range (start.frame, end, _("set loop start from EP")); } } @@ -6582,7 +6685,7 @@ Editor::set_loop_end_from_edit_point () if (_session) { framepos_t start = 0; - framepos_t end = max_framepos; + MusicFrame end (max_framepos, 0); //use the existing loop start, if any Location* tpl = transport_loop_location(); @@ -6591,15 +6694,15 @@ Editor::set_loop_end_from_edit_point () } if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) { - end = _session->audible_frame(); + end.frame = _session->audible_frame(); } else { - end = get_preferred_edit_position(); + end.frame = get_preferred_edit_position(); } //snap the selection start/end snap_to(end); - set_loop_range (start, end, _("set loop end from EP")); + set_loop_range (start, end.frame, _("set loop end from EP")); } } @@ -6732,12 +6835,13 @@ Editor::define_one_bar (framepos_t start, framepos_t end) XMLNode& before (_session->tempo_map().get_state()); if (do_global) { - _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type()); + _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute()); } else if (t.frame() == start) { - _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type()); + _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute()); } else { + /* constant tempo */ const Tempo tempo (beats_per_minute, t.note_type()); - _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime); + _session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime); } XMLNode& after (_session->tempo_map().get_state()); @@ -7013,10 +7117,12 @@ Editor::snap_regions_to_grid () used_playlists.push_back(pl); pl->freeze(); } + (*r)->region()->clear_changes (); - framepos_t start_frame = (*r)->region()->first_frame (); - snap_to (start_frame); - (*r)->region()->set_position (start_frame); + MusicFrame start ((*r)->region()->first_frame (), 0); + snap_to (start); + (*r)->region()->set_position (start.frame, start.division); + _session->add_command(new StatefulDiffCommand ((*r)->region())); } while (used_playlists.size() > 0) { @@ -7110,11 +7216,16 @@ Editor::close_region_gaps () continue; } + (*r)->region()->clear_changes (); (*r)->region()->trim_front( (position - pull_back_frames)); + + last_region->clear_changes (); last_region->trim_end( (position - pull_back_frames + crossfade_len)); - last_region = (*r)->region(); + _session->add_command (new StatefulDiffCommand ((*r)->region())); + _session->add_command (new StatefulDiffCommand (last_region)); + last_region = (*r)->region(); idx++; } @@ -7214,11 +7325,12 @@ Editor::playhead_forward_to_grid () return; } - framepos_t pos = playhead_cursor->current_frame (); - if (pos < max_framepos - 1) { - pos += 2; - snap_to_internal (pos, RoundUpAlways, false); - _session->request_locate (pos); + MusicFrame pos (playhead_cursor->current_frame (), 0); + + if (pos.frame < max_framepos - 1) { + pos.frame += 2; + snap_to_internal (pos, RoundUpAlways, false, true); + _session->request_locate (pos.frame); } } @@ -7230,11 +7342,12 @@ Editor::playhead_backward_to_grid () return; } - framepos_t pos = playhead_cursor->current_frame (); - if (pos > 2) { - pos -= 2; - snap_to_internal (pos, RoundDownAlways, false); - _session->request_locate (pos); + MusicFrame pos (playhead_cursor->current_frame (), 0); + + if (pos.frame > 2) { + pos.frame -= 2; + snap_to_internal (pos, RoundDownAlways, false, true); + _session->request_locate (pos.frame); } } @@ -7303,20 +7416,29 @@ Editor::_remove_tracks () string prompt; int ntracks = 0; int nbusses = 0; + int nvcas = 0; const char* trackstr; const char* busstr; + const char* vcastr; vector > routes; + vector > vcas; bool special_bus = false; for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) { + VCATimeAxisView* vtv = dynamic_cast (*x); + if (vtv) { + vcas.push_back (vtv->vca()); + ++nvcas; + continue; + } RouteTimeAxisView* rtv = dynamic_cast (*x); if (!rtv) { continue; } if (rtv->is_track()) { - ntracks++; + ++ntracks; } else { - nbusses++; + ++nbusses; } routes.push_back (rtv->_route); @@ -7343,69 +7465,111 @@ edit your ardour.rc file to set the\n\ return; } - if (ntracks + nbusses == 0) { + if (ntracks + nbusses + nvcas == 0) { return; } + string title; + trackstr = P_("track", "tracks", ntracks); busstr = P_("bus", "busses", nbusses); + vcastr = P_("VCA", "VCAs", nvcas); - if (ntracks) { - if (nbusses) { - prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n" - "(You may also lose the playlists associated with the %2)\n\n" - "This action cannot be undone, and the session file will be overwritten!"), - ntracks, trackstr, nbusses, busstr); - } else { - prompt = string_compose (_("Do you really want to remove %1 %2?\n" - "(You may also lose the playlists associated with the %2)\n\n" - "This action cannot be undone, and the session file will be overwritten!"), - ntracks, trackstr); - } - } else if (nbusses) { - prompt = string_compose (_("Do you really want to remove %1 %2?\n\n" - "This action cannot be undone, and the session file will be overwritten"), - nbusses, busstr); + if (ntracks > 0 && nbusses > 0 && nvcas > 0) { + title = _("Remove various strips"); + prompt = string_compose (_("Do you really want to remove %1 %2, %3 %4 and %5 %6?"), + ntracks, trackstr, nbusses, busstr, nvcas, vcastr); + } + else if (ntracks > 0 && nbusses > 0) { + title = string_compose (_("Remove %1 and %2"), trackstr, busstr); + prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"), + ntracks, trackstr, nbusses, busstr); + } + else if (ntracks > 0 && nvcas > 0) { + title = string_compose (_("Remove %1 and %2"), trackstr, vcastr); + prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"), + ntracks, trackstr, nvcas, vcastr); + } + else if (nbusses > 0 && nvcas > 0) { + title = string_compose (_("Remove %1 and %2"), busstr, vcastr); + prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"), + nbusses, busstr, nvcas, vcastr); + } + else if (ntracks > 0) { + title = string_compose (_("Remove %1"), trackstr); + prompt = string_compose (_("Do you really want to remove %1 %2?"), + ntracks, trackstr); + } + else if (nbusses > 0) { + title = string_compose (_("Remove %1"), busstr); + prompt = string_compose (_("Do you really want to remove %1 %2?"), + nbusses, busstr); + } + else if (nvcas > 0) { + title = string_compose (_("Remove %1"), vcastr); + prompt = string_compose (_("Do you really want to remove %1 %2?"), + nvcas, vcastr); + } + else { + assert (0); + } + + if (ntracks > 0) { + prompt += "\n" + string_compose ("(You may also lose the playlists associated with the %1)", trackstr) + "\n"; } + prompt += "\n" + string(_("This action cannot be undone, and the session file will be overwritten!")); + choices.push_back (_("No, do nothing.")); - if (ntracks + nbusses > 1) { + if (ntracks + nbusses + nvcas > 1) { choices.push_back (_("Yes, remove them.")); } else { choices.push_back (_("Yes, remove it.")); } - string title; - if (ntracks) { - title = string_compose (_("Remove %1"), trackstr); - } else { - title = string_compose (_("Remove %1"), busstr); - } - Choice prompter (title, prompt, choices); if (prompter.run () != 1) { return; } + if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) { + /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted + * route). If the deleted route is currently displayed in the Editor-Mixer (highly + * likely because deletion requires selection) this will call + * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ). + * It's likewise likely that the route that has just been displayed in the + * Editor-Mixer will be next in line for deletion. + * + * So simply switch to the master-bus (if present) + */ + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + if ((*i)->stripable ()->is_master ()) { + set_selected_mixer_strip (*(*i)); + break; + } + } + } - Mixer_UI::instance()->selection().block_routes_changed (true); - selection->block_tracks_changed (true); { + PresentationInfo::ChangeSuspender cs; DisplaySuspender ds; + boost::shared_ptr rl (new RouteList); for (vector >::iterator x = routes.begin(); x != routes.end(); ++x) { rl->push_back (*x); } _session->remove_routes (rl); + + for (vector >::iterator x = vcas.begin(); x != vcas.end(); ++x) { + _session->vca_manager().remove_vca (*x); + } + } /* TrackSelection and RouteList leave scope, * destructors are called, * diskstream drops references, save_state is called (again for every track) */ - selection->block_tracks_changed (false); - Mixer_UI::instance()->selection().block_routes_changed (false); - selection->TracksChanged (); /* EMIT SIGNAL */ } void @@ -7483,17 +7647,18 @@ Editor::insert_time ( (*i)->clear_changes (); (*i)->clear_owned_changes (); + if (!in_command) { + begin_reversible_command (_("insert time")); + in_command = true; + } + if (opt == SplitIntersected) { /* non musical split */ - (*i)->split (pos, 0); + (*i)->split (MusicFrame (pos, 0)); } (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue); - if (!in_command) { - begin_reversible_command (_("insert time")); - in_command = true; - } vector cmds; (*i)->rdiff (cmds); _session->add_commands (cmds); @@ -7515,6 +7680,7 @@ Editor::insert_time ( /* markers */ if (markers_too) { bool moved = false; + const int32_t divisions = get_grid_music_divisions (0); XMLNode& before (_session->locations()->get_state()); Locations::LocationList copy (_session->locations()->list()); @@ -7531,9 +7697,9 @@ Editor::insert_time ( if ((*i)->start() >= pos) { // move end first, in case we're moving by more than the length of the range if (!(*i)->is_mark()) { - (*i)->set_end ((*i)->end() + frames); + (*i)->set_end ((*i)->end() + frames, false, true, divisions); } - (*i)->set_start ((*i)->start() + frames); + (*i)->set_start ((*i)->start() + frames, false, true, divisions); moved = true; } @@ -7604,7 +7770,7 @@ Editor::do_remove_time () void Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, - bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too) + bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too) { if (Config->get_edit_mode() == Lock) { error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg; @@ -7620,16 +7786,17 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, XMLNode &before = pl->get_state(); + if (!in_command) { + begin_reversible_command (_("remove time")); + in_command = true; + } + std::list rl; AudioRange ar(pos, pos+frames, 0); rl.push_back(ar); pl->cut (rl); pl->shift (pos, -frames, true, ignore_music_glue); - if (!in_command) { - begin_reversible_command (_("remove time")); - in_command = true; - } XMLNode &after = pl->get_state(); _session->add_command (new MementoCommand (*pl, &before, &after)); @@ -7646,6 +7813,7 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, } } + const int32_t divisions = get_grid_music_divisions (0); std::list loc_kill_list; /* markers */ @@ -7674,20 +7842,20 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, // if we're removing more time than the length of the range if ((*i)->start() >= pos && (*i)->start() < pos+frames) { // start is within cut - (*i)->set_start (pos); // bring the start marker to the beginning of the cut + (*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut moved = true; } else if ((*i)->start() >= pos+frames) { // start (and thus entire range) lies beyond end of cut - (*i)->set_start ((*i)->start() - frames); // slip the start marker back + (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back moved = true; } if ((*i)->end() >= pos && (*i)->end() < pos+frames) { // end is inside cut - (*i)->set_end (pos); // bring the end to the cut + (*i)->set_end (pos, false, true, divisions); // bring the end to the cut moved = true; } else if ((*i)->end() >= pos+frames) { // end is beyond end of cut - (*i)->set_end ((*i)->end() - frames); // slip the end marker back + (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back moved = true; } @@ -7696,7 +7864,7 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, loc_kill_list.push_back(*i); moved = true; } else if ((*i)->start() >= pos) { - (*i)->set_start ((*i)->start() -frames); + (*i)->set_start ((*i)->start() -frames, false, true, divisions); moved = true; } @@ -7741,32 +7909,31 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, void Editor::fit_selection () { - if (!selection->tracks.empty()) { - fit_tracks (selection->tracks); - } else { - TrackViewList tvl; - - /* no selected tracks - use tracks with selected regions */ + if (!selection->tracks.empty()) { + fit_tracks (selection->tracks); + } else { + TrackViewList tvl; - if (!selection->regions.empty()) { - for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) { - tvl.push_back (&(*r)->get_time_axis_view ()); - } + /* no selected tracks - use tracks with selected regions */ - if (!tvl.empty()) { - fit_tracks (tvl); - } - } else if (internal_editing()) { - /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use - the entered track - */ - if (entered_track) { - tvl.push_back (entered_track); - fit_tracks (tvl); - } - } - } + if (!selection->regions.empty()) { + for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) { + tvl.push_back (&(*r)->get_time_axis_view ()); + } + if (!tvl.empty()) { + fit_tracks (tvl); + } + } else if (internal_editing()) { + /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use + * the entered track + */ + if (entered_track) { + tvl.push_back (entered_track); + fit_tracks (tvl); + } + } + } } void @@ -7790,11 +7957,11 @@ Editor::fit_tracks (TrackViewList & tracks) } /* compute the per-track height from: - - total canvas visible height - - height that will be taken by visible children of selected - tracks - height of the ruler/hscroll area - */ + * + * total canvas visible height + * - height that will be taken by visible children of selected tracks + * - height of the ruler/hscroll area + */ uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks); double first_y_pos = DBL_MAX; @@ -7907,7 +8074,7 @@ Editor::start_visual_state_op (uint32_t n) void Editor::cancel_visual_state_op (uint32_t n) { - goto_visual_state (n); + goto_visual_state (n); } void