/*
- Copyright (C) 2000-2004 Paul Davis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
+ * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
+ * Copyright (C) 2005-2009 Sampo Savolainen <v2@iki.fi>
+ * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
+ * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
+ * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
+ * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
+ * Copyright (C) 2007-2017 Tim Mayberry <mojofunk@gmail.com>
+ * Copyright (C) 2013-2016 Colin Fletcher <colin.m.fletcher@googlemail.com>
+ * Copyright (C) 2013-2017 John Emmas <john@creativepost.co.uk>
+ * Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
+ * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2014-2019 Ben Loftis <ben@harrisonconsoles.com>
+ * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
/* Note: public Editor methods are documented in public_editor.h */
#include "ardour/legatize.h"
#include "ardour/region_factory.h"
#include "ardour/reverse.h"
+#include "ardour/selection.h"
#include "ardour/session.h"
#include "ardour/session_playlists.h"
+#include "ardour/source.h"
#include "ardour/strip_silence.h"
#include "ardour/transient_detector.h"
+#include "ardour/transport_master_manager.h"
#include "ardour/transpose.h"
+#include "ardour/vca_manager.h"
#include "canvas/canvas.h"
#include "actions.h"
+#include "ardour_message.h"
+#include "ardour_ui.h"
#include "audio_region_view.h"
#include "audio_streamview.h"
#include "audio_time_axis.h"
#include "editor_cursors.h"
#include "editor_drag.h"
#include "editor_regions.h"
+#include "editor_sources.h"
#include "editor_routes.h"
#include "gui_thread.h"
#include "insert_remove_time_dialog.h"
#include "transpose_dialog.h"
#include "transform_dialog.h"
#include "ui_config.h"
+#include "utils.h"
+#include "vca_time_axis.h"
#include "pbd/i18n.h"
if (_drags->active ()) {
_drags->abort ();
}
+ paste_count = 0;
if (_session) {
_session->undo (n);
if (_drags->active ()) {
_drags->abort ();
}
+ paste_count = 0;
if (_session) {
_session->redo (n);
}
void
-Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame)
+Editor::split_regions_at (MusicSample where, RegionSelection& regions)
{
bool frozen = false;
- RegionSelection pre_selected_regions = selection->regions;
- bool working_on_selection = !pre_selected_regions.empty();
-
list<boost::shared_ptr<Playlist> > used_playlists;
list<RouteTimeAxisView*> used_trackviews;
begin_reversible_command (_("split"));
- // if splitting a single region, and snap-to is using
- // region boundaries, don't pay attention to them
if (regions.size() == 1) {
- switch (_snap_type) {
- case SnapToRegionStart:
- case SnapToRegionSync:
- case SnapToRegionEnd:
- break;
- default:
- if (snap_frame) {
- snap_to (where);
- }
- }
+ /* TODO: if splitting a single region, and snap-to is using
+ region boundaries, mabye we shouldn't pay attention to them? */
} else {
- if (snap_frame) {
- snap_to (where);
- }
-
frozen = true;
EditorFreeze(); /* Emit Signal */
}
have something to split.
*/
- if (!(*a)->region()->covers (where.frame)) {
+ if (!(*a)->region()->covers (where.sample)) {
++a;
continue;
}
EditorThaw(); /* Emit Signal */
}
- if (working_on_selection) {
- // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
-
- RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
- /* There are three classes of regions that we might want selected after
- splitting selected regions:
- - regions selected before the split operation, and unaffected by it
- - newly-created regions before the split
- - newly-created regions after the split
- */
-
- if (rsas & Existing) {
- // region selections that existed before the split.
- selection->add ( pre_selected_regions );
- }
+ RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
+ //if the user has "Clear Selection" as their post-split behavior, then clear the selection
+ if (!latest_regionviews.empty() && (rsas == None)) {
+ selection->clear_objects();
+ selection->clear_time();
+ //but leave track selection intact
+ }
+
+ //if the user doesn't want to preserve the "Existing" selection, then clear the selection
+ if (!(rsas & Existing)) {
+ selection->clear_objects();
+ selection->clear_time();
+ }
+
+ //if the user wants newly-created regions to be selected, then select them:
+ if (mouse_mode == MouseObject) {
for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
- if ((*ri)->region()->position() < where.frame) {
+ if ((*ri)->region()->position() < where.sample) {
// new regions created before the split
if (rsas & NewlyCreatedLeft) {
selection->add (*ri);
}
}
}
- } else {
- if( working_on_selection ) {
- selection->add (latest_regionviews); //these are the new regions created after the split
- }
}
commit_reversible_command ();
void
Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
{
- if (selection->time.start() == selection->time.end_frame()) {
+ if (selection->time.start() == selection->time.end_sample()) {
return;
}
- framepos_t start = selection->time.start ();
- framepos_t end = selection->time.end_frame ();
+ samplepos_t start = selection->time.start ();
+ samplepos_t end = selection->time.end_sample ();
/* the position of the thing we may move */
- framepos_t pos = move_end ? end : start;
+ samplepos_t pos = move_end ? end : start;
int dir = next ? 1 : -1;
/* so we don't find the current region again */
pos += dir;
}
- framepos_t const target = get_region_boundary (pos, dir, true, false);
+ samplepos_t const target = get_region_boundary (pos, dir, true, false);
if (target < 0) {
return;
}
void
Editor::nudge_forward (bool next, bool force_playhead)
{
- framepos_t distance;
- framepos_t next_distance;
+ samplepos_t distance;
+ samplepos_t next_distance;
if (!_session) {
return;
if (next) {
distance = next_distance;
}
- if (max_framepos - distance > loc->start() + loc->length()) {
+ if (max_samplepos - distance > loc->start() + loc->length()) {
loc->set_start (loc->start() + distance, false, true, divisions);
} else {
- loc->set_start (max_framepos - loc->length(), false, true, divisions);
+ loc->set_start (max_samplepos - loc->length(), false, true, divisions);
}
} else {
distance = get_nudge_distance (loc->end(), next_distance);
if (next) {
distance = next_distance;
}
- if (max_framepos - distance > loc->end()) {
+ if (max_samplepos - distance > loc->end()) {
loc->set_end (loc->end() + distance, false, true, divisions);
} else {
- loc->set_end (max_framepos, false, true, divisions);
+ loc->set_end (max_samplepos, false, true, divisions);
}
if (loc->is_session_range()) {
- _session->set_end_is_free (false);
+ _session->set_session_range_is_free (false);
}
}
if (!in_command) {
commit_reversible_command ();
}
} else {
- distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
- _session->request_locate (playhead_cursor->current_frame () + distance);
+ distance = get_nudge_distance (playhead_cursor->current_sample (), next_distance);
+ _session->request_locate (playhead_cursor->current_sample () + distance);
}
}
void
Editor::nudge_backward (bool next, bool force_playhead)
{
- framepos_t distance;
- framepos_t next_distance;
+ samplepos_t distance;
+ samplepos_t next_distance;
if (!_session) {
return;
loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
}
if (loc->is_session_range()) {
- _session->set_end_is_free (false);
+ _session->set_session_range_is_free (false);
}
}
if (!in_command) {
} else {
- distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
+ distance = get_nudge_distance (playhead_cursor->current_sample (), next_distance);
- if (playhead_cursor->current_frame () > distance) {
- _session->request_locate (playhead_cursor->current_frame () - distance);
+ if (playhead_cursor->current_sample () > distance) {
+ _session->request_locate (playhead_cursor->current_sample () - distance);
} else {
_session->goto_start();
}
begin_reversible_command (_("nudge forward"));
- framepos_t const distance = _session->worst_output_latency();
+ samplepos_t const distance = _session->worst_output_latency();
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
boost::shared_ptr<Region> r ((*i)->region());
begin_reversible_command (_("nudge backward"));
- framepos_t const distance = _session->worst_output_latency();
+ samplepos_t const distance = _session->worst_output_latency();
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
boost::shared_ptr<Region> r ((*i)->region());
void
Editor::sequence_regions ()
{
- framepos_t r_end;
- framepos_t r_end_prev;
+ samplepos_t r_end;
+ samplepos_t r_end_prev;
int iCount=0;
Editor::move_to_end ()
{
- _session->request_locate (_session->current_end_frame());
+ _session->request_locate (_session->current_end_sample());
}
void
Editor::build_region_boundary_cache ()
{
- framepos_t pos = 0;
+
+ /* TODO: maybe set a timer so we don't recalutate when lots of changes are coming in */
+ /* TODO: maybe somehow defer this until session is fully loaded. */
+
+ if (!_region_boundary_cache_dirty)
+ return;
+
+ samplepos_t pos = 0;
vector<RegionPoint> interesting_points;
boost::shared_ptr<Region> r;
TrackViewList tracks;
return;
}
- bool maybe_first_frame = false;
+ bool maybe_first_sample = false;
- switch (_snap_type) {
- case SnapToRegionStart:
+ if (UIConfiguration::instance().get_snap_to_region_start()) {
interesting_points.push_back (Start);
- maybe_first_frame = true;
- break;
- case SnapToRegionEnd:
+ maybe_first_sample = true;
+ }
+
+ if (UIConfiguration::instance().get_snap_to_region_end()) {
interesting_points.push_back (End);
- break;
- case SnapToRegionSync:
+ }
+
+ if (UIConfiguration::instance().get_snap_to_region_sync()) {
interesting_points.push_back (SyncPoint);
- break;
- 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;
- abort(); /*NOTREACHED*/
+ }
+
+ /* if no snap selections are set, boundary cache should be left empty */
+ if ( interesting_points.empty() ) {
+ _region_boundary_cache_dirty = false;
return;
}
TimeAxisView *ontrack = 0;
TrackViewList tlist;
- if (!selection->tracks.empty()) {
- tlist = selection->tracks.filter_to_unique_playlists ();
- } else {
- tlist = track_views.filter_to_unique_playlists ();
- }
+ tlist = track_views.filter_to_unique_playlists ();
- if (maybe_first_frame) {
+ if (maybe_first_sample) {
TrackViewList::const_iterator i;
for (i = tlist.begin(); i != tlist.end(); ++i) {
boost::shared_ptr<Playlist> pl = (*i)->playlist();
}
}
- while (pos < _session->current_end_frame() && !at_end) {
+ //allow regions to snap to the video start (if any) as if it were a "region"
+ if (ARDOUR_UI::instance()->video_timeline) {
+ region_boundary_cache.push_back (ARDOUR_UI::instance()->video_timeline->get_video_start_offset());
+ }
+
+ std::pair<samplepos_t, samplepos_t> ext = session_gui_extents (false);
+ samplepos_t session_end = ext.second;
+
+ while (pos < session_end && !at_end) {
- framepos_t rpos;
- framepos_t lpos = max_framepos;
+ samplepos_t rpos;
+ samplepos_t lpos = session_end;
for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
switch (*p) {
case Start:
- rpos = r->first_frame();
+ rpos = r->first_sample();
break;
case End:
- rpos = r->last_frame();
+ rpos = r->last_sample();
break;
case SyncPoint:
break;
}
- float speed = 1.0f;
- RouteTimeAxisView *rtav;
-
- if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
- if (rtav->track() != 0) {
- speed = rtav->track()->speed();
- }
- }
-
- rpos = track_frame_to_session_frame (rpos, speed);
-
if (rpos < lpos) {
lpos = rpos;
}
to sort later.
*/
- vector<framepos_t>::iterator ri;
+ vector<samplepos_t>::iterator ri;
for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
if (*ri == rpos) {
/* finally sort to be sure that the order is correct */
sort (region_boundary_cache.begin(), region_boundary_cache.end());
+
+ _region_boundary_cache_dirty = false;
}
boost::shared_ptr<Region>
-Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
+Editor::find_next_region (samplepos_t sample, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
{
TrackViewList::iterator i;
- framepos_t closest = max_framepos;
+ samplepos_t closest = max_samplepos;
boost::shared_ptr<Region> ret;
- framepos_t rpos = 0;
+ samplepos_t rpos = 0;
- float track_speed;
- framepos_t track_frame;
- RouteTimeAxisView *rtav;
+ samplepos_t track_sample;
for (i = tracks.begin(); i != tracks.end(); ++i) {
- framecnt_t distance;
+ samplecnt_t distance;
boost::shared_ptr<Region> r;
- track_speed = 1.0f;
- if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
- if (rtav->track()!=0)
- track_speed = rtav->track()->speed();
- }
-
- track_frame = session_frame_to_track_frame(frame, track_speed);
+ track_sample = sample;
- if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
+ if ((r = (*i)->find_next_region (track_sample, point, dir)) == 0) {
continue;
}
switch (point) {
case Start:
- rpos = r->first_frame ();
+ rpos = r->first_sample ();
break;
case End:
- rpos = r->last_frame ();
+ rpos = r->last_sample ();
break;
case SyncPoint:
break;
}
- // rpos is a "track frame", converting it to "_session frame"
- rpos = track_frame_to_session_frame(rpos, track_speed);
-
- if (rpos > frame) {
- distance = rpos - frame;
+ if (rpos > sample) {
+ distance = rpos - sample;
} else {
- distance = frame - rpos;
+ distance = sample - rpos;
}
if (distance < closest) {
return ret;
}
-framepos_t
-Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
+samplepos_t
+Editor::find_next_region_boundary (samplepos_t pos, int32_t dir, const TrackViewList& tracks)
{
- framecnt_t distance = max_framepos;
- framepos_t current_nearest = -1;
+ samplecnt_t distance = max_samplepos;
+ samplepos_t current_nearest = -1;
for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
- framepos_t contender;
- framecnt_t d;
+ samplepos_t contender;
+ samplecnt_t d;
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
return current_nearest;
}
-framepos_t
-Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
+samplepos_t
+Editor::get_region_boundary (samplepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
{
- framepos_t target;
+ samplepos_t target;
TrackViewList tvl;
if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
void
Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
{
- framepos_t pos = playhead_cursor->current_frame ();
- framepos_t target;
+ samplepos_t pos = playhead_cursor->current_sample ();
+ samplepos_t target;
if (!_session) {
return;
Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
{
boost::shared_ptr<Region> r;
- framepos_t pos = cursor->current_frame ();
+ samplepos_t pos = cursor->current_sample ();
if (!_session) {
return;
switch (point) {
case Start:
- pos = r->first_frame ();
+ pos = r->first_sample ();
break;
case End:
- pos = r->last_frame ();
+ pos = r->last_sample ();
break;
case SyncPoint:
break;
}
- float speed = 1.0f;
- RouteTimeAxisView *rtav;
-
- if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
- if (rtav->track() != 0) {
- speed = rtav->track()->speed();
- }
- }
-
- pos = track_frame_to_session_frame(pos, speed);
-
if (cursor == playhead_cursor) {
_session->request_locate (pos);
} else {
void
Editor::cursor_to_selection_start (EditorCursor *cursor)
{
- framepos_t pos = 0;
+ samplepos_t pos = 0;
switch (mouse_mode) {
case MouseObject:
void
Editor::cursor_to_selection_end (EditorCursor *cursor)
{
- framepos_t pos = 0;
+ samplepos_t pos = 0;
switch (mouse_mode) {
case MouseObject:
if (!selection->regions.empty()) {
- pos = selection->regions.end_frame();
+ pos = selection->regions.end_sample();
}
break;
case MouseRange:
if (!selection->time.empty()) {
- pos = selection->time.end_frame ();
+ pos = selection->time.end_sample ();
}
break;
void
Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
{
- framepos_t target;
+ samplepos_t target;
Location* loc;
bool ignored;
}
if (selection->markers.empty()) {
- framepos_t mouse;
+ samplepos_t mouse;
bool ignored;
- if (!mouse_frame (mouse, ignored)) {
+ if (!mouse_sample (mouse, ignored)) {
return;
}
return;
}
- framepos_t pos = loc->start();
+ samplepos_t pos = loc->start();
// so we don't find the current region again..
if (dir > 0 || pos > 0) {
Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
{
boost::shared_ptr<Region> r;
- framepos_t pos;
+ samplepos_t pos;
Location* loc;
bool ignored;
switch (point) {
case Start:
- pos = r->first_frame ();
+ pos = r->first_sample ();
break;
case End:
- pos = r->last_frame ();
+ pos = r->last_sample ();
break;
case SyncPoint:
- pos = r->adjust_to_sync (r->first_frame());
+ pos = r->adjust_to_sync (r->first_sample());
break;
}
- float speed = 1.0f;
- RouteTimeAxisView *rtav;
-
- if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
- if (rtav->track() != 0) {
- speed = rtav->track()->speed();
- }
- }
-
- pos = track_frame_to_session_frame(pos, speed);
-
loc->move_to (pos, 0);
}
void
Editor::selected_marker_to_selection_start ()
{
- framepos_t pos = 0;
+ samplepos_t pos = 0;
Location* loc;
bool ignored;
void
Editor::selected_marker_to_selection_end ()
{
- framepos_t pos = 0;
+ samplepos_t pos = 0;
Location* loc;
bool ignored;
switch (mouse_mode) {
case MouseObject:
if (!selection->regions.empty()) {
- pos = selection->regions.end_frame();
+ pos = selection->regions.end_sample();
}
break;
case MouseRange:
if (!selection->time.empty()) {
- pos = selection->time.end_frame ();
+ pos = selection->time.end_sample ();
}
break;
void
Editor::scroll_playhead (bool forward)
{
- framepos_t pos = playhead_cursor->current_frame ();
- framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
+ samplepos_t pos = playhead_cursor->current_sample ();
+ samplecnt_t delta = (samplecnt_t) floor (current_page_samples() / 0.8);
if (forward) {
- if (pos == max_framepos) {
+ if (pos == max_samplepos) {
return;
}
- if (pos < max_framepos - delta) {
+ if (pos < max_samplepos - delta) {
pos += delta ;
} else {
- pos = max_framepos;
+ pos = max_samplepos;
}
} else {
Location* loc = find_location_from_marker (*i, ignored);
if (loc->is_mark()) {
- loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
+ loc->set_start (playhead_cursor->current_sample (), false, true, divisions);
} else {
- loc->set (playhead_cursor->current_frame (),
- playhead_cursor->current_frame () + loc->length(), true, divisions);
+ loc->set (playhead_cursor->current_sample (),
+ playhead_cursor->current_sample () + loc->length(), true, divisions);
}
}
}
void
Editor::scroll_backward (float pages)
{
- framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
- framepos_t const cnt = (framepos_t) floor (pages * one_page);
+ samplepos_t const one_page = (samplepos_t) rint (_visible_canvas_width * samples_per_pixel);
+ samplepos_t const cnt = (samplepos_t) floor (pages * one_page);
- framepos_t frame;
- if (leftmost_frame < cnt) {
- frame = 0;
+ samplepos_t sample;
+ if (_leftmost_sample < cnt) {
+ sample = 0;
} else {
- frame = leftmost_frame - cnt;
+ sample = _leftmost_sample - cnt;
}
- reset_x_origin (frame);
+ reset_x_origin (sample);
}
void
Editor::scroll_forward (float pages)
{
- framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
- framepos_t const cnt = (framepos_t) floor (pages * one_page);
+ samplepos_t const one_page = (samplepos_t) rint (_visible_canvas_width * samples_per_pixel);
+ samplepos_t const cnt = (samplepos_t) floor (pages * one_page);
- framepos_t frame;
- if (max_framepos - cnt < leftmost_frame) {
- frame = max_framepos - cnt;
+ samplepos_t sample;
+ if (max_samplepos - cnt < _leftmost_sample) {
+ sample = max_samplepos - cnt;
} else {
- frame = leftmost_frame + cnt;
+ sample = _leftmost_sample + cnt;
}
- reset_x_origin (frame);
+ reset_x_origin (sample);
}
void
void
Editor::scroll_left_step ()
{
- framepos_t xdelta = (current_page_samples() / 8);
+ samplepos_t xdelta = (current_page_samples() / 8);
- if (leftmost_frame > xdelta) {
- reset_x_origin (leftmost_frame - xdelta);
+ if (_leftmost_sample > xdelta) {
+ reset_x_origin (_leftmost_sample - xdelta);
} else {
reset_x_origin (0);
}
void
Editor::scroll_right_step ()
{
- framepos_t xdelta = (current_page_samples() / 8);
+ samplepos_t xdelta = (current_page_samples() / 8);
- if (max_framepos - xdelta > leftmost_frame) {
- reset_x_origin (leftmost_frame + xdelta);
+ if (max_samplepos - xdelta > _leftmost_sample) {
+ reset_x_origin (_leftmost_sample + xdelta);
} else {
- reset_x_origin (max_framepos - current_page_samples());
+ reset_x_origin (max_samplepos - current_page_samples());
}
}
void
Editor::scroll_left_half_page ()
{
- framepos_t xdelta = (current_page_samples() / 2);
- if (leftmost_frame > xdelta) {
- reset_x_origin (leftmost_frame - xdelta);
+ samplepos_t xdelta = (current_page_samples() / 2);
+ if (_leftmost_sample > xdelta) {
+ reset_x_origin (_leftmost_sample - xdelta);
} else {
reset_x_origin (0);
}
void
Editor::scroll_right_half_page ()
{
- framepos_t xdelta = (current_page_samples() / 2);
- if (max_framepos - xdelta > leftmost_frame) {
- reset_x_origin (leftmost_frame + xdelta);
+ samplepos_t xdelta = (current_page_samples() / 2);
+ if (max_samplepos - xdelta > _leftmost_sample) {
+ reset_x_origin (_leftmost_sample + xdelta);
} else {
- reset_x_origin (max_framepos - current_page_samples());
+ reset_x_origin (max_samplepos - current_page_samples());
}
}
{
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
- framecnt_t nspp = samples_per_pixel;
+ samplecnt_t nspp = samples_per_pixel;
if (zoom_out) {
nspp *= 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<RouteList> rl = _session->get_routes();
- for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
- boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*r);
- if (tr) {
- boost::shared_ptr<Playlist> pl = tr->playlist();
- if (pl) {
- pair<framepos_t, framepos_t> 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;
- }
+ //zoom-behavior-tweaks
+ //limit our maximum zoom to the session gui extents value
+ std::pair<samplepos_t, samplepos_t> ext = session_gui_extents();
+ samplecnt_t session_extents_pp = (ext.second - ext.first) / _visible_canvas_width;
+ if (nspp > session_extents_pp)
+ nspp = session_extents_pp;
temporal_zoom (nspp);
}
void
-Editor::temporal_zoom (framecnt_t fpp)
+Editor::temporal_zoom (samplecnt_t fpp)
{
if (!_session) {
return;
}
- framepos_t current_page = current_page_samples();
- framepos_t current_leftmost = leftmost_frame;
- framepos_t current_rightmost;
- framepos_t current_center;
- framepos_t new_page_size;
- framepos_t half_page_size;
- framepos_t leftmost_after_zoom = 0;
- framepos_t where;
+ samplepos_t current_page = current_page_samples();
+ samplepos_t current_leftmost = _leftmost_sample;
+ samplepos_t current_rightmost;
+ samplepos_t current_center;
+ samplepos_t new_page_size;
+ samplepos_t half_page_size;
+ samplepos_t leftmost_after_zoom = 0;
+ samplepos_t where;
bool in_track_canvas;
- bool use_mouse_frame = true;
- framecnt_t nfpp;
+ bool use_mouse_sample = true;
+ samplecnt_t nfpp;
double l;
if (fpp == samples_per_pixel) {
// all of which is used for the editor track displays. The whole day
// would be 4147200000 samples, so 2592000 samples per pixel.
- nfpp = min (fpp, (framecnt_t) 2592000);
- nfpp = max ((framecnt_t) 1, nfpp);
+ nfpp = min (fpp, (samplecnt_t) 2592000);
+ nfpp = max ((samplecnt_t) 1, nfpp);
- new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
+ new_page_size = (samplepos_t) floor (_visible_canvas_width * nfpp);
half_page_size = new_page_size / 2;
- switch (zoom_focus) {
+ Editing::ZoomFocus zf = zoom_focus;
+
+ if (zf == ZoomFocusEdit && _edit_point == EditAtMouse) {
+ zf = ZoomFocusMouse;
+ }
+
+ switch (zf) {
case ZoomFocusLeft:
leftmost_after_zoom = current_leftmost;
break;
case ZoomFocusRight:
- current_rightmost = leftmost_frame + current_page;
+ current_rightmost = _leftmost_sample + current_page;
if (current_rightmost < new_page_size) {
leftmost_after_zoom = 0;
} else {
case ZoomFocusPlayhead:
/* centre playhead */
- l = playhead_cursor->current_frame () - (new_page_size * 0.5);
+ l = playhead_cursor->current_sample () - (new_page_size * 0.5);
if (l < 0) {
leftmost_after_zoom = 0;
- } else if (l > max_framepos) {
- leftmost_after_zoom = max_framepos - new_page_size;
+ } else if (l > max_samplepos) {
+ leftmost_after_zoom = max_samplepos - new_page_size;
} else {
- leftmost_after_zoom = (framepos_t) l;
+ leftmost_after_zoom = (samplepos_t) l;
}
break;
/* try to keep the mouse over the same point in the display */
if (_drags->active()) {
- where = _drags->current_pointer_frame ();
- } else if (!mouse_frame (where, in_track_canvas)) {
- use_mouse_frame = false;
+ where = _drags->current_pointer_sample ();
+ } else if (!mouse_sample (where, in_track_canvas)) {
+ use_mouse_sample = false;
}
- if (use_mouse_frame) {
+ if (use_mouse_sample) {
l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
if (l < 0) {
leftmost_after_zoom = 0;
- } else if (l > max_framepos) {
- leftmost_after_zoom = max_framepos - new_page_size;
+ } else if (l > max_samplepos) {
+ leftmost_after_zoom = max_samplepos - new_page_size;
} else {
- leftmost_after_zoom = (framepos_t) l;
+ leftmost_after_zoom = (samplepos_t) l;
}
} else {
/* use playhead instead */
- where = playhead_cursor->current_frame ();
+ where = playhead_cursor->current_sample ();
if (where < half_page_size) {
leftmost_after_zoom = 0;
case ZoomFocusEdit:
/* try to keep the edit point in the same place */
where = get_preferred_edit_position ();
-
- if (where > 0) {
-
+ {
double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
if (l < 0) {
leftmost_after_zoom = 0;
- } else if (l > max_framepos) {
- leftmost_after_zoom = max_framepos - new_page_size;
+ } else if (l > max_samplepos) {
+ leftmost_after_zoom = max_samplepos - new_page_size;
} else {
- leftmost_after_zoom = (framepos_t) l;
+ leftmost_after_zoom = (samplepos_t) l;
}
-
- } else {
- /* edit point not defined */
- return;
}
break;
}
- // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
+ // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_sample());
reposition_and_zoom (leftmost_after_zoom, nfpp);
}
void
-Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
+Editor::calc_extra_zoom_edges(samplepos_t &start, samplepos_t &end)
{
/* this func helps make sure we leave a little space
at each end of the editor so that the zoom doesn't fit the region
const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
const double one_centimeter_in_pixels = pix_per_mm * 10.0;
- const framepos_t range = end - start;
- const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
- const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
+ const samplepos_t range = end - start;
+ const samplecnt_t new_fpp = (samplecnt_t) ceil ((double) range / (double) _visible_canvas_width);
+ const samplepos_t extra_samples = (samplepos_t) floor (one_centimeter_in_pixels * new_fpp);
if (start > extra_samples) {
start -= extra_samples;
start = 0;
}
- if (max_framepos - extra_samples > end) {
+ if (max_samplepos - extra_samples > end) {
end += extra_samples;
} else {
- end = max_framepos;
+ end = max_samplepos;
}
}
bool
-Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
+Editor::get_selection_extents (samplepos_t &start, samplepos_t &end) const
{
- start = max_framepos;
+ start = max_samplepos;
end = 0;
bool ret = true;
//ToDo: if control points are selected, set extents to that selection
- if ( !selection->regions.empty() ) {
+ if (!selection->regions.empty()) {
RegionSelection rs = get_regions_from_selection_and_entered ();
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
start = (*i)->region()->position();
}
- if ((*i)->region()->last_frame() + 1 > end) {
- end = (*i)->region()->last_frame() + 1;
+ if ((*i)->region()->last_sample() + 1 > end) {
+ end = (*i)->region()->last_sample() + 1;
}
}
} else if (!selection->time.empty()) {
start = selection->time.start();
- end = selection->time.end_frame();
+ end = selection->time.end_sample();
} else
ret = false; //no selection found
{
if (!selection) return;
+ if (selection->regions.empty() && selection->time.empty()) {
+ if (axes == Horizontal || axes == Both) {
+ temporal_zoom_step(true);
+ }
+ if (axes == Vertical || axes == Both) {
+ if (!track_views.empty()) {
+
+ TrackViewList tvl;
+
+ //implicit hack: by extending the top & bottom check outside the current view limits, we include the trackviews immediately above & below what is visible
+ const double top = vertical_adjustment.get_value() - 10;
+ const double btm = top + _visible_canvas_height + 10;
+
+ for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
+ if ((*iter)->covered_by_y_range (top, btm)) {
+ tvl.push_back(*iter);
+ }
+ }
+
+ fit_tracks (tvl);
+ }
+ }
+ return;
+ }
+
//ToDo: if notes are selected, zoom to that
//ToDo: if control points are selected, zoom to that
if (axes == Horizontal || axes == Both) {
- framepos_t start, end;
+ samplepos_t start, end;
if (get_selection_extents (start, end)) {
calc_extra_zoom_edges (start, end);
- temporal_zoom_by_frame (start, end);
+ temporal_zoom_by_sample (start, end);
}
}
if (axes == Vertical || axes == Both) {
fit_selection ();
}
+
+ //normally, we don't do anything "automatic" to the user's selection.
+ //but in this case, we will clear the selection after a zoom-to-selection.
+ selection->clear();
}
void
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
if (_session) {
- framecnt_t start = _session->current_start_frame();
- framecnt_t end = _session->current_end_frame();
+ samplecnt_t start = _session->current_start_sample();
+ samplecnt_t end = _session->current_end_sample();
+
+ if (_session->actively_recording ()) {
+ samplepos_t cur = playhead_cursor->current_sample ();
+ if (cur > end) {
+ /* recording beyond the end marker; zoom out
+ * by 5 seconds more so that if 'follow
+ * playhead' is active we don't immediately
+ * scroll.
+ */
+ end = cur + _session->sample_rate() * 5;
+ }
+ }
+
+ if ((start == 0 && end == 0) || end < start) {
+ return;
+ }
+
+ calc_extra_zoom_edges(start, end);
+
+ temporal_zoom_by_sample (start, end);
+ }
+}
+
+void
+Editor::temporal_zoom_extents ()
+{
+ ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_extents)
+
+ if (_session) {
+ std::pair<samplepos_t, samplepos_t> ext = session_gui_extents (false); //in this case we want to zoom to the extents explicitly; ignore the users prefs for extra padding
+
+ samplecnt_t start = ext.first;
+ samplecnt_t end = ext.second;
- if (_session->actively_recording () ) {
- framepos_t cur = playhead_cursor->current_frame ();
+ if (_session->actively_recording ()) {
+ samplepos_t cur = playhead_cursor->current_sample ();
if (cur > end) {
/* recording beyond the end marker; zoom out
* by 5 seconds more so that if 'follow
* playhead' is active we don't immediately
* scroll.
*/
- end = cur + _session->frame_rate() * 5;
+ end = cur + _session->sample_rate() * 5;
}
}
calc_extra_zoom_edges(start, end);
- temporal_zoom_by_frame (start, end);
+ temporal_zoom_by_sample (start, end);
}
}
void
-Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
+Editor::temporal_zoom_by_sample (samplepos_t start, samplepos_t end)
{
if (!_session) return;
return;
}
- framepos_t range = end - start;
+ samplepos_t range = end - start;
- const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
+ const samplecnt_t new_fpp = (samplecnt_t) ceil ((double) range / (double) _visible_canvas_width);
- framepos_t new_page = range;
- framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
- framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
+ samplepos_t new_page = range;
+ samplepos_t middle = (samplepos_t) floor ((double) start + ((double) range / 2.0f));
+ samplepos_t new_leftmost = (samplepos_t) floor ((double) middle - ((double) new_page / 2.0f));
if (new_leftmost > middle) {
new_leftmost = 0;
}
void
-Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
+Editor::temporal_zoom_to_sample (bool coarser, samplepos_t sample)
{
if (!_session) {
return;
}
- framecnt_t range_before = frame - leftmost_frame;
- framecnt_t new_spp;
+ samplecnt_t range_before = sample - _leftmost_sample;
+ samplecnt_t new_spp;
if (coarser) {
if (samples_per_pixel <= 1) {
return;
}
- /* zoom focus is automatically taken as @param frame when this
+ /* zoom focus is automatically taken as @param sample when this
method is used.
*/
- framepos_t new_leftmost = frame - (framepos_t)range_before;
+ samplepos_t new_leftmost = sample - (samplepos_t)range_before;
- if (new_leftmost > frame) {
+ if (new_leftmost > sample) {
new_leftmost = 0;
}
bool
-Editor::choose_new_marker_name(string &name) {
+Editor::choose_new_marker_name(string &name, bool is_range) {
if (!UIConfiguration::instance().get_name_new_markers()) {
/* don't prompt user for a new name */
dialog.set_prompt (_("New Name:"));
- dialog.set_title (_("New Location Marker"));
+ if (is_range) {
+ dialog.set_title(_("New Range"));
+ } else {
+ dialog.set_title (_("New Location Marker"));
+ }
dialog.set_name ("MarkNameWindow");
dialog.set_size_request (250, -1);
return;
}
- framepos_t start = selection->time[clicked_selection].start;
- framepos_t end = selection->time[clicked_selection].end;
+ samplepos_t start = selection->time[clicked_selection].start;
+ samplepos_t end = selection->time[clicked_selection].end;
_session->locations()->next_available_name(rangename,"selection");
+ if (!choose_new_marker_name(rangename, true)) {
+ return;
+ }
Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
begin_reversible_command (_("add marker"));
}
void
-Editor::add_location_mark (framepos_t where)
+Editor::add_location_mark (samplepos_t where)
{
string markername;
Location* loc;
if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
- _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
+ _session->set_session_extents (_session->audible_sample(), _session->audible_sample());
} else {
XMLNode &before = loc->get_state();
- _session->set_session_extents ( _session->audible_frame(), loc->end() );
+ _session->set_session_extents (_session->audible_sample(), loc->end());
XMLNode &after = loc->get_state();
commit_reversible_command ();
}
+
+ _session->set_session_range_is_free (false);
}
void
Location* loc;
if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
- _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
+ _session->set_session_extents (_session->audible_sample(), _session->audible_sample());
} else {
XMLNode &before = loc->get_state();
- _session->set_session_extents ( loc->start(), _session->audible_frame() );
+ _session->set_session_extents (loc->start(), _session->audible_sample());
XMLNode &after = loc->get_state();
commit_reversible_command ();
}
- _session->set_end_is_free (false);
+ _session->set_session_range_is_free (false);
}
void
Editor::add_location_from_playhead_cursor ()
{
- add_location_mark (_session->audible_frame());
+ add_location_mark (_session->audible_sample());
}
bool
//find location(s) at this time
Locations::LocationList locs;
- _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
+ _session->locations()->find_all_between (_session->audible_sample(), _session->audible_sample()+1, locs, Location::Flags(0));
for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
if ((*i)->is_mark()) {
_session->locations()->remove (*i);
boost::shared_ptr<Region> region = (*i)->region ();
- Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
+ Location *location = new Location (*_session, region->position(), region->last_sample(), region->name(), Location::IsRangeMarker, 0);
_session->locations()->add (location, true);
commit = true;
}
// single range spanning all selected
- Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
+ Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_sample(), markername, Location::IsRangeMarker, 0);
_session->locations()->add (location, true);
begin_reversible_command (_("add marker"));
return;
}
- framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
+ samplepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_sample());
if (pos < 0) {
return;
return;
}
- framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
+ samplepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_sample());
//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 );
+ if (_session->transport_rolling()) {
+ if ((playhead_cursor->current_sample() - pos) < _session->sample_rate()/2) {
+ samplepos_t prior = _session->locations()->first_mark_before (pos);
pos = prior;
}
}
void
Editor::set_mark ()
{
- framepos_t const pos = _session->audible_frame ();
+ samplepos_t const pos = _session->audible_sample ();
string markername;
_session->locations()->next_available_name (markername, "mark");
/* INSERT/REPLACE */
void
-Editor::insert_region_list_selection (float times)
+Editor::insert_source_list_selection (float times)
{
RouteTimeAxisView *tv = 0;
boost::shared_ptr<Playlist> playlist;
return;
}
- boost::shared_ptr<Region> region = _regions->get_single_selection ();
+ boost::shared_ptr<Region> region = _sources->get_single_selection ();
if (region == 0) {
return;
}
}
if (_session->config.get_external_sync()) {
- switch (Config->get_sync_source()) {
+ switch (TransportMasterManager::instance().current()->type()) {
case Engine:
break;
default:
void
Editor::play_from_start ()
{
- _session->request_locate (_session->current_start_frame(), true);
+ _session->request_locate (_session->current_start_sample(), true);
}
void
void
Editor::play_from_edit_point_and_return ()
{
- framepos_t start_frame;
- framepos_t return_frame;
+ samplepos_t start_sample;
+ samplepos_t return_sample;
- start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
+ start_sample = get_preferred_edit_position (EDIT_IGNORE_PHEAD);
if (_session->transport_rolling()) {
- _session->request_locate (start_frame, false);
+ _session->request_locate (start_sample, false);
return;
}
- /* don't reset the return frame if its already set */
+ /* don't reset the return sample if its already set */
- if ((return_frame = _session->requested_return_frame()) < 0) {
- return_frame = _session->audible_frame();
+ if ((return_sample = _session->requested_return_sample()) < 0) {
+ return_sample = _session->audible_sample();
}
- if (start_frame >= 0) {
- _session->request_roll_at_and_return (start_frame, return_frame);
+ if (start_sample >= 0) {
+ _session->request_roll_at_and_return (start_sample, return_sample);
}
}
void
Editor::play_selection ()
{
- framepos_t start, end;
- if (!get_selection_extents ( start, end))
+ samplepos_t start, end;
+ if (!get_selection_extents (start, end))
return;
AudioRange ar (start, end, 0);
void
-Editor::maybe_locate_with_edit_preroll (framepos_t location)
+Editor::maybe_locate_with_edit_preroll (samplepos_t location)
{
- if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
+ if (_session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync())
return;
location -= _session->preroll_samples (location);
}
//if follow_playhead is on, keep the playhead on the screen
- if ( _follow_playhead )
- if ( location < leftmost_frame )
- location = leftmost_frame;
+ if (_follow_playhead)
+ if (location < _leftmost_sample)
+ location = _leftmost_sample;
- _session->request_locate( location );
+ _session->request_locate (location);
}
void
Editor::play_with_preroll ()
{
- framepos_t start, end;
- if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
- const framepos_t preroll = _session->preroll_samples (start);
+ samplepos_t start, end;
+ if (UIConfiguration::instance().get_follow_edits() && get_selection_extents (start, end)) {
+ const samplepos_t preroll = _session->preroll_samples (start);
- framepos_t ret = start;
+ samplepos_t ret = start;
if (start > preroll) {
start = start - 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
+ _session->set_requested_return_sample (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;
+ samplepos_t ph = playhead_cursor->current_sample ();
+ const samplepos_t preroll = _session->preroll_samples (ph);
+ samplepos_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
+ _session->set_requested_return_sample (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);
+ samplepos_t ph = playhead_cursor->current_sample ();
+ samplepos_t preroll = _session->preroll_samples (ph);
_session->request_preroll_record_trim (ph, preroll);
}
void
Editor::play_edit_range ()
{
- framepos_t start, end;
+ samplepos_t start, end;
if (get_edit_op_range (start, end)) {
_session->request_bounded_roll (start, end);
void
Editor::play_selected_region ()
{
- framepos_t start = max_framepos;
- framepos_t end = 0;
+ samplepos_t start = max_samplepos;
+ samplepos_t end = 0;
RegionSelection rs = get_regions_from_selection_and_entered ();
if ((*i)->region()->position() < start) {
start = (*i)->region()->position();
}
- if ((*i)->region()->last_frame() + 1 > end) {
- end = (*i)->region()->last_frame() + 1;
+ if ((*i)->region()->last_sample() + 1 > end) {
+ end = (*i)->region()->last_sample() + 1;
}
}
return;
}
- framepos_t start = selection->time[clicked_selection].start;
- framepos_t end = selection->time[clicked_selection].end;
+ samplepos_t start = selection->time[clicked_selection].start;
+ samplepos_t end = selection->time[clicked_selection].end;
TrackViewList tracks = get_tracks_for_range_action ();
- framepos_t selection_cnt = end - start + 1;
+ samplepos_t selection_cnt = end - start + 1;
for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
boost::shared_ptr<Region> current;
boost::shared_ptr<Playlist> pl;
- framepos_t internal_start;
+ samplepos_t internal_start;
string new_name;
if ((pl = (*i)->playlist()) == 0) {
return;
}
- framepos_t start, end;
+ samplepos_t start, end;
if (clicked_selection) {
start = selection->time[clicked_selection].start;
end = selection->time[clicked_selection].end;
} else {
start = selection->time.start();
- end = selection->time.end_frame();
+ end = selection->time.end_sample();
}
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
boost::shared_ptr<Region> current;
boost::shared_ptr<Playlist> playlist;
- framepos_t internal_start;
+ samplepos_t internal_start;
string new_name;
if ((playlist = (*i)->playlist()) == 0) {
vector< boost::shared_ptr<Region> > v;
for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
- (*x)->region()->separate_by_channel (*_session, v);
+ (*x)->region()->separate_by_channel (v);
}
}
/* XXX need to consider musical time selections here at some point */
- double speed = rtv->track()->speed();
-
for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
sigc::connection c = rtv->view()->RegionViewAdded.connect (
latest_regionviews.clear ();
- playlist->partition ((framepos_t)((*t).start * speed),
- (framepos_t)((*t).end * speed), false);
+ playlist->partition ((*t).start, (*t).end, false);
c.disconnect ();
}
}
- if (in_command) {
-// selection->set (new_selection);
+ if (in_command) {
+
+ RangeSelectionAfterSplit rsas = Config->get_range_selection_after_split();
+
+ //if our config preference says to clear the selection, clear the Range selection
+ if (rsas == ClearSel) {
+ selection->clear_time();
+ //but leave track selection intact
+ } else if (rsas == ForceSel) {
+ //note: forcing the regions to be selected *might* force a tool-change to Object here
+ selection->set(new_selection);
+ }
commit_reversible_command ();
}
} else {
- framepos_t start;
- framepos_t end;
+ samplepos_t start;
+ samplepos_t end;
if (get_edit_op_range (start, end)) {
}
//Partition on the region bounds
- playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
+ playlist->partition ((*rl)->first_sample() - 1, (*rl)->last_sample() + 1, true);
//Re-add region that was just removed due to the partition operation
- playlist->add_region( (*rl), (*rl)->first_frame() );
+ playlist->add_region ((*rl), (*rl)->first_sample());
}
vector<PlaylistState>::iterator pl;
commit_reversible_command();
} else {
- framepos_t start;
- framepos_t end;
+ samplepos_t start;
+ samplepos_t end;
if (get_edit_op_range (start, end)) {
begin_reversible_command (_("Crop Regions to Edit Range"));
}
void
-Editor::crop_region_to (framepos_t start, framepos_t end)
+Editor::crop_region_to (samplepos_t start, samplepos_t end)
{
vector<boost::shared_ptr<Playlist> > playlists;
boost::shared_ptr<Playlist> playlist;
return;
}
- framepos_t pos;
- framepos_t new_start;
- framepos_t new_end;
- framecnt_t new_length;
+ samplepos_t pos;
+ samplepos_t new_start;
+ samplepos_t new_end;
+ samplecnt_t new_length;
for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
pos = (*i)->position();
new_start = max (start, pos);
- if (max_framepos - pos > (*i)->length()) {
+ if (max_samplepos - pos > (*i)->length()) {
new_end = pos + (*i)->length() - 1;
} else {
- new_end = max_framepos;
+ new_end = max_samplepos;
}
new_end = min (end, new_end);
new_length = new_end - new_start + 1;
RegionSelection regions = get_regions_from_selection_and_entered ();
RegionSelection foo;
- framepos_t const end = _session->current_end_frame ();
+ samplepos_t const end = _session->current_end_sample ();
- if (regions.empty () || regions.end_frame () + 1 >= end) {
+ if (regions.empty () || regions.end_sample () + 1 >= end) {
return;
}
- framepos_t const start_frame = regions.start ();
- framepos_t const end_frame = regions.end_frame ();
- framecnt_t const gap = end_frame - start_frame + 1;
+ samplepos_t const start_sample = regions.start ();
+ samplepos_t const end_sample = regions.end_sample ();
+ samplecnt_t const gap = end_sample - start_sample + 1;
begin_reversible_command (Operations::region_fill);
latest_regionviews.clear ();
sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
- framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
+ samplepos_t const position = end_sample + (r->first_sample() - start_sample + 1);
playlist = (*i)->region()->playlist();
playlist->clear_changes ();
playlist->duplicate_until (r, position, gap, end);
}
void
-Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
+Editor::set_sync_point (samplepos_t where, const RegionSelection& rs)
{
bool in_command = false;
begin_reversible_command (_("align selection"));
- framepos_t const position = get_preferred_edit_position ();
+ samplepos_t const position = get_preferred_edit_position ();
for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
align_region_internal ((*i)->region(), what, position);
return;
}
- framepos_t const position = get_preferred_edit_position ();
+ samplepos_t const position = get_preferred_edit_position ();
- framepos_t distance = 0;
- framepos_t pos = 0;
+ samplepos_t distance = 0;
+ samplepos_t pos = 0;
int dir = 1;
list<RegionView*> sorted;
break;
case End:
- if (position > r->last_frame()) {
- distance = position - r->last_frame();
+ if (position > r->last_sample()) {
+ distance = position - r->last_sample();
pos = r->position() + distance;
} else {
- distance = r->last_frame() - position;
+ distance = r->last_sample() - position;
pos = r->position() - distance;
dir = -1;
}
}
void
-Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
+Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, samplepos_t position)
{
begin_reversible_command (_("align region"));
align_region_internal (region, point, position);
}
void
-Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
+Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, samplepos_t position)
{
region->clear_changes ();
void
Editor::trim_region (bool front)
{
- framepos_t where = get_preferred_edit_position();
+ samplepos_t where = get_preferred_edit_position();
RegionSelection rs = get_regions_from_selection_and_edit_point ();
if (rs.empty()) {
return;
}
- float speed = 1.0;
- framepos_t start;
- framepos_t end;
-
- if (tav->track() != 0) {
- speed = tav->track()->speed();
- }
+ samplepos_t start;
+ samplepos_t end;
- start = session_frame_to_track_frame (loc.start(), speed);
- end = session_frame_to_track_frame (loc.end(), speed);
+ start = loc.start();
+ end = loc.end();
rv->region()->clear_changes ();
rv->region()->trim_to (start, (end - start));
continue;
}
- float speed = 1.0;
-
- if (atav->track() != 0) {
- speed = atav->track()->speed();
- }
-
-
boost::shared_ptr<Region> region = arv->region();
boost::shared_ptr<Playlist> playlist (region->playlist());
if (forward) {
- next_region = playlist->find_next_region (region->first_frame(), Start, 1);
+ next_region = playlist->find_next_region (region->first_sample(), Start, 1);
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 (next_region->first_sample() - 1);
+ 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_sample(), Start, 0);
- if(!next_region){
+ if (!next_region) {
continue;
}
- region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
-
+ region->trim_front (next_region->last_sample() + 1);
arv->region_changed (ARDOUR::bounds_change);
}
}
if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
- MessageDialog d (
+ ArdourMessageDialog d (
_("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
"This is typically caused by plugins that generate stereo output from mono input or vice versa.")
);
}
if (clicked_routeview->track()->has_external_redirects()) {
- MessageDialog d (string_compose (_("<b>%1</b>\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);
+ ArdourMessageDialog d (string_compose (_("<b>%1</b>\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);
d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
- MessageDialog d (
+ ArdourMessageDialog d (
_("You can't perform this operation because the processing of the signal "
"will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
"You can do this without processing, which is a different operation.")
}
}
- framepos_t start = selection->time[clicked_selection].start;
- framepos_t end = selection->time[clicked_selection].end;
- framepos_t cnt = end - start + 1;
+ samplepos_t start = selection->time[clicked_selection].start;
+ samplepos_t end = selection->time[clicked_selection].end;
+ samplepos_t cnt = end - start + 1;
bool in_command = false;
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
//special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
//we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
bool deleted = false;
- if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
+ if (current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip())
deleted = current_mixer_strip->delete_processors ();
if (!deleted)
}
}
- if ( op != Delete ) { //"Delete" doesn't change copy/paste buf
+ if (op != Delete) { //"Delete" doesn't change copy/paste buf
cut_buffer->clear ();
}
}
}
} else if (selection->time.empty()) {
- framepos_t start, end;
+ samplepos_t start, end;
/* no time selection, see if we can get an edit range
and use that.
*/
if (did_edit) {
/* reset repeated paste state */
paste_count = 0;
- last_paste_pos = 0;
+ last_paste_pos = -1;
commit_reversible_command ();
}
* @param op Operation (Cut, Copy or Clear)
*/
void
-Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
+Editor::cut_copy_points (Editing::CutCopyOp op, Temporal::Beats earliest, bool midi)
{
if (selection->points.empty ()) {
return;
}
/* Add all selected points to the relevant copy ControlLists */
- MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
+ MusicSample start (std::numeric_limits<samplepos_t>::max(), 0);
for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
if (midi) {
/* Update earliest MIDI start time in beats */
- earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
+ earliest = std::min(earliest, Temporal::Beats((*ctrl_evt)->when));
} else {
- /* Update earliest session start time in frames */
- start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
+ /* Update earliest session start time in samples */
+ start.sample = std::min(start.sample, (*sel_point)->line().session_position(ctrl_evt));
}
}
/* Snap start time backwards, so copy/paste is snap aligned. */
if (midi) {
- if (earliest == Evoral::Beats::max()) {
- earliest = Evoral::Beats(); // Weird... don't offset
+ if (earliest == std::numeric_limits<Temporal::Beats>::max()) {
+ earliest = Temporal::Beats(); // Weird... don't offset
}
earliest.round_down_to_beat();
} else {
- if (start.frame == std::numeric_limits<double>::max()) {
- start.frame = 0; // Weird... don't offset
+ if (start.sample == std::numeric_limits<double>::max()) {
+ start.sample = 0; // Weird... don't offset
}
snap_to(start, RoundDownMaybe);
}
- const double line_offset = midi ? earliest.to_double() : start.frame;
+ const double line_offset = midi ? earliest.to_double() : start.sample;
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
void
Editor::cut_copy_midi (CutCopyOp op)
{
- Evoral::Beats earliest = Evoral::Beats::max();
+ Temporal::Beats earliest = std::numeric_limits<Temporal::Beats>::max();
for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
if (mrv) {
begin_reversible_command (_("remove region"));
boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
+ boost::shared_ptr<Region> region = clicked_regionview->region();
playlist->clear_changes ();
playlist->clear_owned_changes ();
- playlist->remove_region (clicked_regionview->region());
- if (Config->get_edit_mode() == Ripple)
- playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
+ playlist->remove_region (region);
+
+ if (Config->get_edit_mode() == Ripple) {
+ playlist->ripple (region->position(), - region->length(), boost::shared_ptr<Region>());
+ }
/* We might have removed regions, which alters other regions' layering_index,
so we need to do a recursive diff here.
}
+void
+Editor::recover_regions (ARDOUR::RegionList regions)
+{
+#ifdef RECOVER_REGIONS_IS_WORKING
+ begin_reversible_command (_("recover regions"));
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+ boost::shared_ptr<ARDOUR::Source> source = (*i)->source();
+
+ RouteList routes = _session->get_routelist();
+ for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
+ boost::shared_ptr<ARDOUR::Track> track = boost::dynamic_pointer_cast<Track>(*it);
+ if (track) {
+ //ToDo
+ if (source->captured_for() == track->) {
+ //_session->add_command(new StatefulDiffCommand (playlist));
+ }
+ }
+ }
+ }
+
+ commit_reversible_command ();
+#endif
+}
+
+
/** Remove the selected regions */
void
Editor::remove_selected_regions ()
vector<PlaylistMapping> pmap;
- framepos_t first_position = max_framepos;
+ samplepos_t first_position = max_samplepos;
typedef set<boost::shared_ptr<Playlist> > FreezeList;
FreezeList freezelist;
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
- first_position = min ((framepos_t) (*x)->region()->position(), first_position);
+ first_position = min ((samplepos_t) (*x)->region()->position(), first_position);
if (op == Cut || op == Clear || op == Delete) {
boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
Editor::paste (float times, bool from_context)
{
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);
+ MusicSample where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
+ paste_internal (where.sample, times, 0);
}
void
Editor::mouse_paste ()
{
- MusicFrame where (0, 0);
+ MusicSample where (0, 0);
bool ignored;
- if (!mouse_frame (where.frame, ignored)) {
+ if (!mouse_sample (where.sample, ignored)) {
return;
}
snap_to (where);
- paste_internal (where.frame, 1, where.division);
+ paste_internal (where.sample, 1, where.division);
}
void
-Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
+Editor::paste_internal (samplepos_t position, float times, const int32_t sub_num)
{
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
return;
}
- if (position == max_framepos) {
+ if (position == max_samplepos) {
position = get_preferred_edit_position();
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
}
- if (position == last_paste_pos) {
- /* repeated paste in the same position */
- ++paste_count;
- } else {
+ if (position != last_paste_pos) {
/* paste in new location, reset repeated paste state */
paste_count = 0;
last_paste_pos = position;
}
}
+ ++paste_count;
+
commit_reversible_command ();
}
}
boost::shared_ptr<Playlist> playlist;
+ std::set<boost::shared_ptr<Playlist> > playlists; // list of unique playlists affected by duplication
RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
RegionSelection foo;
- framepos_t const start_frame = regions.start ();
- framepos_t const end_frame = regions.end_frame ();
- framecnt_t const gap = end_frame - start_frame + 1;
+ samplepos_t const start_sample = regions.start ();
+ samplepos_t const end_sample = regions.end_sample ();
+ samplecnt_t const span = end_sample - start_sample + 1;
begin_reversible_command (Operations::duplicate_region);
selection->clear_regions ();
+ /* ripple first so that we don't move the duplicates that will be added */
+
+ if (Config->get_edit_mode() == Ripple) {
+
+ /* convert RegionSelection into RegionList so that we can pass it to ripple and exclude the regions we will duplicate */
+
+ RegionList exclude;
+
+ for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
+ exclude.push_back ((*i)->region());
+ playlist = (*i)->region()->playlist();
+ if (playlists.insert (playlist).second) {
+ /* successfully inserted into set, so it's the first time we've seen this playlist */
+ playlist->clear_changes ();
+ }
+ }
+
+ for (set<boost::shared_ptr<Playlist> >::iterator p = playlists.begin(); p != playlists.end(); ++p) {
+ (*p)->ripple (start_sample, span * times, &exclude);
+ }
+ }
+
for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
boost::shared_ptr<Region> r ((*i)->region());
latest_regionviews.clear ();
sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
- framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
+ samplepos_t const position = end_sample + (r->first_sample() - start_sample + 1);
playlist = (*i)->region()->playlist();
- playlist->clear_changes ();
- playlist->duplicate (r, position, gap, times);
- _session->add_command(new StatefulDiffCommand (playlist));
+
+ if (Config->get_edit_mode() != Ripple) {
+ if (playlists.insert (playlist).second) {
+ playlist->clear_changes ();
+ }
+ }
+
+ playlist->duplicate (r, position, span, times);
c.disconnect ();
foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
}
+ for (set<boost::shared_ptr<Playlist> >::iterator p = playlists.begin(); p != playlists.end(); ++p) {
+ _session->add_command (new StatefulDiffCommand (*p));
+ vector<Command*> cmds;
+ (*p)->rdiff (cmds);
+ _session->add_commands (cmds);
+ }
+
if (!foo.empty()) {
selection->set (foo);
}
if (in_command) {
if (times == 1.0f) {
// now "move" range selection to after the current range selection
- framecnt_t distance = 0;
+ samplecnt_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 ();
+ distance = selection->time.end_sample () - selection->time.start ();
}
selection->move_time (distance);
Editor::center_playhead ()
{
float const page = _visible_canvas_width * samples_per_pixel;
- center_screen_internal (playhead_cursor->current_frame (), page);
+ center_screen_internal (playhead_cursor->current_sample (), page);
}
void
Editor::nudge_track (bool use_edit, bool forwards)
{
boost::shared_ptr<Playlist> playlist;
- framepos_t distance;
- framepos_t next_distance;
- framepos_t start;
+ samplepos_t distance;
+ samplepos_t next_distance;
+ samplepos_t start;
if (use_edit) {
start = get_preferred_edit_position();
}
}
+void
+Editor::tag_regions (RegionList regions)
+{
+ ArdourDialog d (_("Tag Last Capture"), true, false);
+ Entry entry;
+ Label label (_("Tag:"));
+ HBox hbox;
+
+ hbox.set_spacing (6);
+ hbox.pack_start (label, false, false);
+ hbox.pack_start (entry, true, true);
+
+ d.get_vbox()->set_border_width (12);
+ d.get_vbox()->pack_start (hbox, false, false);
+
+ d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
+
+ d.set_size_request (300, -1);
+
+ entry.set_text (_("Good"));
+ entry.select_region (0, -1);
+
+ entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
+
+ d.show_all ();
+
+ entry.grab_focus();
+
+ int const ret = d.run();
+
+ d.hide ();
+
+ if (ret != RESPONSE_OK) {
+ return;
+ }
+
+ std::string tagstr = entry.get_text();
+ strip_whitespace_edges (tagstr);
+
+ if (!tagstr.empty()) {
+ for (RegionList::iterator r = regions.begin(); r != regions.end(); r++) {
+ (*r)->set_tags(tagstr);
+ }
+
+ _regions->redisplay ();
+ }
+}
+
+void
+Editor::tag_selected_region ()
+{
+ std::list<boost::shared_ptr<Region> > rlist;
+
+ RegionSelection rs = get_regions_from_selection_and_entered ();
+ for (RegionSelection::iterator r = rs.begin(); r != rs.end(); r++) {
+ rlist.push_back((*r)->region());
+ }
+
+ tag_regions(rlist);
+}
+
+void
+Editor::tag_last_capture ()
+{
+ if (!_session) {
+ return;
+ }
+
+ std::list<boost::shared_ptr<Region> > rlist;
+
+ std::list<boost::shared_ptr<Source> > srcs;
+ _session->get_last_capture_sources (srcs);
+ for (std::list<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
+ boost::shared_ptr<ARDOUR::Source> source = (*i);
+ if (source) {
+
+ set<boost::shared_ptr<Region> > regions;
+ RegionFactory::get_regions_using_source (source, regions);
+ for (set<boost::shared_ptr<Region> >::iterator r = regions.begin(); r != regions.end(); r++) {
+ rlist.push_back(*r);
+ }
+
+ }
+ }
+
+ tag_regions(rlist);
+}
+
void
Editor::normalize_region ()
{
Command*
Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
{
- Evoral::Sequence<Evoral::Beats>::Notes selected;
+ Evoral::Sequence<Temporal::Beats>::Notes selected;
mrv.selection_as_notelist (selected, true);
- vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
+ vector<Evoral::Sequence<Temporal::Beats>::Notes> v;
v.push_back (selected);
- Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
+ Temporal::Beats pos_beats = Temporal::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
return op (mrv.midi_region()->model(), pos_beats, v);
}
if (in_command) {
commit_reversible_command ();
+ _session->set_dirty ();
}
}
return;
}
- const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
+ const samplepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
/* XXX: bit of a hack; use the MIDNAM from the first selected region;
there may be more than one, but the PatchChangeDialog can only offer
*/
MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
- Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
+ Evoral::PatchChange<Temporal::Beats> empty (Temporal::Beats(), 0, 0, 0);
PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
if (d.run() == RESPONSE_CANCEL) {
for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
if (mrv) {
- if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
+ if (p >= mrv->region()->first_sample() && p <= mrv->region()->last_sample()) {
mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
}
}
}
}
+StripableList
+tracklist_to_stripables (TrackViewList list)
+{
+ StripableList ret;
+
+ for (TrackSelection::iterator i = list.begin(); i != list.end(); ++i) {
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
+
+ if (rtv && rtv->is_track()) {
+ ret.push_back (rtv->track());
+ }
+ }
+
+ return ret;
+}
+
+void
+Editor::play_solo_selection (bool restart)
+{
+ //note: session::solo_selection takes care of invalidating the region playlist
+
+ if ((!selection->tracks.empty()) && selection->time.length() > 0) { //a range is selected; solo the tracks and roll
+
+ StripableList sl = tracklist_to_stripables (selection->tracks);
+ _session->solo_selection (sl, true);
+
+ if (restart) {
+ samplepos_t start = selection->time.start();
+ samplepos_t end = selection->time.end_sample();
+ _session->request_bounded_roll (start, end);
+ }
+ } else if (! selection->tracks.empty()) { //no range is selected, but tracks are selected; solo the tracks and roll
+ StripableList sl = tracklist_to_stripables (selection->tracks);
+ _session->solo_selection (sl, true);
+ _session->request_cancel_play_range();
+ transition_to_rolling (true);
+
+ } else if (! selection->regions.empty()) { //solo any tracks with selected regions, and roll
+ StripableList sl = tracklist_to_stripables (get_tracks_for_range_action());
+ _session->solo_selection (sl, true);
+ _session->request_cancel_play_range();
+ transition_to_rolling (true);
+ } else {
+ _session->request_cancel_play_range();
+ transition_to_rolling (true); //no selection. just roll.
+ }
+}
+
void
Editor::toggle_solo ()
{
boost::shared_ptr<ControlList> cl (new ControlList);
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
- RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
+ StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*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);
{
bool new_state = false;
bool first = true;
- boost::shared_ptr<RouteList> rl (new RouteList);
+ boost::shared_ptr<ControlList> cl (new ControlList);
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
- RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
+ StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*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());
+ boost::shared_ptr<MuteControl> mc = stav->stripable()->mute_control();
+ cl->push_back (mc);
+ mc->start_touch (_session->audible_sample ());
}
- _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
RegionView* rv = rs.front ();
- framepos_t pos = get_preferred_edit_position();
- framepos_t len;
+ samplepos_t pos = get_preferred_edit_position();
+ samplepos_t len;
char const * cmd;
- if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
+ if (pos > rv->region()->last_sample() || pos < rv->region()->first_sample()) {
/* edit point is outside the relevant region */
return;
}
len = pos - rv->region()->position();
cmd = _("set fade in length");
} else {
- if (pos >= rv->region()->last_frame()) {
+ if (pos >= rv->region()->last_sample()) {
/* can't do it */
return;
}
- len = rv->region()->last_frame() - pos;
+ len = rv->region()->last_sample() - pos;
cmd = _("set fade out length");
}
Editor::set_edit_point ()
{
bool ignored;
- MusicFrame where (0, 0);
+ MusicSample where (0, 0);
- if (!mouse_frame (where.frame, ignored)) {
+ if (!mouse_sample (where.sample, ignored)) {
return;
}
if (selection->markers.empty()) {
- mouse_add_new_marker (where.frame);
+ mouse_add_new_marker (where.sample);
} else {
bool ignored;
Location* loc = find_location_from_marker (selection->markers.front(), ignored);
if (loc) {
- loc->move_to (where.frame, where.division);
+ loc->move_to (where.sample, where.division);
}
}
}
if (entered_marker) {
_session->request_locate (entered_marker->position(), _session->transport_rolling());
} else {
- MusicFrame where (0, 0);
+ MusicSample where (0, 0);
bool ignored;
- if (!mouse_frame (where.frame, ignored)) {
+ if (!mouse_sample (where.sample, ignored)) {
return;
}
snap_to (where);
if (_session) {
- _session->request_locate (where.frame, _session->transport_rolling());
+ _session->request_locate (where.sample, _session->transport_rolling());
}
}
void
Editor::split_region ()
{
- if (_drags->active ()) {
+ if (_dragging_playhead) {
+ /*continue*/
+ } else if (_drags->active ()) {
+ /*any other kind of drag, bail out so we avoid Undo snafu*/
return;
}
//if a range is selected, separate it
- if ( !selection->time.empty()) {
+ if (!selection->time.empty()) {
separate_regions_between (selection->time);
return;
}
//if no range was selected, try to find some regions to split
- if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
+ if (current_mouse_mode() == MouseObject || current_mouse_mode() == MouseRange ) { //don't try this for Internal Edit, Stretch, Draw, etc.
+
+ RegionSelection rs;
+
+ //new behavior: the Split action will prioritize the entered_regionview rather than selected regions.
+ //this fixes the unexpected case where you point at a region, but
+ // * nothing happens OR
+ // * some other region (maybe off-screen) is split.
+ //NOTE: if the entered_regionview is /part of the selection/ then we should operate on the selection as usual
+ if (_edit_point == EditAtMouse && entered_regionview && !entered_regionview->selected()) {
+ rs.add (entered_regionview);
+ } else {
+ rs = selection->regions; //might be empty
+ }
+
+ if (rs.empty()) {
+ TrackViewList tracks = selection->tracks;
+
+ if (!tracks.empty()) {
+ /* no region selected or entered, but some selected tracks:
+ * act on all regions on the selected tracks at the edit point
+ */
+ samplepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, false);
+ get_regions_at(rs, where, tracks);
+ }
+ }
- RegionSelection rs = get_regions_from_selection_and_edit_point ();
- const framepos_t pos = get_preferred_edit_position();
+ const samplepos_t pos = get_preferred_edit_position();
const int32_t division = get_grid_music_divisions (0);
- MusicFrame where (pos, division);
+ MusicSample where (pos, division);
if (rs.empty()) {
return;
}
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());
- return;
- }
-
- TimeAxisView* current = selection->tracks.front();
-
- RouteUI *rui;
- do {
- for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-
- if (*i == current) {
- ++i;
- if (i != track_views.end()) {
- current = (*i);
- } else {
- current = (*(track_views.begin()));
- //selection->set (*(track_views.begin()));
- }
- break;
- }
- }
-
- rui = dynamic_cast<RouteUI *>(current);
-
- } while (current->hidden() || (rui == NULL) || !rui->route()->active());
-
- selection->set (current);
-
- ensure_time_axis_view_is_visible (*current, false);
+ _session->selection().select_next_stripable (false, routes_only);
}
void
-Editor::select_prev_route()
+Editor::select_prev_stripable (bool routes_only)
{
- if (selection->tracks.empty()) {
- selection->set (track_views.front());
- return;
- }
-
- TimeAxisView* current = selection->tracks.front();
-
- RouteUI *rui;
- do {
- for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
-
- if (*i == current) {
- ++i;
- if (i != track_views.rend()) {
- current = (*i);
- } else {
- current = *(track_views.rbegin());
- }
- break;
- }
- }
- rui = dynamic_cast<RouteUI *>(current);
-
- } while (current->hidden() || (rui == NULL) || !rui->route()->active());
-
- selection->set (current);
-
- ensure_time_axis_view_is_visible (*current, false);
+ _session->selection().select_prev_stripable (false, routes_only);
}
void
return;
}
- framepos_t start, end;
- if (!get_selection_extents ( start, end))
+ samplepos_t start, end;
+ if (!get_selection_extents (start, end))
return;
set_loop_range (start, end, _("set loop range from selection"));
void
Editor::set_loop_from_region (bool play)
{
- framepos_t start, end;
- if (!get_selection_extents ( start, end))
+ samplepos_t start, end;
+ if (!get_selection_extents (start, end))
return;
set_loop_range (start, end, _("set loop range from region"));
return;
}
- framepos_t start, end;
- if (!get_selection_extents ( start, end))
+ samplepos_t start, end;
+ if (!get_selection_extents (start, end))
return;
set_punch_range (start, end, _("set punch range from selection"));
}
Location* tpl = transport_punch_location();
- framepos_t now = playhead_cursor->current_frame();
- framepos_t begin = now;
- framepos_t end = _session->current_end_frame();
+ samplepos_t now = playhead_cursor->current_sample();
+ samplepos_t begin = now;
+ samplepos_t end = _session->current_end_sample();
if (!_session->config.get_punch_in()) {
// First Press - set punch in and create range from here to eternity
set_punch_range (begin, end, _("Auto Punch In/Out"));
} else {
// normal case for 2nd press - set the punch out
- end = playhead_cursor->current_frame ();
+ end = playhead_cursor->current_sample ();
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);
}
return;
}
- framepos_t start, end;
- if (!get_selection_extents ( start, end))
+ samplepos_t start, end;
+ if (!get_selection_extents (start, end))
return;
Location* loc;
commit_reversible_command ();
}
- _session->set_end_is_free (false);
+ _session->set_session_range_is_free (false);
}
void
{
if (_session) {
- MusicFrame start (0, 0);
- framepos_t end = max_framepos;
+ MusicSample start (0, 0);
+ samplepos_t end = max_samplepos;
//use the existing punch end, if any
Location* tpl = transport_punch_location();
}
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
- start.frame = _session->audible_frame();
+ start.sample = _session->audible_sample();
} else {
- start.frame = get_preferred_edit_position();
+ start.sample = 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.frame > end ) {
- end = max_framepos;
+ if (start.sample > end) {
+ end = max_samplepos;
}
- set_punch_range (start.frame, end, _("set punch start from EP"));
+ set_punch_range (start.sample, end, _("set punch start from EP"));
}
}
{
if (_session) {
- framepos_t start = 0;
- MusicFrame end (max_framepos, 0);
+ samplepos_t start = 0;
+ MusicSample end (max_samplepos, 0);
//use the existing punch start, if any
Location* tpl = transport_punch_location();
}
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
- end.frame = _session->audible_frame();
+ end.sample = _session->audible_sample();
} else {
- end.frame = get_preferred_edit_position();
+ end.sample = get_preferred_edit_position();
}
- //snap the selection start/end
- snap_to (end);
-
- set_punch_range (start, end.frame, _("set punch end from EP"));
+ set_punch_range (start, end.sample, _("set punch end from EP"));
}
}
{
if (_session) {
- MusicFrame start (0, 0);
- framepos_t end = max_framepos;
+ MusicSample start (0, 0);
+ samplepos_t end = max_samplepos;
//use the existing loop end, if any
Location* tpl = transport_loop_location();
}
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
- start.frame = _session->audible_frame();
+ start.sample = _session->audible_sample();
} else {
- start.frame = get_preferred_edit_position();
+ start.sample = 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.frame > end ) {
- end = max_framepos;
+ if (start.sample > end) {
+ end = max_samplepos;
}
- set_loop_range (start.frame, end, _("set loop start from EP"));
+ set_loop_range (start.sample, end, _("set loop start from EP"));
}
}
{
if (_session) {
- framepos_t start = 0;
- MusicFrame end (max_framepos, 0);
+ samplepos_t start = 0;
+ MusicSample end (max_samplepos, 0);
//use the existing loop start, if any
Location* tpl = transport_loop_location();
}
if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
- end.frame = _session->audible_frame();
+ end.sample = _session->audible_sample();
} else {
- end.frame = get_preferred_edit_position();
+ end.sample = get_preferred_edit_position();
}
- //snap the selection start/end
- snap_to(end);
-
- set_loop_range (start, end.frame, _("set loop end from EP"));
+ set_loop_range (start, end.sample, _("set loop end from EP"));
}
}
void
Editor::set_punch_from_region ()
{
- framepos_t start, end;
- if (!get_selection_extents ( start, end))
+ samplepos_t start, end;
+ if (!get_selection_extents (start, end))
return;
set_punch_range (start, end, _("set punch range from region"));
RegionView* rv = rs.front();
- define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
+ define_one_bar (rv->region()->position(), rv->region()->last_sample() + 1);
}
void
Editor::use_range_as_bar ()
{
- framepos_t start, end;
+ samplepos_t start, end;
if (get_edit_op_range (start, end)) {
define_one_bar (start, end);
}
}
void
-Editor::define_one_bar (framepos_t start, framepos_t end)
+Editor::define_one_bar (samplepos_t start, samplepos_t end)
{
- framepos_t length = end - start;
+ samplepos_t length = end - start;
- const Meter& m (_session->tempo_map().meter_at_frame (start));
+ const Meter& m (_session->tempo_map().meter_at_sample (start));
/* length = 1 bar */
/* We're going to deliver a constant tempo here,
- so we can use frames per beat to determine length.
- now we want frames per beat.
- we have frames per bar, and beats per bar, so ...
+ so we can use samples per beat to determine length.
+ now we want samples per beat.
+ we have samples per bar, and beats per bar, so ...
*/
/* XXXX METER MATH */
- double frames_per_beat = length / m.divisions_per_bar();
+ double samples_per_beat = length / m.divisions_per_bar();
/* beats per minute = */
- double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
+ double beats_per_minute = (_session->sample_rate() * 60.0) / samples_per_beat;
/* now decide whether to:
*/
- const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
+ const TempoSection& t (_session->tempo_map().tempo_section_at_sample (start));
bool do_global = false;
if (do_global) {
_session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
- } else if (t.frame() == start) {
+ } else if (t.sample() == start) {
_session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
} else {
/* constant tempo */
if (positions.size() > 20 && can_ferret) {
std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
- MessageDialog msg (msgstr,
- false,
- Gtk::MESSAGE_INFO,
- Gtk::BUTTONS_OK_CANCEL);
+ ArdourMessageDialog msg (msgstr,
+ false,
+ Gtk::MESSAGE_INFO,
+ Gtk::BUTTONS_OK_CANCEL);
if (can_ferret) {
msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
}
msg.set_title (_("Excessive split?"));
- msg.present ();
-
int response = msg.run();
msg.hide ();
pl->freeze ();
pl->remove_region (r);
- framepos_t pos = 0;
+ samplepos_t pos = 0;
- framepos_t rstart = r->first_frame ();
- framepos_t rend = r->last_frame ();
+ samplepos_t rstart = r->first_sample ();
+ samplepos_t rend = r->last_sample ();
while (x != positions.end()) {
/* file start = original start + how far we from the initial position ? */
- framepos_t file_start = r->start() + pos;
+ samplepos_t file_start = r->start() + pos;
/* length = next position - current position */
- framepos_t len = (*x) - pos - rstart;
+ samplepos_t len = (*x) - pos - rstart;
/* XXX we do we really want to allow even single-sample regions?
* shouldn't we have some kind of lower limit on region size?
PropertyList plist;
plist.add (ARDOUR::Properties::start, r->start() + pos);
- plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
+ plist.add (ARDOUR::Properties::length, r->last_sample() - (r->position() + pos) + 1);
plist.add (ARDOUR::Properties::name, new_name);
plist.add (ARDOUR::Properties::layer, 0);
return;
}
- framepos_t where = get_preferred_edit_position();
+ samplepos_t where = get_preferred_edit_position();
begin_reversible_command (_("place transient"));
}
(*r)->region()->clear_changes ();
- MusicFrame start ((*r)->region()->first_frame (), 0);
- snap_to (start);
- (*r)->region()->set_position (start.frame, start.division);
+ MusicSample start ((*r)->region()->first_sample (), 0);
+ snap_to (start, RoundNearest, SnapToGrid_Unscaled, true);
+ (*r)->region()->set_position (start.sample, start.division);
_session->add_command(new StatefulDiffCommand ((*r)->region()));
}
return;
}
- framepos_t crossfade_len = spin_crossfade.get_value();
- framepos_t pull_back_frames = spin_pullback.get_value();
+ samplepos_t crossfade_len = spin_crossfade.get_value();
+ samplepos_t pull_back_samples = spin_pullback.get_value();
- crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
- pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
+ crossfade_len = lrintf (crossfade_len * _session->sample_rate()/1000);
+ pull_back_samples = lrintf (pull_back_samples * _session->sample_rate()/1000);
/* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
pl->freeze();
}
- framepos_t position = (*r)->region()->position();
+ samplepos_t position = (*r)->region()->position();
if (idx == 0 || position < last_region->position()){
last_region = (*r)->region();
}
(*r)->region()->clear_changes ();
- (*r)->region()->trim_front( (position - pull_back_frames));
+ (*r)->region()->trim_front((position - pull_back_samples));
last_region->clear_changes ();
- last_region->trim_end( (position - pull_back_frames + crossfade_len));
+ last_region->trim_end ((position - pull_back_samples + crossfade_len));
_session->add_command (new StatefulDiffCommand ((*r)->region()));
_session->add_command (new StatefulDiffCommand (last_region));
return;
}
- framepos_t pos = _session->audible_frame ();
+ samplepos_t pos = _session->audible_sample ();
if (!selection->tracks.empty()) {
if (tr) {
boost::shared_ptr<Playlist> pl = tr->playlist ();
if (pl) {
- framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
+ samplepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
if (result >= 0) {
positions.push_back (result);
}
}
- TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
+ TransientDetector::cleanup_transients (positions, _session->sample_rate(), 3.0);
if (forward) {
AnalysisFeatureList::iterator x;
return;
}
- MusicFrame pos (playhead_cursor->current_frame (), 0);
+ MusicSample pos (playhead_cursor->current_sample (), 0);
+
+ if ( _grid_type == GridTypeNone) {
+ if (pos.sample < max_samplepos - current_page_samples()*0.1) {
+ pos.sample += current_page_samples()*0.1;
+ _session->request_locate (pos.sample);
+ } else {
+ _session->request_locate (0);
+ }
+ } else {
+
+ if (pos.sample < max_samplepos - 1) {
+ pos.sample += 2;
+ pos = snap_to_grid (pos, RoundUpAlways, SnapToGrid_Scaled);
+ _session->request_locate (pos.sample);
+ }
+ }
+
- if (pos.frame < max_framepos - 1) {
- pos.frame += 2;
- snap_to_internal (pos, RoundUpAlways, false, true);
- _session->request_locate (pos.frame);
+ /* keep PH visible in window */
+ if (pos.sample > (_leftmost_sample + current_page_samples() *0.9)) {
+ reset_x_origin (pos.sample - (current_page_samples()*0.9));
}
}
return;
}
- MusicFrame pos (playhead_cursor->current_frame (), 0);
+ MusicSample pos (playhead_cursor->current_sample (), 0);
+
+ if ( _grid_type == GridTypeNone) {
+ if ( pos.sample > current_page_samples()*0.1 ) {
+ pos.sample -= current_page_samples()*0.1;
+ _session->request_locate (pos.sample);
+ } else {
+ _session->request_locate (0);
+ }
+ } else {
+
+ if (pos.sample > 2) {
+ pos.sample -= 2;
+ pos = snap_to_grid (pos, RoundDownAlways, SnapToGrid_Scaled);
+ }
+
+ //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...
+ //also see: jump_backward_to_mark
+ if (_session->transport_rolling()) {
+ if ((playhead_cursor->current_sample() - pos.sample) < _session->sample_rate()/2) {
+ pos = snap_to_grid (pos, RoundDownAlways, SnapToGrid_Scaled);
+ }
+ }
+
+ _session->request_locate (pos.sample, _session->transport_rolling());
+ }
- if (pos.frame > 2) {
- pos.frame -= 2;
- snap_to_internal (pos, RoundDownAlways, false, true);
- _session->request_locate (pos.frame);
+ /* keep PH visible in window */
+ if (pos.sample < (_leftmost_sample + current_page_samples() *0.1)) {
+ reset_x_origin (pos.sample - (current_page_samples()*0.1));
}
}
return;
}
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
+ return;
+ }
+
vector<string> choices;
string prompt;
int ntracks = 0;
int nbusses = 0;
+ int nvcas = 0;
const char* trackstr;
const char* busstr;
+ const char* vcastr;
vector<boost::shared_ptr<Route> > routes;
+ vector<boost::shared_ptr<VCA> > vcas;
bool special_bus = false;
for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
+ VCATimeAxisView* vtv = dynamic_cast<VCATimeAxisView*> (*x);
+ if (vtv) {
+ vcas.push_back (vtv->vca());
+ ++nvcas;
+ continue;
+ }
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
if (!rtv) {
continue;
}
if (rtv->is_track()) {
- ntracks++;
+ ++ntracks;
} else {
- nbusses++;
+ ++nbusses;
}
routes.push_back (rtv->_route);
}
if (special_bus && !Config->get_allow_special_bus_removal()) {
- MessageDialog msg (_("That would be bad news ...."),
- false,
- Gtk::MESSAGE_INFO,
- Gtk::BUTTONS_OK);
- msg.set_secondary_text (string_compose (_(
- "Removing the master or monitor bus is such a bad idea\n\
+ ArdourMessageDialog msg (_("That would be bad news ...."),
+ false,
+ Gtk::MESSAGE_INFO,
+ Gtk::BUTTONS_OK);
+ msg.set_secondary_text (string_compose (_("Removing the master or monitor bus is such a bad idea\n\
that %1 is not going to allow it.\n\
\n\
If you really want to do this sort of thing\n\
edit your ardour.rc file to set the\n\
\"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
- msg.present ();
msg.run ();
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) {
/* 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() ).
+ * 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.
*
rl->push_back (*x);
}
_session->remove_routes (rl);
+
+ for (vector<boost::shared_ptr<VCA> >::iterator x = vcas.begin(); x != vcas.end(); ++x) {
+ _session->vca_manager().remove_vca (*x);
+ }
+
}
/* TrackSelection and RouteList leave scope,
* destructors are called,
Editor::do_insert_time ()
{
if (selection->tracks.empty()) {
+ ArdourMessageDialog msg (_("You must first select some tracks to Insert Time."),
+ true, MESSAGE_INFO, BUTTONS_OK, true);
+ msg.run ();
+ return;
+ }
+
+ if (Config->get_edit_mode() == Lock) {
+ ArdourMessageDialog msg (_("You cannot insert time in Lock Edit mode."),
+ true, MESSAGE_INFO, BUTTONS_OK, true);
+ msg.run ();
return;
}
void
Editor::insert_time (
- framepos_t pos, framecnt_t frames, InsertTimeOption opt,
+ samplepos_t pos, samplecnt_t samples, InsertTimeOption opt,
bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
)
{
if (all_playlists) {
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
if (rtav && rtav->track ()) {
- vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
+ vector<boost::shared_ptr<Playlist> > all = _session->playlists()->playlists_for_track (rtav->track ());
for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
pl.insert (*p);
}
if (opt == SplitIntersected) {
/* non musical split */
- (*i)->split (MusicFrame (pos, 0));
+ (*i)->split (MusicSample (pos, 0));
}
- (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
+ (*i)->shift (pos, samples, (opt == MoveIntersected), ignore_music_glue);
vector<Command*> cmds;
(*i)->rdiff (cmds);
begin_reversible_command (_("insert time"));
in_command = true;
}
- rtav->route ()->shift (pos, frames);
+ rtav->route ()->shift (pos, samples);
}
}
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, false, true, divisions);
+ (*i)->set_end ((*i)->end() + samples, false, true, divisions);
}
- (*i)->set_start ((*i)->start() + frames, false, true, divisions);
+ (*i)->set_start ((*i)->start() + samples, false, true, divisions);
moved = true;
}
in_command = true;
}
XMLNode& before (_session->tempo_map().get_state());
- _session->tempo_map().insert_time (pos, frames);
+ _session->tempo_map().insert_time (pos, samples);
XMLNode& after (_session->tempo_map().get_state());
_session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
}
Editor::do_remove_time ()
{
if (selection->tracks.empty()) {
+ ArdourMessageDialog msg (_("You must first select some tracks to Remove Time."),
+ true, MESSAGE_INFO, BUTTONS_OK, true);
+ msg.run ();
+ return;
+ }
+
+ if (Config->get_edit_mode() == Lock) {
+ ArdourMessageDialog msg (_("You cannot remove time in Lock Edit mode."),
+ true, MESSAGE_INFO, BUTTONS_OK, true);
+ msg.run ();
return;
}
return;
}
- framecnt_t distance = d.distance();
+ samplecnt_t distance = d.distance();
if (distance == 0) {
return;
}
void
-Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
+Editor::remove_time (samplepos_t pos, samplecnt_t samples, InsertTimeOption opt,
bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
{
if (Config->get_edit_mode() == Lock) {
}
std::list<AudioRange> rl;
- AudioRange ar(pos, pos+frames, 0);
+ AudioRange ar(pos, pos+samples, 0);
rl.push_back(ar);
pl->cut (rl);
- pl->shift (pos, -frames, true, ignore_music_glue);
+ pl->shift (pos, -samples, true, ignore_music_glue);
XMLNode &after = pl->get_state();
begin_reversible_command (_("remove time"));
in_command = true;
}
- rtav->route ()->shift (pos, -frames);
+ rtav->route ()->shift (pos, -samples);
}
}
if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
if ((*i)->end() >= pos
- && (*i)->end() < pos+frames
+ && (*i)->end() < pos+samples
&& (*i)->start() >= pos
- && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
+ && (*i)->end() < pos+samples) { // range is completely enclosed; kill it
moved = true;
loc_kill_list.push_back(*i);
} else { // only start or end is included, try to do the right thing
// move start before moving end, to avoid trying to move the end to before the start
// if we're removing more time than the length of the range
- if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
+ if ((*i)->start() >= pos && (*i)->start() < pos+samples) {
// start is within 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) {
+ } else if ((*i)->start() >= pos+samples) {
// start (and thus entire range) lies beyond end of cut
- (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
+ (*i)->set_start ((*i)->start() - samples, false, true, divisions); // slip the start marker back
moved = true;
}
- if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
+ if ((*i)->end() >= pos && (*i)->end() < pos+samples) {
// end is inside cut
(*i)->set_end (pos, false, true, divisions); // bring the end to the cut
moved = true;
- } else if ((*i)->end() >= pos+frames) {
+ } else if ((*i)->end() >= pos+samples) {
// end is beyond end of cut
- (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
+ (*i)->set_end ((*i)->end() - samples, false, true, divisions); // slip the end marker back
moved = true;
}
}
- } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
+ } else if ((*i)->start() >= pos && (*i)->start() < pos+samples) {
loc_kill_list.push_back(*i);
moved = true;
} else if ((*i)->start() >= pos) {
- (*i)->set_start ((*i)->start() -frames, false, true, divisions);
+ (*i)->set_start ((*i)->start() -samples, false, true, divisions);
moved = true;
}
}
for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
- _session->locations()->remove( *i );
+ _session->locations()->remove (*i);
}
if (moved) {
if (tempo_too) {
XMLNode& before (_session->tempo_map().get_state());
- if (_session->tempo_map().remove_time (pos, frames) ) {
+ if (_session->tempo_map().remove_time (pos, samples)) {
if (!in_command) {
begin_reversible_command (_("remove time"));
in_command = true;
double first_y_pos = DBL_MAX;
if (h < TimeAxisView::preset_height (HeightSmall)) {
- MessageDialog msg (_("There are too many tracks to fit in the current window"));
+ ArdourMessageDialog msg (_("There are too many tracks to fit in the current window"));
+ msg.run ();
/* too small to be displayed */
return;
}