2005-09-25 14:42:24 -04:00
|
|
|
/*
|
2009-10-14 12:10:01 -04:00
|
|
|
Copyright (C) 2000-2004 Paul Davis
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2007-05-11 11:06:12 -04:00
|
|
|
/* Note: public Editor methods are documented in public_editor.h */
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cmath>
|
|
|
|
#include <string>
|
2014-11-16 17:04:27 -05:00
|
|
|
#include <limits>
|
2005-09-25 14:42:24 -04:00
|
|
|
#include <map>
|
2008-09-10 11:03:30 -04:00
|
|
|
#include <set>
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "pbd/error.h"
|
|
|
|
#include "pbd/basename.h"
|
|
|
|
#include "pbd/pthread_utils.h"
|
|
|
|
#include "pbd/memento_command.h"
|
2012-03-06 21:11:59 -05:00
|
|
|
#include "pbd/unwind.h"
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "pbd/whitespace.h"
|
2010-02-11 12:08:34 -05:00
|
|
|
#include "pbd/stateful_diff_command.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-09-25 16:33:00 -04:00
|
|
|
#include <gtkmm2ext/utils.h>
|
|
|
|
#include <gtkmm2ext/choice.h>
|
2008-09-10 11:03:30 -04:00
|
|
|
#include <gtkmm2ext/popup.h>
|
|
|
|
|
2011-10-19 17:53:09 -04:00
|
|
|
#include "ardour/audio_track.h"
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "ardour/audioregion.h"
|
2011-10-19 17:53:09 -04:00
|
|
|
#include "ardour/dB.h"
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "ardour/location.h"
|
2011-10-19 17:53:09 -04:00
|
|
|
#include "ardour/midi_region.h"
|
2013-01-21 02:24:42 -05:00
|
|
|
#include "ardour/midi_track.h"
|
2011-10-19 17:53:09 -04:00
|
|
|
#include "ardour/operations.h"
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "ardour/playlist_factory.h"
|
2014-10-02 16:00:33 -04:00
|
|
|
#include "ardour/profile.h"
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "ardour/quantize.h"
|
2014-12-06 23:42:11 -05:00
|
|
|
#include "ardour/legatize.h"
|
2011-10-19 17:53:09 -04:00
|
|
|
#include "ardour/region_factory.h"
|
|
|
|
#include "ardour/reverse.h"
|
|
|
|
#include "ardour/session.h"
|
2011-09-05 19:38:18 -04:00
|
|
|
#include "ardour/session_playlists.h"
|
2011-10-19 17:53:09 -04:00
|
|
|
#include "ardour/strip_silence.h"
|
|
|
|
#include "ardour/transient_detector.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
#include "canvas/canvas.h"
|
|
|
|
|
2014-06-24 09:56:08 -04:00
|
|
|
#include "actions.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "ardour_ui.h"
|
2014-02-26 10:51:38 -05:00
|
|
|
#include "audio_region_view.h"
|
|
|
|
#include "audio_streamview.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "audio_time_axis.h"
|
2014-11-16 17:04:27 -05:00
|
|
|
#include "automation_region_view.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "automation_time_axis.h"
|
2012-04-22 10:03:07 -04:00
|
|
|
#include "control_point.h"
|
2014-02-26 10:51:38 -05:00
|
|
|
#include "debug.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "editing.h"
|
2014-02-26 10:51:38 -05:00
|
|
|
#include "editor.h"
|
|
|
|
#include "editor_cursors.h"
|
2009-05-30 14:25:59 -04:00
|
|
|
#include "editor_drag.h"
|
2009-07-03 18:42:22 -04:00
|
|
|
#include "editor_regions.h"
|
2014-02-26 10:51:38 -05:00
|
|
|
#include "editor_routes.h"
|
|
|
|
#include "gui_thread.h"
|
2010-08-11 19:40:51 -04:00
|
|
|
#include "insert_time_dialog.h"
|
2014-02-26 10:51:38 -05:00
|
|
|
#include "interthread_progress_window.h"
|
2014-11-16 17:04:27 -05:00
|
|
|
#include "item_counts.h"
|
2014-02-26 10:51:38 -05:00
|
|
|
#include "keyboard.h"
|
|
|
|
#include "midi_region_view.h"
|
2014-07-23 17:58:43 -04:00
|
|
|
#include "mixer_strip.h"
|
2010-11-16 09:53:16 -05:00
|
|
|
#include "mouse_cursors.h"
|
2014-02-26 10:51:38 -05:00
|
|
|
#include "normalize_dialog.h"
|
2014-12-07 23:16:42 -05:00
|
|
|
#include "note.h"
|
2014-12-06 12:20:52 -05:00
|
|
|
#include "paste_context.h"
|
2010-12-28 13:19:40 -05:00
|
|
|
#include "patch_change_dialog.h"
|
2014-02-26 10:51:38 -05:00
|
|
|
#include "quantize_dialog.h"
|
|
|
|
#include "region_gain_line.h"
|
|
|
|
#include "rgb_macros.h"
|
|
|
|
#include "route_time_axis.h"
|
|
|
|
#include "selection.h"
|
|
|
|
#include "selection_templates.h"
|
|
|
|
#include "streamview.h"
|
|
|
|
#include "strip_silence_dialog.h"
|
|
|
|
#include "time_axis_view.h"
|
2011-04-05 22:04:37 -04:00
|
|
|
#include "transpose_dialog.h"
|
2014-12-28 15:50:57 -05:00
|
|
|
#include "transform_dialog.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
#include "i18n.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace ARDOUR;
|
Large nasty commit in the form of a 5000 line patch chock-full of completely
unecessary changes. (Sorry, doing a "sprint" based thing, this is the end of the first one)
Achieved MIDI track and bus creation, associated Jack port and diskstream creation, and minimal GUI stuff for creating them. Should be set to start work on actually recording and playing midi to/from disk now.
Relevant (significant) changes:
- Creation of a Buffer class. Base class is type agnostic so things can point to a buffer but not care what kind it is (otherwise it'd be a template). Derived into AudioBuffer and MidiBuffer, with a type tag because checking type is necessary in parts of the code where dynamic_cast wouldn't be wise. Originally I considered this a hack, but passing around a type proved to be a very good solution to all the other problems (below). There is a 1:1 mapping between jack port data types and ardour Buffer types (with a conversion function), but that's easily removed if it ever becomes necessary. Having the type scoped in the Buffer class is maybe not the best spot for it, but whatever (this is proof of concept kinda stuff right now...)
- IO now has a "default" port type (passed to the constructor and stored as a member), used by ensure_io (and similar) to create n ports. IO::register_***_port has a type argument that defaults to the default type if not passed. Rationale: previous IO API is identical, no changes needed to existing code, but path is paved for multiple port types in one IO, which we will need for eg synth plugin inserts, among other things. This is not quite ideal (best would be to only have the two port register functions and have them take a type), but the alternative is a lot of work (namely destroying the 'ensure' functions and everything that uses them) for very little gain. (I am convinced after quite a few tries at the whiteboard that subclassing IO in any way is not a feasible option, look at it's inheritance diagram in Doxygen and you can see why)
- AudioEngine::register_audio_input_port is now register_input_port and takes a type argument. Ditto for output.
- (Most significant change) AudioDiskstream abstracted into Distream, and sibling MidiDiskstream created. Very much still a work in progress, but Diskstream is there to switch references over to (most already are), which is the important part. It is still unclear what the MIDI diskstream's relation to channels is, but I'm pretty sure they will be single channel only (so SMF Type 0) since noone can come up with a reason otherwise.
- MidiTrack creation. Same thing as AudioTrack but with a different default type basically. No big deal here.
- Random cleanups and variable renamings etc. because I have OCD and can't help myself. :)
Known broken: Loading of sessions containing MIDI tracks.
git-svn-id: svn://localhost/ardour2/branches/midi@641 d708f5d6-7413-0410-9779-e7cbd77b26cf
2006-06-26 12:01:34 -04:00
|
|
|
using namespace PBD;
|
2005-09-25 14:42:24 -04:00
|
|
|
using namespace Gtk;
|
2007-03-19 03:07:38 -04:00
|
|
|
using namespace Gtkmm2ext;
|
2005-09-25 14:42:24 -04:00
|
|
|
using namespace Editing;
|
2009-12-04 17:51:32 -05:00
|
|
|
using Gtkmm2ext::Keyboard;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Editor operations
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::undo (uint32_t n)
|
|
|
|
{
|
2011-12-02 22:05:59 -05:00
|
|
|
if (_drags->active ()) {
|
|
|
|
_drags->abort ();
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session) {
|
|
|
|
_session->undo (n);
|
2014-12-22 12:52:29 -05:00
|
|
|
if (_session->undo_depth() == 0) {
|
|
|
|
undo_action->set_sensitive(false);
|
|
|
|
}
|
2014-12-22 08:30:23 -05:00
|
|
|
redo_action->set_sensitive(true);
|
|
|
|
begin_selection_op_history ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::redo (uint32_t n)
|
|
|
|
{
|
2011-12-02 22:05:59 -05:00
|
|
|
if (_drags->active ()) {
|
|
|
|
_drags->abort ();
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session) {
|
|
|
|
_session->redo (n);
|
2014-12-22 08:30:23 -05:00
|
|
|
if (_session->redo_depth() == 0) {
|
|
|
|
redo_action->set_sensitive(false);
|
|
|
|
}
|
2014-12-22 12:52:29 -05:00
|
|
|
undo_action->set_sensitive(true);
|
2014-12-22 08:30:23 -05:00
|
|
|
begin_selection_op_history ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::split_regions_at (framepos_t where, RegionSelection& regions)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2011-02-14 16:49:43 -05:00
|
|
|
bool frozen = false;
|
|
|
|
|
2014-07-06 13:57:26 -04:00
|
|
|
RegionSelection pre_selected_regions = selection->regions;
|
2014-07-08 15:16:13 -04:00
|
|
|
bool working_on_selection = !pre_selected_regions.empty();
|
2014-10-02 16:00:33 -04:00
|
|
|
|
2014-07-03 19:43:28 -04:00
|
|
|
list<boost::shared_ptr<Playlist> > used_playlists;
|
|
|
|
list<RouteTimeAxisView*> used_trackviews;
|
use filechooser widget in export dialog, selected files set format combos, hide progress bar until use in export dialog, speed up 'separate regions in range' operation on larger sessions, ruler scale now calculated separately to mark generation, fix for non-stacked layering regression, try not to generate 'buried' crossfades, use playlist->freeze() to speed up copying/moving regions on large playlists (not done for undo), width dependent items now reset on regionview init, get rid of jack_port_ensure_monitor check, remove audiosourse _length (only source has a length.. i think), make overlapend differ to overlapexternal where start points coincide.
git-svn-id: svn://localhost/ardour2/trunk@2576 d708f5d6-7413-0410-9779-e7cbd77b26cf
2007-10-26 09:32:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
begin_reversible_command (_("split"));
|
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
// if splitting a single region, and snap-to is using
|
|
|
|
// region boundaries, don't pay attention to them
|
|
|
|
|
|
|
|
if (regions.size() == 1) {
|
2009-10-26 19:43:04 -04:00
|
|
|
switch (_snap_type) {
|
2007-10-11 18:07:47 -04:00
|
|
|
case SnapToRegionStart:
|
|
|
|
case SnapToRegionSync:
|
|
|
|
case SnapToRegionEnd:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
snap_to (where);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
snap_to (where);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
frozen = true;
|
|
|
|
EditorFreeze(); /* Emit Signal */
|
2007-10-11 18:07:47 -04:00
|
|
|
}
|
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
RegionSelection::iterator tmp;
|
|
|
|
|
|
|
|
/* XXX this test needs to be more complicated, to make sure we really
|
|
|
|
have something to split.
|
|
|
|
*/
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
if (!(*a)->region()->covers (where)) {
|
|
|
|
++a;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = a;
|
|
|
|
++tmp;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
if (!pl) {
|
|
|
|
a = tmp;
|
|
|
|
continue;
|
|
|
|
}
|
2010-03-04 08:15:04 -05:00
|
|
|
|
|
|
|
if (!pl->frozen()) {
|
use filechooser widget in export dialog, selected files set format combos, hide progress bar until use in export dialog, speed up 'separate regions in range' operation on larger sessions, ruler scale now calculated separately to mark generation, fix for non-stacked layering regression, try not to generate 'buried' crossfades, use playlist->freeze() to speed up copying/moving regions on large playlists (not done for undo), width dependent items now reset on regionview init, get rid of jack_port_ensure_monitor check, remove audiosourse _length (only source has a length.. i think), make overlapend differ to overlapexternal where start points coincide.
git-svn-id: svn://localhost/ardour2/trunk@2576 d708f5d6-7413-0410-9779-e7cbd77b26cf
2007-10-26 09:32:24 -04:00
|
|
|
/* we haven't seen this playlist before */
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
/* remember used playlists so we can thaw them later */
|
use filechooser widget in export dialog, selected files set format combos, hide progress bar until use in export dialog, speed up 'separate regions in range' operation on larger sessions, ruler scale now calculated separately to mark generation, fix for non-stacked layering regression, try not to generate 'buried' crossfades, use playlist->freeze() to speed up copying/moving regions on large playlists (not done for undo), width dependent items now reset on regionview init, get rid of jack_port_ensure_monitor check, remove audiosourse _length (only source has a length.. i think), make overlapend differ to overlapexternal where start points coincide.
git-svn-id: svn://localhost/ardour2/trunk@2576 d708f5d6-7413-0410-9779-e7cbd77b26cf
2007-10-26 09:32:24 -04:00
|
|
|
used_playlists.push_back(pl);
|
2014-07-03 19:43:28 -04:00
|
|
|
|
|
|
|
TimeAxisView& tv = (*a)->get_time_axis_view();
|
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
|
|
|
|
if (rtv) {
|
|
|
|
used_trackviews.push_back (rtv);
|
|
|
|
}
|
use filechooser widget in export dialog, selected files set format combos, hide progress bar until use in export dialog, speed up 'separate regions in range' operation on larger sessions, ruler scale now calculated separately to mark generation, fix for non-stacked layering regression, try not to generate 'buried' crossfades, use playlist->freeze() to speed up copying/moving regions on large playlists (not done for undo), width dependent items now reset on regionview init, get rid of jack_port_ensure_monitor check, remove audiosourse _length (only source has a length.. i think), make overlapend differ to overlapexternal where start points coincide.
git-svn-id: svn://localhost/ardour2/trunk@2576 d708f5d6-7413-0410-9779-e7cbd77b26cf
2007-10-26 09:32:24 -04:00
|
|
|
pl->freeze();
|
|
|
|
}
|
|
|
|
|
2014-07-03 19:43:28 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (pl) {
|
2010-11-25 15:37:39 -05:00
|
|
|
pl->clear_changes ();
|
2006-07-23 08:03:19 -04:00
|
|
|
pl->split_region ((*a)->region(), where);
|
2010-03-01 19:00:00 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (pl));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
a = tmp;
|
use filechooser widget in export dialog, selected files set format combos, hide progress bar until use in export dialog, speed up 'separate regions in range' operation on larger sessions, ruler scale now calculated separately to mark generation, fix for non-stacked layering regression, try not to generate 'buried' crossfades, use playlist->freeze() to speed up copying/moving regions on large playlists (not done for undo), width dependent items now reset on regionview init, get rid of jack_port_ensure_monitor check, remove audiosourse _length (only source has a length.. i think), make overlapend differ to overlapexternal where start points coincide.
git-svn-id: svn://localhost/ardour2/trunk@2576 d708f5d6-7413-0410-9779-e7cbd77b26cf
2007-10-26 09:32:24 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
latest_regionviews.clear ();
|
|
|
|
|
2014-07-03 19:43:28 -04:00
|
|
|
vector<sigc::connection> region_added_connections;
|
|
|
|
|
|
|
|
for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
|
|
|
|
region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
|
|
|
|
}
|
|
|
|
|
2009-02-16 02:04:27 -05:00
|
|
|
while (used_playlists.size() > 0) {
|
use filechooser widget in export dialog, selected files set format combos, hide progress bar until use in export dialog, speed up 'separate regions in range' operation on larger sessions, ruler scale now calculated separately to mark generation, fix for non-stacked layering regression, try not to generate 'buried' crossfades, use playlist->freeze() to speed up copying/moving regions on large playlists (not done for undo), width dependent items now reset on regionview init, get rid of jack_port_ensure_monitor check, remove audiosourse _length (only source has a length.. i think), make overlapend differ to overlapexternal where start points coincide.
git-svn-id: svn://localhost/ardour2/trunk@2576 d708f5d6-7413-0410-9779-e7cbd77b26cf
2007-10-26 09:32:24 -04:00
|
|
|
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
|
|
|
|
(*i)->thaw();
|
|
|
|
used_playlists.pop_front();
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-07-03 19:43:28 -04:00
|
|
|
for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
|
|
|
|
(*c).disconnect ();
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
if (frozen){
|
|
|
|
EditorThaw(); /* Emit Signal */
|
|
|
|
}
|
2014-07-03 19:43:28 -04:00
|
|
|
|
2014-11-18 08:58:37 -05:00
|
|
|
if (working_on_selection) {
|
|
|
|
// IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
|
|
|
|
|
|
|
|
_ignore_follow_edits = true; // a split will change the region selection in mysterious ways; it's not practical or wanted to follow this edit
|
|
|
|
RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
|
|
|
|
/* There are three classes of regions that we might want selected after
|
|
|
|
splitting selected regions:
|
|
|
|
- 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.
|
2014-10-02 16:00:33 -04:00
|
|
|
selection->add ( pre_selected_regions );
|
2014-11-18 08:58:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
|
|
|
|
if ((*ri)->region()->position() < where) {
|
|
|
|
// new regions created before the split
|
|
|
|
if (rsas & NewlyCreatedLeft) {
|
|
|
|
selection->add (*ri);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// new regions created after the split
|
|
|
|
if (rsas & NewlyCreatedRight) {
|
|
|
|
selection->add (*ri);
|
|
|
|
}
|
|
|
|
}
|
2014-10-02 16:00:33 -04:00
|
|
|
}
|
|
|
|
_ignore_follow_edits = false;
|
2014-12-14 08:13:38 -05:00
|
|
|
} else {
|
|
|
|
_ignore_follow_edits = true;
|
|
|
|
if( working_on_selection ) {
|
|
|
|
selection->add (latest_regionviews); //these are the new regions created after the split
|
|
|
|
}
|
|
|
|
_ignore_follow_edits = false;
|
2014-07-03 19:43:28 -04:00
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2011-04-17 09:55:41 -04:00
|
|
|
/** Move one extreme of the current range selection. If more than one range is selected,
|
|
|
|
* the start of the earliest range or the end of the latest range is moved.
|
|
|
|
*
|
|
|
|
* @param move_end true to move the end of the current range selection, false to move
|
|
|
|
* the start.
|
|
|
|
* @param next true to move the extreme to the next region boundary, false to move to
|
|
|
|
* the previous.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2011-04-17 09:55:41 -04:00
|
|
|
if (selection->time.start() == selection->time.end_frame()) {
|
|
|
|
return;
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-04-17 09:55:41 -04:00
|
|
|
framepos_t start = selection->time.start ();
|
|
|
|
framepos_t end = selection->time.end_frame ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-04-17 09:55:41 -04:00
|
|
|
/* the position of the thing we may move */
|
|
|
|
framepos_t pos = move_end ? end : start;
|
|
|
|
int dir = next ? 1 : -1;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-04-17 09:55:41 -04:00
|
|
|
/* so we don't find the current region again */
|
|
|
|
if (dir > 0 || pos > 0) {
|
|
|
|
pos += dir;
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
|
|
|
|
2011-04-17 11:34:26 -04:00
|
|
|
framepos_t const target = get_region_boundary (pos, dir, true, false);
|
2011-04-17 09:55:41 -04:00
|
|
|
if (target < 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-04-17 09:55:41 -04:00
|
|
|
if (move_end) {
|
|
|
|
end = target;
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2011-04-17 09:55:41 -04:00
|
|
|
start = target;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2011-04-17 09:55:41 -04:00
|
|
|
if (end < start) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-04-17 09:55:41 -04:00
|
|
|
begin_reversible_command (_("alter selection"));
|
|
|
|
selection->set_preserving_all_ranges (start, end);
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2008-01-18 22:49:52 -05:00
|
|
|
bool
|
|
|
|
Editor::nudge_forward_release (GdkEventButton* ev)
|
|
|
|
{
|
|
|
|
if (ev->state & Keyboard::PrimaryModifier) {
|
|
|
|
nudge_forward (false, true);
|
|
|
|
} else {
|
|
|
|
nudge_forward (false, false);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
Editor::nudge_backward_release (GdkEventButton* ev)
|
|
|
|
{
|
|
|
|
if (ev->state & Keyboard::PrimaryModifier) {
|
|
|
|
nudge_backward (false, true);
|
|
|
|
} else {
|
|
|
|
nudge_backward (false, false);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
void
|
2008-01-18 22:49:52 -05:00
|
|
|
Editor::nudge_forward (bool next, bool force_playhead)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t distance;
|
|
|
|
framepos_t next_distance;
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (!force_playhead && !rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
begin_reversible_command (_("nudge regions forward"));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r ((*i)->region());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
distance = get_nudge_distance (r->position(), next_distance);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
r->clear_changes ();
|
2011-05-30 09:54:44 -04:00
|
|
|
r->set_position (r->position() + distance);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (r));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-18 22:49:52 -05:00
|
|
|
} else if (!force_playhead && !selection->markers.empty()) {
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
bool is_start;
|
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
begin_reversible_command (_("nudge location forward"));
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
Location* loc = find_location_from_marker ((*i), is_start);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
if (loc) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
XMLNode& before (loc->get_state());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
if (is_start) {
|
|
|
|
distance = get_nudge_distance (loc->start(), next_distance);
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
2010-09-17 12:24:22 -04:00
|
|
|
if (max_framepos - distance > loc->start() + loc->length()) {
|
2008-09-19 10:38:46 -04:00
|
|
|
loc->set_start (loc->start() + distance);
|
|
|
|
} else {
|
2010-09-17 12:24:22 -04:00
|
|
|
loc->set_start (max_framepos - loc->length());
|
2008-09-19 10:38:46 -04:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2008-09-19 10:38:46 -04:00
|
|
|
distance = get_nudge_distance (loc->end(), next_distance);
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
2010-09-17 12:24:22 -04:00
|
|
|
if (max_framepos - distance > loc->end()) {
|
2008-09-19 10:38:46 -04:00
|
|
|
loc->set_end (loc->end() + distance);
|
|
|
|
} else {
|
2010-09-17 12:24:22 -04:00
|
|
|
loc->set_end (max_framepos);
|
2008-09-19 10:38:46 -04:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2008-09-19 10:38:46 -04:00
|
|
|
XMLNode& after (loc->get_state());
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command (new MementoCommand<Location>(*loc, &before, &after));
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
commit_reversible_command ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2013-04-04 00:32:52 -04:00
|
|
|
distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
|
|
|
|
_session->request_locate (playhead_cursor->current_frame () + distance);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2008-01-18 22:49:52 -05:00
|
|
|
Editor::nudge_backward (bool next, bool force_playhead)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t distance;
|
|
|
|
framepos_t next_distance;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (!force_playhead && !rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
begin_reversible_command (_("nudge regions backward"));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r ((*i)->region());
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
distance = get_nudge_distance (r->position(), next_distance);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
r->clear_changes ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
if (r->position() > distance) {
|
2011-05-30 09:54:44 -04:00
|
|
|
r->set_position (r->position() - distance);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2011-05-30 09:54:44 -04:00
|
|
|
r->set_position (0);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (r));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
2008-01-18 22:49:52 -05:00
|
|
|
} else if (!force_playhead && !selection->markers.empty()) {
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
bool is_start;
|
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
begin_reversible_command (_("nudge location forward"));
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
Location* loc = find_location_from_marker ((*i), is_start);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
if (loc) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
XMLNode& before (loc->get_state());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
if (is_start) {
|
|
|
|
distance = get_nudge_distance (loc->start(), next_distance);
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
if (distance < loc->start()) {
|
|
|
|
loc->set_start (loc->start() - distance);
|
|
|
|
} else {
|
|
|
|
loc->set_start (0);
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2008-09-19 10:38:46 -04:00
|
|
|
distance = get_nudge_distance (loc->end(), next_distance);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
if (distance < loc->end() - loc->length()) {
|
|
|
|
loc->set_end (loc->end() - distance);
|
|
|
|
} else {
|
|
|
|
loc->set_end (loc->length());
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-19 10:38:46 -04:00
|
|
|
XMLNode& after (loc->get_state());
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command (new MementoCommand<Location>(*loc, &before, &after));
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
}
|
2008-09-19 10:38:46 -04:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
if (playhead_cursor->current_frame () > distance) {
|
|
|
|
_session->request_locate (playhead_cursor->current_frame () - distance);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->goto_start();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::nudge_forward_capture_offset ()
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
begin_reversible_command (_("nudge forward"));
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
framepos_t const distance = _session->worst_output_latency();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
boost::shared_ptr<Region> r ((*i)->region());
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
r->clear_changes ();
|
2011-05-30 09:54:44 -04:00
|
|
|
r->set_position (r->position() + distance);
|
2010-11-03 18:19:29 -04:00
|
|
|
_session->add_command(new StatefulDiffCommand (r));
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::nudge_backward_capture_offset ()
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
2010-10-19 20:19:09 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2012-03-17 10:15:22 -04:00
|
|
|
begin_reversible_command (_("nudge backward"));
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
framepos_t const distance = _session->worst_output_latency();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
boost::shared_ptr<Region> r ((*i)->region());
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
r->clear_changes ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (r->position() > distance) {
|
2011-05-30 09:54:44 -04:00
|
|
|
r->set_position (r->position() - distance);
|
2010-11-03 18:19:29 -04:00
|
|
|
} else {
|
2011-05-30 09:54:44 -04:00
|
|
|
r->set_position (0);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
_session->add_command(new StatefulDiffCommand (r));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2014-04-29 00:11:05 -04:00
|
|
|
struct RegionSelectionPositionSorter {
|
|
|
|
bool operator() (RegionView* a, RegionView* b) {
|
|
|
|
return a->region()->position() < b->region()->position();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::sequence_regions ()
|
|
|
|
{
|
|
|
|
framepos_t r_end;
|
|
|
|
framepos_t r_end_prev;
|
|
|
|
|
|
|
|
int iCount=0;
|
|
|
|
|
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
|
|
|
rs.sort(RegionSelectionPositionSorter());
|
|
|
|
|
|
|
|
if (!rs.empty()) {
|
|
|
|
|
|
|
|
begin_reversible_command (_("sequence regions"));
|
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
boost::shared_ptr<Region> r ((*i)->region());
|
|
|
|
|
|
|
|
r->clear_changes();
|
|
|
|
|
|
|
|
if(r->locked())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(r->position_locked())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(iCount>0)
|
|
|
|
{
|
|
|
|
r_end_prev=r_end;
|
|
|
|
r->set_position(r_end_prev);
|
|
|
|
}
|
|
|
|
|
|
|
|
_session->add_command (new StatefulDiffCommand (r));
|
|
|
|
|
|
|
|
r_end=r->position() + r->length();
|
|
|
|
|
|
|
|
iCount++;
|
|
|
|
}
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* DISPLAY MOTION */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::move_to_start ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->goto_start ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::move_to_end ()
|
|
|
|
{
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (_session->current_end_frame());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::build_region_boundary_cache ()
|
|
|
|
{
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t pos = 0;
|
2007-04-12 19:20:37 -04:00
|
|
|
vector<RegionPoint> interesting_points;
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r;
|
2005-09-25 14:42:24 -04:00
|
|
|
TrackViewList tracks;
|
2007-04-12 19:20:37 -04:00
|
|
|
bool at_end = false;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
region_boundary_cache.clear ();
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-10-26 19:43:04 -04:00
|
|
|
switch (_snap_type) {
|
2005-09-25 14:42:24 -04:00
|
|
|
case SnapToRegionStart:
|
2007-04-12 19:20:37 -04:00
|
|
|
interesting_points.push_back (Start);
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
case SnapToRegionEnd:
|
2007-04-12 19:20:37 -04:00
|
|
|
interesting_points.push_back (End);
|
2009-10-14 12:10:01 -04:00
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
case SnapToRegionSync:
|
2007-04-12 19:20:37 -04:00
|
|
|
interesting_points.push_back (SyncPoint);
|
2009-10-14 12:10:01 -04:00
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
case SnapToRegionBoundary:
|
2007-04-12 19:20:37 -04:00
|
|
|
interesting_points.push_back (Start);
|
|
|
|
interesting_points.push_back (End);
|
2009-10-14 12:10:01 -04:00
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
default:
|
2009-10-26 19:43:04 -04:00
|
|
|
fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
|
2014-11-14 04:47:43 -05:00
|
|
|
abort(); /*NOTREACHED*/
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
TimeAxisView *ontrack = 0;
|
2007-04-12 19:20:37 -04:00
|
|
|
TrackViewList tlist;
|
2011-12-10 14:20:15 -05:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if (!selection->tracks.empty()) {
|
2011-12-10 14:20:15 -05:00
|
|
|
tlist = selection->tracks.filter_to_unique_playlists ();
|
2007-04-12 19:20:37 -04:00
|
|
|
} else {
|
2011-12-10 14:20:15 -05:00
|
|
|
tlist = track_views.filter_to_unique_playlists ();
|
2007-04-12 19:20:37 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
while (pos < _session->current_end_frame() && !at_end) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t rpos;
|
2010-09-17 12:24:22 -04:00
|
|
|
framepos_t lpos = max_framepos;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
|
2007-10-11 18:07:47 -04:00
|
|
|
if (*p == interesting_points.back()) {
|
|
|
|
at_end = true;
|
|
|
|
}
|
2007-04-12 19:20:37 -04:00
|
|
|
/* move to next point type */
|
|
|
|
continue;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
switch (*p) {
|
|
|
|
case Start:
|
|
|
|
rpos = r->first_frame();
|
|
|
|
break;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
case End:
|
|
|
|
rpos = r->last_frame();
|
2009-10-14 12:10:01 -04:00
|
|
|
break;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
case SyncPoint:
|
2009-04-15 14:04:23 -04:00
|
|
|
rpos = r->sync_position ();
|
2007-04-12 19:20:37 -04:00
|
|
|
break;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
default:
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
float speed = 1.0f;
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView *rtav;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
|
2010-04-21 16:42:22 -04:00
|
|
|
if (rtav->track() != 0) {
|
|
|
|
speed = rtav->track()->speed();
|
2007-04-12 19:20:37 -04:00
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
rpos = track_frame_to_session_frame (rpos, speed);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if (rpos < lpos) {
|
|
|
|
lpos = rpos;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
/* prevent duplicates, but we don't use set<> because we want to be able
|
|
|
|
to sort later.
|
|
|
|
*/
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
vector<framepos_t>::iterator ri;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
|
|
|
|
if (*ri == rpos) {
|
|
|
|
break;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if (ri == region_boundary_cache.end()) {
|
|
|
|
region_boundary_cache.push_back (rpos);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
pos = lpos + 1;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-04-12 19:20:37 -04:00
|
|
|
|
|
|
|
/* finally sort to be sure that the order is correct */
|
|
|
|
|
|
|
|
sort (region_boundary_cache.begin(), region_boundary_cache.end());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region>
|
2010-07-06 07:33:27 -04:00
|
|
|
Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
TrackViewList::iterator i;
|
2010-09-17 12:24:22 -04:00
|
|
|
framepos_t closest = max_framepos;
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> ret;
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t rpos = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
float track_speed;
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t track_frame;
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView *rtav;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
for (i = tracks.begin(); i != tracks.end(); ++i) {
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
framecnt_t distance;
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
track_speed = 1.0f;
|
2009-07-09 13:58:13 -04:00
|
|
|
if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
|
2010-04-21 16:42:22 -04:00
|
|
|
if (rtav->track()!=0)
|
|
|
|
track_speed = rtav->track()->speed();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2005-11-14 10:44:23 -05:00
|
|
|
track_frame = session_frame_to_track_frame(frame, track_speed);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (point) {
|
|
|
|
case Start:
|
|
|
|
rpos = r->first_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case End:
|
|
|
|
rpos = r->last_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyncPoint:
|
2009-04-15 14:04:23 -04:00
|
|
|
rpos = r->sync_position ();
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
// rpos is a "track frame", converting it to "_session frame"
|
2005-11-14 10:44:23 -05:00
|
|
|
rpos = track_frame_to_session_frame(rpos, track_speed);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (rpos > frame) {
|
|
|
|
distance = rpos - frame;
|
|
|
|
} else {
|
|
|
|
distance = frame - rpos;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (distance < closest) {
|
|
|
|
closest = distance;
|
|
|
|
if (ontrack != 0)
|
|
|
|
*ontrack = (*i);
|
|
|
|
ret = r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t
|
|
|
|
Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2010-09-17 12:24:22 -04:00
|
|
|
framecnt_t distance = max_framepos;
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t current_nearest = -1;
|
2009-04-15 14:04:23 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t contender;
|
|
|
|
framecnt_t d;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (!rtv) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
d = ::llabs (pos - contender);
|
|
|
|
|
|
|
|
if (d < distance) {
|
|
|
|
current_nearest = contender;
|
|
|
|
distance = d;
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
return current_nearest;
|
|
|
|
}
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t
|
|
|
|
Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
|
2009-04-15 14:04:23 -04:00
|
|
|
{
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t target;
|
2009-04-15 14:04:23 -04:00
|
|
|
TrackViewList tvl;
|
|
|
|
|
|
|
|
if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
|
|
|
|
|
|
|
|
if (!selection->tracks.empty()) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-15 14:04:23 -04:00
|
|
|
target = find_next_region_boundary (pos, dir, selection->tracks);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-15 14:04:23 -04:00
|
|
|
} else {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-15 14:04:23 -04:00
|
|
|
if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
|
|
|
|
get_onscreen_tracks (tvl);
|
|
|
|
target = find_next_region_boundary (pos, dir, tvl);
|
|
|
|
} else {
|
|
|
|
target = find_next_region_boundary (pos, dir, track_views);
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-15 14:04:23 -04:00
|
|
|
} else {
|
|
|
|
|
|
|
|
if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
|
|
|
|
get_onscreen_tracks (tvl);
|
|
|
|
target = find_next_region_boundary (pos, dir, tvl);
|
|
|
|
} else {
|
|
|
|
target = find_next_region_boundary (pos, dir, track_views);
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-15 14:04:23 -04:00
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
2009-04-15 14:04:23 -04:00
|
|
|
Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2013-04-04 00:32:52 -04:00
|
|
|
framepos_t pos = playhead_cursor->current_frame ();
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t target;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// so we don't find the current region again..
|
|
|
|
if (dir > 0 || pos > 0) {
|
|
|
|
pos += dir;
|
|
|
|
}
|
|
|
|
|
2009-04-15 14:04:23 -04:00
|
|
|
if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (target);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-04-15 14:04:23 -04:00
|
|
|
Editor::cursor_to_next_region_boundary (bool with_selection)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2009-04-15 14:04:23 -04:00
|
|
|
cursor_to_region_boundary (with_selection, 1);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-04-15 14:04:23 -04:00
|
|
|
Editor::cursor_to_previous_region_boundary (bool with_selection)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2009-04-15 14:04:23 -04:00
|
|
|
cursor_to_region_boundary (with_selection, -1);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2009-05-30 14:25:59 -04:00
|
|
|
Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r;
|
2013-04-04 00:32:52 -04:00
|
|
|
framepos_t pos = cursor->current_frame ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
TimeAxisView *ontrack = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
// so we don't find the current region again..
|
|
|
|
if (dir>0 || pos>0)
|
|
|
|
pos+=dir;
|
|
|
|
|
|
|
|
if (!selection->tracks.empty()) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2006-08-16 16:36:14 -04:00
|
|
|
} else if (clicked_axisview) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
TrackViewList t;
|
2006-08-16 16:36:14 -04:00
|
|
|
t.push_back (clicked_axisview);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
r = find_next_region (pos, point, dir, t, &ontrack);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
r = find_next_region (pos, point, dir, track_views, &ontrack);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
switch (point) {
|
2005-09-25 14:42:24 -04:00
|
|
|
case Start:
|
|
|
|
pos = r->first_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case End:
|
|
|
|
pos = r->last_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyncPoint:
|
2009-04-15 14:04:23 -04:00
|
|
|
pos = r->sync_position ();
|
2009-10-14 12:10:01 -04:00
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
float speed = 1.0f;
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView *rtav;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
|
2010-04-21 16:42:22 -04:00
|
|
|
if (rtav->track() != 0) {
|
|
|
|
speed = rtav->track()->speed();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-14 10:44:23 -05:00
|
|
|
pos = track_frame_to_session_frame(pos, speed);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (cursor == playhead_cursor) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (pos);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
cursor->set_position (pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-30 14:25:59 -04:00
|
|
|
Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
cursor_to_region_point (cursor, point, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-30 14:25:59 -04:00
|
|
|
Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
cursor_to_region_point (cursor, point, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-30 14:25:59 -04:00
|
|
|
Editor::cursor_to_selection_start (EditorCursor *cursor)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos = 0;
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
pos = selection->regions.start();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MouseRange:
|
|
|
|
if (!selection->time.empty()) {
|
|
|
|
pos = selection->time.start ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cursor == playhead_cursor) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (pos);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
cursor->set_position (pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-30 14:25:59 -04:00
|
|
|
Editor::cursor_to_selection_end (EditorCursor *cursor)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
pos = selection->regions.end_frame();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MouseRange:
|
|
|
|
if (!selection->time.empty()) {
|
|
|
|
pos = selection->time.end_frame ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cursor == playhead_cursor) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (pos);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
cursor->set_position (pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
2009-04-15 14:04:23 -04:00
|
|
|
Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t target;
|
2008-01-10 16:20:59 -05:00
|
|
|
Location* loc;
|
|
|
|
bool ignored;
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->markers.empty()) {
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t mouse;
|
2008-01-10 16:20:59 -05:00
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!mouse_frame (mouse, ignored)) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
add_location_mark (mouse);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos = loc->start();
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
// so we don't find the current region again..
|
|
|
|
if (dir > 0 || pos > 0) {
|
|
|
|
pos += dir;
|
|
|
|
}
|
|
|
|
|
2009-04-15 14:04:23 -04:00
|
|
|
if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
loc->move_to (target);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-04-15 14:04:23 -04:00
|
|
|
Editor::selected_marker_to_next_region_boundary (bool with_selection)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2009-04-15 14:04:23 -04:00
|
|
|
selected_marker_to_region_boundary (with_selection, 1);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-04-15 14:04:23 -04:00
|
|
|
Editor::selected_marker_to_previous_region_boundary (bool with_selection)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2009-04-15 14:04:23 -04:00
|
|
|
selected_marker_to_region_boundary (with_selection, -1);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
|
|
|
boost::shared_ptr<Region> r;
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos;
|
2007-11-12 17:23:01 -05:00
|
|
|
Location* loc;
|
|
|
|
bool ignored;
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || selection->markers.empty()) {
|
2007-11-12 17:23:01 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
TimeAxisView *ontrack = 0;
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
pos = loc->start();
|
|
|
|
|
|
|
|
// so we don't find the current region again..
|
|
|
|
if (dir>0 || pos>0)
|
|
|
|
pos+=dir;
|
|
|
|
|
|
|
|
if (!selection->tracks.empty()) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
} else {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
r = find_next_region (pos, point, dir, track_views, &ontrack);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
switch (point) {
|
2007-11-12 17:23:01 -05:00
|
|
|
case Start:
|
|
|
|
pos = r->first_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case End:
|
|
|
|
pos = r->last_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyncPoint:
|
|
|
|
pos = r->adjust_to_sync (r->first_frame());
|
2009-10-14 12:10:01 -04:00
|
|
|
break;
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
float speed = 1.0f;
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView *rtav;
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
|
2010-04-21 16:42:22 -04:00
|
|
|
if (rtav->track() != 0) {
|
|
|
|
speed = rtav->track()->speed();
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = track_frame_to_session_frame(pos, speed);
|
|
|
|
|
|
|
|
loc->move_to (pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::selected_marker_to_next_region_point (RegionPoint point)
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
selected_marker_to_region_point (point, 1);
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::selected_marker_to_previous_region_point (RegionPoint point)
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
selected_marker_to_region_point (point, -1);
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::selected_marker_to_selection_start ()
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos = 0;
|
2007-11-12 17:23:01 -05:00
|
|
|
Location* loc;
|
|
|
|
bool ignored;
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || selection->markers.empty()) {
|
2007-11-12 17:23:01 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
pos = selection->regions.start();
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MouseRange:
|
|
|
|
if (!selection->time.empty()) {
|
|
|
|
pos = selection->time.start ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
loc->move_to (pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::selected_marker_to_selection_end ()
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos = 0;
|
2007-11-12 17:23:01 -05:00
|
|
|
Location* loc;
|
|
|
|
bool ignored;
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || selection->markers.empty()) {
|
2007-11-12 17:23:01 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
pos = selection->regions.end_frame();
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MouseRange:
|
|
|
|
if (!selection->time.empty()) {
|
|
|
|
pos = selection->time.end_frame ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
loc->move_to (pos);
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
|
|
|
Editor::scroll_playhead (bool forward)
|
|
|
|
{
|
2013-04-04 00:32:52 -04:00
|
|
|
framepos_t pos = playhead_cursor->current_frame ();
|
2013-04-12 11:21:12 -04:00
|
|
|
framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
if (forward) {
|
2010-09-17 12:24:22 -04:00
|
|
|
if (pos == max_framepos) {
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-17 12:24:22 -04:00
|
|
|
if (pos < max_framepos - delta) {
|
2007-01-28 12:44:13 -05:00
|
|
|
pos += delta ;
|
|
|
|
} else {
|
2010-09-17 12:24:22 -04:00
|
|
|
pos = max_framepos;
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (pos == 0) {
|
|
|
|
return;
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
if (pos > delta) {
|
|
|
|
pos -= delta;
|
|
|
|
} else {
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (pos);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::cursor_align (bool playhead_to_edit)
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2007-11-12 17:23:01 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (playhead_to_edit) {
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
if (selection->markers.empty()) {
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2007-11-12 17:23:01 -05:00
|
|
|
/* move selected markers to playhead */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
|
|
|
|
bool ignored;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
Location* loc = find_location_from_marker (*i, ignored);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if (loc->is_mark()) {
|
2013-04-04 00:32:52 -04:00
|
|
|
loc->set_start (playhead_cursor->current_frame ());
|
2007-11-12 17:23:01 -05:00
|
|
|
} else {
|
2013-04-04 00:32:52 -04:00
|
|
|
loc->set (playhead_cursor->current_frame (),
|
|
|
|
playhead_cursor->current_frame () + loc->length());
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_backward (float pages)
|
|
|
|
{
|
2013-04-12 11:31:50 -04:00
|
|
|
framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
|
2011-03-01 19:30:28 -05:00
|
|
|
framepos_t const cnt = (framepos_t) floor (pages * one_page);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-03-01 19:30:28 -05:00
|
|
|
framepos_t frame;
|
2005-09-25 14:42:24 -04:00
|
|
|
if (leftmost_frame < cnt) {
|
|
|
|
frame = 0;
|
|
|
|
} else {
|
|
|
|
frame = leftmost_frame - cnt;
|
|
|
|
}
|
|
|
|
|
2007-01-11 15:36:35 -05:00
|
|
|
reset_x_origin (frame);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_forward (float pages)
|
|
|
|
{
|
2013-04-12 11:31:50 -04:00
|
|
|
framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
|
2011-03-01 19:30:28 -05:00
|
|
|
framepos_t const cnt = (framepos_t) floor (pages * one_page);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-03-01 19:30:28 -05:00
|
|
|
framepos_t frame;
|
2010-09-17 12:24:22 -04:00
|
|
|
if (max_framepos - cnt < leftmost_frame) {
|
|
|
|
frame = max_framepos - cnt;
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
frame = leftmost_frame + cnt;
|
|
|
|
}
|
|
|
|
|
2007-01-11 15:36:35 -05:00
|
|
|
reset_x_origin (frame);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_tracks_down ()
|
|
|
|
{
|
2011-03-01 19:30:28 -05:00
|
|
|
double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
|
2013-04-04 00:32:52 -04:00
|
|
|
if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
|
|
|
|
vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
|
2006-04-09 22:14:05 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2006-04-09 22:14:05 -04:00
|
|
|
vertical_adjustment.set_value (vert_value);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_tracks_up ()
|
|
|
|
{
|
2011-03-01 19:30:28 -05:00
|
|
|
vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_tracks_down_line ()
|
|
|
|
{
|
2009-12-01 13:38:24 -05:00
|
|
|
double vert_value = vertical_adjustment.get_value() + 60;
|
2006-04-09 22:14:05 -04:00
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
|
|
|
|
vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
|
2006-04-09 22:14:05 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2009-12-01 13:38:24 -05:00
|
|
|
vertical_adjustment.set_value (vert_value);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_tracks_up_line ()
|
|
|
|
{
|
2009-12-01 13:38:24 -05:00
|
|
|
reset_y_origin (vertical_adjustment.get_value() - 60);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2014-03-20 21:59:37 -04:00
|
|
|
bool
|
|
|
|
Editor::scroll_down_one_track ()
|
|
|
|
{
|
2014-10-29 01:35:55 -04:00
|
|
|
TrackViewList::reverse_iterator next = track_views.rend();
|
2014-03-20 21:59:37 -04:00
|
|
|
std::pair<TimeAxisView*,double> res;
|
2014-07-14 12:36:44 -04:00
|
|
|
const double top_of_trackviews = vertical_adjustment.get_value();
|
2014-03-20 21:59:37 -04:00
|
|
|
|
|
|
|
for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
|
|
|
|
if ((*t)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-07-14 12:36:44 -04:00
|
|
|
|
|
|
|
|
|
|
|
/* If this is the upper-most visible trackview, we want to display
|
|
|
|
the one above it (next)
|
2014-06-17 08:08:07 -04:00
|
|
|
*/
|
|
|
|
|
2014-07-14 12:36:44 -04:00
|
|
|
res = (*t)->covers_y_position (top_of_trackviews);
|
2014-03-20 21:59:37 -04:00
|
|
|
|
|
|
|
if (res.first) {
|
|
|
|
break;
|
|
|
|
}
|
2014-10-29 01:35:55 -04:00
|
|
|
next = t;
|
2014-03-20 21:59:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* move to the track below the first one that covers the */
|
|
|
|
|
2014-10-29 01:35:55 -04:00
|
|
|
if (next != track_views.rend()) {
|
2014-07-14 12:36:44 -04:00
|
|
|
ensure_time_axis_view_is_visible (**next, true);
|
2014-03-20 21:59:37 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
Editor::scroll_up_one_track ()
|
|
|
|
{
|
|
|
|
TrackViewList::iterator prev = track_views.end();
|
|
|
|
std::pair<TimeAxisView*,double> res;
|
2014-07-14 12:36:44 -04:00
|
|
|
double top_of_trackviews = vertical_adjustment.get_value ();
|
|
|
|
|
2014-03-20 21:59:37 -04:00
|
|
|
for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
|
|
|
|
|
|
|
|
if ((*t)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-06-03 15:57:56 -04:00
|
|
|
/* find the trackview at the top of the trackview group */
|
2014-07-14 12:36:44 -04:00
|
|
|
res = (*t)->covers_y_position (top_of_trackviews);
|
2014-03-20 21:59:37 -04:00
|
|
|
|
|
|
|
if (res.first) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prev != track_views.end()) {
|
2014-07-14 12:36:44 -04:00
|
|
|
ensure_time_axis_view_is_visible (**prev, true);
|
2014-03-20 21:59:37 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* ZOOM */
|
|
|
|
|
2009-08-24 18:28:00 -04:00
|
|
|
void
|
|
|
|
Editor::tav_zoom_step (bool coarser)
|
|
|
|
{
|
2014-06-28 20:52:56 -04:00
|
|
|
DisplaySuspender ds;
|
2009-08-24 18:28:00 -04:00
|
|
|
|
2012-04-09 14:53:51 -04:00
|
|
|
TrackViewList* ts;
|
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
|
2009-08-24 18:28:00 -04:00
|
|
|
TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
|
|
|
|
tv->step_height (coarser);
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2009-08-24 18:28:00 -04:00
|
|
|
|
2012-04-09 14:53:51 -04:00
|
|
|
void
|
|
|
|
Editor::tav_zoom_smooth (bool coarser, bool force_all)
|
|
|
|
{
|
2014-06-28 20:52:56 -04:00
|
|
|
DisplaySuspender ds;
|
2012-04-09 14:53:51 -04:00
|
|
|
|
|
|
|
TrackViewList* ts;
|
|
|
|
|
|
|
|
if (selection->tracks.empty() || force_all) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
|
|
|
|
TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
|
|
|
|
uint32_t h = tv->current_height ();
|
|
|
|
|
|
|
|
if (coarser) {
|
|
|
|
if (h > 5) {
|
|
|
|
h -= 5; // pixels
|
|
|
|
if (h >= TimeAxisView::preset_height (HeightSmall)) {
|
|
|
|
tv->set_height (h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tv->set_height (h + 5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:14:27 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::temporal_zoom_step (bool coarser)
|
|
|
|
{
|
2009-12-11 18:29:48 -05:00
|
|
|
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
|
2006-04-06 12:51:27 -04:00
|
|
|
|
2013-06-18 23:02:54 -04:00
|
|
|
framecnt_t nspp = samples_per_pixel;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
|
|
|
if (coarser) {
|
2013-06-18 23:02:54 -04:00
|
|
|
nspp *= 2;
|
2009-10-14 12:10:01 -04:00
|
|
|
} else {
|
2013-06-18 23:02:54 -04:00
|
|
|
nspp /= 2;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2013-06-18 23:02:54 -04:00
|
|
|
temporal_zoom (nspp);
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
void
|
2013-06-18 23:02:54 -04:00
|
|
|
Editor::temporal_zoom (framecnt_t fpp)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2012-06-20 10:14:27 -04:00
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2013-04-12 11:21:12 -04:00
|
|
|
framepos_t current_page = current_page_samples();
|
2010-09-17 14:20:37 -04:00
|
|
|
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;
|
2007-11-07 20:40:25 -05:00
|
|
|
bool in_track_canvas;
|
2013-06-18 23:02:54 -04:00
|
|
|
framecnt_t nfpp;
|
2008-01-10 16:20:59 -05:00
|
|
|
double l;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2013-04-12 11:31:50 -04:00
|
|
|
if (fpp == samples_per_pixel) {
|
2008-01-15 12:23:57 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-02 10:51:53 -04:00
|
|
|
// Imposing an arbitrary limit to zoom out as too much zoom out produces
|
|
|
|
// segfaults for lack of memory. If somebody decides this is not high enough I
|
|
|
|
// believe it can be raisen to higher values but some limit must be in place.
|
2013-12-31 15:19:39 -05:00
|
|
|
//
|
|
|
|
// This constant represents 1 day @ 48kHz on a 1600 pixel wide display
|
|
|
|
// all of which is used for the editor track displays. The whole day
|
|
|
|
// would be 4147200000 samples, so 2592000 samples per pixel.
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2013-12-31 15:19:39 -05:00
|
|
|
nfpp = min (fpp, (framecnt_t) 2592000);
|
2014-11-18 02:22:06 -05:00
|
|
|
nfpp = max ((framecnt_t) 1, nfpp);
|
2013-06-18 23:02:54 -04:00
|
|
|
|
2013-06-25 21:56:10 -04:00
|
|
|
new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
|
2008-01-10 16:20:59 -05:00
|
|
|
half_page_size = new_page_size / 2;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
switch (zoom_focus) {
|
|
|
|
case ZoomFocusLeft:
|
|
|
|
leftmost_after_zoom = current_leftmost;
|
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
case ZoomFocusRight:
|
|
|
|
current_rightmost = leftmost_frame + current_page;
|
2008-01-10 16:20:59 -05:00
|
|
|
if (current_rightmost < new_page_size) {
|
2005-09-25 14:42:24 -04:00
|
|
|
leftmost_after_zoom = 0;
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = current_rightmost - new_page_size;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
case ZoomFocusCenter:
|
2009-10-14 12:10:01 -04:00
|
|
|
current_center = current_leftmost + (current_page/2);
|
2008-01-10 16:20:59 -05:00
|
|
|
if (current_center < half_page_size) {
|
2005-09-25 14:42:24 -04:00
|
|
|
leftmost_after_zoom = 0;
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = current_center - half_page_size;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
case ZoomFocusPlayhead:
|
2010-01-14 20:06:13 -05:00
|
|
|
/* centre playhead */
|
2013-04-04 00:32:52 -04:00
|
|
|
l = playhead_cursor->current_frame () - (new_page_size * 0.5);
|
2008-01-15 12:23:57 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (l < 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
leftmost_after_zoom = 0;
|
2010-09-17 12:24:22 -04:00
|
|
|
} else if (l > max_framepos) {
|
|
|
|
leftmost_after_zoom = max_framepos - new_page_size;
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2010-09-17 14:20:37 -04:00
|
|
|
leftmost_after_zoom = (framepos_t) l;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
case ZoomFocusMouse:
|
|
|
|
/* try to keep the mouse over the same point in the display */
|
|
|
|
|
|
|
|
if (!mouse_frame (where, in_track_canvas)) {
|
|
|
|
/* use playhead instead */
|
2013-04-04 00:32:52 -04:00
|
|
|
where = playhead_cursor->current_frame ();
|
2007-11-07 20:40:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (where < half_page_size) {
|
2007-11-07 20:40:25 -05:00
|
|
|
leftmost_after_zoom = 0;
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = where - half_page_size;
|
2007-11-07 20:40:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
|
2007-11-07 20:40:25 -05:00
|
|
|
|
|
|
|
if (l < 0) {
|
|
|
|
leftmost_after_zoom = 0;
|
2010-09-17 12:24:22 -04:00
|
|
|
} else if (l > max_framepos) {
|
|
|
|
leftmost_after_zoom = max_framepos - new_page_size;
|
2007-11-07 20:40:25 -05:00
|
|
|
} else {
|
2010-09-17 14:20:37 -04:00
|
|
|
leftmost_after_zoom = (framepos_t) l;
|
2007-11-07 20:40:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
case ZoomFocusEdit:
|
2008-01-10 16:20:59 -05:00
|
|
|
/* 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;
|
2010-09-17 12:24:22 -04:00
|
|
|
} else if (l > max_framepos) {
|
|
|
|
leftmost_after_zoom = max_framepos - new_page_size;
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2010-09-17 14:20:37 -04:00
|
|
|
leftmost_after_zoom = (framepos_t) l;
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2008-01-10 16:20:59 -05:00
|
|
|
/* edit point not defined */
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
// leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
reposition_and_zoom (leftmost_after_zoom, nfpp);
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2014-07-23 12:28:45 -04:00
|
|
|
void
|
|
|
|
Editor::calc_extra_zoom_edges(framepos_t &start, framepos_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
|
|
|
|
precisely to the screen.
|
|
|
|
*/
|
|
|
|
|
|
|
|
GdkScreen* screen = gdk_screen_get_default ();
|
2014-10-21 14:48:45 -04:00
|
|
|
const gint pixwidth = gdk_screen_get_width (screen);
|
|
|
|
const gint mmwidth = gdk_screen_get_width_mm (screen);
|
|
|
|
const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
|
|
|
|
const double one_centimeter_in_pixels = pix_per_mm * 10.0;
|
2014-07-23 12:28:45 -04:00
|
|
|
|
2014-10-21 14:48:45 -04:00
|
|
|
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);
|
2014-07-23 12:28:45 -04:00
|
|
|
|
|
|
|
if (start > extra_samples) {
|
|
|
|
start -= extra_samples;
|
|
|
|
} else {
|
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max_framepos - extra_samples > end) {
|
|
|
|
end += extra_samples;
|
|
|
|
} else {
|
|
|
|
end = max_framepos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
2008-09-10 11:03:30 -04:00
|
|
|
Editor::temporal_zoom_region (bool both_axes)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2010-09-17 12:24:22 -04:00
|
|
|
framepos_t start = max_framepos;
|
|
|
|
framepos_t end = 0;
|
2009-07-09 13:58:13 -04:00
|
|
|
set<TimeAxisView*> tracks;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
if ( !get_selection_extents(start, end) )
|
2008-09-10 11:03:30 -04:00
|
|
|
return;
|
2015-01-07 16:31:05 -05:00
|
|
|
|
2014-10-21 14:48:45 -04:00
|
|
|
calc_extra_zoom_edges (start, end);
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2012-03-06 21:11:59 -05:00
|
|
|
/* if we're zooming on both axes we need to save track heights etc.
|
|
|
|
*/
|
2008-09-10 11:03:30 -04:00
|
|
|
|
2012-03-06 21:11:59 -05:00
|
|
|
undo_visual_stack.push_back (current_visual_state (both_axes));
|
2008-09-10 11:03:30 -04:00
|
|
|
|
2012-03-06 21:11:59 -05:00
|
|
|
PBD::Unwinder<bool> nsv (no_save_visual, true);
|
|
|
|
|
2012-03-22 12:41:44 -04:00
|
|
|
temporal_zoom_by_frame (start, end);
|
2012-03-06 21:11:59 -05:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
if (both_axes) {
|
2013-04-04 00:32:52 -04:00
|
|
|
uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
/* set visible track heights appropriately */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
|
2008-09-10 11:03:30 -04:00
|
|
|
(*t)->set_height (per_track_height);
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
/* hide irrelevant tracks */
|
2009-07-01 19:20:18 -04:00
|
|
|
|
2014-06-28 20:52:56 -04:00
|
|
|
DisplaySuspender ds;
|
2008-09-10 11:03:30 -04:00
|
|
|
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
|
2011-03-07 08:05:45 -05:00
|
|
|
hide_track_in_display (*i);
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-22 14:24:30 -04:00
|
|
|
vertical_adjustment.set_value (0.0);
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
|
|
|
|
2012-03-06 21:11:59 -05:00
|
|
|
redo_visual_stack.push_back (current_visual_state (both_axes));
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
bool
|
|
|
|
Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
|
|
|
|
{
|
|
|
|
start = max_framepos;
|
|
|
|
end = 0;
|
|
|
|
bool ret = true;
|
|
|
|
|
|
|
|
//ToDo: if notes are selected, set extents to that selection
|
|
|
|
|
|
|
|
//ToDo: if control points are selected, set extents to that selection
|
|
|
|
|
|
|
|
if ( !selection->regions.empty() ) {
|
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
|
|
|
|
if ((*i)->region()->position() < start) {
|
|
|
|
start = (*i)->region()->position();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*i)->region()->last_frame() + 1 > end) {
|
|
|
|
end = (*i)->region()->last_frame() + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (!selection->time.empty()) {
|
|
|
|
start = selection->time.start();
|
|
|
|
end = selection->time.end_frame();
|
|
|
|
} else
|
|
|
|
ret = false; //no selection found
|
|
|
|
|
|
|
|
//range check
|
|
|
|
if ((start == 0 && end == 0) || end < start) {
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2014-07-23 12:28:45 -04:00
|
|
|
Editor::temporal_zoom_selection (bool both_axes)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (!selection) return;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-12-22 12:59:05 -05:00
|
|
|
//ToDo: if notes are selected, zoom to that
|
|
|
|
|
|
|
|
//ToDo: if control points are selected, zoom to that
|
|
|
|
|
|
|
|
//if region(s) are selected, zoom to that
|
|
|
|
if ( !selection->regions.empty() )
|
|
|
|
temporal_zoom_region (both_axes);
|
|
|
|
|
2014-07-23 12:28:45 -04:00
|
|
|
//if a range is selected, zoom to that
|
|
|
|
if (!selection->time.empty()) {
|
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
framepos_t start, end;
|
|
|
|
if (get_selection_extents (start, end)) {
|
|
|
|
calc_extra_zoom_edges(start, end);
|
|
|
|
temporal_zoom_by_frame (start, end);
|
|
|
|
}
|
|
|
|
|
2014-07-23 12:28:45 -04:00
|
|
|
if (both_axes)
|
2015-01-11 12:46:36 -05:00
|
|
|
fit_selection();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::temporal_zoom_session ()
|
|
|
|
{
|
2009-12-11 18:29:48 -05:00
|
|
|
ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
|
2006-04-06 12:51:27 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session) {
|
2014-07-23 12:28:45 -04:00
|
|
|
framecnt_t start = _session->current_start_frame();
|
|
|
|
framecnt_t end = _session->current_end_frame();
|
|
|
|
|
2014-08-02 07:52:51 -04:00
|
|
|
if (_session->actively_recording () ) {
|
|
|
|
framepos_t cur = playhead_cursor->current_frame ();
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-23 12:28:45 -04:00
|
|
|
if ((start == 0 && end == 0) || end < start) {
|
|
|
|
return;
|
2010-05-09 20:48:42 -04:00
|
|
|
}
|
2014-07-23 12:28:45 -04:00
|
|
|
|
|
|
|
calc_extra_zoom_edges(start, end);
|
|
|
|
|
|
|
|
temporal_zoom_by_frame (start, end);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-03-22 12:41:44 -04:00
|
|
|
Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) return;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if ((start == 0 && end == 0) || end < start) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t range = end - start;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2014-10-21 14:48:45 -04:00
|
|
|
const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
|
|
|
|
|
|
|
|
framepos_t new_page = range;
|
2013-04-04 00:32:52 -04:00
|
|
|
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));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
if (new_leftmost > middle) {
|
|
|
|
new_leftmost = 0;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2012-01-24 15:48:08 -05:00
|
|
|
if (new_leftmost < 0) {
|
|
|
|
new_leftmost = 0;
|
|
|
|
}
|
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
reposition_and_zoom (new_leftmost, new_fpp);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2008-09-10 17:27:39 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-05-28 12:18:30 -04:00
|
|
|
framecnt_t range_before = frame - leftmost_frame;
|
|
|
|
framecnt_t new_spp;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
|
|
|
if (coarser) {
|
2014-05-28 12:18:30 -04:00
|
|
|
if (samples_per_pixel <= 1) {
|
|
|
|
new_spp = 2;
|
|
|
|
} else {
|
|
|
|
new_spp = samples_per_pixel + (samples_per_pixel/2);
|
|
|
|
}
|
|
|
|
range_before += range_before/2;
|
2009-10-14 12:10:01 -04:00
|
|
|
} else {
|
2014-05-28 12:18:30 -04:00
|
|
|
if (samples_per_pixel >= 1) {
|
|
|
|
new_spp = samples_per_pixel - (samples_per_pixel/2);
|
|
|
|
} else {
|
|
|
|
/* could bail out here since we cannot zoom any finer,
|
2014-07-02 15:53:24 -04:00
|
|
|
but leave that to the equality test below
|
2014-05-28 12:18:30 -04:00
|
|
|
*/
|
|
|
|
new_spp = samples_per_pixel;
|
|
|
|
}
|
|
|
|
|
|
|
|
range_before -= range_before/2;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2014-05-28 12:18:30 -04:00
|
|
|
if (new_spp == samples_per_pixel) {
|
2008-09-10 17:27:39 -04:00
|
|
|
return;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2014-05-28 12:18:30 -04:00
|
|
|
/* zoom focus is automatically taken as @param frame when this
|
|
|
|
method is used.
|
|
|
|
*/
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t new_leftmost = frame - (framepos_t)range_before;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-09-10 17:27:39 -04:00
|
|
|
if (new_leftmost > frame) {
|
|
|
|
new_leftmost = 0;
|
|
|
|
}
|
2011-02-17 12:44:55 -05:00
|
|
|
|
|
|
|
if (new_leftmost < 0) {
|
|
|
|
new_leftmost = 0;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2014-05-28 12:18:30 -04:00
|
|
|
reposition_and_zoom (new_leftmost, new_spp);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
|
|
|
|
bool
|
|
|
|
Editor::choose_new_marker_name(string &name) {
|
|
|
|
|
2014-12-22 13:39:41 -05:00
|
|
|
if (!ARDOUR_UI::config()->get_name_new_markers()) {
|
2008-09-10 11:03:30 -04:00
|
|
|
/* don't prompt user for a new name */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ArdourPrompter dialog (true);
|
|
|
|
|
|
|
|
dialog.set_prompt (_("New Name:"));
|
|
|
|
|
2009-10-19 13:25:37 -04:00
|
|
|
dialog.set_title (_("New Location Marker"));
|
2008-09-10 11:03:30 -04:00
|
|
|
|
|
|
|
dialog.set_name ("MarkNameWindow");
|
|
|
|
dialog.set_size_request (250, -1);
|
|
|
|
dialog.set_position (Gtk::WIN_POS_MOUSE);
|
|
|
|
|
|
|
|
dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
|
|
|
|
dialog.set_initial_text (name);
|
|
|
|
|
|
|
|
dialog.show ();
|
|
|
|
|
|
|
|
switch (dialog.run ()) {
|
|
|
|
case RESPONSE_ACCEPT:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
dialog.get_result(name);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-03-31 18:00:40 -05:00
|
|
|
void
|
|
|
|
Editor::add_location_from_selection ()
|
|
|
|
{
|
2007-01-09 18:24:54 -05:00
|
|
|
string rangename;
|
|
|
|
|
2006-03-31 18:00:40 -05:00
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session == 0 || clicked_axisview == 0) {
|
2006-03-31 18:00:40 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start = selection->time[clicked_selection].start;
|
|
|
|
framepos_t end = selection->time[clicked_selection].end;
|
2006-03-31 18:00:40 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->next_available_name(rangename,"selection");
|
2010-08-09 12:40:31 -04:00
|
|
|
Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
|
2006-03-31 18:00:40 -05:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("add marker"));
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &before = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->add (location, true);
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &after = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2006-03-31 18:00:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::add_location_mark (framepos_t where)
|
2006-03-31 18:00:40 -05:00
|
|
|
{
|
2007-01-09 18:24:54 -05:00
|
|
|
string markername;
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
select_new_marker = true;
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->next_available_name(markername,"mark");
|
2008-09-10 11:03:30 -04:00
|
|
|
if (!choose_new_marker_name(markername)) {
|
|
|
|
return;
|
|
|
|
}
|
2010-08-09 12:40:31 -04:00
|
|
|
Location *location = new Location (*_session, where, where, markername, Location::IsMark);
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("add marker"));
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &before = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->add (location, true);
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &after = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2006-03-31 18:00:40 -05:00
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::add_location_from_playhead_cursor ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
add_location_mark (_session->audible_frame());
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
2014-07-03 18:50:14 -04:00
|
|
|
void
|
|
|
|
Editor::remove_location_at_playhead_cursor ()
|
|
|
|
{
|
|
|
|
if (_session) {
|
|
|
|
|
|
|
|
//set up for undo
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("remove marker"));
|
|
|
|
|
2014-07-03 18:50:14 -04:00
|
|
|
XMLNode &before = _session->locations()->get_state();
|
|
|
|
bool removed = false;
|
|
|
|
|
|
|
|
//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));
|
|
|
|
for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
|
|
|
|
if ((*i)->is_mark()) {
|
|
|
|
_session->locations()->remove (*i);
|
|
|
|
removed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//store undo
|
|
|
|
if (removed) {
|
|
|
|
XMLNode &after = _session->locations()->get_state();
|
|
|
|
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2014-07-03 18:50:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
/** Add a range marker around each selected region */
|
2006-03-31 18:00:40 -05:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::add_locations_from_region ()
|
2006-03-31 18:00:40 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (rs.empty()) {
|
2006-03-31 18:00:40 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
XMLNode &before = _session->locations()->get_state();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
boost::shared_ptr<Region> region = (*i)->region ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-08-09 12:40:31 -04:00
|
|
|
Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->add (location, true);
|
2008-12-12 09:43:24 -05:00
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
XMLNode &after = _session->locations()->get_state();
|
|
|
|
_session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2008-12-12 09:43:24 -05:00
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
/** Add a single range marker around all selected regions */
|
2008-12-12 09:43:24 -05:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::add_location_from_region ()
|
2008-12-12 09:43:24 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("add marker"));
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
XMLNode &before = _session->locations()->get_state();
|
2008-12-12 09:43:24 -05:00
|
|
|
|
|
|
|
string markername;
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (rs.size() > 1) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->next_available_name(markername, "regions");
|
2008-12-12 09:43:24 -05:00
|
|
|
} else {
|
|
|
|
RegionView* rv = *(rs.begin());
|
|
|
|
boost::shared_ptr<Region> region = rv->region();
|
|
|
|
markername = region->name();
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
if (!choose_new_marker_name(markername)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
// single range spanning all selected
|
2010-11-03 18:19:29 -04:00
|
|
|
Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->add (location, true);
|
2008-12-12 09:43:24 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
XMLNode &after = _session->locations()->get_state();
|
|
|
|
_session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2006-03-31 18:00:40 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* MARKS */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::jump_forward_to_mark ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2013-01-17 08:19:16 -05:00
|
|
|
if (pos < 0) {
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2013-01-17 08:19:16 -05:00
|
|
|
|
|
|
|
_session->request_locate (pos, _session->transport_rolling());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::jump_backward_to_mark ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2013-01-17 08:19:16 -05:00
|
|
|
if (pos < 0) {
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2013-01-17 08:19:16 -05:00
|
|
|
|
|
|
|
_session->request_locate (pos, _session->transport_rolling());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_mark ()
|
|
|
|
{
|
2011-03-01 19:30:28 -05:00
|
|
|
framepos_t const pos = _session->audible_frame ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-03-01 19:30:28 -05:00
|
|
|
string markername;
|
|
|
|
_session->locations()->next_available_name (markername, "mark");
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-03-01 19:30:28 -05:00
|
|
|
if (!choose_new_marker_name (markername)) {
|
2008-09-10 11:03:30 -04:00
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-08-09 12:40:31 -04:00
|
|
|
_session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_markers ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session) {
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("clear markers"));
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &before = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->clear_markers ();
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &after = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_ranges ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session) {
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("clear ranges"));
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &before = _session->locations()->get_state();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->clear_ranges ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &after = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_locations ()
|
|
|
|
{
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("clear locations"));
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &before = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->locations()->clear ();
|
2010-11-25 15:37:39 -05:00
|
|
|
XMLNode &after = _session->locations()->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
void
|
|
|
|
Editor::unhide_markers ()
|
|
|
|
{
|
|
|
|
for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
|
|
|
|
Location *l = (*i).first;
|
|
|
|
if (l->is_hidden() && l->is_mark()) {
|
|
|
|
l->set_hidden(false, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::unhide_ranges ()
|
|
|
|
{
|
|
|
|
for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
|
|
|
|
Location *l = (*i).first;
|
2009-10-14 12:10:01 -04:00
|
|
|
if (l->is_hidden() && l->is_range_marker()) {
|
2007-01-09 18:24:54 -05:00
|
|
|
l->set_hidden(false, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* INSERT/REPLACE */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::insert_region_list_selection (float times)
|
|
|
|
{
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView *tv = 0;
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (clicked_routeview != 0) {
|
|
|
|
tv = clicked_routeview;
|
|
|
|
} else if (!selection->tracks.empty()) {
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (entered_track != 0) {
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((playlist = tv->playlist()) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2009-07-03 18:42:22 -04:00
|
|
|
|
|
|
|
boost::shared_ptr<Region> region = _regions->get_single_selection ();
|
|
|
|
if (region == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-03 18:42:22 -04:00
|
|
|
begin_reversible_command (_("insert region"));
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->clear_changes ();
|
2010-09-20 23:02:30 -04:00
|
|
|
playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
|
Ripple mode: basic implementation
Add a value for Ripple to EditMode enum.
Add Ripple edit mode to edit mode dropdown, by adding it to the
Editor::build_edit_mode_menu() helper function, and remove the old code that
added items to the (now unused) Editor::edit_mode_strings.
Add the regions that should be affected by the drag to RegionDrag::_views so
that the drag carries them along automatically.
Use a copy of the RegionList in Playlist::core_ripple(), since bad things
happen when iterating over regions and they get moved around in the list.
Handle rippling in removal of regions from playlist.
When dragging in ripple mode, exclude all regions that lie before the
original start position of the selected regions being dragged from
rippling: this is what Mixbus does.
Make editor dragging respect snap-to settings, by using the existing
compute_x_delta() function, which did almost the right thing. Move setting
of _last_frame_position out of that function so all ripple-dragged regions
can move.
Ripple when dragging from region list: even though Mixbus doesn't do this, it
seems like a good idea.
Prevent multi-track selection being dragged across tracks, by making
RegionMotionDrag::y_movement_allowed() virtual, and overriding it in
RegionRippleDrag to forbid dragging of selections containing regions on more
than one track to dofferent tracks in ripple mode.
Remember which TimeAxisView a ripple-mode drag that's allowed cross-track
drags started from, so that the effect of rippling regions after any region
that's dragged off that track can be undone.
2013-10-23 16:50:01 -04:00
|
|
|
if (Config->get_edit_mode() == Ripple)
|
|
|
|
playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
|
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (playlist));
|
2009-07-03 18:42:22 -04:00
|
|
|
commit_reversible_command ();
|
2006-10-21 15:01:50 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
/* BUILT-IN EFFECTS */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::reverse_selection ()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* GAIN ENVELOPE EDITING */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::edit_envelope ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PLAYBACK */
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
|
|
|
Editor::transition_to_rolling (bool fwd)
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session->config.get_external_sync()) {
|
2012-10-10 23:10:18 -04:00
|
|
|
switch (Config->get_sync_source()) {
|
2013-09-19 17:34:23 -04:00
|
|
|
case Engine:
|
2009-11-09 15:05:18 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* transport controlled by the master */
|
|
|
|
return;
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session->is_auditioning()) {
|
|
|
|
_session->cancel_audition ();
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_transport_speed (fwd ? 1.0f : -1.0f);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::play_from_start ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (_session->current_start_frame(), true);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2006-11-19 11:45:16 -05:00
|
|
|
void
|
2007-11-12 17:23:01 -05:00
|
|
|
Editor::play_from_edit_point ()
|
2006-11-19 11:45:16 -05:00
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (get_preferred_edit_position(), true);
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::play_from_edit_point_and_return ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start_frame;
|
|
|
|
framepos_t return_frame;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
start_frame = get_preferred_edit_position (true);
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session->transport_rolling()) {
|
|
|
|
_session->request_locate (start_frame, false);
|
2008-03-17 16:54:03 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
/* don't reset the return frame if its already set */
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if ((return_frame = _session->requested_return_frame()) < 0) {
|
|
|
|
return_frame = _session->audible_frame();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (start_frame >= 0) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_roll_at_and_return (start_frame, return_frame);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::play_selection ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2015-01-07 16:31:05 -05:00
|
|
|
framepos_t start, end;
|
|
|
|
if (!get_selection_extents ( start, end))
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
AudioRange ar (start, end, 0);
|
|
|
|
list<AudioRange> lar;
|
|
|
|
lar.push_back (ar);
|
|
|
|
|
|
|
|
_session->request_play_range (&lar, true);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2012-11-20 14:43:43 -05:00
|
|
|
framepos_t
|
|
|
|
Editor::get_preroll ()
|
|
|
|
{
|
|
|
|
return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::maybe_locate_with_edit_preroll ( framepos_t location )
|
|
|
|
{
|
2014-12-22 13:39:41 -05:00
|
|
|
if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
|
2012-11-20 14:43:43 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
location -= get_preroll();
|
|
|
|
|
|
|
|
//don't try to locate before the beginning of time
|
|
|
|
if ( location < 0 )
|
|
|
|
location = 0;
|
|
|
|
|
|
|
|
//if follow_playhead is on, keep the playhead on the screen
|
|
|
|
if ( _follow_playhead )
|
|
|
|
if ( location < leftmost_frame )
|
|
|
|
location = leftmost_frame;
|
|
|
|
|
|
|
|
_session->request_locate( location );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::play_with_preroll ()
|
|
|
|
{
|
2015-01-07 16:31:05 -05:00
|
|
|
{
|
2012-11-20 14:43:43 -05:00
|
|
|
framepos_t preroll = get_preroll();
|
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
framepos_t start, end;
|
|
|
|
if (!get_selection_extents ( start, end))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (start > preroll)
|
|
|
|
start = start - preroll;
|
2012-11-20 14:43:43 -05:00
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
end = end + preroll; //"post-roll"
|
2012-11-20 14:43:43 -05:00
|
|
|
|
|
|
|
AudioRange ar (start, end, 0);
|
|
|
|
list<AudioRange> lar;
|
|
|
|
lar.push_back (ar);
|
|
|
|
|
|
|
|
_session->request_play_range (&lar, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::play_location (Location& location)
|
|
|
|
{
|
|
|
|
if (location.start() <= location.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_bounded_roll (location.start(), location.end());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::loop_location (Location& location)
|
|
|
|
{
|
|
|
|
if (location.start() <= location.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Location* tll;
|
|
|
|
|
|
|
|
if ((tll = transport_loop_location()) != 0) {
|
|
|
|
tll->set (location.start(), location.end());
|
|
|
|
|
|
|
|
// enable looping, reposition and start rolling
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (tll->start(), true);
|
2014-09-15 13:44:45 -04:00
|
|
|
_session->request_play_loop (true);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-27 15:21:00 -05:00
|
|
|
void
|
|
|
|
Editor::do_layer_operation (LayerOperation op)
|
|
|
|
{
|
|
|
|
if (selection->regions.empty ()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool const multiple = selection->regions.size() > 1;
|
|
|
|
switch (op) {
|
|
|
|
case Raise:
|
|
|
|
if (multiple) {
|
|
|
|
begin_reversible_command (_("raise regions"));
|
|
|
|
} else {
|
|
|
|
begin_reversible_command (_("raise region"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RaiseToTop:
|
|
|
|
if (multiple) {
|
|
|
|
begin_reversible_command (_("raise regions to top"));
|
|
|
|
} else {
|
|
|
|
begin_reversible_command (_("raise region to top"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Lower:
|
|
|
|
if (multiple) {
|
|
|
|
begin_reversible_command (_("lower regions"));
|
|
|
|
} else {
|
|
|
|
begin_reversible_command (_("lower region"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LowerToBottom:
|
|
|
|
if (multiple) {
|
|
|
|
begin_reversible_command (_("lower regions to bottom"));
|
|
|
|
} else {
|
|
|
|
begin_reversible_command (_("lower region"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
|
|
|
|
for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
|
|
|
(*i)->clear_owned_changes ();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
boost::shared_ptr<Region> r = (*i)->region ();
|
|
|
|
switch (op) {
|
|
|
|
case Raise:
|
|
|
|
r->raise ();
|
|
|
|
break;
|
|
|
|
case RaiseToTop:
|
|
|
|
r->raise_to_top ();
|
|
|
|
break;
|
|
|
|
case Lower:
|
|
|
|
r->lower ();
|
|
|
|
break;
|
|
|
|
case LowerToBottom:
|
|
|
|
r->lower_to_bottom ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
|
|
|
vector<Command*> cmds;
|
|
|
|
(*i)->rdiff (cmds);
|
|
|
|
_session->add_commands (cmds);
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::raise_region ()
|
|
|
|
{
|
2011-12-27 15:21:00 -05:00
|
|
|
do_layer_operation (Raise);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::raise_region_to_top ()
|
|
|
|
{
|
2011-12-27 15:21:00 -05:00
|
|
|
do_layer_operation (RaiseToTop);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::lower_region ()
|
|
|
|
{
|
2011-12-27 15:21:00 -05:00
|
|
|
do_layer_operation (Lower);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::lower_region_to_bottom ()
|
|
|
|
{
|
2011-12-27 15:21:00 -05:00
|
|
|
do_layer_operation (LowerToBottom);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/** Show the region editor for the selected regions */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::show_region_properties ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2007-05-10 07:53:35 -04:00
|
|
|
selection->foreach_regionview (&RegionView::show_region_editor);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2009-08-26 23:09:30 -04:00
|
|
|
/** Show the midi list editor for the selected MIDI regions */
|
|
|
|
void
|
|
|
|
Editor::show_midi_list_editor ()
|
|
|
|
{
|
|
|
|
selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::rename_region ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-19 13:25:37 -04:00
|
|
|
ArdourDialog d (*this, _("Rename Region"), true, false);
|
2008-01-10 16:20:59 -05:00
|
|
|
Entry entry;
|
|
|
|
Label label (_("New name:"));
|
|
|
|
HBox hbox;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
hbox.set_spacing (6);
|
|
|
|
hbox.pack_start (label, false, false);
|
|
|
|
hbox.pack_start (entry, true, true);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
d.get_vbox()->set_border_width (12);
|
|
|
|
d.get_vbox()->pack_start (hbox, false, false);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
|
2010-03-16 11:33:04 -04:00
|
|
|
d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
d.set_size_request (300, -1);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-10-02 18:16:12 -04:00
|
|
|
entry.set_text (rs.front()->region()->name());
|
2008-01-10 16:20:59 -05:00
|
|
|
entry.select_region (0, -1);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-12-11 18:29:48 -05:00
|
|
|
entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
d.show_all ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
entry.grab_focus();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
int const ret = d.run();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
d.hide ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (ret != RESPONSE_OK) {
|
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
std::string str = entry.get_text();
|
|
|
|
strip_whitespace_edges (str);
|
|
|
|
if (!str.empty()) {
|
|
|
|
rs.front()->region()->set_name (str);
|
|
|
|
_regions->redisplay ();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-08-29 17:21:48 -04:00
|
|
|
Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session->is_auditioning()) {
|
|
|
|
_session->cancel_audition ();
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
// note: some potential for creativity here, because region doesn't
|
|
|
|
// have to belong to the playlist that Route is handling
|
|
|
|
|
|
|
|
// bool was_soloed = route.soloed();
|
|
|
|
|
|
|
|
route.set_solo (true, this);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_bounded_roll (region->position(), region->position() + region->length());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* XXX how to unset the solo state ? */
|
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/** Start an audition of the first selected region */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::play_edit_range ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start, end;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (get_edit_op_range (start, end)) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_bounded_roll (start, end);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::play_selected_region ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-09-17 12:24:22 -04:00
|
|
|
framepos_t start = max_framepos;
|
|
|
|
framepos_t end = 0;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (rs.empty()) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2008-01-10 16:20:59 -05:00
|
|
|
if ((*i)->region()->position() < start) {
|
|
|
|
start = (*i)->region()->position();
|
|
|
|
}
|
|
|
|
if ((*i)->region()->last_frame() + 1 > end) {
|
|
|
|
end = (*i)->region()->last_frame() + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_bounded_roll (start, end);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->audition_region (region);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::region_from_selection ()
|
|
|
|
{
|
2006-08-16 16:36:14 -04:00
|
|
|
if (clicked_axisview == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start = selection->time[clicked_selection].start;
|
|
|
|
framepos_t end = selection->time[clicked_selection].end;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList tracks = get_tracks_for_range_action ();
|
2009-07-21 15:55:12 -04:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t selection_cnt = end - start + 1;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-21 15:55:12 -04:00
|
|
|
for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
|
2009-02-16 02:04:27 -05:00
|
|
|
boost::shared_ptr<Region> current;
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> pl;
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t internal_start;
|
2005-09-25 14:42:24 -04:00
|
|
|
string new_name;
|
|
|
|
|
|
|
|
if ((pl = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-02-16 02:04:27 -05:00
|
|
|
if ((current = pl->top_region_at (start)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-02-16 02:04:27 -05:00
|
|
|
internal_start = start - current->position();
|
2010-03-30 19:40:28 -04:00
|
|
|
RegionFactory::region_name (new_name, current->name(), true);
|
2010-02-18 08:59:49 -05:00
|
|
|
|
2011-06-01 13:00:29 -04:00
|
|
|
PropertyList plist;
|
|
|
|
|
2010-03-02 16:08:37 -05:00
|
|
|
plist.add (ARDOUR::Properties::start, current->start() + internal_start);
|
2010-02-18 08:59:49 -05:00
|
|
|
plist.add (ARDOUR::Properties::length, selection_cnt);
|
|
|
|
plist.add (ARDOUR::Properties::name, new_name);
|
|
|
|
plist.add (ARDOUR::Properties::layer, 0);
|
|
|
|
|
|
|
|
boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
void
|
2008-02-16 17:43:18 -05:00
|
|
|
Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (selection->time.empty() || selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-26 07:05:28 -05:00
|
|
|
framepos_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();
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
|
|
|
|
sort_track_selection (ts);
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
|
2009-02-16 02:04:27 -05:00
|
|
|
boost::shared_ptr<Region> current;
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t internal_start;
|
2005-09-25 14:42:24 -04:00
|
|
|
string new_name;
|
|
|
|
|
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-02-16 02:04:27 -05:00
|
|
|
if ((current = playlist->top_region_at(start)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal_start = start - current->position();
|
2010-03-30 19:40:28 -04:00
|
|
|
RegionFactory::region_name (new_name, current->name(), true);
|
2009-05-30 14:25:59 -04:00
|
|
|
|
2011-06-01 13:00:29 -04:00
|
|
|
PropertyList plist;
|
|
|
|
|
2010-03-02 16:08:37 -05:00
|
|
|
plist.add (ARDOUR::Properties::start, current->start() + internal_start);
|
2010-02-18 08:59:49 -05:00
|
|
|
plist.add (ARDOUR::Properties::length, end - start + 1);
|
|
|
|
plist.add (ARDOUR::Properties::name, new_name);
|
|
|
|
|
|
|
|
new_regions.push_back (RegionFactory::create (current, plist));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split_multichannel_region ()
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-16 02:04:27 -05:00
|
|
|
vector< boost::shared_ptr<Region> > v;
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
|
2009-12-17 13:24:23 -05:00
|
|
|
(*x)->region()->separate_by_channel (*_session, v);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::new_region_from_selection ()
|
|
|
|
{
|
|
|
|
region_from_selection ();
|
|
|
|
cancel_selection ();
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
static void
|
|
|
|
add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
switch (rv->region()->coverage (ar->start, ar->end - 1)) {
|
2014-12-01 15:06:08 -05:00
|
|
|
// n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
|
2012-04-16 12:32:22 -04:00
|
|
|
case Evoral::OverlapNone:
|
2008-01-10 16:20:59 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rs->push_back (rv);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-07-21 15:55:12 -04:00
|
|
|
/** Return either:
|
|
|
|
* - selected tracks, or if there are none...
|
|
|
|
* - tracks containing selected regions, or if there are none...
|
|
|
|
* - all tracks
|
|
|
|
* @return tracks.
|
|
|
|
*/
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList
|
2009-07-21 15:55:12 -04:00
|
|
|
Editor::get_tracks_for_range_action () const
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList t;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
if (selection->tracks.empty()) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
/* use tracks with selected regions */
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2009-07-21 15:55:12 -04:00
|
|
|
RegionSelection rs = selection->regions;
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2009-07-09 13:58:13 -04:00
|
|
|
TimeAxisView* tv = &(*i)->get_time_axis_view();
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2009-07-21 15:55:12 -04:00
|
|
|
if (!t.contains (tv)) {
|
|
|
|
t.push_back (tv);
|
2008-01-10 17:22:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-21 15:55:12 -04:00
|
|
|
if (t.empty()) {
|
|
|
|
/* no regions and no tracks: use all tracks */
|
|
|
|
t = track_views;
|
2008-01-10 17:22:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2009-07-21 15:55:12 -04:00
|
|
|
t = selection->tracks;
|
2008-01-10 17:22:29 -05:00
|
|
|
}
|
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
return t.filter_to_unique_playlists();
|
2009-07-21 15:55:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::separate_regions_between (const TimeSelection& ts)
|
|
|
|
{
|
|
|
|
bool in_command = false;
|
|
|
|
boost::shared_ptr<Playlist> playlist;
|
|
|
|
RegionSelection new_selection;
|
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList tmptracks = get_tracks_for_range_action ();
|
2011-12-10 14:20:15 -05:00
|
|
|
sort_track_selection (tmptracks);
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* rtv;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
if (rtv->is_track()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
/* no edits to destructive tracks */
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2010-04-21 16:42:22 -04:00
|
|
|
if (rtv->track()->destructive()) {
|
2008-01-10 17:22:29 -05:00
|
|
|
continue;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
if ((playlist = rtv->playlist()) != 0) {
|
|
|
|
|
2010-08-25 13:32:08 -04:00
|
|
|
playlist->clear_changes ();
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* XXX need to consider musical time selections here at some point */
|
|
|
|
|
2010-04-21 16:42:22 -04:00
|
|
|
double speed = rtv->track()->speed();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
|
|
|
|
|
2009-02-16 02:04:27 -05:00
|
|
|
sigc::connection c = rtv->view()->RegionViewAdded.connect (
|
2009-12-11 18:29:48 -05:00
|
|
|
sigc::mem_fun(*this, &Editor::collect_new_region_view));
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
latest_regionviews.clear ();
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
playlist->partition ((framepos_t)((*t).start * speed),
|
|
|
|
(framepos_t)((*t).end * speed), false);
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
c.disconnect ();
|
|
|
|
|
|
|
|
if (!latest_regionviews.empty()) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-11 18:29:48 -05:00
|
|
|
rtv->view()->foreach_regionview (sigc::bind (
|
2009-02-16 02:04:27 -05:00
|
|
|
sigc::ptr_fun (add_if_covered),
|
|
|
|
&(*t), &new_selection));
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (!in_command) {
|
|
|
|
begin_reversible_command (_("separate"));
|
|
|
|
in_command = true;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
/* pick up changes to existing regions */
|
2010-06-28 11:01:14 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
vector<Command*> cmds;
|
|
|
|
playlist->rdiff (cmds);
|
2010-08-25 21:44:11 -04:00
|
|
|
_session->add_commands (cmds);
|
2010-06-28 11:01:14 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
/* pick up changes to the playlist itself (adds/removes)
|
|
|
|
*/
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (playlist));
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (in_command) {
|
2014-07-05 21:47:43 -04:00
|
|
|
// selection->set (new_selection);
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
2006-03-31 19:21:25 -05:00
|
|
|
}
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
struct PlaylistState {
|
|
|
|
boost::shared_ptr<Playlist> playlist;
|
|
|
|
XMLNode* before;
|
|
|
|
};
|
|
|
|
|
2009-07-21 15:55:12 -04:00
|
|
|
/** Take tracks from get_tracks_for_range_action and cut any regions
|
|
|
|
* on those tracks so that the tracks are empty over the time
|
|
|
|
* selection.
|
|
|
|
*/
|
2006-03-31 19:21:25 -05:00
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::separate_region_from_selection ()
|
2006-03-31 19:21:25 -05:00
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
/* preferentially use *all* ranges in the time selection if we're in range mode
|
|
|
|
to allow discontiguous operation, since get_edit_op_range() currently
|
|
|
|
returns a single range.
|
2006-03-31 19:21:25 -05:00
|
|
|
*/
|
2008-04-11 10:06:50 -04:00
|
|
|
|
2012-11-28 12:07:35 -05:00
|
|
|
if (!selection->time.empty()) {
|
2006-03-31 19:21:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
separate_regions_between (selection->time);
|
2006-03-31 19:21:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start;
|
|
|
|
framepos_t end;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (get_edit_op_range (start, end)) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
AudioRange ar (start, end, 1);
|
|
|
|
TimeSelection ts;
|
|
|
|
ts.push_back (ar);
|
2006-03-31 19:21:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
separate_regions_between (ts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-03-31 19:21:25 -05:00
|
|
|
|
2008-02-19 17:10:27 -05:00
|
|
|
void
|
|
|
|
Editor::separate_region_from_punch ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
Location* loc = _session->locations()->auto_punch_location();
|
2008-02-19 17:10:27 -05:00
|
|
|
if (loc) {
|
|
|
|
separate_regions_using_location (*loc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::separate_region_from_loop ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
Location* loc = _session->locations()->auto_loop_location();
|
2008-02-19 17:10:27 -05:00
|
|
|
if (loc) {
|
|
|
|
separate_regions_using_location (*loc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::separate_regions_using_location (Location& loc)
|
|
|
|
{
|
|
|
|
if (loc.is_mark()) {
|
|
|
|
return;
|
|
|
|
}
|
2006-03-31 19:21:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
AudioRange ar (loc.start(), loc.end(), 1);
|
|
|
|
TimeSelection ts;
|
2006-03-31 19:21:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
ts.push_back (ar);
|
2006-03-31 19:21:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
separate_regions_between (ts);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
/** Separate regions under the selected region */
|
|
|
|
void
|
|
|
|
Editor::separate_under_selected_regions ()
|
|
|
|
{
|
|
|
|
vector<PlaylistState> playlists;
|
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
RegionSelection rs;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
rs = get_regions_from_selection_and_entered();
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
2010-07-06 07:33:27 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("separate region under"));
|
|
|
|
|
|
|
|
list<boost::shared_ptr<Region> > regions_to_remove;
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
// we can't just remove the region(s) in this loop because
|
|
|
|
// this removes them from the RegionSelection, and they thus
|
|
|
|
// disappear from underneath the iterator, and the ++i above
|
|
|
|
// SEGVs in a puzzling fashion.
|
|
|
|
|
|
|
|
// so, first iterate over the regions to be removed from rs and
|
|
|
|
// add them to the regions_to_remove list, and then
|
|
|
|
// iterate over the list to actually remove them.
|
|
|
|
|
|
|
|
regions_to_remove.push_back ((*i)->region());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
|
|
|
|
|
|
|
|
boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
|
|
|
|
|
|
|
|
if (!playlist) {
|
|
|
|
// is this check necessary?
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<PlaylistState>::iterator i;
|
|
|
|
|
|
|
|
//only take state if this is a new playlist.
|
|
|
|
for (i = playlists.begin(); i != playlists.end(); ++i) {
|
|
|
|
if ((*i).playlist == playlist) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == playlists.end()) {
|
|
|
|
|
|
|
|
PlaylistState before;
|
|
|
|
before.playlist = playlist;
|
|
|
|
before.before = &playlist->get_state();
|
|
|
|
|
|
|
|
playlist->freeze ();
|
|
|
|
playlists.push_back(before);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Partition on the region bounds
|
|
|
|
playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
//Re-add region that was just removed due to the partition operation
|
|
|
|
playlist->add_region( (*rl), (*rl)->first_frame() );
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<PlaylistState>::iterator pl;
|
|
|
|
|
|
|
|
for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
|
|
|
|
(*pl).playlist->thaw ();
|
|
|
|
_session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::crop_region_to_selection ()
|
|
|
|
{
|
2007-11-12 17:23:01 -05:00
|
|
|
if (!selection->time.empty()) {
|
|
|
|
|
|
|
|
crop_region_to (selection->time.start(), selection->time.end_frame());
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start;
|
|
|
|
framepos_t end;
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
if (get_edit_op_range (start, end)) {
|
|
|
|
crop_region_to (start, end);
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::crop_region_to (framepos_t start, framepos_t end)
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
2007-01-09 18:24:54 -05:00
|
|
|
vector<boost::shared_ptr<Playlist> > playlists;
|
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2011-12-10 14:20:15 -05:00
|
|
|
TrackViewList ts;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if (selection->tracks.empty()) {
|
2011-12-10 14:20:15 -05:00
|
|
|
ts = track_views.filter_to_unique_playlists();
|
2007-11-12 17:23:01 -05:00
|
|
|
} else {
|
2011-12-10 14:20:15 -05:00
|
|
|
ts = selection->tracks.filter_to_unique_playlists ();
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
sort_track_selection (ts);
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* rtv;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-06-15 18:05:07 -04:00
|
|
|
boost::shared_ptr<Track> t = rtv->track();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-04-21 16:42:22 -04:00
|
|
|
if (t != 0 && ! t->destructive()) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2006-08-14 04:44:14 -04:00
|
|
|
if ((playlist = rtv->playlist()) != 0) {
|
|
|
|
playlists.push_back (playlist);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if (playlists.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t the_start;
|
|
|
|
framepos_t the_end;
|
|
|
|
framepos_t cnt;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
begin_reversible_command (_("trim to selection"));
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
boost::shared_ptr<Region> region;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
the_start = start;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if ((region = (*i)->top_region_at(the_start)) == 0) {
|
2007-04-12 19:20:37 -04:00
|
|
|
continue;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
/* now adjust lengths to that we do the right thing
|
|
|
|
if the selection extends beyond the region
|
|
|
|
*/
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
the_start = max (the_start, (framepos_t) region->position());
|
2010-09-17 12:24:22 -04:00
|
|
|
if (max_framepos - the_start < region->length()) {
|
2007-11-12 17:23:01 -05:00
|
|
|
the_end = the_start + region->length() - 1;
|
2007-04-12 19:20:37 -04:00
|
|
|
} else {
|
2010-09-17 12:24:22 -04:00
|
|
|
the_end = max_framepos;
|
2007-04-12 19:20:37 -04:00
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
the_end = min (end, the_end);
|
|
|
|
cnt = the_end - the_start + 1;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
region->clear_changes ();
|
2011-05-30 09:54:44 -04:00
|
|
|
region->trim_to (the_start, cnt);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (region));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
commit_reversible_command ();
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_fill_track ()
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
framepos_t const end = _session->current_end_frame ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-01-19 12:38:56 -05:00
|
|
|
begin_reversible_command (Operations::region_fill);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2006-07-23 08:03:19 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region ((*i)->region());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> pl = region->playlist();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
if (end <= region->last_frame()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
double times = (double) (end - region->last_frame()) / (double) region->length();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (times == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
pl->clear_changes ();
|
2010-09-20 23:02:30 -04:00
|
|
|
pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (pl));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_fill_selection ()
|
|
|
|
{
|
2009-10-21 12:56:58 -04:00
|
|
|
if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-03 18:42:22 -04:00
|
|
|
boost::shared_ptr<Region> region = _regions->get_single_selection ();
|
|
|
|
if (region == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start = selection->time[clicked_selection].start;
|
|
|
|
framepos_t end = selection->time[clicked_selection].end;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t selection_length = end - start;
|
2005-09-25 14:42:24 -04:00
|
|
|
float times = (float)selection_length / region->length();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-01-19 12:38:56 -05:00
|
|
|
begin_reversible_command (Operations::fill_selection);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->clear_changes ();
|
2010-09-20 23:02:30 -04:00
|
|
|
playlist->add_region (RegionFactory::create (region, true), start, times);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (playlist));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2006-01-23 15:39:58 -05:00
|
|
|
|
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::set_region_sync_position ()
|
2006-01-23 15:39:58 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
|
2006-01-23 15:39:58 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
bool in_command = false;
|
2007-11-07 20:40:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (!(*r)->region()->covers (where)) {
|
|
|
|
continue;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
boost::shared_ptr<Region> region ((*r)->region());
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (!in_command) {
|
|
|
|
begin_reversible_command (_("set sync point"));
|
|
|
|
in_command = true;
|
|
|
|
}
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
region->clear_changes ();
|
2009-10-19 21:05:33 -04:00
|
|
|
region->set_sync_position (where);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (region));
|
2007-05-10 07:53:35 -04:00
|
|
|
}
|
2007-11-07 20:40:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (in_command) {
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/** Remove the sync positions of the selection */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::remove_region_sync ()
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-05-10 07:53:35 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
begin_reversible_command (_("remove region sync"));
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
(*i)->region()->clear_changes ();
|
2008-09-10 11:03:30 -04:00
|
|
|
(*i)->region()->clear_sync_position ();
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand ((*i)->region()));
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::naturalize_region ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (rs.size() > 1) {
|
|
|
|
begin_reversible_command (_("move regions to original position"));
|
|
|
|
} else {
|
|
|
|
begin_reversible_command (_("move region to original position"));
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2010-08-25 13:32:08 -04:00
|
|
|
(*i)->region()->clear_changes ();
|
2011-05-30 09:54:44 -04:00
|
|
|
(*i)->region()->move_to_natural_position ();
|
2010-02-11 18:10:29 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand ((*i)->region()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::align_regions (RegionPoint what)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection const rs = get_regions_from_selection_and_edit_point ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
begin_reversible_command (_("align selection"));
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
framepos_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);
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
struct RegionSortByTime {
|
2006-08-14 04:44:14 -04:00
|
|
|
bool operator() (const RegionView* a, const RegionView* b) {
|
2006-08-29 17:21:48 -04:00
|
|
|
return a->region()->position() < b->region()->position();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::align_regions_relative (RegionPoint point)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection const rs = get_regions_from_selection_and_edit_point ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
framepos_t const position = get_preferred_edit_position ();
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t distance = 0;
|
|
|
|
framepos_t pos = 0;
|
2008-10-03 14:24:38 -04:00
|
|
|
int dir = 1;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
list<RegionView*> sorted;
|
2007-11-12 17:23:01 -05:00
|
|
|
rs.by_position (sorted);
|
2008-09-10 11:03:30 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r ((*sorted.begin())->region());
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
switch (point) {
|
|
|
|
case Start:
|
2008-01-10 17:22:29 -05:00
|
|
|
pos = position;
|
|
|
|
if (position > r->position()) {
|
|
|
|
distance = position - r->position();
|
|
|
|
} else {
|
|
|
|
distance = r->position() - position;
|
|
|
|
dir = -1;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
case End:
|
2008-01-10 17:22:29 -05:00
|
|
|
if (position > r->last_frame()) {
|
|
|
|
distance = position - r->last_frame();
|
|
|
|
pos = r->position() + distance;
|
|
|
|
} else {
|
|
|
|
distance = r->last_frame() - position;
|
|
|
|
pos = r->position() - distance;
|
|
|
|
dir = -1;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SyncPoint:
|
2008-01-10 17:22:29 -05:00
|
|
|
pos = r->adjust_to_sync (position);
|
|
|
|
if (pos > r->position()) {
|
|
|
|
distance = pos - r->position();
|
|
|
|
} else {
|
|
|
|
distance = r->position() - pos;
|
|
|
|
dir = -1;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
if (pos == r->position()) {
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("align selection (relative)"));
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
/* move first one specially */
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
r->clear_changes ();
|
2011-05-30 09:54:44 -04:00
|
|
|
r->set_position (pos);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (r));
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
/* move rest by the same amount */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
sorted.pop_front();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region ((*i)->region());
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
region->clear_changes ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (dir > 0) {
|
2011-05-30 09:54:44 -04:00
|
|
|
region->set_position (region->position() + distance);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2011-05-30 09:54:44 -04:00
|
|
|
region->set_position (region->position() - distance);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (region));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
begin_reversible_command (_("align region"));
|
|
|
|
align_region_internal (region, point, position);
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-08-25 13:32:08 -04:00
|
|
|
region->clear_changes ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
switch (point) {
|
|
|
|
case SyncPoint:
|
2011-05-30 09:54:44 -04:00
|
|
|
region->set_position (region->adjust_to_sync (position));
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case End:
|
2006-08-29 17:21:48 -04:00
|
|
|
if (position > region->length()) {
|
2011-05-30 09:54:44 -04:00
|
|
|
region->set_position (position - region->length());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Start:
|
2011-05-30 09:54:44 -04:00
|
|
|
region->set_position (position);
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (region));
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-04-20 17:02:46 -04:00
|
|
|
void
|
|
|
|
Editor::trim_region_front ()
|
|
|
|
{
|
|
|
|
trim_region (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_region_back ()
|
|
|
|
{
|
|
|
|
trim_region (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_region (bool front)
|
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t where = get_preferred_edit_position();
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_edit_point ();
|
2009-04-20 17:02:46 -04:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (front ? _("trim front") : _("trim back"));
|
|
|
|
|
|
|
|
for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
|
|
|
|
if (!(*i)->region()->locked()) {
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-08-25 13:32:08 -04:00
|
|
|
(*i)->region()->clear_changes ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2009-04-20 17:02:46 -04:00
|
|
|
if (front) {
|
2011-05-30 09:54:44 -04:00
|
|
|
(*i)->region()->trim_front (where);
|
2012-11-20 14:43:43 -05:00
|
|
|
maybe_locate_with_edit_preroll ( where );
|
2009-04-20 17:02:46 -04:00
|
|
|
} else {
|
2011-05-30 09:54:44 -04:00
|
|
|
(*i)->region()->trim_end (where);
|
2012-11-20 14:43:43 -05:00
|
|
|
maybe_locate_with_edit_preroll ( where );
|
2009-04-20 17:02:46 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand ((*i)->region()));
|
2009-04-20 17:02:46 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/** Trim the end of the selected regions to the position of the edit cursor */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2007-11-12 17:23:01 -05:00
|
|
|
Editor::trim_region_to_loop ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
Location* loc = _session->locations()->auto_loop_location();
|
2007-11-12 17:23:01 -05:00
|
|
|
if (!loc) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
trim_region_to_location (*loc, _("trim to loop"));
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
|
|
|
Editor::trim_region_to_punch ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
Location* loc = _session->locations()->auto_punch_location();
|
2007-11-12 17:23:01 -05:00
|
|
|
if (!loc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
trim_region_to_location (*loc, _("trim to punch"));
|
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
|
|
|
Editor::trim_region_to_location (const Location& loc, const char* str)
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
begin_reversible_command (str);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
2009-02-16 02:04:27 -05:00
|
|
|
RegionView* rv = (*x);
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
/* require region to span proposed trim */
|
2009-02-16 02:04:27 -05:00
|
|
|
switch (rv->region()->coverage (loc.start(), loc.end())) {
|
2012-04-16 12:32:22 -04:00
|
|
|
case Evoral::OverlapInternal:
|
2007-11-12 17:23:01 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
|
2009-02-16 02:04:27 -05:00
|
|
|
if (!tav) {
|
2007-11-12 17:23:01 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float speed = 1.0;
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start;
|
|
|
|
framepos_t end;
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2010-04-21 16:42:22 -04:00
|
|
|
if (tav->track() != 0) {
|
|
|
|
speed = tav->track()->speed();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
start = session_frame_to_track_frame (loc.start(), speed);
|
|
|
|
end = session_frame_to_track_frame (loc.end(), speed);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-08-25 13:32:08 -04:00
|
|
|
rv->region()->clear_changes ();
|
2011-05-30 09:54:44 -04:00
|
|
|
rv->region()->trim_to (start, (end - start));
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (rv->region()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2009-04-20 17:02:46 -04:00
|
|
|
void
|
|
|
|
Editor::trim_region_to_previous_region_end ()
|
|
|
|
{
|
|
|
|
return trim_to_region(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_region_to_next_region_start ()
|
|
|
|
{
|
|
|
|
return trim_to_region(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_to_region(bool forward)
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2009-04-20 17:02:46 -04:00
|
|
|
|
|
|
|
begin_reversible_command (_("trim to region"));
|
|
|
|
|
|
|
|
boost::shared_ptr<Region> next_region;
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
|
|
|
|
|
|
|
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!arv) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
|
2009-04-20 17:02:46 -04:00
|
|
|
|
|
|
|
if (!atav) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float speed = 1.0;
|
|
|
|
|
2010-04-21 16:42:22 -04:00
|
|
|
if (atav->track() != 0) {
|
|
|
|
speed = atav->track()->speed();
|
2009-04-20 17:02:46 -04:00
|
|
|
}
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-20 17:02:46 -04:00
|
|
|
boost::shared_ptr<Region> region = arv->region();
|
|
|
|
boost::shared_ptr<Playlist> playlist (region->playlist());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
region->clear_changes ();
|
2009-04-20 17:02:46 -04:00
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
if (forward) {
|
2009-04-20 17:02:46 -04:00
|
|
|
|
|
|
|
next_region = playlist->find_next_region (region->first_frame(), Start, 1);
|
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
if (!next_region) {
|
2009-04-20 17:02:46 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-05-30 09:54:44 -04:00
|
|
|
region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
|
2010-02-19 13:09:08 -05:00
|
|
|
arv->region_changed (PropertyChange (ARDOUR::Properties::length));
|
2009-04-20 17:02:46 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
next_region = playlist->find_next_region (region->first_frame(), Start, 0);
|
|
|
|
|
|
|
|
if(!next_region){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-05-30 09:54:44 -04:00
|
|
|
region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
|
2010-02-19 13:09:08 -05:00
|
|
|
|
|
|
|
arv->region_changed (ARDOUR::bounds_change);
|
2009-04-20 17:02:46 -04:00
|
|
|
}
|
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (region));
|
2009-04-20 17:02:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::unfreeze_route ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-02-16 02:04:27 -05:00
|
|
|
if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
|
2008-01-12 18:45:50 -05:00
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-02-16 02:04:27 -05:00
|
|
|
clicked_routeview->track()->unfreeze ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
Editor::_freeze_thread (void* arg)
|
|
|
|
{
|
|
|
|
return static_cast<Editor*>(arg)->freeze_thread ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
Editor::freeze_thread ()
|
|
|
|
{
|
2012-03-15 17:40:17 -04:00
|
|
|
/* create event pool because we may need to talk to the session */
|
|
|
|
SessionEvent::create_per_thread_pool ("freeze events", 64);
|
|
|
|
/* create per-thread buffers for process() tree to use */
|
2010-03-02 13:05:26 -05:00
|
|
|
clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
|
2009-02-27 18:26:10 -05:00
|
|
|
current_interthread_info->done = true;
|
2005-09-25 14:42:24 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::freeze_route ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2011-08-13 12:27:29 -04:00
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stop transport before we start. this is important */
|
|
|
|
|
|
|
|
_session->request_transport_speed (0.0);
|
2012-03-15 17:40:17 -04:00
|
|
|
|
|
|
|
/* wait for just a little while, because the above call is asynchronous */
|
|
|
|
|
2013-10-03 04:06:56 -04:00
|
|
|
Glib::usleep (250000);
|
2011-08-13 12:27:29 -04:00
|
|
|
|
2008-01-12 18:45:50 -05:00
|
|
|
if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2012-03-15 17:40:17 -04:00
|
|
|
if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
|
|
|
|
MessageDialog 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.")
|
|
|
|
);
|
|
|
|
d.set_title (_("Cannot freeze"));
|
|
|
|
d.run ();
|
|
|
|
return;
|
2010-12-10 17:28:29 -05:00
|
|
|
}
|
|
|
|
|
2012-03-16 12:51:54 -04:00
|
|
|
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);
|
|
|
|
|
|
|
|
d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
|
|
|
|
d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
|
|
|
|
d.set_title (_("Freeze Limits"));
|
|
|
|
|
|
|
|
int response = d.run ();
|
|
|
|
|
|
|
|
switch (response) {
|
|
|
|
case Gtk::RESPONSE_CANCEL:
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
InterThreadInfo itt;
|
|
|
|
current_interthread_info = &itt;
|
|
|
|
|
2010-04-14 18:16:46 -04:00
|
|
|
InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-12-08 22:05:14 -05:00
|
|
|
pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2014-12-20 01:11:28 -05:00
|
|
|
CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
while (!itt.done && !itt.cancel) {
|
|
|
|
gtk_main_iteration ();
|
|
|
|
}
|
|
|
|
|
|
|
|
current_interthread_info = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-03-06 14:28:39 -05:00
|
|
|
Editor::bounce_range_selection (bool replace, bool enable_processing)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-18 02:07:08 -04:00
|
|
|
TrackSelection views = selection->tracks;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-12-10 17:28:29 -05:00
|
|
|
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
|
2012-03-15 17:40:17 -04:00
|
|
|
|
|
|
|
if (enable_processing) {
|
|
|
|
|
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
|
|
|
|
|
|
if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
|
|
|
|
MessageDialog d (
|
|
|
|
_("You can't perform this operation because the processing of the signal "
|
2013-01-07 14:15:02 -05:00
|
|
|
"will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
|
2012-03-15 17:40:17 -04:00
|
|
|
"You can do this without processing, which is a different operation.")
|
|
|
|
);
|
|
|
|
d.set_title (_("Cannot bounce"));
|
|
|
|
d.run ();
|
|
|
|
return;
|
|
|
|
}
|
2010-12-10 17:28:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start = selection->time[clicked_selection].start;
|
|
|
|
framepos_t end = selection->time[clicked_selection].end;
|
|
|
|
framepos_t cnt = end - start + 1;
|
2007-04-12 19:20:37 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
begin_reversible_command (_("bounce range"));
|
|
|
|
|
2007-03-18 02:07:08 -04:00
|
|
|
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* rtv;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if ((playlist = rtv->playlist()) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterThreadInfo itt;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->clear_changes ();
|
2010-08-25 13:32:08 -04:00
|
|
|
playlist->clear_owned_changes ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2012-03-15 17:40:17 -04:00
|
|
|
boost::shared_ptr<Region> r;
|
|
|
|
|
|
|
|
if (enable_processing) {
|
|
|
|
r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
|
|
|
|
} else {
|
|
|
|
r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-10-07 17:35:33 -04:00
|
|
|
if (!r) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
if (replace) {
|
|
|
|
list<AudioRange> ranges;
|
|
|
|
ranges.push_back (AudioRange (start, start+cnt, 0));
|
|
|
|
playlist->cut (ranges); // discard result
|
|
|
|
playlist->add_region (r, start);
|
|
|
|
}
|
|
|
|
|
2010-08-25 21:44:11 -04:00
|
|
|
vector<Command*> cmds;
|
2010-06-10 18:56:46 -04:00
|
|
|
playlist->rdiff (cmds);
|
2010-08-25 21:44:11 -04:00
|
|
|
_session->add_commands (cmds);
|
2010-06-10 18:56:46 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (playlist));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
/** Delete selected regions, automation points or a time range */
|
|
|
|
void
|
|
|
|
Editor::delete_ ()
|
|
|
|
{
|
2014-07-23 17:58:43 -04:00
|
|
|
//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
|
2014-07-24 13:30:11 -04:00
|
|
|
bool deleted = false;
|
2014-07-24 23:49:33 -04:00
|
|
|
if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
|
2014-07-24 13:30:11 -04:00
|
|
|
deleted = current_mixer_strip->delete_processors ();
|
|
|
|
|
|
|
|
if (!deleted)
|
2014-07-23 17:58:43 -04:00
|
|
|
cut_copy (Delete);
|
2011-06-12 11:50:47 -04:00
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/** Cut selected regions, automation points or a time range */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::cut ()
|
|
|
|
{
|
|
|
|
cut_copy (Cut);
|
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/** Copy selected regions, automation points or a time range */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::copy ()
|
|
|
|
{
|
|
|
|
cut_copy (Copy);
|
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
|
|
|
|
/** @return true if a Cut, Copy or Clear is possible */
|
|
|
|
bool
|
|
|
|
Editor::can_cut_copy () const
|
|
|
|
{
|
2014-07-05 19:27:29 -04:00
|
|
|
if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
|
|
|
|
return true;
|
2007-05-10 07:53:35 -04:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Cut, copy or clear selected regions, automation points or a time range.
|
2014-05-15 19:49:09 -04:00
|
|
|
* @param op Operation (Delete, Cut, Copy or Clear)
|
2007-05-10 07:53:35 -04:00
|
|
|
*/
|
2009-10-14 12:10:01 -04:00
|
|
|
void
|
2005-09-25 14:42:24 -04:00
|
|
|
Editor::cut_copy (CutCopyOp op)
|
|
|
|
{
|
|
|
|
/* only cancel selection if cut/copy is successful.*/
|
|
|
|
|
|
|
|
string opname;
|
|
|
|
|
|
|
|
switch (op) {
|
2011-06-12 11:50:47 -04:00
|
|
|
case Delete:
|
|
|
|
opname = _("delete");
|
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
case Cut:
|
|
|
|
opname = _("cut");
|
|
|
|
break;
|
|
|
|
case Copy:
|
|
|
|
opname = _("copy");
|
|
|
|
break;
|
|
|
|
case Clear:
|
|
|
|
opname = _("clear");
|
|
|
|
break;
|
|
|
|
}
|
2008-09-10 11:03:30 -04:00
|
|
|
|
|
|
|
/* if we're deleting something, and the mouse is still pressed,
|
|
|
|
the thing we started a drag for will be gone when we release
|
|
|
|
the mouse button(s). avoid this. see part 2 at the end of
|
|
|
|
this function.
|
|
|
|
*/
|
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
if (op == Delete || op == Cut || op == Clear) {
|
2010-01-12 11:14:49 -05:00
|
|
|
if (_drags->active ()) {
|
|
|
|
_drags->abort ();
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-05-15 19:49:09 -04:00
|
|
|
if ( op != Delete ) //"Delete" doesn't change copy/paste buf
|
2012-11-26 17:43:10 -05:00
|
|
|
cut_buffer->clear ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if (entered_marker) {
|
|
|
|
|
|
|
|
/* cut/delete op while pointing at a marker */
|
|
|
|
|
|
|
|
bool ignored;
|
|
|
|
Location* loc = find_location_from_marker (entered_marker, ignored);
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session && loc) {
|
2009-12-11 18:29:48 -05:00
|
|
|
Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
|
2010-05-05 18:09:07 -04:00
|
|
|
_drags->abort ();
|
2007-11-12 17:23:01 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-08 23:00:00 -05:00
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseDraw:
|
|
|
|
case MouseContent:
|
|
|
|
begin_reversible_command (opname + ' ' + X_("MIDI"));
|
|
|
|
cut_copy_midi (op);
|
|
|
|
commit_reversible_command ();
|
2014-02-26 10:51:38 -05:00
|
|
|
return;
|
2014-12-08 23:00:00 -05:00
|
|
|
default:
|
|
|
|
break;
|
2014-02-26 10:51:38 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-02-26 10:51:38 -05:00
|
|
|
bool did_edit = false;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-11-16 17:04:27 -05:00
|
|
|
if (!selection->regions.empty() || !selection->points.empty()) {
|
|
|
|
begin_reversible_command (opname + ' ' + _("objects"));
|
2014-07-05 19:27:29 -04:00
|
|
|
did_edit = true;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2014-07-05 19:27:29 -04:00
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
cut_copy_regions (op, selection->regions);
|
2014-02-26 10:51:38 -05:00
|
|
|
|
2014-07-05 19:27:29 -04:00
|
|
|
if (op == Cut || op == Delete) {
|
|
|
|
selection->clear_regions ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2014-02-26 10:51:38 -05:00
|
|
|
}
|
2014-07-05 19:27:29 -04:00
|
|
|
|
|
|
|
if (!selection->points.empty()) {
|
|
|
|
cut_copy_points (op);
|
2012-11-26 17:43:10 -05:00
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
if (op == Cut || op == Delete) {
|
2014-07-05 19:27:29 -04:00
|
|
|
selection->clear_points ();
|
2009-08-10 15:29:29 -04:00
|
|
|
}
|
|
|
|
}
|
2014-07-05 19:27:29 -04:00
|
|
|
} else if (selection->time.empty()) {
|
|
|
|
framepos_t start, end;
|
|
|
|
/* no time selection, see if we can get an edit range
|
|
|
|
and use that.
|
|
|
|
*/
|
|
|
|
if (get_edit_op_range (start, end)) {
|
|
|
|
selection->set (start, end);
|
|
|
|
}
|
|
|
|
} else if (!selection->time.empty()) {
|
2014-11-16 17:04:27 -05:00
|
|
|
begin_reversible_command (opname + ' ' + _("range"));
|
2014-07-05 19:27:29 -04:00
|
|
|
|
|
|
|
did_edit = true;
|
|
|
|
cut_copy_ranges (op);
|
2014-02-26 10:51:38 -05:00
|
|
|
|
2014-07-05 19:27:29 -04:00
|
|
|
if (op == Cut || op == Delete) {
|
|
|
|
selection->clear_time ();
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2014-02-26 10:51:38 -05:00
|
|
|
|
|
|
|
if (did_edit) {
|
2014-11-16 02:51:18 -05:00
|
|
|
/* reset repeated paste state */
|
|
|
|
paste_count = 0;
|
|
|
|
last_paste_pos = 0;
|
2014-02-26 10:51:38 -05:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
if (op == Delete || op == Cut || op == Clear) {
|
2010-05-05 18:09:07 -04:00
|
|
|
_drags->abort ();
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2012-04-22 10:03:07 -04:00
|
|
|
struct AutomationRecord {
|
2014-11-16 17:04:27 -05:00
|
|
|
AutomationRecord () : state (0) , line(NULL) {}
|
|
|
|
AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
|
2012-04-22 10:03:07 -04:00
|
|
|
|
|
|
|
XMLNode* state; ///< state before any operation
|
2014-11-16 17:04:27 -05:00
|
|
|
const AutomationLine* line; ///< line this came from
|
2012-04-22 10:03:07 -04:00
|
|
|
boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
|
|
|
|
};
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/** Cut, copy or clear selected automation points.
|
2012-04-22 10:03:07 -04:00
|
|
|
* @param op Operation (Cut, Copy or Clear)
|
2007-05-10 07:53:35 -04:00
|
|
|
*/
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2015-01-07 00:12:07 -05:00
|
|
|
Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2012-04-22 10:03:07 -04:00
|
|
|
if (selection->points.empty ()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: not ideal, as there may be more than one track involved in the point selection */
|
|
|
|
_last_cut_copy_source_track = &selection->points.front()->line().trackview;
|
|
|
|
|
|
|
|
/* Keep a record of the AutomationLists that we end up using in this operation */
|
|
|
|
typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
|
|
|
|
Lists lists;
|
|
|
|
|
|
|
|
/* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
|
2005-09-25 14:42:24 -04:00
|
|
|
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
|
2014-11-16 17:04:27 -05:00
|
|
|
const AutomationLine& line = (*i)->line();
|
|
|
|
const boost::shared_ptr<AutomationList> al = line.the_list();
|
2012-04-22 10:03:07 -04:00
|
|
|
if (lists.find (al) == lists.end ()) {
|
|
|
|
/* We haven't seen this list yet, so make a record for it. This includes
|
|
|
|
taking a copy of its current state, in case this is needed for undo later.
|
|
|
|
*/
|
2014-11-16 17:04:27 -05:00
|
|
|
lists[al] = AutomationRecord (&al->get_state (), &line);
|
2012-04-22 10:03:07 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (op == Cut || op == Copy) {
|
|
|
|
/* This operation will involve putting things in the cut buffer, so create an empty
|
|
|
|
ControlList for each of our source lists to put the cut buffer data in.
|
|
|
|
*/
|
|
|
|
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
|
2014-12-01 14:28:03 -05:00
|
|
|
i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
|
2012-04-22 10:03:07 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2012-04-22 10:03:07 -04:00
|
|
|
/* Add all selected points to the relevant copy ControlLists */
|
2014-12-07 23:16:42 -05:00
|
|
|
framepos_t start = std::numeric_limits<framepos_t>::max();
|
2012-04-22 10:03:07 -04:00
|
|
|
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
|
|
|
|
boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
|
2014-12-07 23:16:42 -05:00
|
|
|
AutomationList::const_iterator j = (*i)->model();
|
|
|
|
|
2014-11-16 16:48:15 -05:00
|
|
|
lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
|
2014-12-07 23:16:42 -05:00
|
|
|
if (midi) {
|
|
|
|
/* Update earliest MIDI start time in beats */
|
2015-01-07 00:12:07 -05:00
|
|
|
earliest = std::min(earliest, Evoral::Beats((*j)->when));
|
2014-12-07 23:16:42 -05:00
|
|
|
} else {
|
|
|
|
/* Update earliest session start time in frames */
|
|
|
|
start = std::min(start, (*i)->line().session_position(j));
|
|
|
|
}
|
2012-04-22 10:03:07 -04:00
|
|
|
}
|
|
|
|
|
2014-11-16 17:04:27 -05:00
|
|
|
/* Snap start time backwards, so copy/paste is snap aligned. */
|
2014-12-07 23:16:42 -05:00
|
|
|
if (midi) {
|
2015-01-07 00:12:07 -05:00
|
|
|
if (earliest == Evoral::Beats::max()) {
|
|
|
|
earliest = Evoral::Beats(); // Weird... don't offset
|
2014-12-07 23:16:42 -05:00
|
|
|
}
|
|
|
|
earliest.round_down_to_beat();
|
|
|
|
} else {
|
|
|
|
if (start == std::numeric_limits<double>::max()) {
|
|
|
|
start = 0; // Weird... don't offset
|
|
|
|
}
|
|
|
|
snap_to(start, RoundDownMaybe);
|
|
|
|
}
|
2014-11-16 17:04:27 -05:00
|
|
|
|
2014-12-07 23:16:42 -05:00
|
|
|
const double line_offset = midi ? earliest.to_double() : start;
|
2012-04-22 10:03:07 -04:00
|
|
|
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
|
2014-11-16 17:04:27 -05:00
|
|
|
/* Correct this copy list so that it is relative to the earliest
|
|
|
|
start time, so relative ordering between points is preserved
|
2014-12-07 23:16:42 -05:00
|
|
|
when copying from several lists and the paste starts at the
|
|
|
|
earliest copied piece of data. */
|
2012-04-22 10:03:07 -04:00
|
|
|
for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
|
2014-11-16 17:04:27 -05:00
|
|
|
(*j)->when -= line_offset;
|
2012-04-22 10:03:07 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2012-04-22 10:03:07 -04:00
|
|
|
/* And add it to the cut buffer */
|
|
|
|
cut_buffer->add (i->second.copy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (op == Delete || op == Cut) {
|
|
|
|
/* This operation needs to remove things from the main AutomationList, so do that now */
|
|
|
|
|
|
|
|
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
|
|
|
|
i->first->freeze ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove each selected point from its AutomationList */
|
|
|
|
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
|
|
|
|
boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
|
|
|
|
al->erase ((*i)->model ());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Thaw the lists and add undo records for them */
|
|
|
|
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
|
|
|
|
boost::shared_ptr<AutomationList> al = i->first;
|
|
|
|
al->thaw ();
|
|
|
|
_session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-10 15:29:29 -04:00
|
|
|
/** Cut, copy or clear selected automation points.
|
|
|
|
* @param op Operation (Cut, Copy or Clear)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
Editor::cut_copy_midi (CutCopyOp op)
|
|
|
|
{
|
2015-01-07 00:12:07 -05:00
|
|
|
Evoral::Beats earliest = Evoral::Beats::max();
|
2009-08-12 21:57:03 -04:00
|
|
|
for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
|
2014-11-13 21:32:08 -05:00
|
|
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
|
|
|
|
if (mrv) {
|
2014-12-07 23:16:42 -05:00
|
|
|
if (!mrv->selection().empty()) {
|
|
|
|
earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
|
|
|
|
}
|
2014-11-13 21:32:08 -05:00
|
|
|
mrv->cut_copy_clear (op);
|
2014-11-14 17:33:02 -05:00
|
|
|
|
|
|
|
/* XXX: not ideal, as there may be more than one track involved in the selection */
|
|
|
|
_last_cut_copy_source_track = &mrv->get_time_axis_view();
|
2014-11-13 21:32:08 -05:00
|
|
|
}
|
2009-08-10 15:29:29 -04:00
|
|
|
}
|
2014-11-16 22:35:37 -05:00
|
|
|
|
|
|
|
if (!selection->points.empty()) {
|
2014-12-07 23:16:42 -05:00
|
|
|
cut_copy_points (op, earliest, true);
|
2014-11-16 22:35:37 -05:00
|
|
|
if (op == Cut || op == Delete) {
|
|
|
|
selection->clear_points ();
|
|
|
|
}
|
|
|
|
}
|
2009-08-10 15:29:29 -04:00
|
|
|
}
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
struct lt_playlist {
|
|
|
|
bool operator () (const PlaylistState& a, const PlaylistState& b) {
|
|
|
|
return a.playlist < b.playlist;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
struct PlaylistMapping {
|
2009-07-09 13:58:13 -04:00
|
|
|
TimeAxisView* tv;
|
2007-01-28 12:44:13 -05:00
|
|
|
boost::shared_ptr<Playlist> pl;
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
|
2007-01-28 12:44:13 -05:00
|
|
|
};
|
|
|
|
|
2009-05-13 17:34:09 -04:00
|
|
|
/** Remove `clicked_regionview' */
|
|
|
|
void
|
|
|
|
Editor::remove_clicked_region ()
|
|
|
|
{
|
|
|
|
if (clicked_routeview == 0 || clicked_regionview == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-06 18:02:36 -05:00
|
|
|
begin_reversible_command (_("remove region"));
|
|
|
|
|
2009-05-13 17:34:09 -04:00
|
|
|
boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->clear_changes ();
|
2011-12-30 18:41:17 -05:00
|
|
|
playlist->clear_owned_changes ();
|
2009-05-13 17:34:09 -04:00
|
|
|
playlist->remove_region (clicked_regionview->region());
|
Ripple mode: basic implementation
Add a value for Ripple to EditMode enum.
Add Ripple edit mode to edit mode dropdown, by adding it to the
Editor::build_edit_mode_menu() helper function, and remove the old code that
added items to the (now unused) Editor::edit_mode_strings.
Add the regions that should be affected by the drag to RegionDrag::_views so
that the drag carries them along automatically.
Use a copy of the RegionList in Playlist::core_ripple(), since bad things
happen when iterating over regions and they get moved around in the list.
Handle rippling in removal of regions from playlist.
When dragging in ripple mode, exclude all regions that lie before the
original start position of the selected regions being dragged from
rippling: this is what Mixbus does.
Make editor dragging respect snap-to settings, by using the existing
compute_x_delta() function, which did almost the right thing. Move setting
of _last_frame_position out of that function so all ripple-dragged regions
can move.
Ripple when dragging from region list: even though Mixbus doesn't do this, it
seems like a good idea.
Prevent multi-track selection being dragged across tracks, by making
RegionMotionDrag::y_movement_allowed() virtual, and overriding it in
RegionRippleDrag to forbid dragging of selections containing regions on more
than one track to dofferent tracks in ripple mode.
Remember which TimeAxisView a ripple-mode drag that's allowed cross-track
drags started from, so that the effect of rippling regions after any region
that's dragged off that track can be undone.
2013-10-23 16:50:01 -04:00
|
|
|
if (Config->get_edit_mode() == Ripple)
|
|
|
|
playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
|
2011-12-30 18:41:17 -05:00
|
|
|
|
|
|
|
/* We might have removed regions, which alters other regions' layering_index,
|
|
|
|
so we need to do a recursive diff here.
|
|
|
|
*/
|
|
|
|
vector<Command*> cmds;
|
|
|
|
playlist->rdiff (cmds);
|
|
|
|
_session->add_commands (cmds);
|
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (playlist));
|
2009-05-13 17:34:09 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Remove the selected regions */
|
|
|
|
void
|
|
|
|
Editor::remove_selected_regions ()
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
2009-05-13 17:34:09 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("remove region"));
|
|
|
|
|
|
|
|
list<boost::shared_ptr<Region> > regions_to_remove;
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
// we can't just remove the region(s) in this loop because
|
|
|
|
// this removes them from the RegionSelection, and they thus
|
|
|
|
// disappear from underneath the iterator, and the ++i above
|
|
|
|
// SEGVs in a puzzling fashion.
|
|
|
|
|
|
|
|
// so, first iterate over the regions to be removed from rs and
|
|
|
|
// add them to the regions_to_remove list, and then
|
|
|
|
// iterate over the list to actually remove them.
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-05-13 17:34:09 -04:00
|
|
|
regions_to_remove.push_back ((*i)->region());
|
|
|
|
}
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
vector<boost::shared_ptr<Playlist> > playlists;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-05-13 17:34:09 -04:00
|
|
|
for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
|
|
|
|
|
|
|
|
boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
|
|
|
|
|
|
|
|
if (!playlist) {
|
|
|
|
// is this check necessary?
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
/* get_regions_from_selection_and_entered() guarantees that
|
|
|
|
the playlists involved are unique, so there is no need
|
|
|
|
to check here.
|
|
|
|
*/
|
2010-03-02 13:05:26 -05:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
playlists.push_back (playlist);
|
2009-05-13 17:34:09 -04:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
playlist->clear_changes ();
|
2011-12-30 18:41:17 -05:00
|
|
|
playlist->clear_owned_changes ();
|
2011-12-10 14:20:15 -05:00
|
|
|
playlist->freeze ();
|
2009-10-14 12:10:01 -04:00
|
|
|
playlist->remove_region (*rl);
|
Ripple mode: basic implementation
Add a value for Ripple to EditMode enum.
Add Ripple edit mode to edit mode dropdown, by adding it to the
Editor::build_edit_mode_menu() helper function, and remove the old code that
added items to the (now unused) Editor::edit_mode_strings.
Add the regions that should be affected by the drag to RegionDrag::_views so
that the drag carries them along automatically.
Use a copy of the RegionList in Playlist::core_ripple(), since bad things
happen when iterating over regions and they get moved around in the list.
Handle rippling in removal of regions from playlist.
When dragging in ripple mode, exclude all regions that lie before the
original start position of the selected regions being dragged from
rippling: this is what Mixbus does.
Make editor dragging respect snap-to settings, by using the existing
compute_x_delta() function, which did almost the right thing. Move setting
of _last_frame_position out of that function so all ripple-dragged regions
can move.
Ripple when dragging from region list: even though Mixbus doesn't do this, it
seems like a good idea.
Prevent multi-track selection being dragged across tracks, by making
RegionMotionDrag::y_movement_allowed() virtual, and overriding it in
RegionRippleDrag to forbid dragging of selections containing regions on more
than one track to dofferent tracks in ripple mode.
Remember which TimeAxisView a ripple-mode drag that's allowed cross-track
drags started from, so that the effect of rippling regions after any region
that's dragged off that track can be undone.
2013-10-23 16:50:01 -04:00
|
|
|
if (Config->get_edit_mode() == Ripple)
|
|
|
|
playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
|
|
|
|
|
2009-05-13 17:34:09 -04:00
|
|
|
}
|
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
vector<boost::shared_ptr<Playlist> >::iterator pl;
|
2009-05-13 17:34:09 -04:00
|
|
|
|
|
|
|
for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
|
2010-03-02 13:05:26 -05:00
|
|
|
(*pl)->thaw ();
|
2011-12-30 18:41:17 -05:00
|
|
|
|
|
|
|
/* We might have removed regions, which alters other regions' layering_index,
|
|
|
|
so we need to do a recursive diff here.
|
|
|
|
*/
|
|
|
|
vector<Command*> cmds;
|
|
|
|
(*pl)->rdiff (cmds);
|
|
|
|
_session->add_commands (cmds);
|
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (*pl));
|
2009-05-13 17:34:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
2007-05-10 07:53:35 -04:00
|
|
|
|
|
|
|
/** Cut, copy or clear selected regions.
|
|
|
|
* @param op Operation (Cut, Copy or Clear)
|
|
|
|
*/
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2008-03-17 16:54:03 -04:00
|
|
|
Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
|
2009-05-13 17:34:09 -04:00
|
|
|
{
|
2007-01-28 12:44:13 -05:00
|
|
|
/* we can't use a std::map here because the ordering is important, and we can't trivially sort
|
|
|
|
a map when we want ordered access to both elements. i think.
|
|
|
|
*/
|
|
|
|
|
|
|
|
vector<PlaylistMapping> pmap;
|
2006-10-21 18:59:29 -04:00
|
|
|
|
2010-09-17 12:24:22 -04:00
|
|
|
framepos_t first_position = max_framepos;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-03-04 08:15:04 -05:00
|
|
|
typedef set<boost::shared_ptr<Playlist> > FreezeList;
|
2010-11-25 15:37:39 -05:00
|
|
|
FreezeList freezelist;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
/* get ordering correct before we cut/copy */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
rs.sort_by_position_and_track ();
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
first_position = min ((framepos_t) (*x)->region()->position(), first_position);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
if (op == Cut || op == Clear || op == Delete) {
|
2007-01-28 12:44:13 -05:00
|
|
|
boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
|
2007-01-09 18:24:54 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (pl) {
|
2010-03-04 08:15:04 -05:00
|
|
|
FreezeList::iterator fl;
|
2006-10-21 18:59:29 -04:00
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
// only take state if this is a new playlist.
|
2009-05-13 17:34:09 -04:00
|
|
|
for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
|
2010-03-04 08:15:04 -05:00
|
|
|
if ((*fl) == pl) {
|
2009-05-13 17:34:09 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-05-13 17:34:09 -04:00
|
|
|
if (fl == freezelist.end()) {
|
2010-11-25 15:37:39 -05:00
|
|
|
pl->clear_changes();
|
2011-12-30 18:41:17 -05:00
|
|
|
pl->clear_owned_changes ();
|
2005-09-25 14:42:24 -04:00
|
|
|
pl->freeze ();
|
2010-03-04 08:15:04 -05:00
|
|
|
freezelist.insert (pl);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2010-09-06 08:34:11 -04:00
|
|
|
TimeAxisView* tv = &(*x)->get_time_axis_view();
|
2007-01-28 12:44:13 -05:00
|
|
|
vector<PlaylistMapping>::iterator z;
|
|
|
|
|
|
|
|
for (z = pmap.begin(); z != pmap.end(); ++z) {
|
|
|
|
if ((*z).tv == tv) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if (z == pmap.end()) {
|
|
|
|
pmap.push_back (PlaylistMapping (tv));
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if (!pl) {
|
2010-09-15 10:37:08 -04:00
|
|
|
/* region not yet associated with a playlist (e.g. unfinished
|
2010-11-25 15:37:39 -05:00
|
|
|
capture pass.
|
|
|
|
*/
|
|
|
|
++x;
|
2007-01-28 12:44:13 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-09-06 08:34:11 -04:00
|
|
|
TimeAxisView& tv = (*x)->get_time_axis_view();
|
2007-01-28 12:44:13 -05:00
|
|
|
boost::shared_ptr<Playlist> npl;
|
2006-07-23 08:03:19 -04:00
|
|
|
RegionSelection::iterator tmp;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
tmp = x;
|
|
|
|
++tmp;
|
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
if (op != Delete) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
vector<PlaylistMapping>::iterator z;
|
|
|
|
|
|
|
|
for (z = pmap.begin(); z != pmap.end(); ++z) {
|
|
|
|
if ((*z).tv == &tv) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert (z != pmap.end());
|
|
|
|
|
|
|
|
if (!(*z).pl) {
|
|
|
|
npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
|
|
|
|
npl->freeze();
|
|
|
|
(*z).pl = npl;
|
|
|
|
} else {
|
|
|
|
npl = (*z).pl;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
boost::shared_ptr<Region> r = (*x)->region();
|
2007-04-12 19:20:37 -04:00
|
|
|
boost::shared_ptr<Region> _xx;
|
2007-05-02 09:09:03 -04:00
|
|
|
|
|
|
|
assert (r != 0);
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
switch (op) {
|
2011-06-12 11:50:47 -04:00
|
|
|
case Delete:
|
|
|
|
pl->remove_region (r);
|
Ripple mode: basic implementation
Add a value for Ripple to EditMode enum.
Add Ripple edit mode to edit mode dropdown, by adding it to the
Editor::build_edit_mode_menu() helper function, and remove the old code that
added items to the (now unused) Editor::edit_mode_strings.
Add the regions that should be affected by the drag to RegionDrag::_views so
that the drag carries them along automatically.
Use a copy of the RegionList in Playlist::core_ripple(), since bad things
happen when iterating over regions and they get moved around in the list.
Handle rippling in removal of regions from playlist.
When dragging in ripple mode, exclude all regions that lie before the
original start position of the selected regions being dragged from
rippling: this is what Mixbus does.
Make editor dragging respect snap-to settings, by using the existing
compute_x_delta() function, which did almost the right thing. Move setting
of _last_frame_position out of that function so all ripple-dragged regions
can move.
Ripple when dragging from region list: even though Mixbus doesn't do this, it
seems like a good idea.
Prevent multi-track selection being dragged across tracks, by making
RegionMotionDrag::y_movement_allowed() virtual, and overriding it in
RegionRippleDrag to forbid dragging of selections containing regions on more
than one track to dofferent tracks in ripple mode.
Remember which TimeAxisView a ripple-mode drag that's allowed cross-track
drags started from, so that the effect of rippling regions after any region
that's dragged off that track can be undone.
2013-10-23 16:50:01 -04:00
|
|
|
if (Config->get_edit_mode() == Ripple)
|
|
|
|
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
|
2011-06-12 11:50:47 -04:00
|
|
|
break;
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
case Cut:
|
2007-05-02 09:09:03 -04:00
|
|
|
_xx = RegionFactory::create (r);
|
|
|
|
npl->add_region (_xx, r->position() - first_position);
|
|
|
|
pl->remove_region (r);
|
Ripple mode: basic implementation
Add a value for Ripple to EditMode enum.
Add Ripple edit mode to edit mode dropdown, by adding it to the
Editor::build_edit_mode_menu() helper function, and remove the old code that
added items to the (now unused) Editor::edit_mode_strings.
Add the regions that should be affected by the drag to RegionDrag::_views so
that the drag carries them along automatically.
Use a copy of the RegionList in Playlist::core_ripple(), since bad things
happen when iterating over regions and they get moved around in the list.
Handle rippling in removal of regions from playlist.
When dragging in ripple mode, exclude all regions that lie before the
original start position of the selected regions being dragged from
rippling: this is what Mixbus does.
Make editor dragging respect snap-to settings, by using the existing
compute_x_delta() function, which did almost the right thing. Move setting
of _last_frame_position out of that function so all ripple-dragged regions
can move.
Ripple when dragging from region list: even though Mixbus doesn't do this, it
seems like a good idea.
Prevent multi-track selection being dragged across tracks, by making
RegionMotionDrag::y_movement_allowed() virtual, and overriding it in
RegionRippleDrag to forbid dragging of selections containing regions on more
than one track to dofferent tracks in ripple mode.
Remember which TimeAxisView a ripple-mode drag that's allowed cross-track
drags started from, so that the effect of rippling regions after any region
that's dragged off that track can be undone.
2013-10-23 16:50:01 -04:00
|
|
|
if (Config->get_edit_mode() == Ripple)
|
|
|
|
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
case Copy:
|
2007-04-12 19:20:37 -04:00
|
|
|
/* copy region before adding, so we're not putting same object into two different playlists */
|
2007-05-02 11:21:51 -04:00
|
|
|
npl->add_region (RegionFactory::create (r), r->position() - first_position);
|
2011-06-14 19:01:00 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Clear:
|
Ripple mode: basic implementation
Add a value for Ripple to EditMode enum.
Add Ripple edit mode to edit mode dropdown, by adding it to the
Editor::build_edit_mode_menu() helper function, and remove the old code that
added items to the (now unused) Editor::edit_mode_strings.
Add the regions that should be affected by the drag to RegionDrag::_views so
that the drag carries them along automatically.
Use a copy of the RegionList in Playlist::core_ripple(), since bad things
happen when iterating over regions and they get moved around in the list.
Handle rippling in removal of regions from playlist.
When dragging in ripple mode, exclude all regions that lie before the
original start position of the selected regions being dragged from
rippling: this is what Mixbus does.
Make editor dragging respect snap-to settings, by using the existing
compute_x_delta() function, which did almost the right thing. Move setting
of _last_frame_position out of that function so all ripple-dragged regions
can move.
Ripple when dragging from region list: even though Mixbus doesn't do this, it
seems like a good idea.
Prevent multi-track selection being dragged across tracks, by making
RegionMotionDrag::y_movement_allowed() virtual, and overriding it in
RegionRippleDrag to forbid dragging of selections containing regions on more
than one track to dofferent tracks in ripple mode.
Remember which TimeAxisView a ripple-mode drag that's allowed cross-track
drags started from, so that the effect of rippling regions after any region
that's dragged off that track can be undone.
2013-10-23 16:50:01 -04:00
|
|
|
pl->remove_region (r);
|
|
|
|
if (Config->get_edit_mode() == Ripple)
|
|
|
|
pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
x = tmp;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
if (op != Delete) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-06-12 11:50:47 -04:00
|
|
|
list<boost::shared_ptr<Playlist> > foo;
|
|
|
|
|
|
|
|
/* the pmap is in the same order as the tracks in which selected regions occured */
|
|
|
|
|
|
|
|
for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
|
|
|
|
if ((*i).pl) {
|
|
|
|
(*i).pl->thaw();
|
|
|
|
foo.push_back ((*i).pl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foo.empty()) {
|
|
|
|
cut_buffer->set (foo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pmap.empty()) {
|
|
|
|
_last_cut_copy_source_track = 0;
|
|
|
|
} else {
|
|
|
|
_last_cut_copy_source_track = pmap.front().tv;
|
2010-11-25 15:37:39 -05:00
|
|
|
}
|
2010-09-01 21:06:19 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-03-04 08:15:04 -05:00
|
|
|
for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
|
|
|
|
(*pl)->thaw ();
|
2011-12-30 18:41:17 -05:00
|
|
|
|
|
|
|
/* We might have removed regions, which alters other regions' layering_index,
|
|
|
|
so we need to do a recursive diff here.
|
|
|
|
*/
|
|
|
|
vector<Command*> cmds;
|
|
|
|
(*pl)->rdiff (cmds);
|
|
|
|
_session->add_commands (cmds);
|
|
|
|
|
2010-03-04 08:15:04 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (*pl));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cut_copy_ranges (CutCopyOp op)
|
|
|
|
{
|
2011-12-10 14:20:15 -05:00
|
|
|
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2011-04-19 06:18:04 -04:00
|
|
|
/* Sort the track selection now, so that it if is used, the playlists
|
|
|
|
selected by the calls below to cut_copy_clear are in the order that
|
|
|
|
their tracks appear in the editor. This makes things like paste
|
|
|
|
of ranges work properly.
|
|
|
|
*/
|
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
sort_track_selection (ts);
|
|
|
|
|
|
|
|
if (ts.empty()) {
|
2008-03-17 16:54:03 -04:00
|
|
|
if (!entered_track) {
|
|
|
|
return;
|
|
|
|
}
|
2011-12-10 14:20:15 -05:00
|
|
|
ts.push_back (entered_track);
|
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->cut_copy_clear (*selection, op);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-12-30 12:28:05 -05:00
|
|
|
Editor::paste (float times, bool from_context)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2011-02-20 22:22:14 -05:00
|
|
|
DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
|
2011-12-30 12:28:05 -05:00
|
|
|
|
|
|
|
paste_internal (get_preferred_edit_position (false, from_context), times);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::mouse_paste ()
|
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t where;
|
2007-11-07 20:40:25 -05:00
|
|
|
bool ignored;
|
2006-01-02 15:27:51 -05:00
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
if (!mouse_frame (where, ignored)) {
|
|
|
|
return;
|
|
|
|
}
|
2006-01-02 15:27:51 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
snap_to (where);
|
|
|
|
paste_internal (where, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::paste_internal (framepos_t position, float times)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2011-02-20 22:22:14 -05:00
|
|
|
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
|
|
|
|
|
2014-11-16 17:04:27 -05:00
|
|
|
if (cut_buffer->empty(internal_editing())) {
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2010-09-17 12:24:22 -04:00
|
|
|
if (position == max_framepos) {
|
2007-11-07 20:40:25 -05:00
|
|
|
position = get_preferred_edit_position();
|
2011-02-20 22:22:14 -05:00
|
|
|
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2014-11-14 20:04:09 -05:00
|
|
|
if (position == last_paste_pos) {
|
|
|
|
/* repeated paste in the same position */
|
|
|
|
++paste_count;
|
|
|
|
} else {
|
|
|
|
/* paste in new location, reset repeated paste state */
|
|
|
|
paste_count = 0;
|
|
|
|
last_paste_pos = position;
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
/* get everything in the correct order */
|
|
|
|
|
2014-11-16 17:04:27 -05:00
|
|
|
TrackViewList ts;
|
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
/* If there is a track selection, paste into exactly those tracks and
|
|
|
|
only those tracks. This allows the user to be explicit and override
|
|
|
|
the below "do the reasonable thing" logic. */
|
2011-12-10 14:20:15 -05:00
|
|
|
ts = selection->tracks.filter_to_unique_playlists ();
|
|
|
|
sort_track_selection (ts);
|
2014-11-16 17:04:27 -05:00
|
|
|
} else {
|
|
|
|
/* Figure out which track to base the paste at. */
|
2014-11-18 02:22:44 -05:00
|
|
|
TimeAxisView* base_track = NULL;
|
2014-11-16 17:04:27 -05:00
|
|
|
if (_edit_point == Editing::EditAtMouse && entered_track) {
|
|
|
|
/* With the mouse edit point, paste onto the track under the mouse. */
|
|
|
|
base_track = entered_track;
|
|
|
|
} else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
|
|
|
|
/* With the mouse edit point, paste onto the track of the region under the mouse. */
|
|
|
|
base_track = &entered_regionview->get_time_axis_view();
|
|
|
|
} else if (_last_cut_copy_source_track) {
|
|
|
|
/* Paste to the track that the cut/copy came from (see mantis #333). */
|
|
|
|
base_track = _last_cut_copy_source_track;
|
2014-11-18 02:22:44 -05:00
|
|
|
} else {
|
|
|
|
/* This is "impossible" since we've copied... well, do nothing. */
|
|
|
|
return;
|
2014-11-16 17:04:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Walk up to parent if necessary, so base track is a route. */
|
|
|
|
while (base_track->get_parent()) {
|
|
|
|
base_track = base_track->get_parent();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add base track and all tracks below it. The paste logic will select
|
|
|
|
the appropriate object types from the cut buffer in relative order. */
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
if ((*i)->order() >= base_track->order()) {
|
|
|
|
ts.push_back(*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sort tracks so the nth track of type T will pick the nth object of type T. */
|
|
|
|
sort_track_selection (ts);
|
|
|
|
|
|
|
|
/* Add automation children of each track in order, for pasting several lines. */
|
|
|
|
for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
|
|
|
|
/* Add any automation children for pasting several lines */
|
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
|
|
|
|
if (!rtv) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef RouteTimeAxisView::AutomationTracks ATracks;
|
|
|
|
const ATracks& atracks = rtv->automation_tracks();
|
|
|
|
for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
|
|
|
|
i = ts.insert(i, a->second.get());
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We now have a list of trackviews starting at base_track, including
|
|
|
|
automation children, in the order shown in the editor, e.g. R1,
|
|
|
|
R1.A1, R1.A2, R2, R2.A1, ... */
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
2014-12-16 14:37:40 -05:00
|
|
|
begin_reversible_command (Operations::paste);
|
|
|
|
|
2014-12-06 13:37:08 -05:00
|
|
|
if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
|
|
|
|
dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
|
|
|
|
/* Only one line copied, and one automation track selected. Do a
|
|
|
|
"greedy" paste from one automation type to another. */
|
|
|
|
|
|
|
|
PasteContext ctx(paste_count, times, ItemCounts(), true);
|
|
|
|
ts.front()->paste (position, *cut_buffer, ctx);
|
|
|
|
|
2011-03-02 11:18:59 -05:00
|
|
|
} else {
|
2009-08-12 21:57:03 -04:00
|
|
|
|
2014-12-16 14:37:40 -05:00
|
|
|
/* Paste into tracks */
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2014-12-06 12:20:52 -05:00
|
|
|
PasteContext ctx(paste_count, times, ItemCounts(), false);
|
2014-11-16 17:04:27 -05:00
|
|
|
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
|
2014-12-06 12:20:52 -05:00
|
|
|
(*i)->paste (position, *cut_buffer, ctx);
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2014-12-16 14:37:40 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-07-23 08:03:19 -04:00
|
|
|
Editor::duplicate_some_regions (RegionSelection& regions, float times)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-10-14 12:10:01 -04:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2008-01-10 16:20:59 -05:00
|
|
|
RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
|
|
|
|
RegionSelection foo;
|
|
|
|
|
2010-12-03 17:26:29 -05:00
|
|
|
framepos_t const start_frame = regions.start ();
|
|
|
|
framepos_t const end_frame = regions.end_frame ();
|
2009-12-01 18:56:29 -05:00
|
|
|
|
2011-01-19 12:38:56 -05:00
|
|
|
begin_reversible_command (Operations::duplicate_region);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
selection->clear_regions ();
|
2006-01-08 09:50:41 -05:00
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r ((*i)->region());
|
2006-01-08 01:08:15 -05:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
TimeAxisView& tv = (*i)->get_time_axis_view();
|
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
|
2008-01-10 16:20:59 -05:00
|
|
|
latest_regionviews.clear ();
|
2009-12-11 18:29:48 -05:00
|
|
|
sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
playlist = (*i)->region()->playlist();
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->clear_changes ();
|
2010-07-06 07:33:27 -04:00
|
|
|
playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (playlist));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-01-08 01:08:15 -05:00
|
|
|
c.disconnect ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (!foo.empty()) {
|
|
|
|
selection->set (foo);
|
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::duplicate_selection (float times)
|
|
|
|
{
|
|
|
|
if (selection->time.empty() || selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2008-02-16 17:43:18 -05:00
|
|
|
vector<boost::shared_ptr<Region> > new_regions;
|
|
|
|
vector<boost::shared_ptr<Region> >::iterator ri;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
create_region_from_selection (new_regions);
|
|
|
|
|
|
|
|
if (new_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
begin_reversible_command (_("duplicate selection"));
|
|
|
|
|
|
|
|
ri = new_regions.begin();
|
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->clear_changes ();
|
2014-12-26 07:05:28 -05:00
|
|
|
framepos_t end;
|
|
|
|
if (clicked_selection) {
|
|
|
|
end = selection->time[clicked_selection].end;
|
|
|
|
} else {
|
|
|
|
end = selection->time.end_frame();
|
|
|
|
}
|
|
|
|
playlist->duplicate (*ri, end, times);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (playlist));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
++ri;
|
|
|
|
if (ri == new_regions.end()) {
|
|
|
|
--ri;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2012-04-22 10:03:07 -04:00
|
|
|
/** Reset all selected points to the relevant default value */
|
2006-05-19 16:10:35 -04:00
|
|
|
void
|
|
|
|
Editor::reset_point_selection ()
|
|
|
|
{
|
|
|
|
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
|
2012-04-22 10:03:07 -04:00
|
|
|
ARDOUR::AutomationList::iterator j = (*i)->model ();
|
|
|
|
(*j)->value = (*i)->line().the_list()->default_value ();
|
2006-05-19 16:10:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::center_playhead ()
|
|
|
|
{
|
2013-04-12 11:31:50 -04:00
|
|
|
float const page = _visible_canvas_width * samples_per_pixel;
|
2013-04-04 00:32:52 -04:00
|
|
|
center_screen_internal (playhead_cursor->current_frame (), page);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-11-12 17:23:01 -05:00
|
|
|
Editor::center_edit_point ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2013-04-12 11:31:50 -04:00
|
|
|
float const page = _visible_canvas_width * samples_per_pixel;
|
2007-11-07 20:40:25 -05:00
|
|
|
center_screen_internal (get_preferred_edit_position(), page);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2010-11-05 20:30:56 -04:00
|
|
|
/** Caller must begin and commit a reversible command */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2007-01-09 18:24:54 -05:00
|
|
|
Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->clear_changes ();
|
2007-01-09 18:24:54 -05:00
|
|
|
playlist->clear ();
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (playlist));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::nudge_track (bool use_edit, bool forwards)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-10-14 12:10:01 -04:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t distance;
|
|
|
|
framepos_t next_distance;
|
|
|
|
framepos_t start;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if (use_edit) {
|
2007-11-07 20:40:25 -05:00
|
|
|
start = get_preferred_edit_position();
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((distance = get_nudge_distance (start, next_distance)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
begin_reversible_command (_("nudge track"));
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->clear_changes ();
|
|
|
|
playlist->clear_owned_changes ();
|
2010-03-02 13:05:26 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
playlist->nudge_after (start, distance, forwards);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
vector<Command*> cmds;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
playlist->rdiff (cmds);
|
2010-08-25 21:44:11 -04:00
|
|
|
_session->add_commands (cmds);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (playlist));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::remove_last_capture ()
|
|
|
|
{
|
|
|
|
vector<string> choices;
|
|
|
|
string prompt;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Config->get_verify_remove_last_capture()) {
|
|
|
|
prompt = _("Do you really want to destroy the last capture?"
|
|
|
|
"\n(This is destructive and cannot be undone)");
|
|
|
|
|
|
|
|
choices.push_back (_("No, do nothing."));
|
2006-04-20 07:41:45 -04:00
|
|
|
choices.push_back (_("Yes, destroy it."));
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-22 20:26:33 -05:00
|
|
|
Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2006-04-20 07:41:45 -04:00
|
|
|
if (prompter.run () == 1) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->remove_last_capture ();
|
2010-11-25 15:37:39 -05:00
|
|
|
_regions->redisplay ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2005-11-24 09:59:36 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->remove_last_capture();
|
2010-11-25 15:37:39 -05:00
|
|
|
_regions->redisplay ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::normalize_region ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-10-25 20:30:22 -04:00
|
|
|
NormalizeDialog dialog (rs.size() > 1);
|
2009-06-20 10:02:27 -04:00
|
|
|
|
|
|
|
if (dialog.run () == RESPONSE_CANCEL) {
|
|
|
|
return;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2014-12-20 01:11:28 -05:00
|
|
|
CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
|
2005-09-25 14:42:24 -04:00
|
|
|
gdk_flush ();
|
|
|
|
|
2010-10-27 17:21:50 -04:00
|
|
|
/* XXX: should really only count audio regions here */
|
|
|
|
int const regions = rs.size ();
|
2010-10-27 10:22:24 -04:00
|
|
|
|
2010-10-27 17:21:50 -04:00
|
|
|
/* Make a list of the selected audio regions' maximum amplitudes, and also
|
|
|
|
obtain the maximum amplitude of them all.
|
|
|
|
*/
|
|
|
|
list<double> max_amps;
|
|
|
|
double max_amp = 0;
|
|
|
|
for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
|
|
|
|
if (arv) {
|
|
|
|
dialog.descend (1.0 / regions);
|
|
|
|
double const a = arv->audio_region()->maximum_amplitude (&dialog);
|
2010-10-28 13:09:32 -04:00
|
|
|
|
|
|
|
if (a == -1) {
|
|
|
|
/* the user cancelled the operation */
|
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-10-27 17:21:50 -04:00
|
|
|
max_amps.push_back (a);
|
|
|
|
max_amp = max (max_amp, a);
|
2010-10-27 10:22:24 -04:00
|
|
|
dialog.ascend ();
|
2010-08-12 19:26:59 -04:00
|
|
|
}
|
|
|
|
}
|
2010-10-27 17:21:50 -04:00
|
|
|
|
2010-10-28 13:09:32 -04:00
|
|
|
begin_reversible_command (_("normalize"));
|
|
|
|
|
2010-10-27 17:21:50 -04:00
|
|
|
list<double>::const_iterator a = max_amps.begin ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
|
2010-08-12 19:26:59 -04:00
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
|
|
|
|
if (!arv) {
|
2006-07-23 08:03:19 -04:00
|
|
|
continue;
|
2010-08-12 19:26:59 -04:00
|
|
|
}
|
|
|
|
|
2010-10-27 17:21:50 -04:00
|
|
|
arv->region()->clear_changes ();
|
2010-10-27 10:22:24 -04:00
|
|
|
|
2010-10-27 17:21:50 -04:00
|
|
|
double const amp = dialog.normalize_individually() ? *a : max_amp;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-10-25 20:30:22 -04:00
|
|
|
arv->audio_region()->normalize (amp, dialog.target ());
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (arv->region()));
|
2010-10-25 20:30:22 -04:00
|
|
|
|
2010-10-27 17:21:50 -04:00
|
|
|
++a;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2009-09-09 12:39:33 -04:00
|
|
|
Editor::reset_region_scale_amplitude ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-09 12:39:33 -04:00
|
|
|
begin_reversible_command ("reset gain");
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
|
2006-07-23 08:03:19 -04:00
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
|
|
|
|
if (!arv)
|
|
|
|
continue;
|
2010-11-25 15:37:39 -05:00
|
|
|
arv->region()->clear_changes ();
|
2006-08-29 17:21:48 -04:00
|
|
|
arv->audio_region()->set_scale_amplitude (1.0f);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (arv->region()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2008-01-19 00:06:33 -05:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::adjust_region_gain (bool up)
|
2008-01-19 00:06:33 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
2008-01-19 00:06:33 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
begin_reversible_command ("adjust region gain");
|
2008-01-19 00:06:33 -05:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
|
2008-01-19 00:06:33 -05:00
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
|
2010-03-02 13:05:26 -05:00
|
|
|
if (!arv) {
|
2008-01-19 00:06:33 -05:00
|
|
|
continue;
|
2010-11-25 15:37:39 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
arv->region()->clear_changes ();
|
2010-12-11 20:03:56 -05:00
|
|
|
|
|
|
|
double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-19 00:06:33 -05:00
|
|
|
if (up) {
|
2010-12-11 20:03:56 -05:00
|
|
|
dB += 1;
|
2008-01-19 00:06:33 -05:00
|
|
|
} else {
|
2010-12-11 20:03:56 -05:00
|
|
|
dB -= 1;
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-12-11 20:03:56 -05:00
|
|
|
arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (arv->region()));
|
2008-01-19 00:06:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::reverse_region ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
Reverse rev (*_session);
|
2005-09-25 14:42:24 -04:00
|
|
|
apply_filter (rev, _("reverse regions"));
|
|
|
|
}
|
|
|
|
|
2009-04-29 13:01:14 -04:00
|
|
|
void
|
|
|
|
Editor::strip_region_silence ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2009-04-29 13:01:14 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2009-04-30 13:07:57 -04:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-12-08 16:02:37 -05:00
|
|
|
std::list<RegionView*> audio_only;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-30 13:07:57 -04:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
|
|
|
|
if (arv) {
|
2010-12-08 16:02:37 -05:00
|
|
|
audio_only.push_back (arv);
|
2009-04-30 13:07:57 -04:00
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-12-08 16:02:37 -05:00
|
|
|
StripSilenceDialog d (_session, audio_only);
|
2009-04-29 13:01:14 -04:00
|
|
|
int const r = d.run ();
|
|
|
|
|
2010-12-09 11:31:05 -05:00
|
|
|
d.drop_rects ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-12-09 11:31:05 -05:00
|
|
|
if (r == Gtk::RESPONSE_OK) {
|
2010-12-09 13:17:36 -05:00
|
|
|
ARDOUR::AudioIntervalMap silences;
|
|
|
|
d.silences (silences);
|
|
|
|
StripSilence s (*_session, silences, d.fade_length());
|
2010-09-19 20:58:25 -04:00
|
|
|
apply_filter (s, _("strip silence"), &d);
|
2011-06-01 13:00:29 -04:00
|
|
|
}
|
2009-04-29 13:01:14 -04:00
|
|
|
}
|
|
|
|
|
2009-09-07 12:53:53 -04:00
|
|
|
Command*
|
2009-08-26 23:09:30 -04:00
|
|
|
Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
|
|
|
|
{
|
2015-01-07 00:12:07 -05:00
|
|
|
Evoral::Sequence<Evoral::Beats>::Notes selected;
|
2010-05-20 11:06:30 -04:00
|
|
|
mrv.selection_as_notelist (selected, true);
|
2009-09-07 12:53:53 -04:00
|
|
|
|
2015-01-07 00:12:07 -05:00
|
|
|
vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
|
2009-08-26 23:09:30 -04:00
|
|
|
v.push_back (selected);
|
|
|
|
|
2015-01-07 00:12:07 -05:00
|
|
|
framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
|
|
|
|
Evoral::Beats pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
|
2011-05-30 22:59:48 -04:00
|
|
|
|
|
|
|
return op (mrv.midi_region()->model(), pos_beats, v);
|
2009-08-26 23:09:30 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-08-26 23:09:30 -04:00
|
|
|
void
|
2014-12-25 15:32:10 -05:00
|
|
|
Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
|
2009-08-26 23:09:30 -04:00
|
|
|
{
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (op.name ());
|
|
|
|
|
2014-12-25 15:32:10 -05:00
|
|
|
for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
|
|
|
|
RegionSelection::const_iterator tmp = r;
|
2009-08-26 23:09:30 -04:00
|
|
|
++tmp;
|
|
|
|
|
|
|
|
MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
|
|
|
|
|
|
|
|
if (mrv) {
|
2014-12-25 15:32:10 -05:00
|
|
|
Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
|
2009-09-07 12:53:53 -04:00
|
|
|
if (cmd) {
|
|
|
|
(*cmd)();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command (cmd);
|
2009-09-07 12:53:53 -04:00
|
|
|
}
|
2009-08-26 23:09:30 -04:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-08-26 23:09:30 -04:00
|
|
|
r = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
2007-08-06 01:30:18 -04:00
|
|
|
|
2010-05-18 23:03:28 -04:00
|
|
|
void
|
|
|
|
Editor::fork_region ()
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2010-05-18 23:03:28 -04:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("Fork Region(s)"));
|
|
|
|
|
2014-12-20 01:11:28 -05:00
|
|
|
CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
|
2010-05-18 23:03:28 -04:00
|
|
|
gdk_flush ();
|
|
|
|
|
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
|
|
|
|
RegionSelection::iterator tmp = r;
|
|
|
|
++tmp;
|
|
|
|
|
|
|
|
MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
|
|
|
|
|
|
|
|
if (mrv) {
|
2014-04-13 10:29:07 -04:00
|
|
|
try {
|
|
|
|
boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
|
|
|
|
boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
|
|
|
|
boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
|
|
|
|
|
|
|
|
playlist->clear_changes ();
|
|
|
|
playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
|
|
|
|
_session->add_command(new StatefulDiffCommand (playlist));
|
|
|
|
} catch (...) {
|
|
|
|
error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
|
|
|
|
}
|
2010-05-18 23:03:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
r = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::quantize_region ()
|
2007-08-06 01:30:18 -04:00
|
|
|
{
|
2014-12-25 15:32:10 -05:00
|
|
|
if (_session) {
|
|
|
|
quantize_regions(get_regions_from_selection_and_entered ());
|
2010-11-25 15:37:39 -05:00
|
|
|
}
|
2014-12-25 15:32:10 -05:00
|
|
|
}
|
2010-11-23 12:18:16 -05:00
|
|
|
|
2014-12-25 15:32:10 -05:00
|
|
|
void
|
|
|
|
Editor::quantize_regions (const RegionSelection& rs)
|
|
|
|
{
|
|
|
|
if (rs.n_midi_regions() == 0) {
|
2010-11-25 15:37:39 -05:00
|
|
|
return;
|
|
|
|
}
|
2010-11-23 12:18:16 -05:00
|
|
|
|
2009-08-26 23:09:30 -04:00
|
|
|
QuantizeDialog* qd = new QuantizeDialog (*this);
|
|
|
|
|
|
|
|
qd->present ();
|
2009-10-26 22:36:42 -04:00
|
|
|
const int r = qd->run ();
|
2009-08-26 23:09:30 -04:00
|
|
|
qd->hide ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-10-26 22:36:42 -04:00
|
|
|
if (r == Gtk::RESPONSE_OK) {
|
2014-11-25 02:11:44 -05:00
|
|
|
Quantize quant (qd->snap_start(), qd->snap_end(),
|
2009-10-26 22:36:42 -04:00
|
|
|
qd->start_grid_size(), qd->end_grid_size(),
|
|
|
|
qd->strength(), qd->swing(), qd->threshold());
|
2009-08-26 23:09:30 -04:00
|
|
|
|
2014-12-25 15:32:10 -05:00
|
|
|
apply_midi_note_edit_op (quant, rs);
|
2009-10-26 22:36:42 -04:00
|
|
|
}
|
2007-08-06 01:30:18 -04:00
|
|
|
}
|
|
|
|
|
2014-12-06 23:42:11 -05:00
|
|
|
void
|
|
|
|
Editor::legatize_region (bool shrink_only)
|
|
|
|
{
|
2014-12-25 15:32:10 -05:00
|
|
|
if (_session) {
|
|
|
|
legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
|
2014-12-06 23:42:11 -05:00
|
|
|
}
|
2014-12-25 15:32:10 -05:00
|
|
|
}
|
2014-12-06 23:42:11 -05:00
|
|
|
|
2014-12-25 15:32:10 -05:00
|
|
|
void
|
|
|
|
Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
|
|
|
|
{
|
|
|
|
if (rs.n_midi_regions() == 0) {
|
2014-12-06 23:42:11 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Legatize legatize(shrink_only);
|
2014-12-25 15:32:10 -05:00
|
|
|
apply_midi_note_edit_op (legatize, rs);
|
2014-12-06 23:42:11 -05:00
|
|
|
}
|
|
|
|
|
2014-12-28 15:50:57 -05:00
|
|
|
void
|
|
|
|
Editor::transform_region ()
|
|
|
|
{
|
|
|
|
if (_session) {
|
|
|
|
transform_regions(get_regions_from_selection_and_entered ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::transform_regions (const RegionSelection& rs)
|
|
|
|
{
|
|
|
|
if (rs.n_midi_regions() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TransformDialog* td = new TransformDialog();
|
|
|
|
|
|
|
|
td->present();
|
|
|
|
const int r = td->run();
|
|
|
|
td->hide();
|
|
|
|
|
|
|
|
if (r == Gtk::RESPONSE_OK) {
|
|
|
|
Transform transform(td->get());
|
|
|
|
apply_midi_note_edit_op(transform, rs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-22 18:45:04 -05:00
|
|
|
void
|
2011-12-29 20:50:34 -05:00
|
|
|
Editor::insert_patch_change (bool from_context)
|
2010-12-22 18:45:04 -05:00
|
|
|
{
|
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2011-12-30 11:21:10 -05:00
|
|
|
|
2010-12-22 18:45:04 -05:00
|
|
|
if (rs.empty ()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-12-30 12:28:05 -05:00
|
|
|
const framepos_t p = get_preferred_edit_position (false, from_context);
|
2010-12-28 13:19:40 -05:00
|
|
|
|
2012-06-02 09:02:01 -04:00
|
|
|
/* 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
|
|
|
|
one set of patch menus.
|
|
|
|
*/
|
|
|
|
MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
|
|
|
|
|
2015-01-07 00:12:07 -05:00
|
|
|
Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
|
2012-06-11 18:59:35 -04:00
|
|
|
PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-12-22 18:45:04 -05:00
|
|
|
if (d.run() == RESPONSE_CANCEL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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()) {
|
2010-12-28 13:19:40 -05:00
|
|
|
mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
|
2010-12-22 18:45:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-06 01:30:18 -04:00
|
|
|
void
|
2010-09-19 20:58:25 -04:00
|
|
|
Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (command);
|
|
|
|
|
2014-12-20 01:11:28 -05:00
|
|
|
CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
|
2005-09-25 14:42:24 -04:00
|
|
|
gdk_flush ();
|
|
|
|
|
2010-09-19 20:58:25 -04:00
|
|
|
int n = 0;
|
|
|
|
int const N = rs.size ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
|
2007-08-06 01:30:18 -04:00
|
|
|
RegionSelection::iterator tmp = r;
|
|
|
|
++tmp;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-08-06 01:30:18 -04:00
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
|
|
|
|
if (arv) {
|
|
|
|
boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-09-19 20:58:25 -04:00
|
|
|
if (progress) {
|
|
|
|
progress->descend (1.0 / N);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arv->audio_region()->apply (filter, progress) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2010-08-25 13:32:08 -04:00
|
|
|
playlist->clear_changes ();
|
2011-12-30 18:41:17 -05:00
|
|
|
playlist->clear_owned_changes ();
|
2010-09-19 20:58:25 -04:00
|
|
|
|
2009-04-29 13:01:14 -04:00
|
|
|
if (filter.results.empty ()) {
|
|
|
|
|
|
|
|
/* no regions returned; remove the old one */
|
|
|
|
playlist->remove_region (arv->region ());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-29 13:01:14 -04:00
|
|
|
} else {
|
|
|
|
|
|
|
|
std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
|
|
|
|
|
|
|
|
/* first region replaces the old one */
|
|
|
|
playlist->replace_region (arv->region(), *res, (*res)->position());
|
|
|
|
++res;
|
|
|
|
|
|
|
|
/* add the rest */
|
|
|
|
while (res != filter.results.end()) {
|
|
|
|
playlist->add_region (*res, (*res)->position());
|
|
|
|
++res;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-04-29 13:01:14 -04:00
|
|
|
}
|
|
|
|
|
2011-12-30 18:41:17 -05:00
|
|
|
/* We might have removed regions, which alters other regions' layering_index,
|
|
|
|
so we need to do a recursive diff here.
|
|
|
|
*/
|
|
|
|
vector<Command*> cmds;
|
|
|
|
playlist->rdiff (cmds);
|
|
|
|
_session->add_commands (cmds);
|
|
|
|
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (playlist));
|
2007-08-06 01:30:18 -04:00
|
|
|
} else {
|
2014-12-20 01:11:28 -05:00
|
|
|
return;
|
2007-08-06 01:30:18 -04:00
|
|
|
}
|
2010-09-19 20:58:25 -04:00
|
|
|
|
|
|
|
if (progress) {
|
|
|
|
progress->ascend ();
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
r = tmp;
|
2010-09-19 20:58:25 -04:00
|
|
|
++n;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::external_edit_region ()
|
|
|
|
{
|
|
|
|
/* more to come */
|
|
|
|
}
|
|
|
|
|
2006-11-19 11:45:16 -05:00
|
|
|
void
|
|
|
|
Editor::reset_region_gain_envelopes ()
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || rs.empty()) {
|
2006-11-19 11:45:16 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("reset region gain"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2006-11-19 11:45:16 -05:00
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
|
|
|
|
if (arv) {
|
2007-06-29 00:02:58 -04:00
|
|
|
boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
|
|
|
|
XMLNode& before (alist->get_state());
|
2006-11-19 11:45:16 -05:00
|
|
|
|
|
|
|
arv->audio_region()->set_default_envelope ();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2012-05-29 14:30:10 -04:00
|
|
|
Editor::set_region_gain_visibility (RegionView* rv)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2012-02-15 09:03:19 -05:00
|
|
|
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
|
|
|
|
if (arv) {
|
2012-05-29 14:38:54 -04:00
|
|
|
arv->update_envelope_visibility();
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
2012-02-15 09:03:19 -05:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2012-02-15 09:03:19 -05:00
|
|
|
void
|
2012-05-29 14:30:10 -04:00
|
|
|
Editor::set_gain_envelope_visibility ()
|
2012-02-15 09:03:19 -05:00
|
|
|
{
|
|
|
|
if (!_session) {
|
2009-06-26 07:22:16 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-15 09:03:19 -05:00
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
|
|
|
|
if (v) {
|
2012-05-29 14:30:10 -04:00
|
|
|
v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-10-11 18:07:47 -04:00
|
|
|
Editor::toggle_gain_envelope_active ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
if (_ignore_region_action) {
|
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || rs.empty()) {
|
2009-06-26 07:22:16 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("region gain envelope active"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2006-07-23 08:03:19 -04:00
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
|
2006-11-19 11:45:16 -05:00
|
|
|
if (arv) {
|
2010-08-25 13:32:08 -04:00
|
|
|
arv->region()->clear_changes ();
|
2008-01-12 18:45:50 -05:00
|
|
|
arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
|
2010-02-11 18:10:29 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (arv->region()));
|
2007-10-11 18:07:47 -04:00
|
|
|
}
|
2007-05-14 12:16:54 -04:00
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2007-05-14 12:16:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-10-11 18:07:47 -04:00
|
|
|
Editor::toggle_region_lock ()
|
2007-05-14 12:16:54 -04:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
if (_ignore_region_action) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || rs.empty()) {
|
2009-06-26 07:22:16 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("toggle region lock"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2010-08-25 13:32:08 -04:00
|
|
|
(*i)->region()->clear_changes ();
|
2008-01-12 18:45:50 -05:00
|
|
|
(*i)->region()->set_locked (!(*i)->region()->locked());
|
2010-02-11 18:10:29 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand ((*i)->region()));
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
|
|
|
|
2013-03-12 17:00:09 -04:00
|
|
|
void
|
|
|
|
Editor::toggle_region_video_lock ()
|
|
|
|
{
|
|
|
|
if (_ignore_region_action) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
|
|
|
|
|
|
|
if (!_session || rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("Toggle Video Lock"));
|
|
|
|
|
2013-03-12 17:00:09 -04:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
(*i)->region()->clear_changes ();
|
|
|
|
(*i)->region()->set_video_locked (!(*i)->region()->video_locked());
|
|
|
|
_session->add_command (new StatefulDiffCommand ((*i)->region()));
|
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2013-03-12 17:00:09 -04:00
|
|
|
}
|
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
void
|
2010-05-02 10:08:37 -04:00
|
|
|
Editor::toggle_region_lock_style ()
|
2008-02-02 12:22:04 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
if (_ignore_region_action) {
|
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || rs.empty()) {
|
2009-06-26 07:22:16 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("region lock style"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2010-11-25 15:37:39 -05:00
|
|
|
(*i)->region()->clear_changes ();
|
2010-06-27 20:34:09 -04:00
|
|
|
PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
|
2010-05-02 10:08:37 -04:00
|
|
|
(*i)->region()->set_position_lock_style (ns);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand ((*i)->region()));
|
2008-02-02 12:22:04 -05:00
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2008-02-02 12:22:04 -05:00
|
|
|
}
|
|
|
|
|
2006-11-19 11:45:16 -05:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::toggle_opaque_region ()
|
2006-11-19 11:45:16 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
if (_ignore_region_action) {
|
2009-06-26 07:22:16 -04:00
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session || rs.empty()) {
|
2009-06-26 07:22:16 -04:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("change region opacity"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2010-08-25 13:32:08 -04:00
|
|
|
(*i)->region()->clear_changes ();
|
2008-01-12 18:45:50 -05:00
|
|
|
(*i)->region()->set_opaque (!(*i)->region()->opaque());
|
2010-02-11 18:10:29 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand ((*i)->region()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
void
|
|
|
|
Editor::toggle_record_enable ()
|
|
|
|
{
|
|
|
|
bool new_state = false;
|
|
|
|
bool first = true;
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
|
2008-12-12 09:43:24 -05:00
|
|
|
if (!rtav)
|
|
|
|
continue;
|
|
|
|
if (!rtav->is_track())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
new_state = !rtav->track()->record_enabled();
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
2010-07-24 12:40:56 -04:00
|
|
|
rtav->track()->set_record_enabled (new_state, this);
|
2008-12-12 09:43:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-14 12:01:07 -04:00
|
|
|
void
|
|
|
|
Editor::toggle_solo ()
|
|
|
|
{
|
|
|
|
bool new_state = false;
|
|
|
|
bool first = true;
|
|
|
|
boost::shared_ptr<RouteList> rl (new RouteList);
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
|
|
|
|
|
|
|
|
if (!rtav) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
new_state = !rtav->route()->soloed ();
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
rl->push_back (rtav->route());
|
|
|
|
}
|
|
|
|
|
|
|
|
_session->set_solo (rl, new_state, Session::rt_cleanup, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_mute ()
|
|
|
|
{
|
|
|
|
bool new_state = false;
|
|
|
|
bool first = true;
|
|
|
|
boost::shared_ptr<RouteList> rl (new RouteList);
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
|
|
|
|
|
|
|
|
if (!rtav) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (first) {
|
2011-08-14 13:11:33 -04:00
|
|
|
new_state = !rtav->route()->muted();
|
2011-08-14 12:01:07 -04:00
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
rl->push_back (rtav->route());
|
|
|
|
}
|
|
|
|
|
|
|
|
_session->set_mute (rl, new_state, Session::rt_cleanup, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_solo_isolate ()
|
|
|
|
{
|
|
|
|
}
|
2008-12-12 09:43:24 -05:00
|
|
|
|
2014-07-10 08:17:22 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::fade_range ()
|
|
|
|
{
|
|
|
|
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
|
|
|
|
|
|
|
|
begin_reversible_command (_("fade range"));
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
|
|
|
|
(*i)->fade_range (selection->time);
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
|
|
|
Editor::set_fade_length (bool in)
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2009-06-26 07:22:39 -04:00
|
|
|
if (rs.empty()) {
|
2007-11-12 17:23:01 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-26 07:22:39 -04:00
|
|
|
/* we need a region to measure the offset from the start */
|
|
|
|
|
|
|
|
RegionView* rv = rs.front ();
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos = get_preferred_edit_position();
|
|
|
|
framepos_t len;
|
2010-05-07 21:20:33 -04:00
|
|
|
char const * cmd;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
|
|
|
|
/* edit point is outside the relevant region */
|
|
|
|
return;
|
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
if (in) {
|
|
|
|
if (pos <= rv->region()->position()) {
|
|
|
|
/* can't do it */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
len = pos - rv->region()->position();
|
|
|
|
cmd = _("set fade in length");
|
|
|
|
} else {
|
|
|
|
if (pos >= rv->region()->last_frame()) {
|
|
|
|
/* can't do it */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
len = rv->region()->last_frame() - pos;
|
|
|
|
cmd = _("set fade out length");
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (cmd);
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
|
|
|
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
boost::shared_ptr<AutomationList> alist;
|
|
|
|
if (in) {
|
|
|
|
alist = tmp->audio_region()->fade_in();
|
|
|
|
} else {
|
|
|
|
alist = tmp->audio_region()->fade_out();
|
|
|
|
}
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
XMLNode &before = alist->get_state();
|
|
|
|
|
|
|
|
if (in) {
|
|
|
|
tmp->audio_region()->set_fade_in_length (len);
|
2008-02-16 17:43:18 -05:00
|
|
|
tmp->audio_region()->set_fade_in_active (true);
|
2007-11-12 17:23:01 -05:00
|
|
|
} else {
|
|
|
|
tmp->audio_region()->set_fade_out_length (len);
|
2008-02-16 17:43:18 -05:00
|
|
|
tmp->audio_region()->set_fade_out_active (true);
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
XMLNode &after = alist->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
2010-09-18 23:31:03 -04:00
|
|
|
Editor::set_fade_in_shape (FadeShape shape)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
begin_reversible_command (_("set fade in shape"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
2007-01-28 12:44:13 -05:00
|
|
|
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-06-29 00:02:58 -04:00
|
|
|
boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
|
|
|
|
XMLNode &before = alist->get_state();
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
tmp->audio_region()->set_fade_in_shape (shape);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-06-29 00:02:58 -04:00
|
|
|
XMLNode &after = alist->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-18 23:31:03 -04:00
|
|
|
Editor::set_fade_out_shape (FadeShape shape)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
begin_reversible_command (_("set fade out shape"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
2007-01-28 12:44:13 -05:00
|
|
|
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-06-29 00:02:58 -04:00
|
|
|
boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
|
|
|
|
XMLNode &before = alist->get_state();
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
tmp->audio_region()->set_fade_out_shape (shape);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-06-29 00:02:58 -04:00
|
|
|
XMLNode &after = alist->get_state();
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_fade_in_active (bool yn)
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
begin_reversible_command (_("set fade in active"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
2007-01-28 12:44:13 -05:00
|
|
|
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
ar->clear_changes ();
|
2007-01-28 12:44:13 -05:00
|
|
|
ar->set_fade_in_active (yn);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand (ar));
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_fade_out_active (bool yn)
|
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
begin_reversible_command (_("set fade out active"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
2007-01-28 12:44:13 -05:00
|
|
|
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
ar->clear_changes ();
|
2007-01-28 12:44:13 -05:00
|
|
|
ar->set_fade_out_active (yn);
|
2010-03-02 13:05:26 -05:00
|
|
|
_session->add_command(new StatefulDiffCommand (ar));
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2008-10-09 17:55:05 -04:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::toggle_region_fades (int dir)
|
2008-10-09 17:55:05 -04:00
|
|
|
{
|
2012-05-07 08:03:26 -04:00
|
|
|
if (_ignore_region_action) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-10-09 17:55:05 -04:00
|
|
|
boost::shared_ptr<AudioRegion> ar;
|
2011-09-30 13:55:14 -04:00
|
|
|
bool yn = false;
|
2008-10-09 17:55:05 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-10-09 17:55:05 -04:00
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-01 13:00:29 -04:00
|
|
|
RegionSelection::iterator i;
|
2008-10-09 17:55:05 -04:00
|
|
|
for (i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
|
|
|
|
if (dir == -1) {
|
|
|
|
yn = ar->fade_out_active ();
|
|
|
|
} else {
|
|
|
|
yn = ar->fade_in_active ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == rs.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX should this undo-able? */
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (dir == 1 || dir == 0) {
|
|
|
|
ar->set_fade_in_active (!yn);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dir == -1 || dir == 0) {
|
|
|
|
ar->set_fade_out_active (!yn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Update region fade visibility after its configuration has been changed */
|
|
|
|
void
|
|
|
|
Editor::update_region_fade_visibility ()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
bool _fade_visibility = _session->config.get_show_region_fades ();
|
2008-10-09 17:55:05 -04:00
|
|
|
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
2009-07-09 13:58:13 -04:00
|
|
|
AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
|
2008-10-09 17:55:05 -04:00
|
|
|
if (v) {
|
|
|
|
if (_fade_visibility) {
|
|
|
|
v->audio_view()->show_all_fades ();
|
|
|
|
} else {
|
|
|
|
v->audio_view()->hide_all_fades ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-04-22 14:01:10 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
|
|
|
Editor::set_edit_point ()
|
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t where;
|
2007-11-12 17:23:01 -05:00
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!mouse_frame (where, ignored)) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
snap_to (where);
|
|
|
|
|
|
|
|
if (selection->markers.empty()) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
mouse_add_new_marker (where);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
Location* loc = find_location_from_marker (selection->markers.front(), ignored);
|
|
|
|
|
|
|
|
if (loc) {
|
|
|
|
loc->move_to (where);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_playhead_cursor ()
|
|
|
|
{
|
|
|
|
if (entered_marker) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (entered_marker->position(), _session->transport_rolling());
|
2007-11-12 17:23:01 -05:00
|
|
|
} else {
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t where;
|
2007-11-12 17:23:01 -05:00
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!mouse_frame (where, ignored)) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
snap_to (where);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session) {
|
|
|
|
_session->request_locate (where, _session->transport_rolling());
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
}
|
2012-11-20 14:43:43 -05:00
|
|
|
|
2014-12-22 13:39:41 -05:00
|
|
|
if (ARDOUR_UI::config()->get_follow_edits()) {
|
2012-11-20 14:43:43 -05:00
|
|
|
cancel_time_selection();
|
2014-12-22 13:39:41 -05:00
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::split_region ()
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
2015-01-08 17:00:36 -05:00
|
|
|
//if a range is selected, separate it
|
2012-11-26 17:43:10 -05:00
|
|
|
if ( !selection->time.empty()) {
|
2010-11-25 15:37:39 -05:00
|
|
|
separate_regions_between (selection->time);
|
|
|
|
return;
|
2011-06-01 13:00:29 -04:00
|
|
|
}
|
2010-06-28 11:01:14 -04:00
|
|
|
|
2015-01-08 17:00:36 -05:00
|
|
|
//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.
|
|
|
|
|
|
|
|
RegionSelection rs = get_regions_from_selection_and_edit_point ();
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2015-01-08 17:00:36 -05:00
|
|
|
framepos_t where = get_preferred_edit_position ();
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2015-01-08 17:00:36 -05:00
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2015-01-08 17:00:36 -05:00
|
|
|
split_regions_at (where, rs);
|
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
2008-01-07 16:12:29 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
struct EditorOrderRouteSorter {
|
|
|
|
bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
|
2013-10-20 09:19:43 -04:00
|
|
|
return a->order_key () < b->order_key ();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_next_route()
|
|
|
|
{
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
selection->set (track_views.front());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
TimeAxisView* current = selection->tracks.front();
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteUI *rui;
|
2008-12-12 09:43:24 -05:00
|
|
|
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;
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
}
|
2009-07-09 13:58:13 -04:00
|
|
|
rui = dynamic_cast<RouteUI *>(current);
|
|
|
|
} while ( current->hidden() || (rui != NULL && !rui->route()->active()));
|
2008-12-12 09:43:24 -05:00
|
|
|
|
|
|
|
selection->set(current);
|
|
|
|
|
2014-07-14 12:36:44 -04:00
|
|
|
ensure_time_axis_view_is_visible (*current, false);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_prev_route()
|
|
|
|
{
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
selection->set (track_views.front());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
TimeAxisView* current = selection->tracks.front();
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteUI *rui;
|
2008-12-12 09:43:24 -05:00
|
|
|
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;
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
}
|
2009-07-09 13:58:13 -04:00
|
|
|
rui = dynamic_cast<RouteUI *>(current);
|
|
|
|
} while ( current->hidden() || (rui != NULL && !rui->route()->active()));
|
2008-12-12 09:43:24 -05:00
|
|
|
|
|
|
|
selection->set (current);
|
|
|
|
|
2014-07-14 12:36:44 -04:00
|
|
|
ensure_time_axis_view_is_visible (*current, false);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_loop_from_selection (bool play)
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
if (_session == 0) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
framepos_t start, end;
|
|
|
|
if (!get_selection_extents ( start, end))
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
set_loop_range (start, end, _("set loop range from selection"));
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (play) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (start, true);
|
2014-09-15 13:44:45 -04:00
|
|
|
_session->request_play_loop (true);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_loop_from_region (bool play)
|
|
|
|
{
|
2015-01-07 16:31:05 -05:00
|
|
|
framepos_t start, end;
|
|
|
|
if (!get_selection_extents ( start, end))
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
set_loop_range (start, end, _("set loop range from region"));
|
|
|
|
|
|
|
|
if (play) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (start, true);
|
2014-09-15 13:44:45 -04:00
|
|
|
_session->request_play_loop (true);
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_punch_from_selection ()
|
|
|
|
{
|
2015-01-07 16:31:05 -05:00
|
|
|
if (_session == 0) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-07 16:31:05 -05:00
|
|
|
framepos_t start, end;
|
|
|
|
if (!get_selection_extents ( start, end))
|
|
|
|
return;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
set_punch_range (start, end, _("set punch range from selection"));
|
|
|
|
}
|
|
|
|
|
2014-12-09 17:17:47 -05:00
|
|
|
void
|
|
|
|
Editor::set_session_extents_from_selection ()
|
|
|
|
{
|
2015-01-07 16:31:05 -05:00
|
|
|
if (_session == 0) {
|
2014-12-09 17:17:47 -05:00
|
|
|
return;
|
|
|
|
}
|
2015-01-07 16:31:05 -05:00
|
|
|
|
|
|
|
framepos_t start, end;
|
|
|
|
if (!get_selection_extents ( start, end))
|
|
|
|
return;
|
2014-12-09 17:17:47 -05:00
|
|
|
|
|
|
|
begin_reversible_command (_("set session start/stop from selection"));
|
|
|
|
|
|
|
|
Location* loc;
|
|
|
|
if ((loc = _session->locations()->session_range_location()) == 0) {
|
|
|
|
_session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
|
|
|
|
} else {
|
|
|
|
XMLNode &before = loc->get_state();
|
|
|
|
|
|
|
|
_session->set_session_extents ( start, end );
|
|
|
|
|
|
|
|
XMLNode &after = loc->get_state();
|
|
|
|
|
|
|
|
_session->add_command (new MementoCommand<Location>(*loc, &before, &after));
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
void
|
|
|
|
Editor::set_punch_from_region ()
|
|
|
|
{
|
2015-01-07 16:31:05 -05:00
|
|
|
framepos_t start, end;
|
|
|
|
if (!get_selection_extents ( start, end))
|
2008-01-10 17:22:29 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
set_punch_range (start, end, _("set punch range from region"));
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::pitch_shift_region ()
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-04-05 22:04:37 -04:00
|
|
|
RegionSelection audio_rs;
|
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
if (dynamic_cast<AudioRegionView*> (*i)) {
|
|
|
|
audio_rs.push_back (*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (audio_rs.empty()) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-04-05 22:04:37 -04:00
|
|
|
pitch_shift (audio_rs, 1.2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::transpose_region ()
|
|
|
|
{
|
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
|
|
|
|
|
|
|
list<MidiRegionView*> midi_region_views;
|
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
|
|
|
|
if (mrv) {
|
|
|
|
midi_region_views.push_back (mrv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TransposeDialog d;
|
|
|
|
int const r = d.run ();
|
|
|
|
if (r != RESPONSE_ACCEPT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
|
|
|
|
(*i)->midi_region()->transpose (d.semitones ());
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::set_tempo_from_region ()
|
2008-02-01 22:57:35 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
2008-02-01 22:57:35 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
RegionView* rv = rs.front();
|
2008-02-01 22:57:35 -05:00
|
|
|
|
|
|
|
define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::use_range_as_bar ()
|
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t start, end;
|
2008-02-01 22:57:35 -05:00
|
|
|
if (get_edit_op_range (start, end)) {
|
|
|
|
define_one_bar (start, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-17 14:20:37 -04:00
|
|
|
Editor::define_one_bar (framepos_t start, framepos_t end)
|
2008-02-01 22:57:35 -05:00
|
|
|
{
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t length = end - start;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
const Meter& m (_session->tempo_map().meter_at (start));
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
/* length = 1 bar */
|
2008-02-01 22:57:35 -05:00
|
|
|
|
|
|
|
/* now we want frames per beat.
|
|
|
|
we have frames per bar, and beats per bar, so ...
|
|
|
|
*/
|
|
|
|
|
2011-12-12 21:46:36 -05:00
|
|
|
/* XXXX METER MATH */
|
|
|
|
|
|
|
|
double frames_per_beat = length / m.divisions_per_bar();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
/* beats per minute = */
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
/* now decide whether to:
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
(a) set global tempo
|
2008-02-02 12:22:04 -05:00
|
|
|
(b) add a new tempo marker
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
const TempoSection& t (_session->tempo_map().tempo_section_at (start));
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
bool do_global = false;
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
/* only 1 tempo & 1 meter: ask if the user wants to set the tempo
|
|
|
|
at the start, or create a new marker
|
|
|
|
*/
|
|
|
|
|
|
|
|
vector<string> options;
|
|
|
|
options.push_back (_("Cancel"));
|
2008-02-16 17:43:18 -05:00
|
|
|
options.push_back (_("Add new marker"));
|
|
|
|
options.push_back (_("Set global tempo"));
|
2009-12-22 20:26:33 -05:00
|
|
|
|
|
|
|
Choice c (
|
|
|
|
_("Define one bar"),
|
|
|
|
_("Do you want to set the global tempo or add a new tempo marker?"),
|
|
|
|
options
|
|
|
|
);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
c.set_default_response (2);
|
2008-02-02 12:22:04 -05:00
|
|
|
|
|
|
|
switch (c.run()) {
|
|
|
|
case 0:
|
2008-02-16 17:43:18 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
case 2:
|
2008-02-02 12:22:04 -05:00
|
|
|
do_global = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
do_global = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* more than 1 tempo and/or meter section already, go ahead do the "usual":
|
|
|
|
if the marker is at the region starter, change it, otherwise add
|
2009-10-14 12:10:01 -04:00
|
|
|
a new tempo marker
|
2008-02-02 12:22:04 -05:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
begin_reversible_command (_("set tempo from region"));
|
2009-12-17 13:24:23 -05:00
|
|
|
XMLNode& before (_session->tempo_map().get_state());
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
if (do_global) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
|
2008-02-02 12:22:04 -05:00
|
|
|
} else if (t.frame() == start) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
|
2008-02-01 22:57:35 -05:00
|
|
|
} else {
|
2012-12-19 13:40:21 -05:00
|
|
|
Timecode::BBT_Time bbt;
|
|
|
|
_session->tempo_map().bbt_time (start, bbt);
|
|
|
|
_session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
XMLNode& after (_session->tempo_map().get_state());
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
|
2008-02-01 22:57:35 -05:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split_region_at_transients ()
|
|
|
|
{
|
2008-02-02 12:22:04 -05:00
|
|
|
AnalysisFeatureList positions;
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
2008-02-01 22:57:35 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("split regions"));
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
|
2008-02-01 22:57:35 -05:00
|
|
|
|
|
|
|
RegionSelection::iterator tmp;
|
|
|
|
|
|
|
|
tmp = i;
|
|
|
|
++tmp;
|
|
|
|
|
|
|
|
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
if (ar && (ar->get_transients (positions) == 0)) {
|
2008-02-16 17:43:18 -05:00
|
|
|
split_region_at_points ((*i)->region(), positions, true);
|
2008-02-01 22:57:35 -05:00
|
|
|
positions.clear ();
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
i = tmp;
|
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2008-02-01 22:57:35 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-01-19 13:35:11 -05:00
|
|
|
Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
|
2008-02-01 22:57:35 -05:00
|
|
|
{
|
2008-02-16 17:43:18 -05:00
|
|
|
bool use_rhythmic_rodent = false;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
boost::shared_ptr<Playlist> pl = r->playlist();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
list<boost::shared_ptr<Region> > new_regions;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
if (!pl) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
if (positions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2008-02-16 17:43:18 -05:00
|
|
|
|
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
if (positions.size() > 20 && can_ferret) {
|
2010-09-14 12:51:02 -04:00
|
|
|
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);
|
2008-02-16 17:43:18 -05:00
|
|
|
MessageDialog msg (msgstr,
|
|
|
|
false,
|
|
|
|
Gtk::MESSAGE_INFO,
|
|
|
|
Gtk::BUTTONS_OK_CANCEL);
|
|
|
|
|
|
|
|
if (can_ferret) {
|
|
|
|
msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
|
|
|
|
msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
|
|
|
|
} else {
|
|
|
|
msg.set_secondary_text (_("Press OK to continue with this split operation"));
|
|
|
|
}
|
|
|
|
|
|
|
|
msg.set_title (_("Excessive split?"));
|
|
|
|
msg.present ();
|
|
|
|
|
|
|
|
int response = msg.run();
|
|
|
|
msg.hide ();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
switch (response) {
|
|
|
|
case RESPONSE_OK:
|
|
|
|
break;
|
|
|
|
case RESPONSE_APPLY:
|
|
|
|
use_rhythmic_rodent = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (use_rhythmic_rodent) {
|
|
|
|
show_rhythm_ferret ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
AnalysisFeatureList::const_iterator x;
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
pl->clear_changes ();
|
2011-12-30 18:41:17 -05:00
|
|
|
pl->clear_owned_changes ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
x = positions.begin();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
if (x == positions.end()) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
pl->freeze ();
|
2008-02-16 17:43:18 -05:00
|
|
|
pl->remove_region (r);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos = 0;
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
while (x != positions.end()) {
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
/* deal with positons that are out of scope of present region bounds */
|
2011-01-19 13:35:11 -05:00
|
|
|
if (*x <= 0 || *x > r->length()) {
|
2010-07-06 07:33:27 -04:00
|
|
|
++x;
|
|
|
|
continue;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
|
|
|
/* file start = original start + how far we from the initial position ?
|
2008-02-01 22:57:35 -05:00
|
|
|
*/
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t file_start = r->start() + pos;
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
/* length = next position - current position
|
|
|
|
*/
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t len = (*x) - pos;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
/* XXX we do we really want to allow even single-sample regions?
|
|
|
|
shouldn't we have some kind of lower limit on region size?
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (len <= 0) {
|
|
|
|
break;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
string new_name;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-03-30 19:40:28 -04:00
|
|
|
if (RegionFactory::region_name (new_name, r->name())) {
|
2008-02-16 17:43:18 -05:00
|
|
|
break;
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
/* do NOT announce new regions 1 by one, just wait till they are all done */
|
|
|
|
|
2011-06-01 13:00:29 -04:00
|
|
|
PropertyList plist;
|
|
|
|
|
2010-02-18 08:59:49 -05:00
|
|
|
plist.add (ARDOUR::Properties::start, file_start);
|
|
|
|
plist.add (ARDOUR::Properties::length, len);
|
|
|
|
plist.add (ARDOUR::Properties::name, new_name);
|
|
|
|
plist.add (ARDOUR::Properties::layer, 0);
|
|
|
|
|
|
|
|
boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
|
2012-05-27 14:22:45 -04:00
|
|
|
/* because we set annouce to false, manually add the new region to the
|
|
|
|
RegionFactory map
|
|
|
|
*/
|
|
|
|
RegionFactory::map_add (nr);
|
2011-02-14 16:49:43 -05:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
pl->add_region (nr, r->position() + pos);
|
2011-02-14 16:49:43 -05:00
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
if (select_new) {
|
|
|
|
new_regions.push_front(nr);
|
|
|
|
}
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2008-02-01 22:57:35 -05:00
|
|
|
pos += len;
|
|
|
|
++x;
|
2010-07-06 07:33:27 -04:00
|
|
|
}
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
string new_name;
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
RegionFactory::region_name (new_name, r->name());
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
/* Add the final region */
|
2011-06-01 13:00:29 -04:00
|
|
|
PropertyList plist;
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
plist.add (ARDOUR::Properties::start, r->start() + pos);
|
|
|
|
plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
|
|
|
|
plist.add (ARDOUR::Properties::name, new_name);
|
|
|
|
plist.add (ARDOUR::Properties::layer, 0);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
|
2012-05-27 14:22:45 -04:00
|
|
|
/* because we set annouce to false, manually add the new region to the
|
|
|
|
RegionFactory map
|
|
|
|
*/
|
|
|
|
RegionFactory::map_add (nr);
|
2010-07-06 07:33:27 -04:00
|
|
|
pl->add_region (nr, r->position() + pos);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
if (select_new) {
|
|
|
|
new_regions.push_front(nr);
|
|
|
|
}
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
pl->thaw ();
|
2010-02-18 08:59:49 -05:00
|
|
|
|
2011-12-30 18:41:17 -05:00
|
|
|
/* We might have removed regions, which alters other regions' layering_index,
|
|
|
|
so we need to do a recursive diff here.
|
|
|
|
*/
|
|
|
|
vector<Command*> cmds;
|
|
|
|
pl->rdiff (cmds);
|
|
|
|
_session->add_commands (cmds);
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
_session->add_command (new StatefulDiffCommand (pl));
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-01-19 13:35:11 -05:00
|
|
|
if (select_new) {
|
|
|
|
|
|
|
|
for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
|
|
|
|
set_selected_regionview_from_region_list ((*i), Selection::Add);
|
|
|
|
}
|
|
|
|
}
|
2010-07-06 07:33:27 -04:00
|
|
|
}
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
void
|
|
|
|
Editor::place_transient()
|
|
|
|
{
|
|
|
|
if (!_session) {
|
|
|
|
return;
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2008-02-16 17:43:18 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_edit_point ();
|
2010-07-06 07:33:27 -04:00
|
|
|
|
|
|
|
if (rs.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t where = get_preferred_edit_position();
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("place transient"));
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
|
|
|
|
framepos_t position = (*r)->region()->position();
|
|
|
|
(*r)->region()->add_transient(where - position);
|
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2010-07-06 07:33:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::remove_transient(ArdourCanvas::Item* item)
|
|
|
|
{
|
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
|
2010-07-06 07:33:27 -04:00
|
|
|
assert (_line);
|
|
|
|
|
|
|
|
AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
|
2011-02-14 16:49:43 -05:00
|
|
|
_arv->remove_transient (*(float*) _line->get_data ("position"));
|
2010-07-06 07:33:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::snap_regions_to_grid ()
|
2010-07-06 07:33:27 -04:00
|
|
|
{
|
2011-02-14 16:49:43 -05:00
|
|
|
list <boost::shared_ptr<Playlist > > used_playlists;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
2010-07-06 07:33:27 -04:00
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("snap regions to grid"));
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
if (!pl->frozen()) {
|
|
|
|
/* we haven't seen this playlist before */
|
|
|
|
|
|
|
|
/* remember used playlists so we can thaw them later */
|
|
|
|
used_playlists.push_back(pl);
|
|
|
|
pl->freeze();
|
|
|
|
}
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
framepos_t start_frame = (*r)->region()->first_frame ();
|
|
|
|
snap_to (start_frame);
|
2011-05-30 09:54:44 -04:00
|
|
|
(*r)->region()->set_position (start_frame);
|
2010-07-06 07:33:27 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
while (used_playlists.size() > 0) {
|
|
|
|
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
|
|
|
|
(*i)->thaw();
|
|
|
|
used_playlists.pop_front();
|
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2010-07-06 07:33:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::close_region_gaps ()
|
2011-02-14 16:49:43 -05:00
|
|
|
{
|
|
|
|
list <boost::shared_ptr<Playlist > > used_playlists;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!_session || rs.empty()) {
|
2010-07-06 07:33:27 -04:00
|
|
|
return;
|
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
|
2010-11-03 22:04:08 -04:00
|
|
|
Dialog dialog (_("Close Region Gaps"));
|
|
|
|
|
|
|
|
Table table (2, 3);
|
|
|
|
table.set_spacings (12);
|
|
|
|
table.set_border_width (12);
|
2012-06-04 21:03:36 -04:00
|
|
|
Label* l = manage (left_aligned_label (_("Crossfade length")));
|
2010-11-03 22:04:08 -04:00
|
|
|
table.attach (*l, 0, 1, 0, 1);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
SpinButton spin_crossfade (1, 0);
|
|
|
|
spin_crossfade.set_range (0, 15);
|
|
|
|
spin_crossfade.set_increments (1, 1);
|
2011-01-19 13:35:11 -05:00
|
|
|
spin_crossfade.set_value (5);
|
2010-11-03 22:04:08 -04:00
|
|
|
table.attach (spin_crossfade, 1, 2, 0, 1);
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2010-11-03 22:04:08 -04:00
|
|
|
table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
|
|
|
|
|
2012-06-04 21:03:36 -04:00
|
|
|
l = manage (left_aligned_label (_("Pull-back length")));
|
2010-11-03 22:04:08 -04:00
|
|
|
table.attach (*l, 0, 1, 1, 2);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
SpinButton spin_pullback (1, 0);
|
2011-01-19 13:35:11 -05:00
|
|
|
spin_pullback.set_range (0, 100);
|
2010-07-06 07:33:27 -04:00
|
|
|
spin_pullback.set_increments (1, 1);
|
2011-01-19 13:35:11 -05:00
|
|
|
spin_pullback.set_value(30);
|
2010-11-03 22:04:08 -04:00
|
|
|
table.attach (spin_pullback, 1, 2, 1, 2);
|
|
|
|
|
|
|
|
table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 22:04:08 -04:00
|
|
|
dialog.get_vbox()->pack_start (table);
|
2010-07-06 07:33:27 -04:00
|
|
|
dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
|
|
|
|
dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
|
2010-11-03 22:04:08 -04:00
|
|
|
dialog.show_all ();
|
2010-07-06 07:33:27 -04:00
|
|
|
|
|
|
|
if (dialog.run () == RESPONSE_CANCEL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-01 13:00:29 -04:00
|
|
|
framepos_t crossfade_len = spin_crossfade.get_value();
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pull_back_frames = spin_pullback.get_value();
|
2010-07-06 07:33:27 -04:00
|
|
|
|
|
|
|
crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
|
|
|
|
pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
|
|
|
|
|
|
|
|
/* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2014-12-14 08:13:38 -05:00
|
|
|
begin_reversible_command (_("close region gaps"));
|
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
int idx = 0;
|
|
|
|
boost::shared_ptr<Region> last_region;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
rs.sort_by_position_and_track();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
if (!pl->frozen()) {
|
|
|
|
/* we haven't seen this playlist before */
|
|
|
|
|
|
|
|
/* remember used playlists so we can thaw them later */
|
|
|
|
used_playlists.push_back(pl);
|
|
|
|
pl->freeze();
|
|
|
|
}
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t position = (*r)->region()->position();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
if (idx == 0 || position < last_region->position()){
|
|
|
|
last_region = (*r)->region();
|
|
|
|
idx++;
|
|
|
|
continue;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-05-30 09:54:44 -04:00
|
|
|
(*r)->region()->trim_front( (position - pull_back_frames));
|
|
|
|
last_region->trim_end( (position - pull_back_frames + crossfade_len));
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
last_region = (*r)->region();
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-07-06 07:33:27 -04:00
|
|
|
idx++;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-02-14 16:49:43 -05:00
|
|
|
while (used_playlists.size() > 0) {
|
|
|
|
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
|
|
|
|
(*i)->thaw();
|
|
|
|
used_playlists.pop_front();
|
|
|
|
}
|
2014-12-14 08:13:38 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::tab_to_transient (bool forward)
|
|
|
|
{
|
2008-02-02 12:22:04 -05:00
|
|
|
AnalysisFeatureList positions;
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if (!_session) {
|
2008-02-01 22:57:35 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t pos = _session->audible_frame ();
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
if (!selection->tracks.empty()) {
|
2008-02-01 22:57:35 -05:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
/* don't waste time searching for transients in duplicate playlists.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
|
|
|
|
|
|
|
|
for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
|
2008-02-02 12:22:04 -05:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
|
2008-02-02 12:22:04 -05:00
|
|
|
|
|
|
|
if (rtv) {
|
2010-04-21 16:42:22 -04:00
|
|
|
boost::shared_ptr<Track> tr = rtv->track();
|
|
|
|
if (tr) {
|
|
|
|
boost::shared_ptr<Playlist> pl = tr->playlist ();
|
2008-02-02 12:22:04 -05:00
|
|
|
if (pl) {
|
2010-09-17 14:20:37 -04:00
|
|
|
framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
if (result >= 0) {
|
|
|
|
positions.push_back (result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
if (rs.empty()) {
|
2008-02-02 12:22:04 -05:00
|
|
|
return;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
|
2008-02-02 12:22:04 -05:00
|
|
|
(*r)->region()->get_transients (positions);
|
|
|
|
}
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
|
2008-02-01 22:57:35 -05:00
|
|
|
|
|
|
|
if (forward) {
|
2008-02-02 12:22:04 -05:00
|
|
|
AnalysisFeatureList::iterator x;
|
2008-02-01 22:57:35 -05:00
|
|
|
|
|
|
|
for (x = positions.begin(); x != positions.end(); ++x) {
|
|
|
|
if ((*x) > pos) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x != positions.end ()) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (*x);
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2008-02-02 12:22:04 -05:00
|
|
|
AnalysisFeatureList::reverse_iterator x;
|
2008-02-01 22:57:35 -05:00
|
|
|
|
|
|
|
for (x = positions.rbegin(); x != positions.rend(); ++x) {
|
|
|
|
if ((*x) < pos) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x != positions.rend ()) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (*x);
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-07-06 07:33:27 -04:00
|
|
|
|
2008-02-19 17:10:27 -05:00
|
|
|
void
|
|
|
|
Editor::playhead_forward_to_grid ()
|
|
|
|
{
|
2013-04-04 00:32:52 -04:00
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
framepos_t pos = playhead_cursor->current_frame ();
|
2010-09-17 12:24:22 -04:00
|
|
|
if (pos < max_framepos - 1) {
|
2008-09-10 11:03:30 -04:00
|
|
|
pos += 2;
|
2014-11-16 01:05:21 -05:00
|
|
|
snap_to_internal (pos, RoundUpAlways, false);
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (pos);
|
2008-02-19 17:10:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::playhead_backward_to_grid ()
|
|
|
|
{
|
2013-04-04 00:32:52 -04:00
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
framepos_t pos = playhead_cursor->current_frame ();
|
2008-09-10 11:03:30 -04:00
|
|
|
if (pos > 2) {
|
|
|
|
pos -= 2;
|
2014-11-16 01:05:21 -05:00
|
|
|
snap_to_internal (pos, RoundDownAlways, false);
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->request_locate (pos);
|
2008-02-19 17:10:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
void
|
2010-05-10 20:09:41 -04:00
|
|
|
Editor::set_track_height (Height h)
|
2008-03-17 16:54:03 -04:00
|
|
|
{
|
|
|
|
TrackSelection& ts (selection->tracks);
|
|
|
|
|
|
|
|
for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
|
2011-02-16 12:59:28 -05:00
|
|
|
(*x)->set_height_enum (h);
|
2008-03-17 16:54:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_tracks_active ()
|
|
|
|
{
|
|
|
|
TrackSelection& ts (selection->tracks);
|
|
|
|
bool first = true;
|
|
|
|
bool target = false;
|
|
|
|
|
|
|
|
if (ts.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
|
2008-03-17 16:54:03 -04:00
|
|
|
|
|
|
|
if (rtv) {
|
|
|
|
if (first) {
|
|
|
|
target = !rtv->_route->active();
|
|
|
|
first = false;
|
|
|
|
}
|
2011-01-10 18:37:34 -05:00
|
|
|
rtv->_route->set_active (target, this);
|
2008-03-17 16:54:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::remove_tracks ()
|
|
|
|
{
|
|
|
|
TrackSelection& ts (selection->tracks);
|
|
|
|
|
|
|
|
if (ts.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<string> choices;
|
|
|
|
string prompt;
|
|
|
|
int ntracks = 0;
|
|
|
|
int nbusses = 0;
|
|
|
|
const char* trackstr;
|
|
|
|
const char* busstr;
|
|
|
|
vector<boost::shared_ptr<Route> > routes;
|
2010-11-25 15:37:39 -05:00
|
|
|
bool special_bus = false;
|
2008-03-17 16:54:03 -04:00
|
|
|
|
|
|
|
for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
|
2014-03-22 22:11:08 -04:00
|
|
|
if (!rtv) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (rtv->is_track()) {
|
|
|
|
ntracks++;
|
|
|
|
} else {
|
|
|
|
nbusses++;
|
2008-03-17 16:54:03 -04:00
|
|
|
}
|
|
|
|
routes.push_back (rtv->_route);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
|
|
|
|
special_bus = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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\
|
2010-06-16 12:59:20 -04:00
|
|
|
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));
|
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
msg.present ();
|
|
|
|
msg.run ();
|
|
|
|
return;
|
|
|
|
}
|
2011-01-19 13:35:11 -05:00
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
if (ntracks + nbusses == 0) {
|
2011-01-19 13:35:11 -05:00
|
|
|
return;
|
2008-03-17 16:54:03 -04:00
|
|
|
}
|
|
|
|
|
2014-07-09 14:13:31 -04:00
|
|
|
// XXX should be using gettext plural forms, maybe?
|
2008-03-17 16:54:03 -04:00
|
|
|
if (ntracks > 1) {
|
|
|
|
trackstr = _("tracks");
|
|
|
|
} else {
|
|
|
|
trackstr = _("track");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nbusses > 1) {
|
|
|
|
busstr = _("busses");
|
|
|
|
} else {
|
|
|
|
busstr = _("bus");
|
|
|
|
}
|
|
|
|
|
|
|
|
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"
|
2010-08-16 20:28:20 -04:00
|
|
|
"This action cannot be undone, and the session file will be overwritten!"),
|
2008-03-17 16:54:03 -04:00
|
|
|
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"
|
2010-08-16 20:28:20 -04:00
|
|
|
"This action cannot be undone, and the session file will be overwritten!"),
|
2008-03-17 16:54:03 -04:00
|
|
|
ntracks, trackstr);
|
|
|
|
}
|
|
|
|
} else if (nbusses) {
|
2010-08-16 20:28:20 -04:00
|
|
|
prompt = string_compose (_("Do you really want to remove %1 %2?\n\n"
|
2014-07-09 14:13:31 -04:00
|
|
|
"This action cannot be undone, and the session file will be overwritten"),
|
2008-03-17 16:54:03 -04:00
|
|
|
nbusses, busstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
choices.push_back (_("No, do nothing."));
|
|
|
|
if (ntracks + nbusses > 1) {
|
|
|
|
choices.push_back (_("Yes, remove them."));
|
|
|
|
} else {
|
|
|
|
choices.push_back (_("Yes, remove it."));
|
|
|
|
}
|
|
|
|
|
2009-12-22 20:26:33 -05:00
|
|
|
string title;
|
|
|
|
if (ntracks) {
|
|
|
|
title = string_compose (_("Remove %1"), trackstr);
|
|
|
|
} else {
|
|
|
|
title = string_compose (_("Remove %1"), busstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
Choice prompter (title, prompt, choices);
|
2008-03-17 16:54:03 -04:00
|
|
|
|
|
|
|
if (prompter.run () != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-28 15:36:13 -04:00
|
|
|
{
|
|
|
|
Session::StateProtector sp (_session);
|
2014-08-31 16:54:43 -04:00
|
|
|
DisplaySuspender ds;
|
2014-06-28 15:36:13 -04:00
|
|
|
for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
|
|
|
|
_session->remove_route (*x);
|
|
|
|
}
|
2008-03-17 16:54:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-11 10:06:50 -04:00
|
|
|
void
|
|
|
|
Editor::do_insert_time ()
|
|
|
|
{
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-08-11 19:40:51 -04:00
|
|
|
InsertTimeDialog d (*this);
|
2008-04-11 10:06:50 -04:00
|
|
|
int response = d.run ();
|
|
|
|
|
|
|
|
if (response != RESPONSE_OK) {
|
|
|
|
return;
|
|
|
|
}
|
2009-06-08 18:59:27 -04:00
|
|
|
|
2010-08-11 19:40:51 -04:00
|
|
|
if (d.distance() == 0) {
|
2008-04-11 10:06:50 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-08-11 19:40:51 -04:00
|
|
|
InsertTimeOption opt = d.intersected_region_action ();
|
2008-04-11 10:06:50 -04:00
|
|
|
|
2010-08-11 19:41:26 -04:00
|
|
|
insert_time (
|
|
|
|
get_preferred_edit_position(),
|
|
|
|
d.distance(),
|
|
|
|
opt,
|
2011-09-05 19:38:18 -04:00
|
|
|
d.all_playlists(),
|
2010-08-11 19:41:26 -04:00
|
|
|
d.move_glued(),
|
|
|
|
d.move_markers(),
|
|
|
|
d.move_glued_markers(),
|
|
|
|
d.move_locked_markers(),
|
|
|
|
d.move_tempos()
|
|
|
|
);
|
2008-04-11 10:06:50 -04:00
|
|
|
}
|
2008-09-10 11:03:30 -04:00
|
|
|
|
2008-04-11 10:06:50 -04:00
|
|
|
void
|
2011-09-05 19:38:18 -04:00
|
|
|
Editor::insert_time (
|
|
|
|
framepos_t pos, framecnt_t frames, InsertTimeOption opt,
|
|
|
|
bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
|
|
|
|
)
|
2008-04-11 10:06:50 -04:00
|
|
|
{
|
|
|
|
bool commit = false;
|
|
|
|
|
|
|
|
if (Config->get_edit_mode() == Lock) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("insert time"));
|
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
|
|
|
|
|
|
|
|
for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
|
2011-09-05 19:38:18 -04:00
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
/* regions */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
/* don't operate on any playlist more than once, which could
|
|
|
|
* happen if "all playlists" is enabled, but there is more
|
|
|
|
* than 1 track using playlists "from" a given track.
|
|
|
|
*/
|
|
|
|
|
|
|
|
set<boost::shared_ptr<Playlist> > pl;
|
|
|
|
|
2011-09-05 19:38:18 -04:00
|
|
|
if (all_playlists) {
|
|
|
|
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
|
|
|
|
if (rtav) {
|
2011-12-10 14:20:15 -05:00
|
|
|
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);
|
|
|
|
}
|
2011-09-05 19:38:18 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((*x)->playlist ()) {
|
2011-12-10 14:20:15 -05:00
|
|
|
pl.insert ((*x)->playlist ());
|
2011-09-05 19:38:18 -04:00
|
|
|
}
|
|
|
|
}
|
2011-12-10 14:20:15 -05:00
|
|
|
|
|
|
|
for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
|
2011-09-05 19:38:18 -04:00
|
|
|
|
|
|
|
(*i)->clear_changes ();
|
|
|
|
(*i)->clear_owned_changes ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
if (opt == SplitIntersected) {
|
2011-09-05 19:38:18 -04:00
|
|
|
(*i)->split (pos);
|
2008-12-12 09:43:24 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-09-05 19:38:18 -04:00
|
|
|
(*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-11-25 15:37:39 -05:00
|
|
|
vector<Command*> cmds;
|
2011-09-05 19:38:18 -04:00
|
|
|
(*i)->rdiff (cmds);
|
2010-08-25 21:44:11 -04:00
|
|
|
_session->add_commands (cmds);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-09-05 19:38:18 -04:00
|
|
|
_session->add_command (new StatefulDiffCommand (*i));
|
2008-12-12 09:43:24 -05:00
|
|
|
commit = true;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
/* automation */
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
|
2008-12-12 09:43:24 -05:00
|
|
|
if (rtav) {
|
|
|
|
rtav->route ()->shift (pos, frames);
|
|
|
|
commit = true;
|
2008-04-11 10:06:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-12 09:43:24 -05:00
|
|
|
/* markers */
|
2008-09-10 11:03:30 -04:00
|
|
|
if (markers_too) {
|
|
|
|
bool moved = false;
|
2009-12-17 13:24:23 -05:00
|
|
|
XMLNode& before (_session->locations()->get_state());
|
|
|
|
Locations::LocationList copy (_session->locations()->list());
|
2008-09-10 11:03:30 -04:00
|
|
|
|
|
|
|
for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
Locations::LocationList::const_iterator tmp;
|
|
|
|
|
2010-08-11 19:41:26 -04:00
|
|
|
bool const was_locked = (*i)->locked ();
|
|
|
|
if (locked_markers_too) {
|
|
|
|
(*i)->unlock ();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
|
|
|
|
|
|
|
|
if ((*i)->start() >= pos) {
|
|
|
|
(*i)->set_start ((*i)->start() + frames);
|
|
|
|
if (!(*i)->is_mark()) {
|
|
|
|
(*i)->set_end ((*i)->end() + frames);
|
|
|
|
}
|
|
|
|
moved = true;
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-08-11 19:41:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (was_locked) {
|
|
|
|
(*i)->lock ();
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (moved) {
|
2009-12-17 13:24:23 -05:00
|
|
|
XMLNode& after (_session->locations()->get_state());
|
|
|
|
_session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-08 19:24:14 -04:00
|
|
|
if (tempo_too) {
|
2009-12-17 13:24:23 -05:00
|
|
|
_session->tempo_map().insert_time (pos, frames);
|
2009-06-08 19:24:14 -04:00
|
|
|
}
|
|
|
|
|
2008-04-11 10:06:50 -04:00
|
|
|
if (commit) {
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
2008-09-10 11:03:30 -04:00
|
|
|
|
|
|
|
void
|
2015-01-11 12:46:36 -05:00
|
|
|
Editor::fit_selection ()
|
2008-09-10 11:03:30 -04:00
|
|
|
{
|
2011-03-01 21:46:19 -05:00
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
fit_tracks (selection->tracks);
|
|
|
|
} else {
|
|
|
|
TrackViewList tvl;
|
|
|
|
|
|
|
|
/* no selected tracks - use tracks with selected regions */
|
|
|
|
|
2011-03-01 21:59:44 -05:00
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
|
|
|
|
tvl.push_back (&(*r)->get_time_axis_view ());
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-03-01 21:59:44 -05:00
|
|
|
if (!tvl.empty()) {
|
|
|
|
fit_tracks (tvl);
|
|
|
|
}
|
|
|
|
} else if (internal_editing()) {
|
|
|
|
/* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
|
|
|
|
the entered track
|
|
|
|
*/
|
|
|
|
if (entered_track) {
|
|
|
|
tvl.push_back (entered_track);
|
|
|
|
fit_tracks (tvl);
|
|
|
|
}
|
2011-03-01 21:46:19 -05:00
|
|
|
}
|
|
|
|
}
|
2014-07-15 18:09:04 -04:00
|
|
|
|
2009-06-21 21:01:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-12-13 14:09:52 -05:00
|
|
|
Editor::fit_tracks (TrackViewList & tracks)
|
2009-06-21 21:01:43 -04:00
|
|
|
{
|
|
|
|
if (tracks.empty()) {
|
2008-09-10 11:03:30 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t child_heights = 0;
|
2011-02-06 21:11:31 -05:00
|
|
|
int visible_tracks = 0;
|
2008-09-10 11:03:30 -04:00
|
|
|
|
2009-06-21 21:01:43 -04:00
|
|
|
for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
|
2008-09-10 11:03:30 -04:00
|
|
|
|
|
|
|
if (!(*t)->marked_for_display()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-01-01 19:17:55 -05:00
|
|
|
child_heights += (*t)->effective_height() - (*t)->current_height();
|
2011-02-06 21:11:31 -05:00
|
|
|
++visible_tracks;
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
|
|
|
|
2014-06-09 09:08:51 -04:00
|
|
|
/* compute the per-track height from:
|
|
|
|
|
|
|
|
total canvas visible height -
|
|
|
|
height that will be taken by visible children of selected
|
|
|
|
tracks - height of the ruler/hscroll area
|
|
|
|
*/
|
2014-07-15 18:09:04 -04:00
|
|
|
uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
|
2008-09-10 11:03:30 -04:00
|
|
|
double first_y_pos = DBL_MAX;
|
|
|
|
|
2010-05-10 20:09:41 -04:00
|
|
|
if (h < TimeAxisView::preset_height (HeightSmall)) {
|
2009-06-21 21:01:43 -04:00
|
|
|
MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
|
2008-10-14 10:20:29 -04:00
|
|
|
/* too small to be displayed */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-06 21:11:59 -05:00
|
|
|
undo_visual_stack.push_back (current_visual_state (true));
|
|
|
|
no_save_visual = true;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2010-08-09 13:28:38 -04:00
|
|
|
/* build a list of all tracks, including children */
|
|
|
|
|
|
|
|
TrackViewList all;
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
all.push_back (*i);
|
|
|
|
TimeAxisView::Children c = (*i)->get_child_list ();
|
|
|
|
for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
|
|
|
|
all.push_back (j->get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 06:18:40 -04:00
|
|
|
bool prev_was_selected = false;
|
|
|
|
bool is_selected = tracks.contains (all.front());
|
|
|
|
bool next_is_selected;
|
2008-10-14 10:20:29 -04:00
|
|
|
|
2010-08-09 13:28:38 -04:00
|
|
|
for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
|
2008-10-14 10:20:29 -04:00
|
|
|
|
|
|
|
TrackViewList::iterator next;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-10-14 10:20:29 -04:00
|
|
|
next = t;
|
|
|
|
++next;
|
2014-07-11 06:18:40 -04:00
|
|
|
|
|
|
|
if (next != all.end()) {
|
|
|
|
next_is_selected = tracks.contains (*next);
|
|
|
|
} else {
|
|
|
|
next_is_selected = false;
|
|
|
|
}
|
|
|
|
|
2011-02-06 21:11:31 -05:00
|
|
|
if ((*t)->marked_for_display ()) {
|
2014-07-11 06:18:40 -04:00
|
|
|
if (is_selected) {
|
2011-02-06 21:11:31 -05:00
|
|
|
(*t)->set_height (h);
|
|
|
|
first_y_pos = std::min ((*t)->y_position (), first_y_pos);
|
2014-07-11 06:18:40 -04:00
|
|
|
} else {
|
|
|
|
if (prev_was_selected && next_is_selected) {
|
|
|
|
hide_track_in_display (*t);
|
|
|
|
}
|
2008-10-14 10:20:29 -04:00
|
|
|
}
|
|
|
|
}
|
2014-07-11 06:18:40 -04:00
|
|
|
|
|
|
|
prev_was_selected = is_selected;
|
|
|
|
is_selected = next_is_selected;
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
2008-10-14 10:20:29 -04:00
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
/*
|
|
|
|
set the controls_layout height now, because waiting for its size
|
|
|
|
request signal handler will cause the vertical adjustment setting to fail
|
|
|
|
*/
|
2008-10-14 10:20:29 -04:00
|
|
|
|
2013-04-04 00:32:52 -04:00
|
|
|
controls_layout.property_height () = _full_canvas_height;
|
2008-09-10 11:03:30 -04:00
|
|
|
vertical_adjustment.set_value (first_y_pos);
|
|
|
|
|
2012-03-06 21:11:59 -05:00
|
|
|
redo_visual_stack.push_back (current_visual_state (true));
|
2014-07-15 18:09:04 -04:00
|
|
|
|
|
|
|
visible_tracks_selector.set_text (_("Sel"));
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::save_visual_state (uint32_t n)
|
|
|
|
{
|
|
|
|
while (visual_states.size() <= n) {
|
|
|
|
visual_states.push_back (0);
|
|
|
|
}
|
|
|
|
|
2012-03-16 11:04:28 -04:00
|
|
|
if (visual_states[n] != 0) {
|
|
|
|
delete visual_states[n];
|
|
|
|
}
|
2008-09-10 11:03:30 -04:00
|
|
|
|
|
|
|
visual_states[n] = current_visual_state (true);
|
|
|
|
gdk_beep ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::goto_visual_state (uint32_t n)
|
|
|
|
{
|
|
|
|
if (visual_states.size() <= n) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (visual_states[n] == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
use_visual_state (*visual_states[n]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::start_visual_state_op (uint32_t n)
|
|
|
|
{
|
|
|
|
save_visual_state (n);
|
2012-03-16 11:04:28 -04:00
|
|
|
|
2008-09-10 11:03:30 -04:00
|
|
|
PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
|
|
|
|
char buf[32];
|
|
|
|
snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
|
|
|
|
pup->set_text (buf);
|
|
|
|
pup->touch();
|
2012-03-16 11:04:28 -04:00
|
|
|
}
|
2008-09-10 11:03:30 -04:00
|
|
|
|
2012-03-16 11:04:28 -04:00
|
|
|
void
|
|
|
|
Editor::cancel_visual_state_op (uint32_t n)
|
|
|
|
{
|
|
|
|
goto_visual_state (n);
|
2008-09-10 11:03:30 -04:00
|
|
|
}
|
2008-10-09 17:55:05 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
void
|
|
|
|
Editor::toggle_region_mute ()
|
|
|
|
{
|
|
|
|
if (_ignore_region_action) {
|
|
|
|
return;
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
RegionSelection rs = get_regions_from_selection_and_entered ();
|
|
|
|
|
|
|
|
if (rs.empty ()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rs.size() > 1) {
|
|
|
|
begin_reversible_command (_("mute regions"));
|
|
|
|
} else {
|
|
|
|
begin_reversible_command (_("mute region"));
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
(*i)->region()->playlist()->clear_changes ();
|
|
|
|
(*i)->region()->set_muted (!(*i)->region()->muted ());
|
2014-12-14 08:13:38 -05:00
|
|
|
_session->add_command (new StatefulDiffCommand ((*i)->region()));
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2011-05-15 22:17:58 -04:00
|
|
|
void
|
2011-05-16 16:16:57 -04:00
|
|
|
Editor::combine_regions ()
|
2011-05-15 22:17:58 -04:00
|
|
|
{
|
|
|
|
/* foreach track with selected regions, take all selected regions
|
|
|
|
and join them into a new region containing the subregions (as a
|
|
|
|
playlist)
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef set<RouteTimeAxisView*> RTVS;
|
|
|
|
RTVS tracks;
|
|
|
|
|
2011-05-16 16:16:57 -04:00
|
|
|
if (selection->regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-05-15 22:17:58 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
|
|
|
|
|
|
|
|
if (rtv) {
|
|
|
|
tracks.insert (rtv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-16 16:16:57 -04:00
|
|
|
begin_reversible_command (_("combine regions"));
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2011-05-24 20:40:32 -04:00
|
|
|
vector<RegionView*> new_selection;
|
2011-05-16 16:16:57 -04:00
|
|
|
|
2011-05-15 22:17:58 -04:00
|
|
|
for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
|
2011-05-24 20:40:32 -04:00
|
|
|
RegionView* rv;
|
|
|
|
|
|
|
|
if ((rv = (*i)->combine_regions ()) != 0) {
|
|
|
|
new_selection.push_back (rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
selection->clear_regions ();
|
|
|
|
for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
|
|
|
|
selection->add (*i);
|
2011-05-15 22:17:58 -04:00
|
|
|
}
|
2011-05-16 16:16:57 -04:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2011-05-15 22:17:58 -04:00
|
|
|
}
|
|
|
|
|
2011-05-22 12:11:00 -04:00
|
|
|
void
|
|
|
|
Editor::uncombine_regions ()
|
|
|
|
{
|
|
|
|
typedef set<RouteTimeAxisView*> RTVS;
|
|
|
|
RTVS tracks;
|
|
|
|
|
|
|
|
if (selection->regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
|
|
|
|
|
|
|
|
if (rtv) {
|
|
|
|
tracks.insert (rtv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("uncombine regions"));
|
|
|
|
|
|
|
|
for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
|
|
|
|
(*i)->uncombine_regions ();
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2012-11-12 21:19:04 -05:00
|
|
|
void
|
|
|
|
Editor::toggle_midi_input_active (bool flip_others)
|
|
|
|
{
|
2013-07-28 14:32:52 -04:00
|
|
|
bool onoff = false;
|
2012-11-12 21:19:04 -05:00
|
|
|
boost::shared_ptr<RouteList> rl (new RouteList);
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
|
|
|
|
|
|
|
|
if (!rtav) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
|
|
|
|
|
|
|
|
if (mt) {
|
|
|
|
rl->push_back (rtav->route());
|
|
|
|
onoff = !mt->input_active();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_session->set_exclusive_input_active (rl, onoff, flip_others);
|
|
|
|
}
|
2014-06-24 09:56:08 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::lock ()
|
|
|
|
{
|
2014-06-24 10:14:07 -04:00
|
|
|
if (!lock_dialog) {
|
2014-06-25 12:10:56 -04:00
|
|
|
lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
|
2014-06-24 11:26:21 -04:00
|
|
|
|
2014-06-25 15:27:37 -04:00
|
|
|
Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
|
2014-06-24 11:26:21 -04:00
|
|
|
lock_dialog->get_vbox()->pack_start (*padlock);
|
|
|
|
|
|
|
|
ArdourButton* b = manage (new ArdourButton);
|
|
|
|
b->set_name ("lock button");
|
2014-09-05 18:41:56 -04:00
|
|
|
b->set_text (_("Click to unlock"));
|
2014-06-24 11:26:21 -04:00
|
|
|
b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
|
2014-06-24 10:14:07 -04:00
|
|
|
lock_dialog->get_vbox()->pack_start (*b);
|
2014-06-24 11:26:21 -04:00
|
|
|
|
2014-06-24 10:14:07 -04:00
|
|
|
lock_dialog->get_vbox()->show_all ();
|
2014-06-24 11:26:21 -04:00
|
|
|
lock_dialog->set_size_request (200, 200);
|
2014-06-24 10:14:07 -04:00
|
|
|
}
|
|
|
|
|
2014-06-25 08:28:36 -04:00
|
|
|
#ifdef __APPLE__
|
|
|
|
/* The global menu bar continues to be accessible to applications
|
|
|
|
with modal dialogs, which means that we need to desensitize
|
|
|
|
all items in the menu bar. Since those items are really just
|
|
|
|
proxies for actions, that means disabling all actions.
|
|
|
|
*/
|
2014-06-24 09:56:08 -04:00
|
|
|
ActionManager::disable_all_actions ();
|
2014-06-25 08:28:36 -04:00
|
|
|
#endif
|
2014-06-24 10:14:07 -04:00
|
|
|
lock_dialog->present ();
|
2014-06-24 09:56:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::unlock ()
|
|
|
|
{
|
2014-06-24 10:14:07 -04:00
|
|
|
lock_dialog->hide ();
|
2014-06-25 08:28:36 -04:00
|
|
|
|
|
|
|
#ifdef __APPLE__
|
2014-06-24 09:56:08 -04:00
|
|
|
ActionManager::pop_action_state ();
|
2014-06-25 08:28:36 -04:00
|
|
|
#endif
|
|
|
|
|
2014-06-25 11:34:58 -04:00
|
|
|
if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
|
|
|
|
start_lock_event_timing ();
|
|
|
|
}
|
2014-06-24 09:56:08 -04:00
|
|
|
}
|
2014-07-08 00:53:06 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
|
|
|
|
{
|
|
|
|
Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
|
|
|
|
{
|
|
|
|
label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
|
|
|
|
Gtkmm2ext::UI::instance()->flush_pending ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::bring_all_sources_into_session ()
|
|
|
|
{
|
|
|
|
if (!_session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Gtk::Label msg;
|
|
|
|
ArdourDialog w (_("Moving embedded files into session folder"));
|
|
|
|
w.get_vbox()->pack_start (msg);
|
|
|
|
w.present ();
|
|
|
|
|
|
|
|
/* flush all pending GUI events because we're about to start copying
|
|
|
|
* files
|
|
|
|
*/
|
|
|
|
|
|
|
|
Gtkmm2ext::UI::instance()->flush_pending ();
|
|
|
|
|
|
|
|
cerr << " Do it\n";
|
|
|
|
|
|
|
|
_session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
|
|
|
|
}
|