2005-09-25 14:42:24 -04:00
|
|
|
/*
|
|
|
|
Copyright (C) 2000-2004 Paul Davis
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
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>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
#include <pbd/error.h>
|
|
|
|
#include <pbd/basename.h>
|
|
|
|
#include <pbd/pthread_utils.h>
|
2006-08-09 21:22:45 -04:00
|
|
|
#include <pbd/memento_command.h>
|
2008-01-10 16:20:59 -05:00
|
|
|
#include <pbd/whitespace.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>
|
2007-03-19 03:07:38 -04:00
|
|
|
#include <gtkmm2ext/window_title.h>
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
#include <ardour/audioengine.h>
|
|
|
|
#include <ardour/session.h>
|
|
|
|
#include <ardour/audioplaylist.h>
|
|
|
|
#include <ardour/audioregion.h>
|
2006-06-14 21:34:54 -04:00
|
|
|
#include <ardour/audio_diskstream.h>
|
2005-09-25 14:42:24 -04:00
|
|
|
#include <ardour/utils.h>
|
|
|
|
#include <ardour/location.h>
|
|
|
|
#include <ardour/named_selection.h>
|
|
|
|
#include <ardour/audio_track.h>
|
|
|
|
#include <ardour/audioplaylist.h>
|
|
|
|
#include <ardour/region_factory.h>
|
2007-01-09 18:24:54 -05:00
|
|
|
#include <ardour/playlist_factory.h>
|
2005-09-25 14:42:24 -04:00
|
|
|
#include <ardour/reverse.h>
|
2007-08-06 01:30:18 -04:00
|
|
|
#include <ardour/quantize.h>
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
#include "ardour_ui.h"
|
|
|
|
#include "editor.h"
|
|
|
|
#include "time_axis_view.h"
|
|
|
|
#include "audio_time_axis.h"
|
|
|
|
#include "automation_time_axis.h"
|
|
|
|
#include "streamview.h"
|
2006-08-01 13:19:38 -04:00
|
|
|
#include "audio_region_view.h"
|
2007-08-06 01:30:18 -04:00
|
|
|
#include "midi_region_view.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "rgb_macros.h"
|
|
|
|
#include "selection_templates.h"
|
|
|
|
#include "selection.h"
|
|
|
|
#include "editing.h"
|
|
|
|
#include "gtk-custom-hruler.h"
|
2006-04-06 12:51:27 -04:00
|
|
|
#include "gui_thread.h"
|
2008-01-18 22:49:52 -05:00
|
|
|
#include "keyboard.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 16:33:00 -04:00
|
|
|
using namespace sigc;
|
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;
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Editor operations
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::undo (uint32_t n)
|
|
|
|
{
|
|
|
|
if (session) {
|
|
|
|
session->undo (n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::redo (uint32_t n)
|
|
|
|
{
|
|
|
|
if (session) {
|
|
|
|
session->redo (n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split_region ()
|
|
|
|
{
|
2007-11-07 20:40:25 -05:00
|
|
|
split_region_at (get_preferred_edit_position());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::split_region_at (nframes_t where)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
split_regions_at (where, selection->regions);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::split_regions_at (nframes_t where, RegionSelection& regions)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
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 > > used_playlists;
|
|
|
|
|
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) {
|
|
|
|
switch (snap_type) {
|
|
|
|
case SnapToRegionStart:
|
|
|
|
case SnapToRegionSync:
|
|
|
|
case SnapToRegionEnd:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
snap_to (where);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
snap_to (where);
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
if (arv) {
|
2006-07-23 08:03:19 -04:00
|
|
|
_new_regionviews_show_envelope = arv->envelope_visible();
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (pl) {
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = pl->get_state();
|
2006-07-23 08:03:19 -04:00
|
|
|
pl->split_region ((*a)->region(), where);
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = pl->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
|
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
|
|
|
}
|
|
|
|
while (used_playlists.size() > 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
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();
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
_new_regionviews_show_envelope = false;
|
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
|
|
|
|
/** Remove `clicked_regionview' */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::remove_clicked_region ()
|
|
|
|
{
|
2006-08-16 16:36:14 -04:00
|
|
|
if (clicked_routeview == 0 || clicked_regionview == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
begin_reversible_command (_("remove region"));
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = playlist->get_state();
|
2006-08-29 17:21:48 -04:00
|
|
|
playlist->remove_region (clicked_regionview->region());
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = playlist->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
|
|
|
|
/** Remove the selected regions */
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2007-05-10 07:53:35 -04:00
|
|
|
Editor::remove_selected_regions ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2007-05-10 07:53:35 -04:00
|
|
|
if (selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/* XXX: should be called remove regions if we're removing more than one */
|
|
|
|
begin_reversible_command (_("remove region"));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-10-11 18:07:47 -04:00
|
|
|
|
2007-09-09 20:06:58 -04:00
|
|
|
while (!selection->regions.empty()) {
|
|
|
|
boost::shared_ptr<Region> region = selection->regions.front()->region ();
|
2007-05-10 07:53:35 -04:00
|
|
|
boost::shared_ptr<Playlist> playlist = region->playlist ();
|
2007-10-11 18:07:47 -04:00
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
XMLNode &before = playlist->get_state();
|
|
|
|
playlist->remove_region (region);
|
|
|
|
XMLNode &after = playlist->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-10-11 18:07:47 -04:00
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region>
|
2005-09-25 14:42:24 -04:00
|
|
|
Editor::select_region_for_operation (int dir, TimeAxisView **tv)
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
RegionView* rv;
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (selection->time.start () == selection->time.end_frame ()) {
|
|
|
|
|
|
|
|
/* no current selection-> is there a selected regionview? */
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (selection->regions.empty()) {
|
2006-08-29 17:21:48 -04:00
|
|
|
return region;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (!selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
rv = *(selection->regions.begin());
|
2005-09-25 14:42:24 -04:00
|
|
|
(*tv) = &rv->get_time_axis_view();
|
2006-08-29 17:21:48 -04:00
|
|
|
region = rv->region();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
} else if (!selection->tracks.empty()) {
|
|
|
|
|
|
|
|
(*tv) = selection->tracks.front();
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
RouteTimeAxisView* rtv;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> pl;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if ((pl = rtv->playlist()) == 0) {
|
2006-08-29 17:21:48 -04:00
|
|
|
return region;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
region = pl->top_region_at (start);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return region;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::extend_selection_to_end_of_region (bool next)
|
|
|
|
{
|
|
|
|
TimeAxisView *tv;
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (region && selection->time.start () == selection->time.end_frame ()) {
|
|
|
|
start = region->position();
|
|
|
|
} else {
|
|
|
|
start = selection->time.start ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to leave the selection with the same route if possible */
|
|
|
|
|
|
|
|
if ((tv = selection->time.track) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("extend selection"));
|
|
|
|
selection->set (tv, start, region->position() + region->length());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::extend_selection_to_start_of_region (bool previous)
|
|
|
|
{
|
|
|
|
TimeAxisView *tv;
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t end;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (region && selection->time.start () == selection->time.end_frame ()) {
|
|
|
|
end = region->position() + region->length();
|
|
|
|
} else {
|
|
|
|
end = selection->time.end_frame ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to leave the selection with the same route if possible */
|
|
|
|
|
|
|
|
if ((tv = selection->time.track) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("extend selection"));
|
|
|
|
selection->set (tv, region->position(), end);
|
|
|
|
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
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t distance;
|
|
|
|
nframes_t next_distance;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (!session) return;
|
|
|
|
|
2008-01-18 22:49:52 -05:00
|
|
|
if (!force_playhead && !selection->regions.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
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.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);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &before = r->playlist()->get_state();
|
|
|
|
r->set_position (r->position() + distance, this);
|
|
|
|
XMLNode &after = r->playlist()->get_state();
|
|
|
|
session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
2008-01-10 16:20:59 -05: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;
|
|
|
|
Location* loc = find_location_from_marker (selection->markers.front(), is_start);
|
|
|
|
|
|
|
|
if (loc) {
|
|
|
|
|
|
|
|
begin_reversible_command (_("nudge location forward"));
|
|
|
|
|
|
|
|
XMLNode& before (loc->get_state());
|
|
|
|
|
|
|
|
if (is_start) {
|
|
|
|
distance = get_nudge_distance (loc->start(), next_distance);
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
if (max_frames - distance > loc->start() + loc->length()) {
|
|
|
|
loc->set_start (loc->start() + distance);
|
|
|
|
} else {
|
|
|
|
loc->set_start (max_frames - loc->length());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
distance = get_nudge_distance (loc->end(), next_distance);
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
if (max_frames - distance > loc->end()) {
|
|
|
|
loc->set_end (loc->end() + distance);
|
|
|
|
} else {
|
|
|
|
loc->set_end (max_frames);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
XMLNode& after (loc->get_state());
|
|
|
|
session->add_command (new MementoCommand<Location>(*loc, &before, &after));
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
|
|
|
|
session->request_locate (playhead_cursor->current_frame + distance);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t distance;
|
|
|
|
nframes_t next_distance;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (!session) return;
|
|
|
|
|
2008-01-18 22:49:52 -05:00
|
|
|
if (!force_playhead && !selection->regions.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
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.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);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &before = r->playlist()->get_state();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
if (r->position() > distance) {
|
|
|
|
r->set_position (r->position() - distance, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-08-29 17:21:48 -04:00
|
|
|
r->set_position (0, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &after = r->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
|
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;
|
|
|
|
Location* loc = find_location_from_marker (selection->markers.front(), is_start);
|
|
|
|
|
|
|
|
if (loc) {
|
|
|
|
|
|
|
|
begin_reversible_command (_("nudge location forward"));
|
|
|
|
XMLNode& before (loc->get_state());
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
distance = get_nudge_distance (loc->end(), next_distance);
|
|
|
|
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (distance < loc->end() - loc->length()) {
|
|
|
|
loc->set_end (loc->end() - distance);
|
|
|
|
} else {
|
|
|
|
loc->set_end (loc->length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XMLNode& after (loc->get_state());
|
|
|
|
session->add_command (new MementoCommand<Location>(*loc, &before, &after));
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
|
|
|
|
distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
|
|
|
|
|
|
|
|
if (playhead_cursor->current_frame > distance) {
|
|
|
|
session->request_locate (playhead_cursor->current_frame - distance);
|
|
|
|
} else {
|
2006-03-11 11:01:06 -05:00
|
|
|
session->goto_start();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::nudge_forward_capture_offset ()
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t distance;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (!session) return;
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (!selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
begin_reversible_command (_("nudge forward"));
|
|
|
|
|
|
|
|
distance = session->worst_output_latency();
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.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
|
|
|
XMLNode &before = r->playlist()->get_state();
|
|
|
|
r->set_position (r->position() + distance, this);
|
|
|
|
XMLNode &after = r->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::nudge_backward_capture_offset ()
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t distance;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (!session) return;
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (!selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
begin_reversible_command (_("nudge forward"));
|
|
|
|
|
|
|
|
distance = session->worst_output_latency();
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.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
|
|
|
XMLNode &before = r->playlist()->get_state();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
if (r->position() > distance) {
|
|
|
|
r->set_position (r->position() - distance, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-08-29 17:21:48 -04:00
|
|
|
r->set_position (0, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &after = r->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DISPLAY MOTION */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::move_to_start ()
|
|
|
|
{
|
2006-03-11 11:01:06 -05:00
|
|
|
session->goto_start ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::move_to_end ()
|
|
|
|
{
|
|
|
|
|
|
|
|
session->request_locate (session->current_end_frame());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::build_region_boundary_cache ()
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_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 ();
|
|
|
|
|
|
|
|
if (session == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (snap_type) {
|
|
|
|
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);
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
case SnapToRegionSync:
|
2007-04-12 19:20:37 -04:00
|
|
|
interesting_points.push_back (SyncPoint);
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
case SnapToRegionBoundary:
|
2007-04-12 19:20:37 -04:00
|
|
|
interesting_points.push_back (Start);
|
|
|
|
interesting_points.push_back (End);
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
default:
|
2005-10-06 15:10:57 -04:00
|
|
|
fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
|
2005-09-25 14:42:24 -04:00
|
|
|
/*NOTREACHED*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeAxisView *ontrack = 0;
|
2007-04-12 19:20:37 -04:00
|
|
|
TrackViewList tlist;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
tlist = selection->tracks;
|
|
|
|
} else {
|
|
|
|
tlist = track_views;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
while (pos < session->current_end_frame() && !at_end) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
nframes_t rpos;
|
|
|
|
nframes_t lpos = max_frames;
|
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();
|
|
|
|
break;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
case SyncPoint:
|
|
|
|
rpos = r->adjust_to_sync (r->first_frame());
|
|
|
|
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;
|
|
|
|
}
|
2007-04-12 19:20:37 -04:00
|
|
|
|
|
|
|
float speed = 1.0f;
|
|
|
|
RouteTimeAxisView *rtav;
|
|
|
|
|
|
|
|
if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
|
|
|
|
if (rtav->get_diskstream() != 0) {
|
|
|
|
speed = rtav->get_diskstream()->speed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
vector<nframes_t>::iterator ri;
|
|
|
|
|
|
|
|
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>
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
TrackViewList::iterator i;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t closest = max_frames;
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> ret;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t rpos = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
float track_speed;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t track_frame;
|
2007-04-12 19:20:37 -04:00
|
|
|
RouteTimeAxisView *rtav;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
for (i = tracks.begin(); i != tracks.end(); ++i) {
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t distance;
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r;
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
track_speed = 1.0f;
|
2007-04-12 19:20:37 -04:00
|
|
|
if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
|
|
|
|
if (rtav->get_diskstream()!=0)
|
|
|
|
track_speed = rtav->get_diskstream()->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:
|
|
|
|
rpos = r->adjust_to_sync (r->first_frame());
|
|
|
|
break;
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2005-11-14 10:44:23 -05:00
|
|
|
// rpos is a "track frame", converting it to "session frame"
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
nframes64_t
|
|
|
|
Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackViewList& tracks)
|
|
|
|
{
|
|
|
|
nframes64_t distance = max_frames;
|
|
|
|
nframes64_t current_nearest = -1;
|
|
|
|
|
|
|
|
for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
|
|
|
|
nframes64_t contender;
|
|
|
|
nframes64_t d;
|
|
|
|
|
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return current_nearest;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_to_region_boundary (Cursor* cursor, int32_t dir)
|
|
|
|
{
|
|
|
|
nframes64_t pos = cursor->current_frame;
|
|
|
|
nframes64_t target;
|
|
|
|
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// so we don't find the current region again..
|
|
|
|
if (dir > 0 || pos > 0) {
|
|
|
|
pos += dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
|
|
|
|
target = find_next_region_boundary (pos, dir, selection->tracks);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
target = find_next_region_boundary (pos, dir, track_views);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (cursor == playhead_cursor) {
|
|
|
|
session->request_locate (target);
|
|
|
|
} else {
|
|
|
|
cursor->set_position (target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_to_next_region_boundary (Cursor* cursor)
|
|
|
|
{
|
|
|
|
cursor_to_region_boundary (cursor, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_to_previous_region_boundary (Cursor* cursor)
|
|
|
|
{
|
|
|
|
cursor_to_region_boundary (cursor, -1);
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
|
|
|
|
{
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> r;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t pos = cursor->current_frame;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeAxisView *ontrack = 0;
|
|
|
|
|
|
|
|
// so we don't find the current region again..
|
|
|
|
if (dir>0 || pos>0)
|
|
|
|
pos+=dir;
|
|
|
|
|
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
|
|
|
|
r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
|
|
|
|
|
2006-08-16 16:36:14 -04:00
|
|
|
} else if (clicked_axisview) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
TrackViewList t;
|
2006-08-16 16:36:14 -04:00
|
|
|
t.push_back (clicked_axisview);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
r = find_next_region (pos, point, dir, t, &ontrack);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
r = find_next_region (pos, point, dir, track_views, &ontrack);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (point){
|
|
|
|
case Start:
|
|
|
|
pos = r->first_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case End:
|
|
|
|
pos = r->last_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyncPoint:
|
|
|
|
pos = r->adjust_to_sync (r->first_frame());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
float speed = 1.0f;
|
2007-04-12 19:20:37 -04:00
|
|
|
RouteTimeAxisView *rtav;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
|
|
|
|
if (rtav->get_diskstream() != 0) {
|
|
|
|
speed = rtav->get_diskstream()->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);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (cursor == playhead_cursor) {
|
|
|
|
session->request_locate (pos);
|
|
|
|
} else {
|
|
|
|
cursor->set_position (pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
|
|
|
|
{
|
|
|
|
cursor_to_region_point (cursor, point, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
|
|
|
|
{
|
|
|
|
cursor_to_region_point (cursor, point, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_to_selection_start (Cursor *cursor)
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t pos = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
2006-07-23 08:03:19 -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) {
|
|
|
|
session->request_locate (pos);
|
|
|
|
} else {
|
|
|
|
cursor->set_position (pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_to_selection_end (Cursor *cursor)
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t pos = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
2006-07-23 08:03:19 -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) {
|
|
|
|
session->request_locate (pos);
|
|
|
|
} else {
|
|
|
|
cursor->set_position (pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::selected_marker_to_region_boundary (int32_t dir)
|
|
|
|
{
|
|
|
|
nframes64_t target;
|
|
|
|
Location* loc;
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->markers.empty()) {
|
|
|
|
nframes64_t mouse;
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!mouse_frame (mouse, ignored)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_location_mark (mouse);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nframes64_t pos = loc->start();
|
|
|
|
|
|
|
|
// so we don't find the current region again..
|
|
|
|
if (dir > 0 || pos > 0) {
|
|
|
|
pos += dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
|
|
|
|
target = find_next_region_boundary (pos, dir, selection->tracks);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
target = find_next_region_boundary (pos, dir, track_views);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
loc->move_to (target);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::selected_marker_to_next_region_boundary ()
|
|
|
|
{
|
|
|
|
selected_marker_to_region_boundary (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::selected_marker_to_previous_region_boundary ()
|
|
|
|
{
|
|
|
|
selected_marker_to_region_boundary (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
nframes_t pos;
|
|
|
|
Location* loc;
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!session || selection->markers.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeAxisView *ontrack = 0;
|
|
|
|
|
|
|
|
pos = loc->start();
|
|
|
|
|
|
|
|
// so we don't find the current region again..
|
|
|
|
if (dir>0 || pos>0)
|
|
|
|
pos+=dir;
|
|
|
|
|
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
|
|
|
|
r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
r = find_next_region (pos, point, dir, track_views, &ontrack);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (point){
|
|
|
|
case Start:
|
|
|
|
pos = r->first_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case End:
|
|
|
|
pos = r->last_frame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyncPoint:
|
|
|
|
pos = r->adjust_to_sync (r->first_frame());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
float speed = 1.0f;
|
|
|
|
AudioTimeAxisView *atav;
|
|
|
|
|
|
|
|
if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
|
|
|
|
if (atav->get_diskstream() != 0) {
|
|
|
|
speed = atav->get_diskstream()->speed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
nframes_t pos = 0;
|
|
|
|
Location* loc;
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!session || selection->markers.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
pos = selection->regions.start();
|
|
|
|
}
|
|
|
|
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
|
|
|
{
|
|
|
|
nframes_t pos = 0;
|
|
|
|
Location* loc;
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!session || selection->markers.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
pos = selection->regions.end_frame();
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
nframes_t pos = playhead_cursor->current_frame;
|
|
|
|
nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8);
|
|
|
|
|
|
|
|
if (forward) {
|
|
|
|
if (pos == max_frames) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos < max_frames - delta) {
|
|
|
|
pos += delta ;
|
|
|
|
} else {
|
|
|
|
pos = max_frames;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (pos == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos > delta) {
|
|
|
|
pos -= delta;
|
|
|
|
} else {
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
session->request_locate (pos);
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::playhead_backward ()
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t pos;
|
|
|
|
nframes_t cnt;
|
2005-09-25 14:42:24 -04:00
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix * session->frame_rate ());
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) prefix;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = playhead_cursor->current_frame;
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
if ((nframes_t) pos < cnt) {
|
2005-09-25 14:42:24 -04:00
|
|
|
pos = 0;
|
|
|
|
} else {
|
|
|
|
pos -= cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX this is completely insane. with the current buffering
|
|
|
|
design, we'll force a complete track buffer flush and
|
|
|
|
reload, just to move 1 sample !!!
|
|
|
|
*/
|
|
|
|
|
|
|
|
session->request_locate (pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::playhead_forward ()
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t pos;
|
|
|
|
nframes_t cnt;
|
2005-09-25 14:42:24 -04:00
|
|
|
bool was_floating;
|
|
|
|
float prefix;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix * session->frame_rate ());
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = playhead_cursor->current_frame;
|
|
|
|
|
|
|
|
/* XXX this is completely insane. with the current buffering
|
|
|
|
design, we'll force a complete track buffer flush and
|
|
|
|
reload, just to move 1 sample !!!
|
|
|
|
*/
|
|
|
|
|
|
|
|
session->request_locate (pos+cnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_align (bool playhead_to_edit)
|
|
|
|
{
|
2007-11-12 17:23:01 -05:00
|
|
|
if (!session) {
|
|
|
|
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
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
session->request_locate (selection->markers.front()->position(), session->transport_rolling());
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2007-11-12 17:23:01 -05:00
|
|
|
/* move selected markers to playhead */
|
|
|
|
|
|
|
|
for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
Location* loc = find_location_from_marker (*i, ignored);
|
|
|
|
|
|
|
|
if (loc->is_mark()) {
|
|
|
|
loc->set_start (playhead_cursor->current_frame);
|
|
|
|
} else {
|
|
|
|
loc->set (playhead_cursor->current_frame,
|
|
|
|
playhead_cursor->current_frame + loc->length());
|
|
|
|
}
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::edit_cursor_backward ()
|
|
|
|
{
|
2007-11-07 20:40:25 -05:00
|
|
|
nframes64_t pos;
|
|
|
|
nframes64_t cnt;
|
2005-09-25 14:42:24 -04:00
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix * session->frame_rate ());
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) prefix;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
if ((pos = get_preferred_edit_position()) < 0) {
|
|
|
|
return;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
if (pos < cnt) {
|
2005-09-25 14:42:24 -04:00
|
|
|
pos = 0;
|
|
|
|
} else {
|
|
|
|
pos -= cnt;
|
|
|
|
}
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
// EDIT CURSOR edit_cursor->set_position (pos);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::edit_cursor_forward ()
|
|
|
|
{
|
2007-11-24 20:05:48 -05:00
|
|
|
//nframes_t pos;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t cnt;
|
2005-09-25 14:42:24 -04:00
|
|
|
bool was_floating;
|
|
|
|
float prefix;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix * session->frame_rate ());
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
// pos = edit_cursor->current_frame;
|
|
|
|
// EDIT CURSOR edit_cursor->set_position (pos+cnt);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::goto_frame ()
|
|
|
|
{
|
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t frame;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (was_floating) {
|
2006-10-21 15:01:50 -04:00
|
|
|
frame = (nframes_t) floor (prefix * session->frame_rate());
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-10-21 15:01:50 -04:00
|
|
|
frame = (nframes_t) floor (prefix);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
session->request_locate (frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_backward (float pages)
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t frame;
|
|
|
|
nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
|
2005-09-25 14:42:24 -04:00
|
|
|
bool was_floating;
|
|
|
|
float prefix;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t cnt;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (pages * one_page);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix * session->frame_rate());
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix * one_page);
|
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)
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t frame;
|
|
|
|
nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
|
2005-09-25 14:42:24 -04:00
|
|
|
bool was_floating;
|
|
|
|
float prefix;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t cnt;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (pages * one_page);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix * session->frame_rate());
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-10-21 15:01:50 -04:00
|
|
|
cnt = (nframes_t) floor (prefix * one_page);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
if (max_frames - cnt < leftmost_frame) {
|
|
|
|
frame = max_frames - 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 ()
|
|
|
|
{
|
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
|
|
|
int cnt;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
cnt = (int) floor (prefix);
|
|
|
|
}
|
|
|
|
|
2006-04-09 22:14:05 -04:00
|
|
|
double vert_value = vertical_adjustment.get_value() + (cnt *
|
|
|
|
vertical_adjustment.get_page_size());
|
|
|
|
if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
|
|
|
|
vert_value = vertical_adjustment.get_upper() - canvas_height;
|
|
|
|
}
|
|
|
|
vertical_adjustment.set_value (vert_value);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_tracks_up ()
|
|
|
|
{
|
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
|
|
|
int cnt;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
cnt = (int) floor (prefix);
|
|
|
|
}
|
|
|
|
|
2005-12-12 15:54:55 -05:00
|
|
|
vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_tracks_down_line ()
|
|
|
|
{
|
2006-04-09 22:14:05 -04:00
|
|
|
|
2005-11-12 22:53:51 -05:00
|
|
|
Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
|
2006-04-09 22:14:05 -04:00
|
|
|
double vert_value = adj->get_value() + 20;
|
|
|
|
|
|
|
|
if (vert_value>adj->get_upper() - canvas_height) {
|
|
|
|
vert_value = adj->get_upper() - canvas_height;
|
|
|
|
}
|
|
|
|
adj->set_value (vert_value);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_tracks_up_line ()
|
|
|
|
{
|
2005-11-12 22:53:51 -05:00
|
|
|
Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
|
2006-04-09 22:14:05 -04:00
|
|
|
adj->set_value (adj->get_value() - 20);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ZOOM */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::temporal_zoom_step (bool coarser)
|
|
|
|
{
|
2006-04-06 12:51:27 -04:00
|
|
|
ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
double nfpu;
|
|
|
|
|
|
|
|
nfpu = frames_per_unit;
|
|
|
|
|
|
|
|
if (coarser) {
|
2006-09-18 23:29:16 -04:00
|
|
|
nfpu *= 1.61803399;
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-09-18 23:29:16 -04:00
|
|
|
nfpu = max(1.0,(nfpu/1.61803399));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
temporal_zoom (nfpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::temporal_zoom (gdouble fpu)
|
|
|
|
{
|
|
|
|
if (!session) return;
|
|
|
|
|
2007-11-07 20:40:25 -05:00
|
|
|
nframes64_t current_page = current_page_frames();
|
|
|
|
nframes64_t current_leftmost = leftmost_frame;
|
|
|
|
nframes64_t current_rightmost;
|
|
|
|
nframes64_t current_center;
|
2008-01-10 16:20:59 -05:00
|
|
|
nframes64_t new_page_size;
|
|
|
|
nframes64_t half_page_size;
|
2007-11-07 20:40:25 -05:00
|
|
|
nframes64_t leftmost_after_zoom = 0;
|
|
|
|
nframes64_t where;
|
|
|
|
bool in_track_canvas;
|
2005-09-25 14:42:24 -04:00
|
|
|
double nfpu;
|
2008-01-10 16:20:59 -05:00
|
|
|
double l;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-15 12:23:57 -05:00
|
|
|
/* XXX this limit is also in ::set_frames_per_unit() */
|
|
|
|
|
|
|
|
if (frames_per_unit <= 2.0 && fpu <= frames_per_unit) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
nfpu = fpu;
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
new_page_size = (nframes_t) floor (canvas_width * nfpu);
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
case ZoomFocusCenter:
|
|
|
|
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;
|
|
|
|
|
|
|
|
case ZoomFocusPlayhead:
|
2008-01-10 16:20:59 -05:00
|
|
|
/* try to keep the playhead in the same place */
|
|
|
|
|
|
|
|
where = playhead_cursor->current_frame;
|
|
|
|
|
|
|
|
l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
|
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;
|
2008-01-10 16:20:59 -05:00
|
|
|
} else if (l > max_frames) {
|
|
|
|
leftmost_after_zoom = max_frames - new_page_size;
|
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = (nframes64_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 */
|
|
|
|
where = playhead_cursor->current_frame;
|
|
|
|
|
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;
|
|
|
|
} else if (l > max_frames) {
|
2008-01-10 16:20:59 -05:00
|
|
|
leftmost_after_zoom = max_frames - new_page_size;
|
2007-11-07 20:40:25 -05:00
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = (nframes64_t) l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
} else if (l > max_frames) {
|
|
|
|
leftmost_after_zoom = max_frames - new_page_size;
|
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = (nframes64_t) l;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
|
|
|
|
|
|
|
|
reposition_and_zoom (leftmost_after_zoom, nfpu);
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::temporal_zoom_region ()
|
|
|
|
{
|
|
|
|
|
|
|
|
nframes64_t start = max_frames;
|
|
|
|
nframes64_t end = 0;
|
|
|
|
|
|
|
|
ensure_entered_region_selected (true);
|
|
|
|
|
|
|
|
if (selection->regions.empty()) {
|
|
|
|
info << _("cannot set loop: no region selected") << endmsg;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
if ((*i)->region()->position() < start) {
|
|
|
|
start = (*i)->region()->position();
|
|
|
|
}
|
|
|
|
if ((*i)->region()->last_frame() + 1 > end) {
|
|
|
|
end = (*i)->region()->last_frame() + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now comes an "interesting" hack ... 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 ();
|
|
|
|
gint pixwidth = gdk_screen_get_width (screen);
|
|
|
|
gint mmwidth = gdk_screen_get_width_mm (screen);
|
|
|
|
double pix_per_mm = (double) pixwidth/ (double) mmwidth;
|
|
|
|
double one_centimeter_in_pixels = pix_per_mm * 10.0;
|
|
|
|
nframes_t extra_samples = unit_to_frame (one_centimeter_in_pixels);
|
|
|
|
|
|
|
|
if (start > extra_samples) {
|
|
|
|
start -= extra_samples;
|
|
|
|
} else {
|
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max_frames - extra_samples > end) {
|
|
|
|
end += extra_samples;
|
|
|
|
} else {
|
|
|
|
end = max_frames;
|
|
|
|
}
|
|
|
|
|
|
|
|
temporal_zoom_by_frame (start, end, "zoom to region");
|
|
|
|
zoomed_to_region = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_zoom_region ()
|
|
|
|
{
|
|
|
|
if (zoomed_to_region) {
|
|
|
|
swap_visual_state ();
|
|
|
|
} else {
|
|
|
|
temporal_zoom_region ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::temporal_zoom_selection ()
|
|
|
|
{
|
|
|
|
if (!selection) return;
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
nframes_t end = selection->time[clicked_selection].end;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
temporal_zoom_by_frame (start, end, "zoom to selection");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::temporal_zoom_session ()
|
|
|
|
{
|
2006-04-06 12:51:27 -04:00
|
|
|
ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (session) {
|
2006-03-31 11:16:16 -05:00
|
|
|
temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (!session) return;
|
|
|
|
|
|
|
|
if ((start == 0 && end == 0) || end < start) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t range = end - start;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
double new_fpu = (double)range / (double)canvas_width;
|
|
|
|
// double p2 = 1.0;
|
|
|
|
|
|
|
|
// while (p2 < new_fpu) {
|
|
|
|
// p2 *= 2.0;
|
|
|
|
// }
|
|
|
|
// new_fpu = p2;
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
|
|
|
|
nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
|
|
|
|
nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (new_leftmost > middle) new_leftmost = 0;
|
|
|
|
|
|
|
|
// begin_reversible_command (op);
|
2005-09-25 17:19:23 -04:00
|
|
|
// session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
|
|
|
|
// session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
|
2005-09-25 14:42:24 -04:00
|
|
|
// commit_reversible_command ();
|
|
|
|
|
|
|
|
reposition_and_zoom (new_leftmost, new_fpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (!session) return;
|
|
|
|
|
2006-09-18 23:29:16 -04:00
|
|
|
double range_before = frame - leftmost_frame;
|
2005-09-25 14:42:24 -04:00
|
|
|
double new_fpu;
|
|
|
|
|
|
|
|
new_fpu = frames_per_unit;
|
|
|
|
|
|
|
|
if (coarser) {
|
2006-09-18 23:29:16 -04:00
|
|
|
new_fpu *= 1.61803399;
|
|
|
|
range_before *= 1.61803399;
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-09-18 23:29:16 -04:00
|
|
|
new_fpu = max(1.0,(new_fpu/1.61803399));
|
|
|
|
range_before /= 1.61803399;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (new_fpu == frames_per_unit) return;
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t new_leftmost = frame - (nframes_t)range_before;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (new_leftmost > frame) new_leftmost = 0;
|
|
|
|
|
|
|
|
// begin_reversible_command (_("zoom to frame"));
|
2005-09-25 17:19:23 -04:00
|
|
|
// session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
|
|
|
|
// session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
|
2005-09-25 14:42:24 -04:00
|
|
|
// commit_reversible_command ();
|
|
|
|
|
|
|
|
reposition_and_zoom (new_leftmost, new_fpu);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-08-16 16:36:14 -04:00
|
|
|
if (session == 0 || clicked_axisview == 0) {
|
2006-03-31 18:00:40 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
nframes_t end = selection->time[clicked_selection].end;
|
2006-03-31 18:00:40 -05:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
session->locations()->next_available_name(rangename,"selection");
|
|
|
|
Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
|
2006-03-31 18:00:40 -05:00
|
|
|
|
|
|
|
session->begin_reversible_command (_("add marker"));
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = session->locations()->get_state();
|
2006-03-31 18:00:40 -05:00
|
|
|
session->locations()->add (location, true);
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = session->locations()->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
|
2006-03-31 18:00:40 -05:00
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::add_location_mark (nframes64_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;
|
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
session->locations()->next_available_name(markername,"mark");
|
|
|
|
Location *location = new Location (where, where, markername, Location::IsMark);
|
2006-03-31 18:00:40 -05:00
|
|
|
session->begin_reversible_command (_("add marker"));
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = session->locations()->get_state();
|
2006-03-31 18:00:40 -05:00
|
|
|
session->locations()->add (location, true);
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = session->locations()->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
|
2006-03-31 18:00:40 -05:00
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::add_location_from_playhead_cursor ()
|
|
|
|
{
|
|
|
|
add_location_mark (session->audible_frame());
|
|
|
|
}
|
|
|
|
|
2006-03-31 18:00:40 -05:00
|
|
|
void
|
|
|
|
Editor::add_location_from_audio_region ()
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
if (selection->regions.empty()) {
|
2006-03-31 18:00:40 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
RegionView* rv = *(selection->regions.begin());
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region = rv->region();
|
2006-03-31 18:00:40 -05:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
|
2006-03-31 18:00:40 -05:00
|
|
|
session->begin_reversible_command (_("add marker"));
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = session->locations()->get_state();
|
2006-03-31 18:00:40 -05:00
|
|
|
session->locations()->add (location, true);
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = session->locations()->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
|
2006-03-31 18:00:40 -05:00
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::amplitude_zoom_step (bool in)
|
|
|
|
{
|
|
|
|
gdouble zoom = 1.0;
|
|
|
|
|
|
|
|
if (in) {
|
|
|
|
zoom *= 2.0;
|
|
|
|
} else {
|
|
|
|
if (zoom > 2.0) {
|
|
|
|
zoom /= 2.0;
|
|
|
|
} else {
|
|
|
|
zoom = 1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef FIX_FOR_CANVAS
|
|
|
|
/* XXX DO SOMETHING */
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* DELETION */
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::delete_sample_forward ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::delete_sample_backward ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::delete_screen ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SEARCH */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::search_backwards ()
|
|
|
|
{
|
|
|
|
/* what ? */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::search_forwards ()
|
|
|
|
{
|
|
|
|
/* what ? */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MARKS */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::jump_forward_to_mark ()
|
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
|
|
|
|
|
|
|
|
if (location) {
|
|
|
|
session->request_locate (location->start(), session->transport_rolling());
|
|
|
|
} else {
|
|
|
|
session->request_locate (session->current_end_frame());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::jump_backward_to_mark ()
|
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
|
|
|
|
|
|
|
|
if (location) {
|
|
|
|
session->request_locate (location->start(), session->transport_rolling());
|
|
|
|
} else {
|
2006-03-11 11:01:06 -05:00
|
|
|
session->goto_start ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_mark ()
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t pos;
|
2005-09-25 14:42:24 -04:00
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
2007-01-09 18:24:54 -05:00
|
|
|
string markername;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
pos = session->audible_frame ();
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
2006-10-21 15:01:50 -04:00
|
|
|
pos = (nframes_t) floor (prefix * session->frame_rate ());
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-10-21 15:01:50 -04:00
|
|
|
pos = (nframes_t) floor (prefix);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
session->locations()->next_available_name(markername,"mark");
|
|
|
|
session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_markers ()
|
|
|
|
{
|
|
|
|
if (session) {
|
|
|
|
session->begin_reversible_command (_("clear markers"));
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = session->locations()->get_state();
|
2005-09-25 14:42:24 -04:00
|
|
|
session->locations()->clear_markers ();
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = session->locations()->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_ranges ()
|
|
|
|
{
|
|
|
|
if (session) {
|
|
|
|
session->begin_reversible_command (_("clear ranges"));
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = session->locations()->get_state();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
Location * looploc = session->locations()->auto_loop_location();
|
|
|
|
Location * punchloc = session->locations()->auto_punch_location();
|
|
|
|
|
|
|
|
session->locations()->clear_ranges ();
|
|
|
|
// re-add these
|
|
|
|
if (looploc) session->locations()->add (looploc);
|
|
|
|
if (punchloc) session->locations()->add (punchloc);
|
|
|
|
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = session->locations()->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_locations ()
|
|
|
|
{
|
|
|
|
session->begin_reversible_command (_("clear locations"));
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = session->locations()->get_state();
|
2005-09-25 14:42:24 -04:00
|
|
|
session->locations()->clear ();
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = session->locations()->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
session->commit_reversible_command ();
|
|
|
|
session->locations()->clear ();
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
if (l->is_hidden() && l->is_range_marker()) {
|
|
|
|
l->set_hidden(false, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* INSERT/REPLACE */
|
|
|
|
|
|
|
|
void
|
2006-08-29 17:21:48 -04:00
|
|
|
Editor::insert_region_list_drag (boost::shared_ptr<Region> region, int x, int y)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
double wx, wy;
|
|
|
|
double cx, cy;
|
|
|
|
TimeAxisView *tv;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t where;
|
2007-04-12 19:20:37 -04:00
|
|
|
RouteTimeAxisView *rtv = 0;
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-11-12 17:07:07 -05:00
|
|
|
track_canvas.window_to_world (x, y, wx, wy);
|
2006-01-02 15:27:51 -05:00
|
|
|
wx += horizontal_adjustment.get_value();
|
|
|
|
wy += vertical_adjustment.get_value();
|
2005-11-12 22:53:51 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
GdkEvent event;
|
|
|
|
event.type = GDK_BUTTON_RELEASE;
|
|
|
|
event.button.x = wx;
|
|
|
|
event.button.y = wy;
|
|
|
|
|
|
|
|
where = event_frame (&event, &cx, &cy);
|
|
|
|
|
|
|
|
if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
|
|
|
|
/* clearly outside canvas area */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tv = trackview_by_y_position (cy)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if ((playlist = rtv->playlist()) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
snap_to (where);
|
|
|
|
|
|
|
|
begin_reversible_command (_("insert dragged region"));
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = playlist->get_state();
|
2006-08-29 17:21:48 -04:00
|
|
|
playlist->add_region (RegionFactory::create (region), where, 1.0);
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::insert_region_list_selection (float times)
|
|
|
|
{
|
2006-07-23 08:03:19 -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()) {
|
|
|
|
if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (entered_track != 0) {
|
|
|
|
if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((playlist = tv->playlist()) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-11-12 22:53:51 -05:00
|
|
|
Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-11-24 09:59:36 -05:00
|
|
|
if (selected->count_selected_rows() != 1) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
/* only one row selected, so rows.begin() is it */
|
|
|
|
|
|
|
|
TreeIter iter;
|
|
|
|
|
|
|
|
if ((iter = region_list_model->get_iter (*rows.begin()))) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
|
|
|
|
|
|
|
|
begin_reversible_command (_("insert region"));
|
|
|
|
XMLNode &before = playlist->get_state();
|
2007-11-07 20:40:25 -05:00
|
|
|
playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
|
2006-10-21 15:01:50 -04:00
|
|
|
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
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)
|
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Config->get_slave_source()) {
|
|
|
|
case None:
|
|
|
|
case JACK:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* transport controlled by the master */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->is_auditioning()) {
|
|
|
|
session->cancel_audition ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->request_transport_speed (fwd ? 1.0f : -1.0f);
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::toggle_playback (bool with_abort)
|
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
switch (Config->get_slave_source()) {
|
|
|
|
case None:
|
|
|
|
case JACK:
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* transport controlled by the master */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->is_auditioning()) {
|
|
|
|
session->cancel_audition ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->transport_rolling()) {
|
|
|
|
session->request_stop (with_abort);
|
2006-11-19 11:45:16 -05:00
|
|
|
if (session->get_play_loop()) {
|
2006-10-21 15:01:50 -04:00
|
|
|
session->request_play_loop (false);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
session->request_transport_speed (1.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::play_from_start ()
|
|
|
|
{
|
2006-03-11 11:01:06 -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
|
|
|
{
|
2007-11-07 20:40:25 -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
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
nframes64_t start_frame;
|
|
|
|
nframes64_t return_frame;
|
|
|
|
|
|
|
|
/* don't reset the return frame if its already set */
|
|
|
|
|
|
|
|
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
|
|
|
start_frame = get_preferred_edit_position (true);
|
|
|
|
|
|
|
|
if (start_frame >= 0) {
|
|
|
|
session->request_roll_at_and_return (start_frame, return_frame);
|
|
|
|
}
|
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
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
session->request_play_range (true);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::loop_selected_region ()
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
RegionView *rv = *(selection->regions.begin());
|
2005-09-25 14:42:24 -04:00
|
|
|
Location* tll;
|
|
|
|
|
|
|
|
if ((tll = transport_loop_location()) != 0) {
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
tll->set (rv->region()->position(), rv->region()->last_frame());
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
// enable looping, reposition and start rolling
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
session->request_play_loop (true);
|
2005-09-25 14:42:24 -04:00
|
|
|
session->request_locate (tll->start(), false);
|
|
|
|
session->request_transport_speed (1.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::play_location (Location& location)
|
|
|
|
{
|
|
|
|
if (location.start() <= location.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->request_bounded_roll (location.start(), location.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2006-10-21 15:01:50 -04:00
|
|
|
session->request_play_loop (true);
|
2005-09-25 14:42:24 -04:00
|
|
|
session->request_locate (tll->start(), true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::raise_region ()
|
|
|
|
{
|
|
|
|
selection->foreach_region (&Region::raise);
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::raise_region_to_top ()
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
selection->foreach_region (&Region::raise_to_top);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::lower_region ()
|
|
|
|
{
|
|
|
|
selection->foreach_region (&Region::lower);
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::lower_region_to_bottom ()
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
selection->foreach_region (&Region::lower_to_bottom);
|
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
|
|
|
|
Editor::edit_region ()
|
|
|
|
{
|
2007-05-10 07:53:35 -04:00
|
|
|
selection->foreach_regionview (&RegionView::show_region_editor);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::rename_region()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
if (selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
WindowTitle title (Glib::get_application_name());
|
2007-03-19 03:07:38 -04:00
|
|
|
title += _("Rename Region");
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
ArdourDialog d (*this, title.get_string(), true, false);
|
|
|
|
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::OK, Gtk::RESPONSE_OK);
|
|
|
|
d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
d.set_size_request (300, -1);
|
|
|
|
d.set_position (Gtk::WIN_POS_MOUSE);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
entry.set_text (selection->regions.front()->region()->name());
|
|
|
|
entry.select_region (0, -1);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
entry.signal_activate().connect (bind (mem_fun (d, &Dialog::response), RESPONSE_OK));
|
|
|
|
|
|
|
|
d.show_all ();
|
|
|
|
|
|
|
|
entry.grab_focus();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
int 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
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (ret == RESPONSE_OK) {
|
|
|
|
std::string str = entry.get_text();
|
|
|
|
strip_whitespace_edges (str);
|
|
|
|
if (!str.empty()) {
|
|
|
|
selection->regions.front()->region()->set_name (str);
|
|
|
|
redisplay_regions ();
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
if (session->is_auditioning()) {
|
|
|
|
session->cancel_audition ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
session->request_bounded_roll (region->position(), region->position() + region->length());
|
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
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
nframes64_t start, end;
|
|
|
|
|
|
|
|
if (get_edit_op_range (start, end)) {
|
|
|
|
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
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
nframes64_t start = max_frames;
|
|
|
|
nframes64_t end = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
ExclusiveRegionSelection esr (*this, entered_regionview);
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (selection->regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
if ((*i)->region()->position() < start) {
|
|
|
|
start = (*i)->region()->position();
|
|
|
|
}
|
|
|
|
if ((*i)->region()->last_frame() + 1 > end) {
|
|
|
|
end = (*i)->region()->last_frame() + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
session->request_stop ();
|
2008-01-10 16:20:59 -05:00
|
|
|
session->request_bounded_roll (start, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
|
|
|
|
{
|
|
|
|
session->audition_region (region);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::build_interthread_progress_window ()
|
|
|
|
{
|
|
|
|
interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-10-09 01:03:29 -04:00
|
|
|
interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-11-27 16:17:41 -05:00
|
|
|
interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
|
|
|
|
interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
|
|
|
|
|
|
|
|
// GTK2FIX: this button needs a modifiable label
|
|
|
|
|
|
|
|
Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
|
|
|
|
b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
interthread_cancel_button.add (interthread_cancel_label);
|
|
|
|
|
|
|
|
interthread_progress_window->set_default_size (200, 100);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::interthread_cancel_clicked ()
|
|
|
|
{
|
|
|
|
if (current_interthread_info) {
|
|
|
|
current_interthread_info->cancel = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
nframes_t end = selection->time[clicked_selection].end;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t selection_cnt = end - start + 1;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<AudioRegion> current;
|
|
|
|
boost::shared_ptr<Region> current_r;
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> pl;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t internal_start;
|
2005-09-25 14:42:24 -04:00
|
|
|
string new_name;
|
|
|
|
|
|
|
|
if ((pl = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((current_r = pl->top_region_at (start)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
|
2006-08-01 13:19:38 -04:00
|
|
|
assert(current); // FIXME
|
|
|
|
if (current != 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
internal_start = start - current->position();
|
|
|
|
session->region_name (new_name, current->name(), true);
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-08-29 17:21:48 -04:00
|
|
|
Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (selection->time.empty() || selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
nframes_t end = selection->time[clicked_selection].end;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
sort_track_selection ();
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<AudioRegion> current;
|
|
|
|
boost::shared_ptr<Region> current_r;
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t internal_start;
|
2005-09-25 14:42:24 -04:00
|
|
|
string new_name;
|
|
|
|
|
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((current_r = playlist->top_region_at(start)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal_start = start - current->position();
|
|
|
|
session->region_name (new_name, current->name(), true);
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split_multichannel_region ()
|
|
|
|
{
|
2007-01-28 12:44:13 -05:00
|
|
|
if (selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
vector<boost::shared_ptr<AudioRegion> > v;
|
|
|
|
|
|
|
|
for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
|
|
|
|
|
|
|
|
if (!arv || arv->audio_region()->n_channels() < 2) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
(arv)->audio_region()->separate_by_channel (*session, v);
|
|
|
|
}
|
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)) {
|
|
|
|
case OverlapNone:
|
|
|
|
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
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::separate_regions_between (const TimeSelection& ts)
|
|
|
|
{
|
|
|
|
bool in_command = false;
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2008-01-10 16:20:59 -05:00
|
|
|
RegionSelection new_selection;
|
2008-01-10 17:22:29 -05:00
|
|
|
TrackSelection tmptracks;
|
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
/* use tracks with selected regions */
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
TimeAxisView* tv = &(*i)->get_time_axis_view();
|
|
|
|
|
|
|
|
if (find (tmptracks.begin(), tmptracks.end(), tv) == tmptracks.end()) {
|
|
|
|
tmptracks.push_back (tv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmptracks.empty()) {
|
|
|
|
/* no regions selected: use all tracks */
|
|
|
|
tmptracks = track_views;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
tmptracks = selection->tracks;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sort_track_selection (&tmptracks);
|
|
|
|
|
2008-01-12 18:45:50 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
RouteTimeAxisView* rtv;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2007-04-12 19:20:37 -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
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
if (rtv->track()->diskstream()->destructive()) {
|
|
|
|
continue;
|
|
|
|
}
|
2007-04-12 19:20:37 -04:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
if ((playlist = rtv->playlist()) != 0) {
|
|
|
|
|
|
|
|
XMLNode *before;
|
|
|
|
bool got_some;
|
|
|
|
|
|
|
|
before = &(playlist->get_state());
|
|
|
|
got_some = false;
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* XXX need to consider musical time selections here at some point */
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
double speed = rtv->get_diskstream()->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) {
|
|
|
|
|
|
|
|
sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
|
|
|
|
latest_regionviews.clear ();
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
c.disconnect ();
|
|
|
|
|
|
|
|
if (!latest_regionviews.empty()) {
|
|
|
|
|
|
|
|
got_some = true;
|
|
|
|
|
|
|
|
rtv->view()->foreach_regionview (bind (sigc::ptr_fun (add_if_covered), &(*t), &new_selection));
|
|
|
|
|
|
|
|
if (!in_command) {
|
|
|
|
begin_reversible_command (_("separate"));
|
|
|
|
in_command = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
|
|
|
|
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (!got_some) {
|
|
|
|
delete before;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (in_command) {
|
|
|
|
selection->set (new_selection);
|
|
|
|
set_mouse_mode (MouseObject);
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
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-01-10 16:20:59 -05:00
|
|
|
if (mouse_mode == MouseRange && !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 {
|
|
|
|
|
|
|
|
nframes64_t start;
|
|
|
|
nframes64_t end;
|
2007-04-12 19:20:37 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (get_edit_op_range (start, end)) {
|
|
|
|
|
|
|
|
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
|
|
|
/* force track selection */
|
2006-03-31 19:21:25 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
ensure_entered_region_selected ();
|
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-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
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::crop_region_to_selection ()
|
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
ensure_entered_region_selected (true);
|
2008-01-07 16:12:29 -05:00
|
|
|
|
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
|
|
|
|
|
|
|
nframes64_t start;
|
|
|
|
nframes64_t end;
|
|
|
|
|
|
|
|
if (get_edit_op_range (start, end)) {
|
|
|
|
crop_region_to (start, end);
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
|
|
|
Editor::crop_region_to (nframes_t start, nframes_t end)
|
|
|
|
{
|
2007-01-09 18:24:54 -05:00
|
|
|
vector<boost::shared_ptr<Playlist> > playlists;
|
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2007-11-12 17:23:01 -05:00
|
|
|
TrackSelection* ts;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
sort_track_selection ();
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
2007-04-12 19:20:37 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
RouteTimeAxisView* rtv;
|
|
|
|
|
|
|
|
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
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if (t != 0 && ! t->diskstream()->destructive()) {
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
nframes_t the_start;
|
|
|
|
nframes_t the_end;
|
2007-04-12 19:20:37 -04:00
|
|
|
nframes_t cnt;
|
|
|
|
|
|
|
|
begin_reversible_command (_("trim to selection"));
|
|
|
|
|
|
|
|
for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
|
|
|
|
|
|
|
boost::shared_ptr<Region> region;
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
the_start = start;
|
|
|
|
|
|
|
|
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
|
|
|
}
|
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
|
|
|
|
*/
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
the_start = max (the_start, region->position());
|
|
|
|
if (max_frames - the_start < region->length()) {
|
|
|
|
the_end = the_start + region->length() - 1;
|
2007-04-12 19:20:37 -04:00
|
|
|
} else {
|
2007-11-12 17:23:01 -05:00
|
|
|
the_end = max_frames;
|
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;
|
2007-04-12 19:20:37 -04:00
|
|
|
|
|
|
|
XMLNode &before = (*i)->get_state();
|
2007-11-12 17:23:01 -05:00
|
|
|
region->trim_to (the_start, cnt, this);
|
2007-04-12 19:20:37 -04:00
|
|
|
XMLNode &after = (*i)->get_state();
|
|
|
|
session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-04-12 19:20:37 -04:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_fill_track ()
|
|
|
|
{
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t end;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (!session || selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
end = session->current_end_frame ();
|
|
|
|
|
|
|
|
begin_reversible_command (_("region fill"));
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region ((*i)->region());
|
2006-07-23 08:03:19 -04:00
|
|
|
|
|
|
|
// FIXME
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
|
2006-08-14 04:44:14 -04:00
|
|
|
assert(ar);
|
2005-09-25 14:42:24 -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;
|
|
|
|
}
|
|
|
|
|
2006-08-14 04:44:14 -04:00
|
|
|
XMLNode &before = pl->get_state();
|
2006-08-29 17:21:48 -04:00
|
|
|
pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_fill_selection ()
|
|
|
|
{
|
2006-08-16 16:36:14 -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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-12 22:53:51 -05:00
|
|
|
Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
|
2005-11-12 17:07:07 -05:00
|
|
|
|
2005-11-24 09:59:36 -05:00
|
|
|
if (selected->count_selected_rows() != 1) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-11-12 17:07:07 -05:00
|
|
|
TreeModel::iterator i = region_list_display.get_selection()->get_selected();
|
2006-08-29 17:21:48 -04:00
|
|
|
boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
nframes_t end = selection->time[clicked_selection].end;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t selection_length = end - start;
|
2005-09-25 14:42:24 -04:00
|
|
|
float times = (float)selection_length / region->length();
|
|
|
|
|
|
|
|
begin_reversible_command (_("fill selection"));
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
|
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = playlist->get_state();
|
2006-08-29 17:21:48 -04:00
|
|
|
playlist->add_region (RegionFactory::create (region), start, times);
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
2006-01-23 15:39:58 -05:00
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::set_region_sync_from_edit_point ()
|
2006-01-23 15:39:58 -05:00
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
nframes64_t where = get_preferred_edit_position ();
|
|
|
|
ensure_entered_region_selected (true);
|
|
|
|
set_sync_point (where, selection->regions);
|
2006-01-23 15:39:58 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::set_sync_point (nframes64_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) {
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
XMLNode &before = region->playlist()->get_state();
|
|
|
|
region->set_sync_position (get_preferred_edit_position());
|
|
|
|
XMLNode &after = region->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
|
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 ()
|
|
|
|
{
|
2007-05-10 07:53:35 -04:00
|
|
|
begin_reversible_command (_("remove sync"));
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
boost::shared_ptr<Region> r = (*i)->region();
|
|
|
|
XMLNode &before = r->playlist()->get_state();
|
|
|
|
r->clear_sync_position ();
|
|
|
|
XMLNode &after = r->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-05-10 07:53:35 -04:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::naturalize ()
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
if (selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
begin_reversible_command (_("naturalize"));
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &before = (*i)->region()->get_state();
|
|
|
|
(*i)->region()->move_to_natural_position (this);
|
|
|
|
XMLNode &after = (*i)->region()->get_state();
|
|
|
|
session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::align (RegionPoint what)
|
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
ensure_entered_region_selected ();
|
2008-01-07 16:12:29 -05:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
nframes64_t where = get_preferred_edit_position();
|
|
|
|
|
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
align_selection (what, where, selection->regions);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
RegionSelection rs;
|
|
|
|
rs = get_regions_at (where, selection->tracks);
|
|
|
|
align_selection (what, where, rs);
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::align_relative (RegionPoint what)
|
|
|
|
{
|
2007-11-12 17:23:01 -05:00
|
|
|
nframes64_t where = get_preferred_edit_position();
|
|
|
|
|
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
align_selection_relative (what, where, selection->regions);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
RegionSelection rs;
|
|
|
|
rs = get_regions_at (where, selection->tracks);
|
|
|
|
align_selection_relative (what, where, rs);
|
|
|
|
}
|
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
|
2007-11-12 17:23:01 -05:00
|
|
|
Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2007-11-12 17:23:01 -05:00
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t distance;
|
|
|
|
nframes_t pos = 0;
|
2005-09-25 14:42:24 -04:00
|
|
|
int dir;
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
list<RegionView*> sorted;
|
2007-11-12 17:23:01 -05:00
|
|
|
rs.by_position (sorted);
|
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();
|
|
|
|
dir = 1;
|
|
|
|
} else {
|
|
|
|
distance = r->position() - position;
|
|
|
|
dir = -1;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
2008-01-10 17:22:29 -05: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;
|
|
|
|
dir = 1;
|
|
|
|
} 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();
|
|
|
|
dir = 1;
|
|
|
|
} else {
|
|
|
|
distance = r->position() - pos;
|
|
|
|
dir = -1;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
XMLNode &before = r->playlist()->get_state();
|
|
|
|
r->set_position (pos, this);
|
|
|
|
XMLNode &after = r->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
|
|
|
|
|
|
|
|
/* move rest by the same amount */
|
|
|
|
|
|
|
|
RegionSelection::const_iterator i = rs.begin();
|
|
|
|
++i;
|
|
|
|
|
|
|
|
for (; i != rs.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
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &before = region->playlist()->get_state();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (dir > 0) {
|
2006-08-29 17:21:48 -04:00
|
|
|
region->set_position (region->position() + distance, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2006-08-29 17:21:48 -04:00
|
|
|
region->set_position (region->position() - distance, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &after = region->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-11-12 17:23:01 -05:00
|
|
|
Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2007-11-12 17:23:01 -05:00
|
|
|
if (rs.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("align selection"));
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
|
2006-07-23 08:03:19 -04:00
|
|
|
align_region_internal ((*i)->region(), point, position);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_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
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &before = region->playlist()->get_state();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
switch (point) {
|
|
|
|
case SyncPoint:
|
2006-08-29 17:21:48 -04:00
|
|
|
region->set_position (region->adjust_to_sync (position), this);
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case End:
|
2006-08-29 17:21:48 -04:00
|
|
|
if (position > region->length()) {
|
|
|
|
region->set_position (position - region->length(), this);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Start:
|
2006-08-29 17:21:48 -04:00
|
|
|
region->set_position (position, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &after = region->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2007-11-12 17:23:01 -05:00
|
|
|
Location* loc = session->locations()->auto_loop_location();
|
|
|
|
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 ()
|
|
|
|
{
|
|
|
|
Location* loc = session->locations()->auto_punch_location();
|
|
|
|
if (!loc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
trim_region_to_location (*loc, _("trim to punch"));
|
|
|
|
}
|
|
|
|
void
|
|
|
|
Editor::trim_region_to_location (const Location& loc, const char* str)
|
|
|
|
{
|
2008-01-10 17:22:29 -05:00
|
|
|
ExclusiveRegionSelection ers (*this, entered_regionview);
|
2008-01-07 16:12:29 -05:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
RegionSelection& rs (get_regions_for_action ());
|
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) {
|
|
|
|
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!arv) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* require region to span proposed trim */
|
|
|
|
|
|
|
|
switch (arv->region()->coverage (loc.start(), loc.end())) {
|
|
|
|
case OverlapInternal:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
|
|
|
|
|
|
|
|
if (!atav) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float speed = 1.0;
|
|
|
|
nframes_t start;
|
|
|
|
nframes_t end;
|
|
|
|
|
|
|
|
if (atav->get_diskstream() != 0) {
|
|
|
|
speed = atav->get_diskstream()->speed();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-05-10 07:53:35 -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);
|
|
|
|
|
|
|
|
XMLNode &before = arv->region()->playlist()->get_state();
|
|
|
|
arv->region()->trim_to (start, (end - start), this);
|
|
|
|
XMLNode &after = arv->region()->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
|
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 ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-11-12 17:23:01 -05:00
|
|
|
Editor::trim_region_to_edit_point ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2008-01-10 17:22:29 -05:00
|
|
|
ExclusiveRegionSelection ers (*this, entered_regionview);
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
RegionSelection& rs (get_regions_for_action ());
|
|
|
|
nframes64_t where = get_preferred_edit_position();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
begin_reversible_command (_("trim region start to edit point"));
|
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) {
|
|
|
|
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!arv) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* require region to cover trim */
|
|
|
|
|
|
|
|
if (!arv->region()->covers (where)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
|
|
|
|
|
|
|
|
if (!atav) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float speed = 1.0;
|
|
|
|
|
|
|
|
if (atav->get_diskstream() != 0) {
|
|
|
|
speed = atav->get_diskstream()->speed();
|
|
|
|
}
|
|
|
|
|
|
|
|
XMLNode &before = arv->region()->playlist()->get_state();
|
|
|
|
arv->region()->trim_end( session_frame_to_track_frame(where, speed), this);
|
|
|
|
XMLNode &after = arv->region()->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
|
|
|
|
}
|
2007-05-10 07:53:35 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
|
|
|
Editor::trim_region_from_edit_point ()
|
|
|
|
{
|
2008-01-10 17:22:29 -05:00
|
|
|
ExclusiveRegionSelection ers (*this, entered_regionview);
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
RegionSelection& rs (get_regions_for_action ());
|
|
|
|
nframes64_t where = get_preferred_edit_position();
|
|
|
|
|
|
|
|
begin_reversible_command (_("trim region end to edit point"));
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
|
|
|
|
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!arv) {
|
|
|
|
continue;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
/* require region to cover trim */
|
|
|
|
|
|
|
|
if (!arv->region()->covers (where)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
|
|
|
|
|
|
|
|
if (!atav) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float speed = 1.0;
|
|
|
|
|
|
|
|
if (atav->get_diskstream() != 0) {
|
|
|
|
speed = atav->get_diskstream()->speed();
|
|
|
|
}
|
|
|
|
|
|
|
|
XMLNode &before = arv->region()->playlist()->get_state();
|
|
|
|
arv->region()->trim_front ( session_frame_to_track_frame(where, speed), this);
|
|
|
|
XMLNode &after = arv->region()->playlist()->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
|
2007-05-10 07:53:35 -04:00
|
|
|
}
|
2007-11-12 17:23:01 -05: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
|
|
|
{
|
2008-01-12 18:45:50 -05:00
|
|
|
if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
|
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2008-01-12 18:45:50 -05:00
|
|
|
|
|
|
|
clicked_routeview->audio_track()->unfreeze ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
Editor::_freeze_thread (void* arg)
|
|
|
|
{
|
|
|
|
PBD::ThreadCreated (pthread_self(), X_("Freeze"));
|
|
|
|
return static_cast<Editor*>(arg)->freeze_thread ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
Editor::freeze_thread ()
|
|
|
|
{
|
2008-01-12 18:45:50 -05:00
|
|
|
clicked_routeview->audio_track()->freeze (*current_interthread_info);
|
2005-09-25 14:42:24 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
Editor::freeze_progress_timeout (void *arg)
|
|
|
|
{
|
2005-10-09 01:03:29 -04:00
|
|
|
interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
|
2005-09-25 14:42:24 -04:00
|
|
|
return !(current_interthread_info->done || current_interthread_info->cancel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::freeze_route ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2008-01-12 18:45:50 -05:00
|
|
|
if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
InterThreadInfo itt;
|
|
|
|
|
|
|
|
if (interthread_progress_window == 0) {
|
|
|
|
build_interthread_progress_window ();
|
|
|
|
}
|
2007-03-19 03:07:38 -04:00
|
|
|
|
|
|
|
WindowTitle title(Glib::get_application_name());
|
|
|
|
title += _("Freeze");
|
|
|
|
interthread_progress_window->set_title (title.get_string());
|
2005-09-25 16:33:00 -04:00
|
|
|
interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
|
2005-09-25 14:42:24 -04:00
|
|
|
interthread_progress_window->show_all ();
|
2005-10-26 21:10:36 -04:00
|
|
|
interthread_progress_bar.set_fraction (0.0f);
|
2005-09-25 14:42:24 -04:00
|
|
|
interthread_progress_label.set_text ("");
|
|
|
|
interthread_cancel_label.set_text (_("Cancel Freeze"));
|
|
|
|
current_interthread_info = &itt;
|
|
|
|
|
|
|
|
interthread_progress_connection =
|
2005-10-09 01:03:29 -04:00
|
|
|
Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
itt.done = false;
|
|
|
|
itt.cancel = false;
|
|
|
|
itt.progress = 0.0f;
|
2007-01-11 14:50:49 -05:00
|
|
|
|
|
|
|
pthread_attr_t attr;
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
pthread_attr_setstacksize(&attr, 500000);
|
|
|
|
|
|
|
|
pthread_create (&itt.thread, &attr, _freeze_thread, this);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-01-11 14:50:49 -05:00
|
|
|
pthread_attr_destroy(&attr);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-12-12 15:54:55 -05:00
|
|
|
track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
while (!itt.done && !itt.cancel) {
|
|
|
|
gtk_main_iteration ();
|
|
|
|
}
|
|
|
|
|
|
|
|
interthread_progress_connection.disconnect ();
|
|
|
|
interthread_progress_window->hide_all ();
|
|
|
|
current_interthread_info = 0;
|
2005-12-12 15:54:55 -05:00
|
|
|
track_canvas.get_window()->set_cursor (*current_canvas_cursor);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::bounce_range_selection ()
|
|
|
|
{
|
|
|
|
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
|
|
|
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
nframes_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
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
RouteTimeAxisView* rtv;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2005-09-25 14:42:24 -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;
|
|
|
|
|
|
|
|
itt.done = false;
|
|
|
|
itt.cancel = false;
|
|
|
|
itt.progress = false;
|
2007-04-12 19:20:37 -04:00
|
|
|
|
|
|
|
XMLNode &before = playlist->get_state();
|
|
|
|
rtv->track()->bounce_range (start, cnt, itt);
|
|
|
|
XMLNode &after = playlist->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
switch (current_mouse_mode()) {
|
|
|
|
|
|
|
|
case MouseObject:
|
|
|
|
if (!selection->regions.empty() || !selection->points.empty()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MouseRange:
|
|
|
|
if (!selection->time.empty()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Cut, copy or clear selected regions, automation points or a time range.
|
|
|
|
* @param op Operation (Cut, Copy or Clear)
|
|
|
|
*/
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::cut_copy (CutCopyOp op)
|
|
|
|
{
|
|
|
|
/* only cancel selection if cut/copy is successful.*/
|
|
|
|
|
|
|
|
string opname;
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case Cut:
|
|
|
|
opname = _("cut");
|
|
|
|
break;
|
|
|
|
case Copy:
|
|
|
|
opname = _("copy");
|
|
|
|
break;
|
|
|
|
case Clear:
|
|
|
|
opname = _("clear");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cut_buffer->clear ();
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (session && loc) {
|
|
|
|
Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
switch (current_mouse_mode()) {
|
|
|
|
case MouseObject:
|
2008-01-10 16:20:59 -05:00
|
|
|
cerr << "cutting in object mode\n";
|
2006-07-23 08:03:19 -04:00
|
|
|
if (!selection->regions.empty() || !selection->points.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
begin_reversible_command (opname + _(" objects"));
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (!selection->regions.empty()) {
|
2008-01-10 16:20:59 -05:00
|
|
|
cerr << "have regions to cut" << endl;
|
2005-09-25 14:42:24 -04:00
|
|
|
cut_copy_regions (op);
|
|
|
|
|
|
|
|
if (op == Cut) {
|
2006-07-23 08:03:19 -04:00
|
|
|
selection->clear_regions ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!selection->points.empty()) {
|
|
|
|
cut_copy_points (op);
|
|
|
|
|
|
|
|
if (op == Cut) {
|
|
|
|
selection->clear_points ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
2007-11-12 17:23:01 -05:00
|
|
|
break; // terminate case statement here
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
cerr << "nope, now cutting time range" << endl;
|
2007-11-12 17:23:01 -05:00
|
|
|
if (!selection->time.empty()) {
|
|
|
|
/* don't cause suprises */
|
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
// fall thru if there was nothing selected
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
case MouseRange:
|
2007-11-12 17:23:01 -05:00
|
|
|
if (selection->time.empty()) {
|
|
|
|
nframes64_t start, end;
|
2008-01-10 16:20:59 -05:00
|
|
|
cerr << "no time selection, get edit op range" << endl;
|
2007-11-12 17:23:01 -05:00
|
|
|
if (!get_edit_op_range (start, end)) {
|
2008-01-10 16:20:59 -05:00
|
|
|
cerr << "no edit op range" << endl;
|
2007-11-12 17:23:01 -05:00
|
|
|
return;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
selection->set ((TimeAxisView*) 0, start, end);
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
begin_reversible_command (opname + _(" range"));
|
|
|
|
cut_copy_ranges (op);
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
|
|
|
if (op == Cut) {
|
|
|
|
selection->clear_time ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-10 07:53:35 -04:00
|
|
|
/** Cut, copy or clear selected automation points.
|
|
|
|
* @param op Operation (Cut, Copy or Clear)
|
|
|
|
*/
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::cut_copy_points (CutCopyOp op)
|
|
|
|
{
|
|
|
|
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
|
|
|
|
|
|
|
|
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
|
|
|
|
|
|
|
|
if (atv) {
|
|
|
|
atv->cut_copy_clear_objects (selection->points, op);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-21 18:59:29 -04:00
|
|
|
struct PlaylistState {
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2006-10-21 18:59:29 -04:00
|
|
|
XMLNode* before;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct lt_playlist {
|
|
|
|
bool operator () (const PlaylistState& a, const PlaylistState& b) {
|
|
|
|
return a.playlist < b.playlist;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
struct PlaylistMapping {
|
|
|
|
TimeAxisView* tv;
|
|
|
|
boost::shared_ptr<Playlist> pl;
|
|
|
|
|
|
|
|
PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
|
|
|
|
};
|
|
|
|
|
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
|
|
|
|
Editor::cut_copy_regions (CutCopyOp op)
|
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
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
nframes_t first_position = max_frames;
|
|
|
|
|
2006-10-21 18:59:29 -04:00
|
|
|
set<PlaylistState, lt_playlist> freezelist;
|
|
|
|
pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
/* get ordering correct before we cut/copy */
|
|
|
|
|
|
|
|
selection->regions.sort_by_position_and_track ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
first_position = min ((*x)->region()->position(), first_position);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (op == Cut || op == Clear) {
|
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) {
|
2006-10-21 18:59:29 -04:00
|
|
|
|
|
|
|
PlaylistState before;
|
|
|
|
before.playlist = pl;
|
|
|
|
before.before = &pl->get_state();
|
|
|
|
|
|
|
|
insert_result = freezelist.insert (before);
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (insert_result.second) {
|
|
|
|
pl->freeze ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
TimeAxisView* tv = &(*x)->get_trackview();
|
|
|
|
vector<PlaylistMapping>::iterator z;
|
|
|
|
|
|
|
|
for (z = pmap.begin(); z != pmap.end(); ++z) {
|
|
|
|
if ((*z).tv == tv) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (z == pmap.end()) {
|
|
|
|
pmap.push_back (PlaylistMapping (tv));
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.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();
|
|
|
|
|
|
|
|
if (!pl) {
|
|
|
|
/* impossible, but this handles it for the future */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeAxisView& tv = (*x)->get_trackview();
|
|
|
|
boost::shared_ptr<Playlist> npl;
|
2006-07-23 08:03:19 -04:00
|
|
|
RegionSelection::iterator tmp;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
tmp = x;
|
|
|
|
++tmp;
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
vector<PlaylistMapping>::iterator z;
|
|
|
|
|
|
|
|
for (z = pmap.begin(); z != pmap.end(); ++z) {
|
|
|
|
if ((*z).tv == &tv) {
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
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);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
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);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Clear:
|
|
|
|
pl->remove_region (r);
|
|
|
|
break;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
x = tmp;
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
list<boost::shared_ptr<Playlist> > foo;
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
(*i).pl->thaw();
|
|
|
|
foo.push_back ((*i).pl);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (!foo.empty()) {
|
|
|
|
cut_buffer->set (foo);
|
|
|
|
}
|
2007-04-12 19:20:37 -04:00
|
|
|
|
2006-10-21 18:59:29 -04:00
|
|
|
for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
|
|
|
|
(*pl).playlist->thaw ();
|
|
|
|
session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cut_copy_ranges (CutCopyOp op)
|
|
|
|
{
|
2007-11-12 17:23:01 -05:00
|
|
|
TrackSelection* ts;
|
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->cut_copy_clear (*selection, op);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::paste (float times)
|
|
|
|
{
|
2007-11-07 20:40:25 -05:00
|
|
|
paste_internal (get_preferred_edit_position(), times);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::mouse_paste ()
|
|
|
|
{
|
2007-11-07 20:40:25 -05:00
|
|
|
nframes64_t where;
|
|
|
|
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
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::paste_internal (nframes_t position, float times)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
bool commit = false;
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (cut_buffer->empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (position == max_frames) {
|
2007-11-07 20:40:25 -05:00
|
|
|
position = get_preferred_edit_position();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("paste"));
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
TrackSelection ts;
|
2005-09-25 14:42:24 -04:00
|
|
|
TrackSelection::iterator i;
|
|
|
|
size_t nth;
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
/* get everything in the correct order */
|
|
|
|
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
sort_track_selection ();
|
|
|
|
ts = selection->tracks;
|
|
|
|
} else if (entered_track) {
|
|
|
|
ts.push_back (entered_track);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* undo/redo is handled by individual tracks */
|
|
|
|
|
|
|
|
if ((*i)->paste (position, times, *cut_buffer, nth)) {
|
|
|
|
commit = true;
|
|
|
|
}
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (commit) {
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::paste_named_selection (float times)
|
|
|
|
{
|
2005-11-24 09:59:36 -05:00
|
|
|
TrackSelection::iterator t;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-11-12 22:53:51 -05:00
|
|
|
Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
|
2005-11-12 17:07:07 -05:00
|
|
|
|
2005-11-24 09:59:36 -05:00
|
|
|
if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-11-12 17:07:07 -05:00
|
|
|
TreeModel::iterator i = selected->get_selected();
|
2005-11-12 22:53:51 -05:00
|
|
|
NamedSelection* ns = (*i)[named_selection_columns.selection];
|
2005-11-12 17:07:07 -05:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
list<boost::shared_ptr<Playlist> >::iterator chunk;
|
|
|
|
list<boost::shared_ptr<Playlist> >::iterator tmp;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
chunk = ns->playlists.begin();
|
|
|
|
|
|
|
|
begin_reversible_command (_("paste chunk"));
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
sort_track_selection ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-11-24 09:59:36 -05:00
|
|
|
for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
RouteTimeAxisView* rtv;
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> pl;
|
|
|
|
boost::shared_ptr<AudioPlaylist> apl;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if ((rtv = dynamic_cast<RouteTimeAxisView*> (*t)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
if ((pl = rtv->playlist()) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
2007-01-09 18:24:54 -05:00
|
|
|
|
|
|
|
if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = chunk;
|
|
|
|
++tmp;
|
|
|
|
|
2007-04-12 19:20:37 -04:00
|
|
|
XMLNode &before = apl->get_state();
|
2007-11-07 20:40:25 -05:00
|
|
|
apl->paste (*chunk, get_preferred_edit_position(), times);
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (tmp != ns->playlists.end()) {
|
|
|
|
chunk = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command();
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2007-01-09 18:24:54 -05: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;
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
begin_reversible_command (_("duplicate region"));
|
|
|
|
|
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
|
|
|
|
|
|
|
TimeAxisView& tv = (*i)->get_time_axis_view();
|
2007-04-12 19:20:37 -04:00
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
|
2008-01-10 16:20:59 -05:00
|
|
|
latest_regionviews.clear ();
|
2007-04-12 19:20:37 -04:00
|
|
|
sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-08-29 17:21:48 -04:00
|
|
|
playlist = (*i)->region()->playlist();
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = playlist->get_state();
|
2006-08-29 17:21:48 -04:00
|
|
|
playlist->duplicate (r, r->last_frame(), times);
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2006-01-08 01:08:15 -05:00
|
|
|
c.disconnect ();
|
|
|
|
|
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
|
|
|
|
|
|
|
commit_reversible_command ();
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (!foo.empty()) {
|
|
|
|
selection->set (foo);
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::duplicate_selection (float times)
|
|
|
|
{
|
|
|
|
if (selection->time.empty() || selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2006-08-29 17:21:48 -04:00
|
|
|
vector<boost::shared_ptr<AudioRegion> > new_regions;
|
|
|
|
vector<boost::shared_ptr<AudioRegion> >::iterator ri;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
create_region_from_selection (new_regions);
|
|
|
|
|
|
|
|
if (new_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("duplicate selection"));
|
|
|
|
|
|
|
|
ri = new_regions.begin();
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = playlist->get_state();
|
2006-08-29 17:21:48 -04:00
|
|
|
playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = playlist->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
++ri;
|
|
|
|
if (ri == new_regions.end()) {
|
|
|
|
--ri;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2006-05-19 16:10:35 -04:00
|
|
|
void
|
|
|
|
Editor::reset_point_selection ()
|
|
|
|
{
|
|
|
|
/* reset all selected points to the relevant default value */
|
|
|
|
|
|
|
|
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
|
|
|
|
|
|
|
|
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
|
|
|
|
|
|
|
|
if (atv) {
|
|
|
|
atv->reset_objects (selection->points);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::center_playhead ()
|
|
|
|
{
|
|
|
|
float page = canvas_width * frames_per_unit;
|
|
|
|
center_screen_internal (playhead_cursor->current_frame, page);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-11-12 17:23:01 -05:00
|
|
|
Editor::center_edit_point ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
float page = canvas_width * frames_per_unit;
|
2007-11-07 20:40:25 -05:00
|
|
|
center_screen_internal (get_preferred_edit_position(), page);
|
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
|
|
|
{
|
|
|
|
begin_reversible_command (_("clear playlist"));
|
2007-01-09 18:24:54 -05:00
|
|
|
XMLNode &before = playlist->get_state();
|
|
|
|
playlist->clear ();
|
|
|
|
XMLNode &after = playlist->get_state();
|
|
|
|
session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2007-01-09 18:24:54 -05:00
|
|
|
boost::shared_ptr<Playlist> playlist;
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t distance;
|
|
|
|
nframes_t next_distance;
|
|
|
|
nframes_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("nudge track"));
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
|
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &before = playlist->get_state();
|
2005-09-25 14:42:24 -04:00
|
|
|
playlist->nudge_after (start, distance, forwards);
|
2006-08-09 21:22:45 -04:00
|
|
|
XMLNode &after = playlist->get_state();
|
2006-08-24 03:37:17 -04:00
|
|
|
session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::remove_last_capture ()
|
|
|
|
{
|
|
|
|
vector<string> choices;
|
|
|
|
string prompt;
|
|
|
|
|
|
|
|
if (!session) {
|
|
|
|
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."));
|
2005-11-24 09:59:36 -05:00
|
|
|
|
2005-09-25 16:33:00 -04:00
|
|
|
Gtkmm2ext::Choice prompter (prompt, choices);
|
2005-11-24 09:59:36 -05:00
|
|
|
|
2006-04-20 07:41:45 -04:00
|
|
|
if (prompter.run () == 1) {
|
2006-03-22 12:03:00 -05:00
|
|
|
session->remove_last_capture ();
|
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 {
|
|
|
|
session->remove_last_capture();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::normalize_region ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("normalize"));
|
|
|
|
|
2005-12-12 15:54:55 -05:00
|
|
|
track_canvas.get_window()->set_cursor (*wait_cursor);
|
2005-09-25 14:42:24 -04:00
|
|
|
gdk_flush ();
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
|
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
|
|
|
|
if (!arv)
|
|
|
|
continue;
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &before = arv->region()->get_state();
|
|
|
|
arv->audio_region()->normalize_to (0.0f);
|
2006-11-19 11:45:16 -05:00
|
|
|
session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
2005-12-12 15:54:55 -05:00
|
|
|
track_canvas.get_window()->set_cursor (*current_canvas_cursor);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::denormalize_region ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command ("denormalize");
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
|
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
|
|
|
|
if (!arv)
|
|
|
|
continue;
|
2006-08-29 17:21:48 -04:00
|
|
|
XMLNode &before = arv->region()->get_state();
|
|
|
|
arv->audio_region()->set_scale_amplitude (1.0f);
|
|
|
|
session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::reverse_region ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Reverse rev (*session);
|
|
|
|
apply_filter (rev, _("reverse regions"));
|
|
|
|
}
|
|
|
|
|
2007-08-06 01:30:18 -04:00
|
|
|
|
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
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: varying meter?
|
|
|
|
Quantize quant (*session, snap_length_beats(0));
|
|
|
|
apply_filter (quant, _("quantize regions"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::apply_filter (Filter& filter, string command)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
if (selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (command);
|
|
|
|
|
2005-12-12 15:54:55 -05:00
|
|
|
track_canvas.get_window()->set_cursor (*wait_cursor);
|
2005-09-25 14:42:24 -04:00
|
|
|
gdk_flush ();
|
|
|
|
|
2007-08-06 01:30:18 -04:00
|
|
|
/* this is ugly. */
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.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
|
|
|
MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
|
|
|
|
if (mrv) {
|
|
|
|
if (mrv->midi_region()->apply(filter) == 0) {
|
|
|
|
mrv->redisplay_model();
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
2007-08-06 01:30:18 -04:00
|
|
|
if (arv->audio_region()->apply (filter) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-08-06 01:30:18 -04:00
|
|
|
XMLNode &before = playlist->get_state();
|
|
|
|
playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
|
|
|
|
XMLNode &after = playlist->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
|
|
|
|
} else {
|
|
|
|
goto out;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
r = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
2006-07-23 08:03:19 -04:00
|
|
|
selection->regions.clear ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
out:
|
2005-12-12 15:54:55 -05:00
|
|
|
track_canvas.get_window()->set_cursor (*current_canvas_cursor);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_selection_op (void (Region::*pmf)(void))
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2006-08-29 17:21:48 -04:00
|
|
|
Region* region = (*i)->region().get();
|
|
|
|
(region->*pmf)();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2006-08-29 17:21:48 -04:00
|
|
|
Region* region = (*i)->region().get();
|
|
|
|
(region->*pmf)(arg);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
|
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2006-08-29 17:21:48 -04:00
|
|
|
Region* region = (*i)->region().get();
|
|
|
|
(region->*pmf)(yn);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::external_edit_region ()
|
|
|
|
{
|
|
|
|
/* more to come */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-21 15:01:50 -04:00
|
|
|
Editor::brush (nframes_t pos)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
RegionSelection sel;
|
2005-09-25 14:42:24 -04:00
|
|
|
snap_to (pos);
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
if (selection->regions.empty()) {
|
2005-09-25 14:42:24 -04:00
|
|
|
/* XXX get selection from region list */
|
|
|
|
} else {
|
2006-07-23 08:03:19 -04:00
|
|
|
sel = selection->regions;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sel.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
mouse_brush_insert_region ((*i), pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-19 11:45:16 -05:00
|
|
|
void
|
|
|
|
Editor::reset_region_gain_envelopes ()
|
|
|
|
{
|
|
|
|
if (!session || selection->regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->begin_reversible_command (_("reset region gain"));
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
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 ();
|
2007-06-29 00:02:58 -04:00
|
|
|
session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2007-10-11 18:07:47 -04:00
|
|
|
Editor::toggle_gain_envelope_visibility ()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
|
2006-11-19 11:45:16 -05:00
|
|
|
if (arv) {
|
2008-01-12 18:45:50 -05:00
|
|
|
arv->set_envelope_visible (!arv->envelope_visible());
|
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
|
|
|
{
|
2006-07-23 08:03:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
|
2006-11-19 11:45:16 -05:00
|
|
|
if (arv) {
|
2008-01-12 18:45:50 -05:00
|
|
|
arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
|
2007-10-11 18:07:47 -04:00
|
|
|
}
|
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
|
|
|
{
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2008-01-12 18:45:50 -05:00
|
|
|
(*i)->region()->set_locked (!(*i)->region()->locked());
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-10-11 18:07:47 -04:00
|
|
|
Editor::toggle_region_mute ()
|
2006-11-19 11:45:16 -05:00
|
|
|
{
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2008-01-12 18:45:50 -05:00
|
|
|
(*i)->region()->set_muted (!(*i)->region()->muted());
|
2006-11-19 11:45:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-10-11 18:07:47 -04:00
|
|
|
Editor::toggle_region_opaque ()
|
2006-11-19 11:45:16 -05:00
|
|
|
{
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2008-01-12 18:45:50 -05:00
|
|
|
(*i)->region()->set_opaque (!(*i)->region()->opaque());
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
|
|
|
Editor::set_fade_length (bool in)
|
|
|
|
{
|
2008-01-10 17:22:29 -05:00
|
|
|
ExclusiveRegionSelection esr (*this, entered_regionview);
|
2008-01-07 16:12:29 -05:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
/* we need a region to measure the offset from the start */
|
|
|
|
|
|
|
|
RegionView* rv;
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
if (!selection->regions.empty()) {
|
2007-11-12 17:23:01 -05:00
|
|
|
rv = selection->regions.front();
|
2008-01-10 17:22:29 -05:00
|
|
|
} else if (entered_regionview) {
|
|
|
|
rv = entered_regionview;
|
2007-11-12 17:23:01 -05:00
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nframes64_t pos = get_preferred_edit_position();
|
|
|
|
nframes_t len;
|
|
|
|
char* cmd;
|
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);
|
|
|
|
|
|
|
|
RegionSelection& rs (get_regions_for_action());
|
|
|
|
|
|
|
|
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);
|
|
|
|
} else {
|
|
|
|
tmp->audio_region()->set_fade_out_length (len);
|
|
|
|
}
|
|
|
|
|
|
|
|
XMLNode &after = alist->get_state();
|
2008-01-10 17:22:29 -05:00
|
|
|
session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::toggle_fade_active (bool in)
|
|
|
|
{
|
|
|
|
ensure_entered_region_selected (true);
|
|
|
|
|
|
|
|
if (selection->regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* cmd = (in ? _("toggle fade in active") : _("toggle fade out active"));
|
|
|
|
bool have_switch = false;
|
|
|
|
bool yn;
|
|
|
|
|
|
|
|
begin_reversible_command (cmd);
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
|
|
|
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<AudioRegion> region (tmp->audio_region());
|
|
|
|
|
|
|
|
/* make the behaviour consistent across all regions */
|
|
|
|
|
|
|
|
if (!have_switch) {
|
2008-01-10 17:22:29 -05:00
|
|
|
if (in) {
|
|
|
|
yn = region->fade_in_active();
|
|
|
|
} else {
|
|
|
|
yn = region->fade_out_active();
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
have_switch = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
XMLNode &before = region->get_state();
|
2008-01-10 17:22:29 -05:00
|
|
|
if (in) {
|
|
|
|
region->set_fade_in_active (!yn);
|
|
|
|
} else {
|
|
|
|
region->set_fade_out_active (!yn);
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
XMLNode &after = region->get_state();
|
|
|
|
session->add_command(new MementoCommand<AudioRegion>(*region.get(), &before, &after));
|
|
|
|
}
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
commit_reversible_command ();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
|
|
|
Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
|
|
|
|
{
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
begin_reversible_command (_("set fade in shape"));
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
|
|
|
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);
|
|
|
|
|
2007-06-29 00:02:58 -04:00
|
|
|
XMLNode &after = alist->get_state();
|
|
|
|
session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
|
|
|
|
{
|
|
|
|
begin_reversible_command (_("set fade out shape"));
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
|
|
|
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);
|
|
|
|
|
2007-06-29 00:02:58 -04:00
|
|
|
XMLNode &after = alist->get_state();
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
begin_reversible_command (_("set fade in active"));
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
|
|
|
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
|
|
|
|
|
|
|
|
XMLNode &before = ar->get_state();
|
|
|
|
|
|
|
|
ar->set_fade_in_active (yn);
|
|
|
|
|
|
|
|
XMLNode &after = ar->get_state();
|
|
|
|
session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
|
|
|
|
}
|
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)
|
|
|
|
{
|
|
|
|
begin_reversible_command (_("set fade out active"));
|
|
|
|
|
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
|
|
|
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
|
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
|
|
|
|
|
|
|
|
XMLNode &before = ar->get_state();
|
|
|
|
|
|
|
|
ar->set_fade_out_active (yn);
|
|
|
|
|
|
|
|
XMLNode &after = ar->get_state();
|
|
|
|
session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
|
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2007-04-22 14:01:10 -04:00
|
|
|
|
|
|
|
/** Update crossfade visibility after its configuration has been changed */
|
|
|
|
void
|
|
|
|
Editor::update_xfade_visibility ()
|
|
|
|
{
|
|
|
|
_xfade_visibility = Config->get_xfades_visible ();
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
|
|
|
|
if (v) {
|
|
|
|
if (_xfade_visibility) {
|
|
|
|
v->show_all_xfades ();
|
|
|
|
} else {
|
|
|
|
v->hide_all_xfades ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_edit_point ()
|
|
|
|
{
|
|
|
|
nframes64_t where;
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!mouse_frame (where, ignored)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
snap_to (where);
|
|
|
|
|
|
|
|
if (selection->markers.empty()) {
|
|
|
|
|
|
|
|
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) {
|
|
|
|
session->request_locate (entered_marker->position(), session->transport_rolling());
|
|
|
|
} else {
|
|
|
|
nframes64_t where;
|
|
|
|
bool ignored;
|
|
|
|
|
|
|
|
if (!mouse_frame (where, ignored)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
snap_to (where);
|
|
|
|
|
|
|
|
if (session) {
|
|
|
|
session->request_locate (where, session->transport_rolling());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split ()
|
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
ensure_entered_region_selected ();
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
nframes64_t where = get_preferred_edit_position();
|
|
|
|
|
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
|
|
|
|
split_regions_at (where, selection->regions);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
RegionSelection rs;
|
|
|
|
rs = get_regions_at (where, selection->tracks);
|
|
|
|
split_regions_at (where, rs);
|
|
|
|
}
|
|
|
|
}
|
2008-01-07 16:12:29 -05:00
|
|
|
|
|
|
|
void
|
2008-01-10 16:20:59 -05:00
|
|
|
Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
|
2008-01-07 16:12:29 -05:00
|
|
|
{
|
2008-01-10 16:20:59 -05:00
|
|
|
if (entered_track && mouse_mode == MouseObject) {
|
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
if (!selection->selected (entered_track)) {
|
|
|
|
selection->add (entered_track);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* there is no selection, but this operation requires/prefers selected objects */
|
|
|
|
|
|
|
|
if (op_really_wants_one_track_if_none_are_selected) {
|
|
|
|
selection->set (entered_track);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::ensure_entered_region_selected (bool op_really_wants_one_region_if_none_are_selected)
|
|
|
|
{
|
2008-01-10 17:22:29 -05:00
|
|
|
if (!entered_regionview || mouse_mode != MouseObject) {
|
|
|
|
return;
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
/* heuristic:
|
|
|
|
|
|
|
|
- if there is no existing selection, don't change it. the operation will thus apply to "all"
|
|
|
|
|
|
|
|
- if there is an existing selection, but the entered regionview isn't in it, add it. this
|
|
|
|
avoids key-mouse ops on unselected regions from interfering with an existing selection,
|
|
|
|
but also means that the operation will apply to the pointed-at region.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
if (!selection->selected (entered_regionview)) {
|
|
|
|
selection->add (entered_regionview);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* there is no selection, but this operation requires/prefers selected objects */
|
|
|
|
|
|
|
|
if (op_really_wants_one_region_if_none_are_selected) {
|
|
|
|
selection->set (entered_regionview, false);
|
2008-01-07 16:12:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_region_front ()
|
|
|
|
{
|
|
|
|
trim_region (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_region_back ()
|
|
|
|
{
|
|
|
|
trim_region (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_region (bool front)
|
|
|
|
{
|
2008-01-10 17:22:29 -05:00
|
|
|
ExclusiveRegionSelection ers (*this, entered_regionview);
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
nframes64_t where = get_preferred_edit_position();
|
|
|
|
RegionSelection& rs = get_regions_for_action ();
|
|
|
|
|
|
|
|
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()) {
|
|
|
|
boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
|
|
|
|
XMLNode &before = pl->get_state();
|
|
|
|
if (front) {
|
|
|
|
(*i)->region()->trim_front (where, this);
|
|
|
|
} else {
|
|
|
|
(*i)->region()->trim_end (where, this);
|
|
|
|
}
|
|
|
|
XMLNode &after = pl->get_state();
|
|
|
|
session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
|
|
|
|
}
|
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct EditorOrderRouteSorter {
|
|
|
|
bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
|
|
|
|
/* use of ">" forces the correct sort order */
|
|
|
|
return a->order_key ("editor") < b->order_key ("editor");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_next_route()
|
|
|
|
{
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
selection->set (track_views.front());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeAxisView* current = selection->tracks.front();
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
if (*i == current) {
|
|
|
|
++i;
|
|
|
|
if (i != track_views.end()) {
|
|
|
|
selection->set (*i);
|
|
|
|
} else {
|
|
|
|
selection->set (*(track_views.begin()));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_prev_route()
|
|
|
|
{
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
selection->set (track_views.front());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeAxisView* current = selection->tracks.front();
|
|
|
|
|
|
|
|
for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
|
|
|
|
if (*i == current) {
|
|
|
|
++i;
|
|
|
|
if (i != track_views.rend()) {
|
|
|
|
selection->set (*i);
|
|
|
|
} else {
|
|
|
|
selection->set (*(track_views.rbegin()));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_loop_from_selection (bool play)
|
|
|
|
{
|
|
|
|
if (session == 0 || selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
|
|
|
|
set_loop_range (start, end, _("set loop range from selection"));
|
|
|
|
|
|
|
|
if (play) {
|
|
|
|
session->request_play_loop (true);
|
|
|
|
session->request_locate (start, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_loop_from_edit_range (bool play)
|
|
|
|
{
|
|
|
|
if (session == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nframes64_t start;
|
|
|
|
nframes64_t end;
|
|
|
|
|
|
|
|
if (!get_edit_op_range (start, end)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_loop_range (start, end, _("set loop range from edit range"));
|
|
|
|
|
|
|
|
if (play) {
|
|
|
|
session->request_play_loop (true);
|
|
|
|
session->request_locate (start, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_loop_from_region (bool play)
|
|
|
|
{
|
|
|
|
nframes64_t start = max_frames;
|
|
|
|
nframes64_t end = 0;
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
ExclusiveRegionSelection esr (*this, entered_regionview);
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (selection->regions.empty()) {
|
|
|
|
info << _("cannot set loop: no region selected") << endmsg;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
if ((*i)->region()->position() < start) {
|
|
|
|
start = (*i)->region()->position();
|
|
|
|
}
|
|
|
|
if ((*i)->region()->last_frame() + 1 > end) {
|
|
|
|
end = (*i)->region()->last_frame() + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_loop_range (start, end, _("set loop range from region"));
|
|
|
|
|
|
|
|
if (play) {
|
|
|
|
session->request_play_loop (true);
|
|
|
|
session->request_locate (start, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_punch_from_selection ()
|
|
|
|
{
|
|
|
|
if (session == 0 || selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
|
|
|
|
set_punch_range (start, end, _("set punch range from selection"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_punch_from_edit_range ()
|
|
|
|
{
|
|
|
|
if (session == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nframes64_t start;
|
|
|
|
nframes64_t end;
|
|
|
|
|
|
|
|
if (!get_edit_op_range (start, end)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_punch_range (start, end, _("set punch range from edit range"));
|
|
|
|
}
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
void
|
|
|
|
Editor::set_punch_from_region ()
|
|
|
|
{
|
|
|
|
nframes64_t start = max_frames;
|
|
|
|
nframes64_t end = 0;
|
|
|
|
|
|
|
|
ExclusiveRegionSelection esr (*this, entered_regionview);
|
|
|
|
|
|
|
|
if (selection->regions.empty()) {
|
|
|
|
info << _("cannot set punch: no region selected") << endmsg;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
if ((*i)->region()->position() < start) {
|
|
|
|
start = (*i)->region()->position();
|
|
|
|
}
|
|
|
|
if ((*i)->region()->last_frame() + 1 > end) {
|
|
|
|
end = (*i)->region()->last_frame() + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_punch_range (start, end, _("set punch range from region"));
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
|
|
|
Editor::pitch_shift_regions ()
|
|
|
|
{
|
|
|
|
ensure_entered_region_selected (true);
|
|
|
|
|
|
|
|
if (selection->regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pitch_shift (selection->regions, 1.2);
|
|
|
|
}
|
|
|
|
|