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.
|
|
|
|
|
|
|
|
$Id$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cmath>
|
|
|
|
#include <string>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
#include <pbd/error.h>
|
|
|
|
#include <pbd/basename.h>
|
|
|
|
#include <pbd/pthread_utils.h>
|
|
|
|
|
2005-09-25 16:33:00 -04:00
|
|
|
#include <gtkmm2ext/utils.h>
|
|
|
|
#include <gtkmm2ext/choice.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>
|
|
|
|
#include <ardour/reverse.h>
|
|
|
|
|
|
|
|
#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"
|
|
|
|
#include "regionview.h"
|
|
|
|
#include "rgb_macros.h"
|
|
|
|
#include "selection_templates.h"
|
|
|
|
#include "selection.h"
|
2005-10-12 17:59:45 -04:00
|
|
|
#include "sfdb_ui.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "editing.h"
|
|
|
|
#include "gtk-custom-hruler.h"
|
2006-04-06 12:51:27 -04:00
|
|
|
#include "gui_thread.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;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-07 21:56:49 -05:00
|
|
|
void
|
|
|
|
Editor::set_meter_hold (int32_t cnt)
|
|
|
|
{
|
2006-06-08 19:46:42 -04:00
|
|
|
Config->set_meter_hold_off(false);
|
|
|
|
Config->set_meter_hold_short(false);
|
|
|
|
Config->set_meter_hold_medium(false);
|
|
|
|
Config->set_meter_hold_long(false);
|
|
|
|
|
|
|
|
switch (cnt)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
Config->set_meter_hold_off(true);
|
|
|
|
break;
|
|
|
|
case 40:
|
|
|
|
Config->set_meter_hold_short(true);
|
|
|
|
break;
|
|
|
|
case 100:
|
|
|
|
Config->set_meter_hold_medium(true);
|
|
|
|
break;
|
|
|
|
case 200:
|
|
|
|
Config->set_meter_hold_long(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-01-07 21:56:49 -05:00
|
|
|
if (session) {
|
|
|
|
session->set_meter_hold (cnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-06-08 19:46:42 -04:00
|
|
|
Editor::set_meter_falloff (int intval)
|
2006-01-07 21:56:49 -05:00
|
|
|
{
|
2006-06-14 21:34:54 -04:00
|
|
|
float val = 0.0f; /* off */
|
2006-06-08 19:46:42 -04:00
|
|
|
std::string str;
|
2006-06-14 21:34:54 -04:00
|
|
|
|
2006-06-08 19:46:42 -04:00
|
|
|
Config->set_meter_falloff_off(false);
|
|
|
|
Config->set_meter_falloff_slowest(false);
|
|
|
|
Config->set_meter_falloff_slow(false);
|
|
|
|
Config->set_meter_falloff_medium(false);
|
|
|
|
Config->set_meter_falloff_fast(false);
|
|
|
|
Config->set_meter_falloff_faster(false);
|
|
|
|
Config->set_meter_falloff_fastest(false);
|
|
|
|
|
|
|
|
switch (intval)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
val = 0.0f;
|
|
|
|
Config->set_meter_falloff_off(true);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
val = 0.266f;
|
|
|
|
Config->set_meter_falloff_slowest(true);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
val = 0.342f;
|
|
|
|
Config->set_meter_falloff_slow(true);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
val = 0.7f;
|
|
|
|
Config->set_meter_falloff_medium(true);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
val = 1.1f;
|
|
|
|
Config->set_meter_falloff_fast(true);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
val = 1.5f;
|
|
|
|
Config->set_meter_falloff_faster(true);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
val = 2.5f;
|
|
|
|
Config->set_meter_falloff_fastest(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-01-07 21:56:49 -05:00
|
|
|
if (session) {
|
|
|
|
session->set_meter_falloff (val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
int
|
|
|
|
Editor::ensure_cursor (jack_nframes_t *pos)
|
|
|
|
{
|
|
|
|
*pos = edit_cursor->current_frame;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split_region ()
|
|
|
|
{
|
|
|
|
split_region_at (edit_cursor->current_frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split_region_at (jack_nframes_t where)
|
|
|
|
{
|
|
|
|
split_regions_at (where, selection->audio_regions);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split_regions_at (jack_nframes_t where, AudioRegionSelection& regions)
|
|
|
|
{
|
|
|
|
begin_reversible_command (_("split"));
|
|
|
|
|
|
|
|
snap_to (where);
|
|
|
|
for (AudioRegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
|
|
|
|
|
|
|
|
AudioRegionSelection::iterator tmp;
|
|
|
|
|
|
|
|
tmp = a;
|
|
|
|
++tmp;
|
|
|
|
|
|
|
|
Playlist* pl = (*a)->region.playlist();
|
|
|
|
|
|
|
|
_new_regionviews_show_envelope = (*a)->envelope_visible();
|
|
|
|
|
|
|
|
if (pl) {
|
|
|
|
session->add_undo (pl->get_memento());
|
|
|
|
pl->split_region ((*a)->region, where);
|
|
|
|
session->add_redo_no_execute (pl->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
a = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
_new_regionviews_show_envelope = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::remove_clicked_region ()
|
|
|
|
{
|
|
|
|
if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist* playlist = clicked_audio_trackview->playlist();
|
|
|
|
|
|
|
|
begin_reversible_command (_("remove region"));
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
playlist->remove_region (&clicked_regionview->region);
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::destroy_clicked_region ()
|
|
|
|
{
|
|
|
|
int32_t selected = selection->audio_regions.size();
|
|
|
|
|
|
|
|
if (!session || clicked_regionview == 0 && selected == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<string> choices;
|
|
|
|
string prompt;
|
|
|
|
|
2005-10-06 15:10:57 -04:00
|
|
|
prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\
|
2005-09-25 14:42:24 -04:00
|
|
|
It cannot be undone\n\
|
|
|
|
Do you really want to destroy %1 ?"),
|
|
|
|
(selected > 1 ?
|
|
|
|
_("these regions") : _("this region")));
|
|
|
|
|
2006-04-20 07:41:45 -04:00
|
|
|
choices.push_back (_("No, do nothing."));
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (selected > 1) {
|
|
|
|
choices.push_back (_("Yes, destroy them."));
|
|
|
|
} else {
|
|
|
|
choices.push_back (_("Yes, destroy it."));
|
|
|
|
}
|
|
|
|
|
2005-09-25 16:33:00 -04:00
|
|
|
Gtkmm2ext::Choice prompter (prompt, choices);
|
2006-03-22 12:03:00 -05:00
|
|
|
|
2006-04-20 07:41:45 -04:00
|
|
|
if (prompter.run() == 0) { /* first choice */
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selected > 0) {
|
|
|
|
list<Region*> r;
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
r.push_back (&(*i)->region);
|
|
|
|
}
|
|
|
|
|
|
|
|
session->destroy_regions (r);
|
|
|
|
|
|
|
|
} else if (clicked_regionview) {
|
|
|
|
session->destroy_region (&clicked_regionview->region);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioRegion *
|
|
|
|
Editor::select_region_for_operation (int dir, TimeAxisView **tv)
|
|
|
|
{
|
|
|
|
AudioRegionView* rv;
|
|
|
|
AudioRegion *region;
|
|
|
|
jack_nframes_t start = 0;
|
|
|
|
|
|
|
|
if (selection->time.start () == selection->time.end_frame ()) {
|
|
|
|
|
|
|
|
/* no current selection-> is there a selected regionview? */
|
|
|
|
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
region = 0;
|
|
|
|
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
|
|
|
|
rv = *(selection->audio_regions.begin());
|
|
|
|
(*tv) = &rv->get_time_axis_view();
|
|
|
|
region = &rv->region;
|
|
|
|
|
|
|
|
} else if (!selection->tracks.empty()) {
|
|
|
|
|
|
|
|
(*tv) = selection->tracks.front();
|
|
|
|
|
|
|
|
AudioTimeAxisView* atv;
|
|
|
|
|
|
|
|
if ((atv = dynamic_cast<AudioTimeAxisView*> (*tv)) != 0) {
|
|
|
|
Playlist *pl;
|
|
|
|
|
|
|
|
if ((pl = atv->playlist()) == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
region = dynamic_cast<AudioRegion*> (pl->top_region_at (start));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return region;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::extend_selection_to_end_of_region (bool next)
|
|
|
|
{
|
|
|
|
TimeAxisView *tv;
|
|
|
|
Region *region;
|
|
|
|
jack_nframes_t start;
|
|
|
|
|
|
|
|
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;
|
|
|
|
Region *region;
|
|
|
|
jack_nframes_t end;
|
|
|
|
|
|
|
|
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 ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::nudge_forward (bool next)
|
|
|
|
{
|
|
|
|
jack_nframes_t distance;
|
|
|
|
jack_nframes_t next_distance;
|
|
|
|
|
|
|
|
if (!session) return;
|
|
|
|
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
|
|
|
|
begin_reversible_command (_("nudge forward"));
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
AudioRegion& r ((*i)->region);
|
|
|
|
|
|
|
|
distance = get_nudge_distance (r.position(), next_distance);
|
|
|
|
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->add_undo (r.playlist()->get_memento());
|
|
|
|
r.set_position (r.position() + distance, this);
|
|
|
|
session->add_redo_no_execute (r.playlist()->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
|
|
|
|
session->request_locate (playhead_cursor->current_frame + distance);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::nudge_backward (bool next)
|
|
|
|
{
|
|
|
|
jack_nframes_t distance;
|
|
|
|
jack_nframes_t next_distance;
|
|
|
|
|
|
|
|
if (!session) return;
|
|
|
|
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
|
|
|
|
begin_reversible_command (_("nudge forward"));
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
AudioRegion& r ((*i)->region);
|
|
|
|
|
|
|
|
distance = get_nudge_distance (r.position(), next_distance);
|
|
|
|
|
|
|
|
if (next) {
|
|
|
|
distance = next_distance;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->add_undo (r.playlist()->get_memento());
|
|
|
|
|
|
|
|
if (r.position() > distance) {
|
|
|
|
r.set_position (r.position() - distance, this);
|
|
|
|
} else {
|
|
|
|
r.set_position (0, this);
|
|
|
|
}
|
|
|
|
session->add_redo_no_execute (r.playlist()->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
|
|
|
} 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 ()
|
|
|
|
{
|
|
|
|
jack_nframes_t distance;
|
|
|
|
|
|
|
|
if (!session) return;
|
|
|
|
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
|
|
|
|
begin_reversible_command (_("nudge forward"));
|
|
|
|
|
|
|
|
distance = session->worst_output_latency();
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
AudioRegion& r ((*i)->region);
|
|
|
|
|
|
|
|
session->add_undo (r.playlist()->get_memento());
|
|
|
|
r.set_position (r.position() + distance, this);
|
|
|
|
session->add_redo_no_execute (r.playlist()->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::nudge_backward_capture_offset ()
|
|
|
|
{
|
|
|
|
jack_nframes_t distance;
|
|
|
|
|
|
|
|
if (!session) return;
|
|
|
|
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
|
|
|
|
begin_reversible_command (_("nudge forward"));
|
|
|
|
|
|
|
|
distance = session->worst_output_latency();
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
AudioRegion& r ((*i)->region);
|
|
|
|
|
|
|
|
session->add_undo (r.playlist()->get_memento());
|
|
|
|
|
|
|
|
if (r.position() > distance) {
|
|
|
|
r.set_position (r.position() - distance, this);
|
|
|
|
} else {
|
|
|
|
r.set_position (0, this);
|
|
|
|
}
|
|
|
|
session->add_redo_no_execute (r.playlist()->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ()
|
|
|
|
{
|
|
|
|
jack_nframes_t pos = 0;
|
|
|
|
RegionPoint point;
|
|
|
|
Region *r;
|
|
|
|
TrackViewList tracks;
|
|
|
|
|
|
|
|
region_boundary_cache.clear ();
|
|
|
|
|
|
|
|
if (session == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (snap_type) {
|
|
|
|
case SnapToRegionStart:
|
|
|
|
point = Start;
|
|
|
|
break;
|
|
|
|
case SnapToRegionEnd:
|
|
|
|
point = End;
|
|
|
|
break;
|
|
|
|
case SnapToRegionSync:
|
|
|
|
point = SyncPoint;
|
|
|
|
break;
|
|
|
|
case SnapToRegionBoundary:
|
|
|
|
point = Start;
|
|
|
|
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;
|
|
|
|
|
|
|
|
while (pos < session->current_end_frame()) {
|
|
|
|
|
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
|
|
|
|
if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (clicked_trackview) {
|
|
|
|
|
|
|
|
TrackViewList t;
|
|
|
|
t.push_back (clicked_trackview);
|
|
|
|
|
|
|
|
if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t rpos;
|
|
|
|
|
|
|
|
switch (snap_type) {
|
|
|
|
case SnapToRegionStart:
|
|
|
|
rpos = r->first_frame();
|
|
|
|
break;
|
|
|
|
case SnapToRegionEnd:
|
|
|
|
rpos = r->last_frame();
|
|
|
|
break;
|
|
|
|
case SnapToRegionSync:
|
|
|
|
rpos = r->adjust_to_sync (r->first_frame());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SnapToRegionBoundary:
|
|
|
|
rpos = r->last_frame();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-14 10:44:23 -05:00
|
|
|
rpos = track_frame_to_session_frame(rpos, speed);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
|
|
|
|
if (snap_type == SnapToRegionBoundary) {
|
|
|
|
region_boundary_cache.push_back (r->first_frame());
|
|
|
|
}
|
|
|
|
region_boundary_cache.push_back (rpos);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = rpos + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Region*
|
|
|
|
Editor::find_next_region (jack_nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
|
|
|
|
{
|
|
|
|
TrackViewList::iterator i;
|
|
|
|
jack_nframes_t closest = max_frames;
|
|
|
|
Region* ret = 0;
|
|
|
|
jack_nframes_t rpos = 0;
|
|
|
|
|
|
|
|
float track_speed;
|
|
|
|
jack_nframes_t track_frame;
|
|
|
|
AudioTimeAxisView *atav;
|
|
|
|
|
|
|
|
for (i = tracks.begin(); i != tracks.end(); ++i) {
|
|
|
|
|
|
|
|
jack_nframes_t distance;
|
|
|
|
Region* r;
|
|
|
|
|
|
|
|
track_speed = 1.0f;
|
|
|
|
if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
|
|
|
|
if (atav->get_diskstream()!=0)
|
|
|
|
track_speed = atav->get_diskstream()->speed();
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
|
|
|
|
{
|
|
|
|
Region* r;
|
|
|
|
jack_nframes_t pos = cursor->current_frame;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
} else if (clicked_trackview) {
|
|
|
|
|
|
|
|
TrackViewList t;
|
|
|
|
t.push_back (clicked_trackview);
|
|
|
|
|
|
|
|
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;
|
|
|
|
AudioTimeAxisView *atav;
|
|
|
|
|
|
|
|
if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
|
|
|
|
if (atav->get_diskstream() != 0) {
|
|
|
|
speed = atav->get_diskstream()->speed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
jack_nframes_t pos = 0;
|
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
pos = selection->audio_regions.start();
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
jack_nframes_t pos = 0;
|
|
|
|
|
|
|
|
switch (mouse_mode) {
|
|
|
|
case MouseObject:
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
pos = selection->audio_regions.end_frame();
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::playhead_backward ()
|
|
|
|
{
|
|
|
|
jack_nframes_t pos;
|
|
|
|
jack_nframes_t cnt;
|
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
|
|
|
|
} else {
|
|
|
|
cnt = (jack_nframes_t) prefix;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = playhead_cursor->current_frame;
|
|
|
|
|
|
|
|
if ((jack_nframes_t) pos < cnt) {
|
|
|
|
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 ()
|
|
|
|
{
|
|
|
|
jack_nframes_t pos;
|
|
|
|
jack_nframes_t cnt;
|
|
|
|
bool was_floating;
|
|
|
|
float prefix;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
|
|
|
|
} else {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (playhead_to_edit) {
|
|
|
|
if (session) {
|
|
|
|
session->request_locate (edit_cursor->current_frame);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
edit_cursor->set_position (playhead_cursor->current_frame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::edit_cursor_backward ()
|
|
|
|
{
|
|
|
|
jack_nframes_t pos;
|
|
|
|
jack_nframes_t cnt;
|
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
|
|
|
|
} else {
|
|
|
|
cnt = (jack_nframes_t) prefix;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = edit_cursor->current_frame;
|
|
|
|
|
|
|
|
if ((jack_nframes_t) pos < cnt) {
|
|
|
|
pos = 0;
|
|
|
|
} else {
|
|
|
|
pos -= cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
edit_cursor->set_position (pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::edit_cursor_forward ()
|
|
|
|
{
|
|
|
|
jack_nframes_t pos;
|
|
|
|
jack_nframes_t cnt;
|
|
|
|
bool was_floating;
|
|
|
|
float prefix;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = 1;
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
|
|
|
|
} else {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = edit_cursor->current_frame;
|
|
|
|
edit_cursor->set_position (pos+cnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::goto_frame ()
|
|
|
|
{
|
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
|
|
|
jack_nframes_t frame;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (was_floating) {
|
|
|
|
frame = (jack_nframes_t) floor (prefix * session->frame_rate());
|
|
|
|
} else {
|
|
|
|
frame = (jack_nframes_t) floor (prefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
session->request_locate (frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_backward (float pages)
|
|
|
|
{
|
|
|
|
jack_nframes_t frame;
|
|
|
|
jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
|
|
|
|
bool was_floating;
|
|
|
|
float prefix;
|
|
|
|
jack_nframes_t cnt;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = (jack_nframes_t) floor (pages * one_page);
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
|
|
|
|
} else {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix * one_page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (leftmost_frame < cnt) {
|
|
|
|
frame = 0;
|
|
|
|
} else {
|
|
|
|
frame = leftmost_frame - cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
reposition_x_origin (frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::scroll_forward (float pages)
|
|
|
|
{
|
|
|
|
jack_nframes_t frame;
|
|
|
|
jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
|
|
|
|
bool was_floating;
|
|
|
|
float prefix;
|
|
|
|
jack_nframes_t cnt;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
cnt = (jack_nframes_t) floor (pages * one_page);
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
|
|
|
|
} else {
|
|
|
|
cnt = (jack_nframes_t) floor (prefix * one_page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ULONG_MAX - cnt < leftmost_frame) {
|
|
|
|
frame = ULONG_MAX - cnt;
|
|
|
|
} else {
|
|
|
|
frame = leftmost_frame + cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
reposition_x_origin (frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
nfpu *= 2.0;
|
|
|
|
} else {
|
|
|
|
nfpu = max(1.0,(nfpu/2.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
temporal_zoom (nfpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::temporal_zoom (gdouble fpu)
|
|
|
|
{
|
|
|
|
if (!session) return;
|
|
|
|
|
|
|
|
jack_nframes_t current_page = current_page_frames();
|
|
|
|
jack_nframes_t current_leftmost = leftmost_frame;
|
|
|
|
jack_nframes_t current_rightmost;
|
|
|
|
jack_nframes_t current_center;
|
|
|
|
jack_nframes_t new_page;
|
|
|
|
jack_nframes_t leftmost_after_zoom = 0;
|
|
|
|
double nfpu;
|
|
|
|
|
|
|
|
nfpu = fpu;
|
|
|
|
|
|
|
|
new_page = (jack_nframes_t) floor (canvas_width * nfpu);
|
|
|
|
|
|
|
|
switch (zoom_focus) {
|
|
|
|
case ZoomFocusLeft:
|
|
|
|
leftmost_after_zoom = current_leftmost;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ZoomFocusRight:
|
|
|
|
current_rightmost = leftmost_frame + current_page;
|
|
|
|
if (current_rightmost > new_page) {
|
|
|
|
leftmost_after_zoom = current_rightmost - new_page;
|
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ZoomFocusCenter:
|
|
|
|
current_center = current_leftmost + (current_page/2);
|
|
|
|
if (current_center > (new_page/2)) {
|
|
|
|
leftmost_after_zoom = current_center - (new_page / 2);
|
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ZoomFocusPlayhead:
|
|
|
|
/* try to keep the playhead in the center */
|
|
|
|
if (playhead_cursor->current_frame > new_page/2) {
|
|
|
|
leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
|
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ZoomFocusEdit:
|
|
|
|
/* try to keep the edit cursor in the center */
|
|
|
|
if (edit_cursor->current_frame > leftmost_frame + (new_page/2)) {
|
|
|
|
leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
|
|
|
|
} else {
|
|
|
|
leftmost_after_zoom = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
|
|
|
|
|
|
|
|
// begin_reversible_command (_("zoom"));
|
2005-09-25 17:19:23 -04:00
|
|
|
// session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
|
|
|
|
// session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
|
2005-09-25 14:42:24 -04:00
|
|
|
// commit_reversible_command ();
|
|
|
|
|
|
|
|
reposition_and_zoom (leftmost_after_zoom, nfpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::temporal_zoom_selection ()
|
|
|
|
{
|
|
|
|
if (!selection) return;
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
jack_nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
|
|
|
|
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
|
2005-12-22 07:23:54 -05:00
|
|
|
Editor::temporal_zoom_by_frame (jack_nframes_t start, jack_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t range = end - start;
|
|
|
|
|
|
|
|
double new_fpu = (double)range / (double)canvas_width;
|
|
|
|
// double p2 = 1.0;
|
|
|
|
|
|
|
|
// while (p2 < new_fpu) {
|
|
|
|
// p2 *= 2.0;
|
|
|
|
// }
|
|
|
|
// new_fpu = p2;
|
|
|
|
|
|
|
|
jack_nframes_t new_page = (jack_nframes_t) floor (canvas_width * new_fpu);
|
|
|
|
jack_nframes_t middle = (jack_nframes_t) floor( (double)start + ((double)range / 2.0f ));
|
|
|
|
jack_nframes_t new_leftmost = (jack_nframes_t) floor( (double)middle - ((double)new_page/2.0f));
|
|
|
|
|
|
|
|
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
|
|
|
|
Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame)
|
|
|
|
{
|
|
|
|
if (!session) return;
|
|
|
|
|
|
|
|
jack_nframes_t range_before = frame - leftmost_frame;
|
|
|
|
double new_fpu;
|
|
|
|
|
|
|
|
new_fpu = frames_per_unit;
|
|
|
|
|
|
|
|
if (coarser) {
|
|
|
|
new_fpu *= 2.0;
|
|
|
|
range_before *= 2;
|
|
|
|
} else {
|
|
|
|
new_fpu = max(1.0,(new_fpu/2.0));
|
|
|
|
range_before /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_fpu == frames_per_unit) return;
|
|
|
|
|
|
|
|
jack_nframes_t new_leftmost = frame - range_before;
|
|
|
|
|
|
|
|
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 ()
|
|
|
|
{
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session == 0 || clicked_trackview == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
jack_nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
|
|
|
|
Location *location = new Location (start, end, "selection");
|
|
|
|
|
|
|
|
session->begin_reversible_command (_("add marker"));
|
|
|
|
session->add_undo (session->locations()->get_memento());
|
|
|
|
session->locations()->add (location, true);
|
|
|
|
session->add_redo_no_execute (session->locations()->get_memento());
|
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::add_location_from_playhead_cursor ()
|
|
|
|
{
|
|
|
|
jack_nframes_t where = session->audible_frame();
|
|
|
|
|
|
|
|
Location *location = new Location (where, where, "mark", Location::IsMark);
|
|
|
|
session->begin_reversible_command (_("add marker"));
|
|
|
|
session->add_undo (session->locations()->get_memento());
|
|
|
|
session->locations()->add (location, true);
|
|
|
|
session->add_redo_no_execute (session->locations()->get_memento());
|
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::add_location_from_audio_region ()
|
|
|
|
{
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioRegionView* rv = *(selection->audio_regions.begin());
|
|
|
|
Region& region = rv->region;
|
|
|
|
|
|
|
|
Location *location = new Location (region.position(), region.last_frame(), region.name());
|
|
|
|
session->begin_reversible_command (_("add marker"));
|
|
|
|
session->add_undo (session->locations()->get_memento());
|
|
|
|
session->locations()->add (location, true);
|
|
|
|
session->add_redo_no_execute (session->locations()->get_memento());
|
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2006-03-05 14:39:16 -05:00
|
|
|
Editor::select_all_in_track (Selection::Operation op)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
if (!clicked_trackview) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
|
|
|
|
|
2006-03-05 14:39:16 -05:00
|
|
|
switch (op) {
|
|
|
|
case Selection::Toggle:
|
2005-09-25 14:42:24 -04:00
|
|
|
selection->add (touched);
|
2006-03-05 14:39:16 -05:00
|
|
|
break;
|
|
|
|
case Selection::Set:
|
2005-09-25 14:42:24 -04:00
|
|
|
selection->set (touched);
|
2006-03-05 14:39:16 -05:00
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
|
|
|
/* not defined yet */
|
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-03-05 14:39:16 -05:00
|
|
|
Editor::select_all (Selection::Operation op)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
|
|
|
|
}
|
2006-02-15 07:15:29 -05:00
|
|
|
begin_reversible_command (_("select all"));
|
2006-03-05 14:39:16 -05:00
|
|
|
switch (op) {
|
|
|
|
case Selection::Toggle:
|
2005-09-25 14:42:24 -04:00
|
|
|
selection->add (touched);
|
2006-03-05 14:39:16 -05:00
|
|
|
break;
|
|
|
|
case Selection::Set:
|
2005-09-25 14:42:24 -04:00
|
|
|
selection->set (touched);
|
2006-03-05 14:39:16 -05:00
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
|
|
|
/* not defined yet */
|
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2006-02-15 07:15:29 -05:00
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::invert_selection_in_track ()
|
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
if (!clicked_trackview) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
clicked_trackview->get_inverted_selectables (*selection, touched);
|
|
|
|
selection->set (touched);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::invert_selection ()
|
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_inverted_selectables (*selection, touched);
|
|
|
|
}
|
|
|
|
|
|
|
|
selection->set (touched);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2006-03-05 14:39:16 -05:00
|
|
|
Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, Selection::Operation op)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_selectables (start, end, top, bot, touched);
|
|
|
|
}
|
2006-05-19 16:10:35 -04:00
|
|
|
|
|
|
|
cerr << "select all within found " << touched.size() << endl;
|
|
|
|
|
2006-01-23 17:08:41 -05:00
|
|
|
begin_reversible_command (_("select all within"));
|
2006-03-05 14:39:16 -05:00
|
|
|
switch (op) {
|
|
|
|
case Selection::Toggle:
|
2006-05-19 16:10:35 -04:00
|
|
|
cerr << "toggle\n";
|
2005-09-25 14:42:24 -04:00
|
|
|
selection->add (touched);
|
2006-03-05 14:39:16 -05:00
|
|
|
break;
|
|
|
|
case Selection::Set:
|
2006-05-19 16:10:35 -04:00
|
|
|
cerr << "set\n";
|
2005-09-25 14:42:24 -04:00
|
|
|
selection->set (touched);
|
2006-03-05 14:39:16 -05:00
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
2006-05-19 16:10:35 -04:00
|
|
|
cerr << "extend\n";
|
2006-03-05 14:39:16 -05:00
|
|
|
/* not defined yet */
|
|
|
|
break;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2006-05-19 16:10:35 -04:00
|
|
|
|
|
|
|
cerr << "selection now has " << selection->points.size() << endl;
|
|
|
|
|
2006-01-23 17:08:41 -05:00
|
|
|
commit_reversible_command ();
|
2005-09-25 14:42:24 -04:00
|
|
|
return !touched.empty();
|
|
|
|
}
|
|
|
|
|
2006-03-31 18:00:40 -05:00
|
|
|
void
|
|
|
|
Editor::set_selection_from_audio_region ()
|
|
|
|
{
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioRegionView* rv = *(selection->audio_regions.begin());
|
|
|
|
Region& region = rv->region;
|
|
|
|
|
|
|
|
begin_reversible_command (_("set selection from region"));
|
|
|
|
selection->set (0, region.position(), region.last_frame());
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
|
|
|
set_mouse_mode (Editing::MouseRange, false);
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::set_selection_from_punch()
|
|
|
|
{
|
|
|
|
Location* location;
|
|
|
|
|
|
|
|
if ((location = session->locations()->auto_punch_location()) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_selection_from_range (*location);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_selection_from_loop()
|
|
|
|
{
|
|
|
|
Location* location;
|
|
|
|
|
|
|
|
if ((location = session->locations()->auto_loop_location()) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
set_selection_from_range (*location);
|
|
|
|
}
|
|
|
|
|
2006-01-23 11:02:48 -05:00
|
|
|
void
|
2006-02-15 07:15:29 -05:00
|
|
|
Editor::set_selection_from_range (Location& loc)
|
2006-01-23 11:02:48 -05:00
|
|
|
{
|
2006-02-15 07:15:29 -05:00
|
|
|
begin_reversible_command (_("set selection from range"));
|
|
|
|
selection->set (0, loc.start(), loc.end());
|
|
|
|
commit_reversible_command ();
|
2006-03-31 18:00:40 -05:00
|
|
|
|
|
|
|
set_mouse_mode (Editing::MouseRange, false);
|
2006-02-15 07:15:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_all_selectables_using_time_selection ()
|
|
|
|
{
|
2006-01-23 11:02:48 -05:00
|
|
|
list<Selectable *> touched;
|
2006-02-15 07:15:29 -05:00
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
jack_nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
|
|
|
|
if (end - start < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
|
2006-01-23 11:02:48 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2006-02-15 07:15:29 -05:00
|
|
|
(*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
|
2006-01-23 11:02:48 -05:00
|
|
|
}
|
2006-04-03 23:26:08 -04:00
|
|
|
|
2006-02-15 07:15:29 -05:00
|
|
|
begin_reversible_command (_("select all from range"));
|
2006-01-23 13:59:30 -05:00
|
|
|
selection->set (touched);
|
|
|
|
commit_reversible_command ();
|
2006-01-23 11:02:48 -05:00
|
|
|
}
|
|
|
|
|
2006-02-15 07:15:29 -05:00
|
|
|
|
2006-01-23 11:02:48 -05:00
|
|
|
void
|
2006-02-15 07:15:29 -05:00
|
|
|
Editor::select_all_selectables_using_punch()
|
2006-01-23 11:02:48 -05:00
|
|
|
{
|
2006-02-15 07:15:29 -05:00
|
|
|
Location* location = session->locations()->auto_punch_location();
|
2006-01-23 11:02:48 -05:00
|
|
|
list<Selectable *> touched;
|
|
|
|
|
2006-02-15 07:15:29 -05:00
|
|
|
if (location == 0 || (location->end() - location->start() <= 1)) {
|
2006-01-23 11:02:48 -05:00
|
|
|
return;
|
|
|
|
}
|
2006-02-15 07:15:29 -05:00
|
|
|
|
2006-01-23 11:02:48 -05:00
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2006-02-15 07:15:29 -05:00
|
|
|
(*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
|
2006-01-23 11:02:48 -05:00
|
|
|
}
|
2006-02-15 07:15:29 -05:00
|
|
|
begin_reversible_command (_("select all from punch"));
|
2006-01-23 13:59:30 -05:00
|
|
|
selection->set (touched);
|
|
|
|
commit_reversible_command ();
|
2006-01-23 11:02:48 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
2006-02-15 07:15:29 -05:00
|
|
|
Editor::select_all_selectables_using_loop()
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-02-15 15:04:29 -05:00
|
|
|
Location* location = session->locations()->auto_loop_location();
|
2006-02-15 07:15:29 -05:00
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
if (location == 0 || (location->end() - location->start() <= 1)) {
|
2005-09-25 14:42:24 -04:00
|
|
|
return;
|
|
|
|
}
|
2006-02-15 07:15:29 -05:00
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
|
|
|
|
}
|
|
|
|
begin_reversible_command (_("select all from loop"));
|
|
|
|
selection->set (touched);
|
2005-09-25 14:42:24 -04:00
|
|
|
commit_reversible_command ();
|
2006-02-15 07:15:29 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2006-01-23 11:02:48 -05:00
|
|
|
void
|
2006-02-15 07:15:29 -05:00
|
|
|
Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
|
2006-01-23 11:02:48 -05:00
|
|
|
{
|
|
|
|
jack_nframes_t start;
|
|
|
|
jack_nframes_t end;
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
if (after) {
|
2006-04-03 23:26:08 -04:00
|
|
|
begin_reversible_command (_("select all after cursor"));
|
|
|
|
start = cursor->current_frame ;
|
|
|
|
end = session->current_end_frame();
|
2006-01-23 11:02:48 -05:00
|
|
|
} else {
|
2006-04-03 23:26:08 -04:00
|
|
|
if (cursor->current_frame > 0) {
|
|
|
|
begin_reversible_command (_("select all before cursor"));
|
|
|
|
start = 0;
|
|
|
|
end = cursor->current_frame - 1;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
2006-01-23 11:02:48 -05:00
|
|
|
}
|
2006-04-03 23:26:08 -04:00
|
|
|
|
2006-01-23 11:02:48 -05:00
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
|
|
|
|
}
|
|
|
|
selection->set (touched);
|
2006-01-23 13:59:30 -05:00
|
|
|
commit_reversible_command ();
|
2006-01-23 11:02:48 -05:00
|
|
|
}
|
|
|
|
|
2006-03-31 19:21:25 -05:00
|
|
|
void
|
|
|
|
Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
|
|
|
|
{
|
|
|
|
jack_nframes_t start;
|
|
|
|
jack_nframes_t end;
|
|
|
|
list<Selectable *> touched;
|
|
|
|
bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
|
2006-04-03 23:26:08 -04:00
|
|
|
|
2006-03-31 19:21:25 -05:00
|
|
|
if (cursor->current_frame == other_cursor->current_frame) {
|
2006-04-03 23:26:08 -04:00
|
|
|
return;
|
2006-03-31 19:21:25 -05:00
|
|
|
}
|
|
|
|
|
2006-04-03 23:26:08 -04:00
|
|
|
begin_reversible_command (_("select all between cursors"));
|
|
|
|
if (other_cursor_is_first) {
|
|
|
|
start = other_cursor->current_frame;
|
|
|
|
end = cursor->current_frame - 1;
|
|
|
|
|
2006-03-31 19:21:25 -05:00
|
|
|
} else {
|
2006-04-03 23:26:08 -04:00
|
|
|
start = cursor->current_frame;
|
|
|
|
end = other_cursor->current_frame - 1;
|
2006-03-31 19:21:25 -05:00
|
|
|
}
|
2006-04-03 23:26:08 -04:00
|
|
|
|
2006-03-31 19:21:25 -05:00
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
|
|
|
|
}
|
|
|
|
selection->set (touched);
|
|
|
|
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 ()
|
|
|
|
{
|
|
|
|
jack_nframes_t pos;
|
|
|
|
float prefix;
|
|
|
|
bool was_floating;
|
|
|
|
|
|
|
|
if (get_prefix (prefix, was_floating)) {
|
|
|
|
pos = session->audible_frame ();
|
|
|
|
} else {
|
|
|
|
if (was_floating) {
|
|
|
|
pos = (jack_nframes_t) floor (prefix * session->frame_rate ());
|
|
|
|
} else {
|
|
|
|
pos = (jack_nframes_t) floor (prefix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
session->locations()->add (new Location (pos, 0, "mark", Location::IsMark), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_markers ()
|
|
|
|
{
|
|
|
|
if (session) {
|
|
|
|
session->begin_reversible_command (_("clear markers"));
|
|
|
|
session->add_undo (session->locations()->get_memento());
|
|
|
|
session->locations()->clear_markers ();
|
|
|
|
session->add_redo_no_execute (session->locations()->get_memento());
|
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_ranges ()
|
|
|
|
{
|
|
|
|
if (session) {
|
|
|
|
session->begin_reversible_command (_("clear ranges"));
|
|
|
|
session->add_undo (session->locations()->get_memento());
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
session->add_redo_no_execute (session->locations()->get_memento());
|
|
|
|
session->commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_locations ()
|
|
|
|
{
|
|
|
|
session->begin_reversible_command (_("clear locations"));
|
|
|
|
session->add_undo (session->locations()->get_memento());
|
|
|
|
session->locations()->clear ();
|
|
|
|
session->add_redo_no_execute (session->locations()->get_memento());
|
|
|
|
session->commit_reversible_command ();
|
|
|
|
session->locations()->clear ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* INSERT/REPLACE */
|
|
|
|
|
|
|
|
void
|
2005-12-30 15:38:41 -05:00
|
|
|
Editor::insert_region_list_drag (AudioRegion& region, int x, int y)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
double wx, wy;
|
|
|
|
double cx, cy;
|
|
|
|
TimeAxisView *tv;
|
|
|
|
jack_nframes_t where;
|
|
|
|
AudioTimeAxisView *atv = 0;
|
|
|
|
Playlist *playlist;
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((playlist = atv->playlist()) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
snap_to (where);
|
|
|
|
|
|
|
|
begin_reversible_command (_("insert dragged region"));
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
playlist->add_region (*(new AudioRegion (region)), where, 1.0);
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::insert_region_list_selection (float times)
|
|
|
|
{
|
|
|
|
AudioTimeAxisView *tv = 0;
|
|
|
|
Playlist *playlist;
|
|
|
|
|
|
|
|
if (clicked_audio_trackview != 0) {
|
|
|
|
tv = clicked_audio_trackview;
|
|
|
|
} else if (!selection->tracks.empty()) {
|
|
|
|
if ((tv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.front())) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-11-12 17:07:07 -05:00
|
|
|
TreeModel::iterator i = region_list_display.get_selection()->get_selected();
|
2005-11-12 22:53:51 -05:00
|
|
|
Region* region = (*i)[region_list_columns.region];
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
begin_reversible_command (_("insert region"));
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
playlist->add_region (*(createRegion (*region)), edit_cursor->current_frame, times);
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* BUILT-IN EFFECTS */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::reverse_selection ()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* GAIN ENVELOPE EDITING */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::edit_envelope ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PLAYBACK */
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_playback (bool with_abort)
|
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (session->slave_source()) {
|
|
|
|
case Session::None:
|
|
|
|
case Session::JACK:
|
|
|
|
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);
|
|
|
|
if (session->get_auto_loop()) {
|
|
|
|
session->request_auto_loop (false);
|
|
|
|
}
|
|
|
|
} 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
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::play_selection ()
|
|
|
|
{
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->request_play_range (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::play_selected_region ()
|
|
|
|
{
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
AudioRegionView *rv = *(selection->audio_regions.begin());
|
|
|
|
|
|
|
|
session->request_bounded_roll (rv->region.position(), rv->region.last_frame());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::loop_selected_region ()
|
|
|
|
{
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
AudioRegionView *rv = *(selection->audio_regions.begin());
|
|
|
|
Location* tll;
|
|
|
|
|
|
|
|
if ((tll = transport_loop_location()) != 0) {
|
|
|
|
|
|
|
|
tll->set (rv->region.position(), rv->region.last_frame());
|
|
|
|
|
|
|
|
// enable looping, reposition and start rolling
|
|
|
|
|
|
|
|
session->request_auto_loop (true);
|
|
|
|
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
|
|
|
|
session->request_auto_loop (true);
|
|
|
|
session->request_locate (tll->start(), true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_region_mute ()
|
|
|
|
{
|
|
|
|
if (clicked_regionview) {
|
|
|
|
clicked_regionview->region.set_muted (!clicked_regionview->region.muted());
|
|
|
|
} else if (!selection->audio_regions.empty()) {
|
|
|
|
bool yn = ! (*selection->audio_regions.begin())->region.muted();
|
|
|
|
selection->foreach_audio_region (&AudioRegion::set_muted, yn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_region_opaque ()
|
|
|
|
{
|
|
|
|
if (clicked_regionview) {
|
|
|
|
clicked_regionview->region.set_opaque (!clicked_regionview->region.opaque());
|
|
|
|
} else if (!selection->audio_regions.empty()) {
|
|
|
|
bool yn = ! (*selection->audio_regions.begin())->region.opaque();
|
|
|
|
selection->foreach_audio_region (&Region::set_opaque, yn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::raise_region ()
|
|
|
|
{
|
|
|
|
selection->foreach_audio_region (&Region::raise);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::raise_region_to_top ()
|
|
|
|
{
|
|
|
|
selection->foreach_audio_region (&Region::raise_to_top);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::lower_region ()
|
|
|
|
{
|
|
|
|
selection->foreach_audio_region (&Region::lower);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::lower_region_to_bottom ()
|
|
|
|
{
|
|
|
|
selection->foreach_audio_region (&Region::lower_to_bottom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::edit_region ()
|
|
|
|
{
|
|
|
|
if (clicked_regionview == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
clicked_regionview->show_region_editor ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::rename_region ()
|
|
|
|
{
|
|
|
|
Dialog dialog;
|
|
|
|
Entry entry;
|
|
|
|
Button ok_button (_("OK"));
|
|
|
|
Button cancel_button (_("Cancel"));
|
|
|
|
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dialog.set_title (_("ardour: rename region"));
|
|
|
|
dialog.set_name ("RegionRenameWindow");
|
2005-09-25 16:33:00 -04:00
|
|
|
dialog.set_size_request (300, -1);
|
|
|
|
dialog.set_position (Gtk::WIN_POS_MOUSE);
|
2005-09-25 14:42:24 -04:00
|
|
|
dialog.set_modal (true);
|
|
|
|
|
|
|
|
dialog.get_vbox()->set_border_width (10);
|
|
|
|
dialog.get_vbox()->pack_start (entry);
|
|
|
|
dialog.get_action_area()->pack_start (ok_button);
|
|
|
|
dialog.get_action_area()->pack_start (cancel_button);
|
|
|
|
|
|
|
|
entry.set_name ("RegionNameDisplay");
|
|
|
|
ok_button.set_name ("EditorGTKButton");
|
|
|
|
cancel_button.set_name ("EditorGTKButton");
|
|
|
|
|
|
|
|
region_renamed = false;
|
|
|
|
|
2005-10-09 01:03:29 -04:00
|
|
|
entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
|
2005-09-25 17:19:23 -04:00
|
|
|
ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
|
|
|
|
cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
/* recurse */
|
|
|
|
|
|
|
|
dialog.show_all ();
|
|
|
|
Main::run ();
|
|
|
|
|
|
|
|
if (region_renamed) {
|
|
|
|
(*selection->audio_regions.begin())->region.set_name (entry.get_text());
|
|
|
|
redisplay_regions ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::rename_region_finished (bool status)
|
|
|
|
|
|
|
|
{
|
|
|
|
region_renamed = status;
|
|
|
|
Main::quit ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
session->request_bounded_roll (region.position(), region.position() + region.length());
|
|
|
|
|
|
|
|
/* XXX how to unset the solo state ? */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::audition_selected_region ()
|
|
|
|
{
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
AudioRegionView* rv = *(selection->audio_regions.begin());
|
|
|
|
session->audition_region (rv->region);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::audition_playlist_region_standalone (AudioRegion& region)
|
|
|
|
{
|
|
|
|
session->audition_region (region);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::build_interthread_progress_window ()
|
|
|
|
{
|
2005-11-27 16:17:41 -05:00
|
|
|
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 ()
|
|
|
|
{
|
|
|
|
if (clicked_trackview == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
jack_nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
|
|
|
|
jack_nframes_t selection_cnt = end - start + 1;
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
|
|
|
|
AudioRegion *region;
|
|
|
|
AudioRegion *current;
|
|
|
|
Region* current_r;
|
|
|
|
Playlist *pl;
|
|
|
|
|
|
|
|
jack_nframes_t internal_start;
|
|
|
|
string new_name;
|
|
|
|
|
|
|
|
if ((pl = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((current_r = pl->top_region_at (start)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((current = dynamic_cast<AudioRegion*> (current_r)) != 0) {
|
|
|
|
internal_start = start - current->position();
|
|
|
|
session->region_name (new_name, current->name(), true);
|
|
|
|
region = new AudioRegion (*current, internal_start, selection_cnt, new_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::create_region_from_selection (vector<AudioRegion *>& new_regions)
|
|
|
|
{
|
|
|
|
if (selection->time.empty() || selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
jack_nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
|
|
|
|
AudioRegion* current;
|
|
|
|
Region* current_r;
|
|
|
|
Playlist* playlist;
|
|
|
|
jack_nframes_t internal_start;
|
|
|
|
string new_name;
|
|
|
|
|
|
|
|
if ((playlist = (*i)->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((current_r = playlist->top_region_at(start)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((current = dynamic_cast<AudioRegion*>(current_r)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal_start = start - current->position();
|
|
|
|
session->region_name (new_name, current->name(), true);
|
|
|
|
|
|
|
|
new_regions.push_back (new AudioRegion (*current, internal_start, end - start + 1, new_name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::split_multichannel_region ()
|
|
|
|
{
|
|
|
|
vector<AudioRegion*> v;
|
|
|
|
|
|
|
|
if (!clicked_regionview || clicked_regionview->region.n_channels() < 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
clicked_regionview->region.separate_by_channel (*session, v);
|
|
|
|
|
|
|
|
/* nothing else to do, really */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::new_region_from_selection ()
|
|
|
|
{
|
|
|
|
region_from_selection ();
|
|
|
|
cancel_selection ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::separate_region_from_selection ()
|
|
|
|
{
|
|
|
|
bool doing_undo = false;
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist *playlist;
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
|
|
|
|
AudioTimeAxisView* atv;
|
|
|
|
|
|
|
|
if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
|
|
|
|
|
|
|
|
if (atv->is_audio_track()) {
|
|
|
|
|
|
|
|
if ((playlist = atv->playlist()) != 0) {
|
|
|
|
if (!doing_undo) {
|
|
|
|
begin_reversible_command (_("separate"));
|
|
|
|
doing_undo = true;
|
|
|
|
}
|
|
|
|
if (doing_undo) session->add_undo ((playlist)->get_memento());
|
|
|
|
|
|
|
|
/* XXX need to consider musical time selections here at some point */
|
|
|
|
|
|
|
|
double speed = atv->get_diskstream()->speed();
|
|
|
|
|
|
|
|
for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
|
|
|
|
playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doing_undo) session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-31 19:21:25 -05:00
|
|
|
if (doing_undo) commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::separate_regions_using_location (Location& loc)
|
|
|
|
{
|
|
|
|
bool doing_undo = false;
|
|
|
|
|
|
|
|
if (loc.is_mark()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist *playlist;
|
|
|
|
|
|
|
|
/* XXX i'm unsure as to whether this should operate on selected tracks only
|
|
|
|
or the entire enchillada. uncomment the below line to correct the behaviour
|
|
|
|
(currently set for all tracks)
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
//for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
|
|
|
|
AudioTimeAxisView* atv;
|
|
|
|
|
|
|
|
if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
|
|
|
|
|
|
|
|
if (atv->is_audio_track()) {
|
|
|
|
|
|
|
|
if ((playlist = atv->playlist()) != 0) {
|
|
|
|
if (!doing_undo) {
|
|
|
|
begin_reversible_command (_("separate"));
|
|
|
|
doing_undo = true;
|
|
|
|
}
|
|
|
|
if (doing_undo) session->add_undo ((playlist)->get_memento());
|
|
|
|
|
|
|
|
/* XXX need to consider musical time selections here at some point */
|
|
|
|
|
|
|
|
double speed = atv->get_diskstream()->speed();
|
|
|
|
|
|
|
|
|
|
|
|
playlist->partition ((jack_nframes_t)(loc.start() * speed), (jack_nframes_t)(loc.end() * speed), true);
|
|
|
|
if (doing_undo) session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (doing_undo) commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::crop_region_to_selection ()
|
|
|
|
{
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<Playlist*> playlists;
|
|
|
|
Playlist *playlist;
|
|
|
|
|
|
|
|
if (clicked_trackview != 0) {
|
|
|
|
|
|
|
|
if ((playlist = clicked_trackview->playlist()) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
playlists.push_back (playlist);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
|
|
|
|
AudioTimeAxisView* atv;
|
|
|
|
|
|
|
|
if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
|
|
|
|
|
|
|
|
if (atv->is_audio_track()) {
|
|
|
|
|
|
|
|
if ((playlist = atv->playlist()) != 0) {
|
|
|
|
playlists.push_back (playlist);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!playlists.empty()) {
|
|
|
|
|
|
|
|
jack_nframes_t start;
|
|
|
|
jack_nframes_t end;
|
|
|
|
jack_nframes_t cnt;
|
|
|
|
|
|
|
|
begin_reversible_command (_("trim to selection"));
|
|
|
|
|
|
|
|
for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
|
|
|
|
|
|
|
|
Region *region;
|
|
|
|
|
|
|
|
start = selection->time.start();
|
|
|
|
|
|
|
|
if ((region = (*i)->top_region_at(start)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now adjust lengths to that we do the right thing
|
|
|
|
if the selection extends beyond the region
|
|
|
|
*/
|
|
|
|
|
|
|
|
start = max (start, region->position());
|
|
|
|
end = min (selection->time.end_frame(), start + region->length() - 1);
|
|
|
|
cnt = end - start + 1;
|
|
|
|
|
|
|
|
session->add_undo ((*i)->get_memento());
|
|
|
|
region->trim_to (start, cnt, this);
|
|
|
|
session->add_redo_no_execute ((*i)->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_fill_track ()
|
|
|
|
{
|
|
|
|
jack_nframes_t end;
|
|
|
|
|
|
|
|
if (!session || selection->audio_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
end = session->current_end_frame ();
|
|
|
|
|
|
|
|
begin_reversible_command (_("region fill"));
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
|
|
|
|
AudioRegion& region ((*i)->region);
|
|
|
|
Playlist* pl = region.playlist();
|
|
|
|
|
|
|
|
if (end <= region.last_frame()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
double times = (double) (end - region.last_frame()) / (double) region.length();
|
|
|
|
|
|
|
|
if (times == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->add_undo (pl->get_memento());
|
|
|
|
pl->add_region (*(new AudioRegion (region)), region.last_frame(), times);
|
|
|
|
session->add_redo_no_execute (pl->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_fill_selection ()
|
|
|
|
{
|
|
|
|
if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Region *region;
|
|
|
|
|
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();
|
2005-11-12 22:53:51 -05:00
|
|
|
region = (*i)[region_list_columns.region];
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
jack_nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
jack_nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
|
|
|
|
Playlist *playlist;
|
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t selection_length = end - start;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
playlist->add_region (*(createRegion (*region)), start, times);
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
2006-01-23 15:39:58 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_a_regions_sync_position (Region& region, jack_nframes_t position)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!region.covers (position)) {
|
|
|
|
error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
begin_reversible_command (_("set region sync position"));
|
|
|
|
session->add_undo (region.playlist()->get_memento());
|
|
|
|
region.set_sync_position (position);
|
|
|
|
session->add_redo_no_execute (region.playlist()->get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
Editor::set_region_sync_from_edit_cursor ()
|
|
|
|
{
|
|
|
|
if (clicked_regionview == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!clicked_regionview->region.covers (edit_cursor->current_frame)) {
|
|
|
|
error << _("Place the edit cursor at the desired sync point") << endmsg;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Region& region (clicked_regionview->region);
|
|
|
|
begin_reversible_command (_("set sync from edit cursor"));
|
|
|
|
session->add_undo (region.playlist()->get_memento());
|
|
|
|
region.set_sync_position (edit_cursor->current_frame);
|
|
|
|
session->add_redo_no_execute (region.playlist()->get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::remove_region_sync ()
|
|
|
|
{
|
|
|
|
if (clicked_regionview) {
|
|
|
|
Region& region (clicked_regionview->region);
|
|
|
|
begin_reversible_command (_("remove sync"));
|
|
|
|
session->add_undo (region.playlist()->get_memento());
|
|
|
|
region.clear_sync_position ();
|
|
|
|
session->add_redo_no_execute (region.playlist()->get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::naturalize ()
|
|
|
|
{
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
begin_reversible_command (_("naturalize"));
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
session->add_undo ((*i)->region.get_memento());
|
|
|
|
(*i)->region.move_to_natural_position (this);
|
|
|
|
session->add_redo_no_execute ((*i)->region.get_memento());
|
|
|
|
}
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::align (RegionPoint what)
|
|
|
|
{
|
|
|
|
align_selection (what, edit_cursor->current_frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::align_relative (RegionPoint what)
|
|
|
|
{
|
|
|
|
align_selection_relative (what, edit_cursor->current_frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct RegionSortByTime {
|
|
|
|
bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
|
|
|
|
return a->region.position() < b->region.position();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::align_selection_relative (RegionPoint point, jack_nframes_t position)
|
|
|
|
{
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
jack_nframes_t distance;
|
|
|
|
jack_nframes_t pos = 0;
|
|
|
|
int dir;
|
|
|
|
|
|
|
|
list<AudioRegionView*> sorted;
|
|
|
|
selection->audio_regions.by_position (sorted);
|
|
|
|
Region& r ((*sorted.begin())->region);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos > position) {
|
|
|
|
distance = pos - position;
|
|
|
|
dir = -1;
|
|
|
|
} else {
|
|
|
|
distance = position - pos;
|
|
|
|
dir = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("align selection (relative)"));
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
|
|
|
|
Region& region ((*i)->region);
|
|
|
|
|
|
|
|
session->add_undo (region.playlist()->get_memento());
|
|
|
|
|
|
|
|
if (dir > 0) {
|
|
|
|
region.set_position (region.position() + distance, this);
|
|
|
|
} else {
|
|
|
|
region.set_position (region.position() - distance, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
session->add_redo_no_execute (region.playlist()->get_memento());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::align_selection (RegionPoint point, jack_nframes_t position)
|
|
|
|
{
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("align selection"));
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
align_region_internal ((*i)->region, point, position);
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::align_region (Region& region, RegionPoint point, jack_nframes_t position)
|
|
|
|
{
|
|
|
|
begin_reversible_command (_("align region"));
|
|
|
|
align_region_internal (region, point, position);
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t position)
|
|
|
|
{
|
|
|
|
session->add_undo (region.playlist()->get_memento());
|
|
|
|
|
|
|
|
switch (point) {
|
|
|
|
case SyncPoint:
|
|
|
|
region.set_position (region.adjust_to_sync (position), this);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case End:
|
|
|
|
if (position > region.length()) {
|
|
|
|
region.set_position (position - region.length(), this);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Start:
|
|
|
|
region.set_position (position, this);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->add_redo_no_execute (region.playlist()->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_region_to_edit_cursor ()
|
|
|
|
{
|
|
|
|
if (clicked_regionview == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Region& region (clicked_regionview->region);
|
|
|
|
|
|
|
|
float speed = 1.0f;
|
|
|
|
AudioTimeAxisView *atav;
|
|
|
|
|
|
|
|
if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
|
|
|
|
if (atav->get_diskstream() != 0) {
|
|
|
|
speed = atav->get_diskstream()->speed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("trim to edit"));
|
|
|
|
session->add_undo (region.playlist()->get_memento());
|
2005-11-14 10:44:23 -05:00
|
|
|
region.trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
|
2005-09-25 14:42:24 -04:00
|
|
|
session->add_redo_no_execute (region.playlist()->get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::trim_region_from_edit_cursor ()
|
|
|
|
{
|
|
|
|
if (clicked_regionview == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Region& region (clicked_regionview->region);
|
|
|
|
|
|
|
|
float speed = 1.0f;
|
|
|
|
AudioTimeAxisView *atav;
|
|
|
|
|
|
|
|
if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
|
|
|
|
if (atav->get_diskstream() != 0) {
|
|
|
|
speed = atav->get_diskstream()->speed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("trim to edit"));
|
|
|
|
session->add_undo (region.playlist()->get_memento());
|
2006-02-07 08:58:33 -05:00
|
|
|
region.trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
|
2005-09-25 14:42:24 -04:00
|
|
|
session->add_redo_no_execute (region.playlist()->get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::unfreeze_route ()
|
|
|
|
{
|
|
|
|
if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
clicked_audio_trackview->audio_track()->unfreeze ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
Editor::_freeze_thread (void* arg)
|
|
|
|
{
|
|
|
|
PBD::ThreadCreated (pthread_self(), X_("Freeze"));
|
|
|
|
return static_cast<Editor*>(arg)->freeze_thread ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
Editor::freeze_thread ()
|
|
|
|
{
|
|
|
|
clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
|
|
|
|
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
|
|
|
|
Editor::freeze_route ()
|
|
|
|
{
|
|
|
|
if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterThreadInfo itt;
|
|
|
|
|
|
|
|
if (interthread_progress_window == 0) {
|
|
|
|
build_interthread_progress_window ();
|
|
|
|
}
|
|
|
|
|
|
|
|
interthread_progress_window->set_title (_("ardour: freeze"));
|
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;
|
|
|
|
|
|
|
|
pthread_create (&itt.thread, 0, _freeze_thread, this);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
|
|
|
|
|
|
|
|
jack_nframes_t start = selection->time[clicked_selection].start;
|
|
|
|
jack_nframes_t end = selection->time[clicked_selection].end;
|
|
|
|
jack_nframes_t cnt = end - start + 1;
|
|
|
|
|
|
|
|
begin_reversible_command (_("bounce range"));
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
|
|
|
|
|
|
|
|
AudioTimeAxisView* atv;
|
|
|
|
|
|
|
|
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist* playlist;
|
|
|
|
|
|
|
|
if ((playlist = atv->playlist()) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterThreadInfo itt;
|
|
|
|
|
|
|
|
itt.done = false;
|
|
|
|
itt.cancel = false;
|
|
|
|
itt.progress = false;
|
|
|
|
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
atv->audio_track()->bounce_range (start, cnt, itt);
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
|
|
|
delete views;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cut ()
|
|
|
|
{
|
|
|
|
cut_copy (Cut);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::copy ()
|
|
|
|
{
|
|
|
|
cut_copy (Copy);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ();
|
|
|
|
|
|
|
|
switch (current_mouse_mode()) {
|
|
|
|
case MouseObject:
|
|
|
|
if (!selection->audio_regions.empty() || !selection->points.empty()) {
|
|
|
|
|
|
|
|
begin_reversible_command (opname + _(" objects"));
|
|
|
|
|
|
|
|
if (!selection->audio_regions.empty()) {
|
|
|
|
|
|
|
|
cut_copy_regions (op);
|
|
|
|
|
|
|
|
if (op == Cut) {
|
|
|
|
selection->clear_audio_regions ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!selection->points.empty()) {
|
|
|
|
cut_copy_points (op);
|
|
|
|
|
|
|
|
if (op == Cut) {
|
|
|
|
selection->clear_points ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MouseRange:
|
|
|
|
if (!selection->time.empty()) {
|
|
|
|
|
|
|
|
begin_reversible_command (opname + _(" range"));
|
|
|
|
cut_copy_ranges (op);
|
|
|
|
commit_reversible_command ();
|
|
|
|
|
|
|
|
if (op == Cut) {
|
|
|
|
selection->clear_time ();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cut_copy_regions (CutCopyOp op)
|
|
|
|
{
|
2005-10-26 21:10:36 -04:00
|
|
|
typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
|
2005-09-25 14:42:24 -04:00
|
|
|
PlaylistMapping pmap;
|
|
|
|
jack_nframes_t first_position = max_frames;
|
|
|
|
set<Playlist*> freezelist;
|
|
|
|
pair<set<Playlist*>::iterator,bool> insert_result;
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) {
|
|
|
|
first_position = min ((*x)->region.position(), first_position);
|
|
|
|
|
|
|
|
if (op == Cut || op == Clear) {
|
|
|
|
AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
|
|
|
|
if (pl) {
|
|
|
|
insert_result = freezelist.insert (pl);
|
|
|
|
if (insert_result.second) {
|
|
|
|
pl->freeze ();
|
|
|
|
session->add_undo (pl->get_memento());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ) {
|
|
|
|
|
|
|
|
AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
|
|
|
|
AudioPlaylist* npl;
|
|
|
|
AudioRegionSelection::iterator tmp;
|
|
|
|
|
|
|
|
tmp = x;
|
|
|
|
++tmp;
|
|
|
|
|
|
|
|
if (pl) {
|
|
|
|
|
|
|
|
PlaylistMapping::iterator pi = pmap.find (pl);
|
|
|
|
|
|
|
|
if (pi == pmap.end()) {
|
|
|
|
npl = new AudioPlaylist (*session, "cutlist", true);
|
|
|
|
npl->freeze();
|
|
|
|
pmap[pl] = npl;
|
|
|
|
} else {
|
|
|
|
npl = pi->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case Cut:
|
|
|
|
npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
|
|
|
|
pl->remove_region (&((*x)->region));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Copy:
|
|
|
|
npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Clear:
|
|
|
|
pl->remove_region (&((*x)->region));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
x = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
list<Playlist*> foo;
|
|
|
|
|
|
|
|
for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
|
|
|
|
foo.push_back (i->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foo.empty()) {
|
|
|
|
cut_buffer->set (foo);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
|
|
|
|
(*pl)->thaw ();
|
|
|
|
session->add_redo_no_execute ((*pl)->get_memento());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::cut_copy_ranges (CutCopyOp op)
|
|
|
|
{
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
(*i)->cut_copy_clear (*selection, op);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::paste (float times)
|
|
|
|
{
|
|
|
|
paste_internal (edit_cursor->current_frame, times);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::mouse_paste ()
|
|
|
|
{
|
2005-11-24 09:59:36 -05:00
|
|
|
int x, y;
|
2005-09-25 14:42:24 -04:00
|
|
|
double wx, wy;
|
2006-01-02 15:27:51 -05:00
|
|
|
|
2005-10-26 21:10:36 -04:00
|
|
|
track_canvas.get_pointer (x, y);
|
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-09-25 14:42:24 -04:00
|
|
|
GdkEvent event;
|
|
|
|
event.type = GDK_BUTTON_RELEASE;
|
|
|
|
event.button.x = wx;
|
|
|
|
event.button.y = wy;
|
|
|
|
|
|
|
|
jack_nframes_t where = event_frame (&event, 0, 0);
|
|
|
|
snap_to (where);
|
|
|
|
paste_internal (where, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::paste_internal (jack_nframes_t position, float times)
|
|
|
|
{
|
|
|
|
bool commit = false;
|
|
|
|
|
|
|
|
if (cut_buffer->empty() || selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (position == max_frames) {
|
|
|
|
position = edit_cursor->current_frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command (_("paste"));
|
|
|
|
|
|
|
|
TrackSelection::iterator i;
|
|
|
|
size_t nth;
|
|
|
|
|
|
|
|
for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
|
|
|
|
|
|
|
|
/* undo/redo is handled by individual tracks */
|
|
|
|
|
|
|
|
if ((*i)->paste (position, times, *cut_buffer, nth)) {
|
|
|
|
commit = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
list<Playlist*>::iterator chunk;
|
|
|
|
list<Playlist*>::iterator tmp;
|
|
|
|
|
|
|
|
chunk = ns->playlists.begin();
|
|
|
|
|
|
|
|
begin_reversible_command (_("paste chunk"));
|
|
|
|
|
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
|
|
|
|
|
|
|
AudioTimeAxisView* atv;
|
|
|
|
Playlist* pl;
|
|
|
|
AudioPlaylist* apl;
|
|
|
|
|
2005-11-24 09:59:36 -05:00
|
|
|
if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
|
2005-09-25 14:42:24 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((pl = atv->playlist()) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = chunk;
|
|
|
|
++tmp;
|
|
|
|
|
|
|
|
session->add_undo (apl->get_memento());
|
|
|
|
apl->paste (**chunk, edit_cursor->current_frame, times);
|
|
|
|
session->add_redo_no_execute (apl->get_memento());
|
|
|
|
|
|
|
|
if (tmp != ns->playlists.end()) {
|
|
|
|
chunk = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::duplicate_some_regions (AudioRegionSelection& regions, float times)
|
|
|
|
{
|
|
|
|
Playlist *playlist;
|
2006-01-08 09:50:41 -05:00
|
|
|
AudioRegionSelection sel = regions; // clear (below) will clear the argument list
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
begin_reversible_command (_("duplicate region"));
|
|
|
|
|
2006-01-08 09:50:41 -05:00
|
|
|
selection->clear_audio_regions ();
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
Region& r ((*i)->region);
|
2006-01-08 01:08:15 -05:00
|
|
|
|
|
|
|
TimeAxisView& tv = (*i)->get_time_axis_view();
|
|
|
|
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
|
|
|
|
sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
playlist = (*i)->region.playlist();
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
playlist->duplicate (r, r.last_frame(), times);
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
|
2006-01-08 01:08:15 -05:00
|
|
|
c.disconnect ();
|
2006-01-08 09:50:41 -05:00
|
|
|
|
|
|
|
if (latest_regionview) {
|
|
|
|
selection->add (latest_regionview);
|
|
|
|
}
|
2006-01-08 01:08:15 -05:00
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::duplicate_selection (float times)
|
|
|
|
{
|
|
|
|
if (selection->time.empty() || selection->tracks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Playlist *playlist;
|
|
|
|
vector<AudioRegion*> new_regions;
|
|
|
|
vector<AudioRegion*>::iterator ri;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
playlist->duplicate (**ri, selection->time[clicked_selection].end, times);
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
|
|
|
|
++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 */
|
|
|
|
|
|
|
|
cerr << "point selection has " << selection->points.size() << " entries\n";
|
|
|
|
|
|
|
|
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
|
|
|
|
Editor::center_edit_cursor ()
|
|
|
|
{
|
|
|
|
float page = canvas_width * frames_per_unit;
|
|
|
|
|
|
|
|
center_screen_internal (edit_cursor->current_frame, page);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::clear_playlist (Playlist& playlist)
|
|
|
|
{
|
|
|
|
begin_reversible_command (_("clear playlist"));
|
|
|
|
session->add_undo (playlist.get_memento());
|
|
|
|
playlist.clear ();
|
|
|
|
session->add_redo_no_execute (playlist.get_memento());
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::nudge_track (bool use_edit_cursor, bool forwards)
|
|
|
|
{
|
|
|
|
Playlist *playlist;
|
|
|
|
jack_nframes_t distance;
|
|
|
|
jack_nframes_t next_distance;
|
|
|
|
jack_nframes_t start;
|
|
|
|
|
|
|
|
if (use_edit_cursor) {
|
|
|
|
start = edit_cursor->current_frame;
|
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
playlist->nudge_after (start, distance, forwards);
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
Editor::normalize_region ()
|
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
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 ();
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
|
|
|
|
session->add_undo ((*r)->region.get_memento());
|
|
|
|
(*r)->region.normalize_to (0.0f);
|
|
|
|
session->add_redo_no_execute ((*r)->region.get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
Editor::denormalize_region ()
|
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_command ("denormalize");
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
|
|
|
|
session->add_undo ((*r)->region.get_memento());
|
|
|
|
(*r)->region.set_scale_amplitude (1.0f);
|
|
|
|
session->add_redo_no_execute ((*r)->region.get_memento());
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::reverse_region ()
|
|
|
|
{
|
|
|
|
if (!session) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Reverse rev (*session);
|
|
|
|
apply_filter (rev, _("reverse regions"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::apply_filter (AudioFilter& filter, string command)
|
|
|
|
{
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
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 ();
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ) {
|
|
|
|
|
|
|
|
AudioRegion& region ((*r)->region);
|
|
|
|
Playlist* playlist = region.playlist();
|
|
|
|
|
|
|
|
AudioRegionSelection::iterator tmp;
|
|
|
|
|
|
|
|
tmp = r;
|
|
|
|
++tmp;
|
|
|
|
|
|
|
|
if (region.apply (filter) == 0) {
|
|
|
|
|
|
|
|
session->add_undo (playlist->get_memento());
|
|
|
|
playlist->replace_region (region, *(filter.results.front()), region.position());
|
|
|
|
session->add_redo_no_execute (playlist->get_memento());
|
|
|
|
} else {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_command ();
|
|
|
|
selection->audio_regions.clear ();
|
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
((*i)->region.*pmf)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
|
|
|
|
{
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
((*i)->region.*pmf)(arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
|
|
|
|
{
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
((*i)->region.*pmf)(yn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::external_edit_region ()
|
|
|
|
{
|
|
|
|
if (!clicked_regionview) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* more to come */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::brush (jack_nframes_t pos)
|
|
|
|
{
|
|
|
|
AudioRegionSelection sel;
|
|
|
|
snap_to (pos);
|
|
|
|
|
|
|
|
if (selection->audio_regions.empty()) {
|
|
|
|
/* XXX get selection from region list */
|
|
|
|
} else {
|
|
|
|
sel = selection->audio_regions;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sel.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
mouse_brush_insert_region ((*i), pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_gain_envelope_visibility ()
|
|
|
|
{
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
(*i)->set_envelope_visible (!(*i)->envelope_visible());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::toggle_gain_envelope_active ()
|
|
|
|
{
|
|
|
|
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
|
|
|
|
AudioRegion* ar = dynamic_cast<AudioRegion*>(&(*i)->region);
|
|
|
|
if (ar) {
|
|
|
|
ar->set_envelope_active (true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|