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 <pbd/error.h>
#include <pbd/basename.h>
#include <pbd/pthread_utils.h>
+#include <pbd/memento_command.h>
+#include <pbd/whitespace.h>
#include <gtkmm2ext/utils.h>
#include <gtkmm2ext/choice.h>
+#include <gtkmm2ext/window_title.h>
#include <ardour/audioengine.h>
#include <ardour/session.h>
#include <ardour/audio_track.h>
#include <ardour/audioplaylist.h>
#include <ardour/region_factory.h>
+#include <ardour/playlist_factory.h>
#include <ardour/reverse.h>
#include "ardour_ui.h"
#include "audio_time_axis.h"
#include "automation_time_axis.h"
#include "streamview.h"
-#include "regionview.h"
+#include "audio_region_view.h"
#include "rgb_macros.h"
#include "selection_templates.h"
#include "selection.h"
-#include "sfdb_ui.h"
#include "editing.h"
#include "gtk-custom-hruler.h"
#include "gui_thread.h"
using namespace PBD;
using namespace sigc;
using namespace Gtk;
+using namespace Gtkmm2ext;
using namespace Editing;
/***********************************************************************
}
}
-void
-Editor::set_meter_hold (int32_t cnt)
-{
- 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;
- }
-
- if (session) {
- session->set_meter_hold (cnt);
- }
-}
-
-void
-Editor::set_meter_falloff (int intval)
-{
- float val = 0.0f; /* off */
- std::string str;
-
- 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;
- }
-
- if (session) {
- session->set_meter_falloff (val);
- }
-}
-
-
-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);
+ split_region_at (get_preferred_edit_position());
}
void
-Editor::split_region_at (jack_nframes_t where)
+Editor::split_region_at (nframes_t where)
{
- split_regions_at (where, selection->audio_regions);
+ split_regions_at (where, selection->regions);
}
void
-Editor::split_regions_at (jack_nframes_t where, AudioRegionSelection& regions)
+Editor::split_regions_at (nframes_t where, RegionSelection& regions)
{
+ if (regions.empty()) {
+ return;
+ }
+
begin_reversible_command (_("split"));
- snap_to (where);
- for (AudioRegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
+ // if splitting a single region, and snap-to is using
+ // region boundaries, don't pay attention to them
+
+ if (regions.size() == 1) {
+ switch (snap_type) {
+ case SnapToRegionStart:
+ case SnapToRegionSync:
+ case SnapToRegionEnd:
+ break;
+ default:
+ snap_to (where);
+ }
+ } else {
+ snap_to (where);
+ }
+
+
+ for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
- AudioRegionSelection::iterator tmp;
+ RegionSelection::iterator tmp;
+
+ /* XXX this test needs to be more complicated, to make sure we really
+ have something to split.
+ */
+ if (!(*a)->region()->covers (where)) {
+ ++a;
+ continue;
+ }
+
tmp = a;
++tmp;
- Playlist* pl = (*a)->region.playlist();
+ boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
- _new_regionviews_show_envelope = (*a)->envelope_visible();
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
+
+ if (arv) {
+ _new_regionviews_show_envelope = arv->envelope_visible();
+ }
if (pl) {
- XMLNode &before, &after;
- before = pl->get_state();
- pl->split_region ((*a)->region, where);
- after = pl->get_state();
- session->add_command(MementoCommand<Playlist>(*pl, before, after));
+ XMLNode &before = pl->get_state();
+ pl->split_region ((*a)->region(), where);
+ XMLNode &after = pl->get_state();
+ session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
}
a = tmp;
- }
-
+ }
+
commit_reversible_command ();
_new_regionviews_show_envelope = false;
}
return;
}
- Playlist* playlist = clicked_audio_trackview->playlist();
+ boost::shared_ptr<Playlist> playlist = clicked_audio_trackview->playlist();
begin_reversible_command (_("remove region"));
XMLNode &before = playlist->get_state();
- playlist->remove_region (&clicked_regionview->region);
+ playlist->remove_region (clicked_regionview->region());
XMLNode &after = playlist->get_state();
- session->add_command(MementoCommand<Playlist>(*playlist, before, after));
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
commit_reversible_command ();
}
void
Editor::destroy_clicked_region ()
{
- int32_t selected = selection->audio_regions.size();
+ uint32_t selected = selection->regions.size();
- if (!session || clicked_regionview == 0 && selected == 0) {
+ if (!session || !selected) {
return;
}
return;
}
- if (selected > 0) {
- list<Region*> r;
+ if (selected) {
+ list<boost::shared_ptr<Region> > r;
- for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
- r.push_back (&(*i)->region);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ r.push_back ((*i)->region());
}
session->destroy_regions (r);
-
- } else if (clicked_regionview) {
- session->destroy_region (&clicked_regionview->region);
}
}
-AudioRegion *
+boost::shared_ptr<Region>
Editor::select_region_for_operation (int dir, TimeAxisView **tv)
{
- AudioRegionView* rv;
- AudioRegion *region;
- jack_nframes_t start = 0;
+ RegionView* rv;
+ boost::shared_ptr<Region> region;
+ 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;
+ if (selection->regions.empty()) {
+ return region;
}
}
- region = 0;
-
- if (!selection->audio_regions.empty()) {
+ if (!selection->regions.empty()) {
- rv = *(selection->audio_regions.begin());
+ rv = *(selection->regions.begin());
(*tv) = &rv->get_time_axis_view();
- region = &rv->region;
+ region = rv->region();
} else if (!selection->tracks.empty()) {
(*tv) = selection->tracks.front();
- AudioTimeAxisView* atv;
+ RouteTimeAxisView* rtv;
- if ((atv = dynamic_cast<AudioTimeAxisView*> (*tv)) != 0) {
- Playlist *pl;
+ if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
+ boost::shared_ptr<Playlist> pl;
- if ((pl = atv->playlist()) == 0) {
- return 0;
+ if ((pl = rtv->playlist()) == 0) {
+ return region;
}
- region = dynamic_cast<AudioRegion*> (pl->top_region_at (start));
+ region = pl->top_region_at (start);
}
}
Editor::extend_selection_to_end_of_region (bool next)
{
TimeAxisView *tv;
- Region *region;
- jack_nframes_t start;
+ boost::shared_ptr<Region> region;
+ nframes_t start;
if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
return;
Editor::extend_selection_to_start_of_region (bool previous)
{
TimeAxisView *tv;
- Region *region;
- jack_nframes_t end;
+ boost::shared_ptr<Region> region;
+ nframes_t end;
if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
return;
void
Editor::nudge_forward (bool next)
{
- jack_nframes_t distance;
- jack_nframes_t next_distance;
+ nframes_t distance;
+ nframes_t next_distance;
if (!session) return;
- if (!selection->audio_regions.empty()) {
+ if (!selection->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);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ boost::shared_ptr<Region> r ((*i)->region());
- distance = get_nudge_distance (r.position(), next_distance);
+ distance = get_nudge_distance (r->position(), next_distance);
if (next) {
distance = next_distance;
}
- XMLNode &before = r.playlist()->get_state();
- r.set_position (r.position() + distance, this);
- XMLNode &after = r.playlist()->get_state();
- session->add_command (MementoCommand<Playlist>(*(r.playlist()), before, after));
+ XMLNode &before = r->playlist()->get_state();
+ r->set_position (r->position() + distance, this);
+ XMLNode &after = r->playlist()->get_state();
+ session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
}
commit_reversible_command ();
+
+ } else if (!selection->markers.empty()) {
+
+ bool ignored;
+ Location* loc = find_location_from_marker (selection->markers.front(), ignored);
+
+ if (loc) {
+ distance = get_nudge_distance (loc->start(), next_distance);
+ loc->set_start (loc->start() + distance);
+ }
+
} 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;
+ nframes_t distance;
+ nframes_t next_distance;
if (!session) return;
- if (!selection->audio_regions.empty()) {
+ if (!selection->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);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ boost::shared_ptr<Region> r ((*i)->region());
- distance = get_nudge_distance (r.position(), next_distance);
+ distance = get_nudge_distance (r->position(), next_distance);
if (next) {
distance = next_distance;
}
- XMLNode &before = r.playlist()->get_state();
+ XMLNode &before = r->playlist()->get_state();
- if (r.position() > distance) {
- r.set_position (r.position() - distance, this);
+ if (r->position() > distance) {
+ r->set_position (r->position() - distance, this);
} else {
- r.set_position (0, this);
+ r->set_position (0, this);
}
- XMLNode &after = r.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(r.playlist()), before, after));
+ XMLNode &after = r->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
}
commit_reversible_command ();
void
Editor::nudge_forward_capture_offset ()
{
- jack_nframes_t distance;
+ nframes_t distance;
if (!session) return;
- if (!selection->audio_regions.empty()) {
+ if (!selection->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);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ boost::shared_ptr<Region> r ((*i)->region());
- XMLNode &before, &after;
- before = r.playlist()->get_state();
- r.set_position (r.position() + distance, this);
- after = r.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(r.playlist()), before, after));
+ XMLNode &before = r->playlist()->get_state();
+ r->set_position (r->position() + distance, this);
+ XMLNode &after = r->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
}
commit_reversible_command ();
void
Editor::nudge_backward_capture_offset ()
{
- jack_nframes_t distance;
+ nframes_t distance;
if (!session) return;
- if (!selection->audio_regions.empty()) {
+ if (!selection->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);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ boost::shared_ptr<Region> r ((*i)->region());
- XMLNode &before = r.playlist()->get_state();
+ XMLNode &before = r->playlist()->get_state();
- if (r.position() > distance) {
- r.set_position (r.position() - distance, this);
+ if (r->position() > distance) {
+ r->set_position (r->position() - distance, this);
} else {
- r.set_position (0, this);
+ r->set_position (0, this);
}
- XMLNode &after = r.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(r.playlist()), before, after));
+ XMLNode &after = r->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
}
commit_reversible_command ();
void
Editor::build_region_boundary_cache ()
{
- jack_nframes_t pos = 0;
- RegionPoint point;
- Region *r;
+ nframes_t pos = 0;
+ vector<RegionPoint> interesting_points;
+ boost::shared_ptr<Region> r;
TrackViewList tracks;
+ bool at_end = false;
region_boundary_cache.clear ();
switch (snap_type) {
case SnapToRegionStart:
- point = Start;
+ interesting_points.push_back (Start);
break;
case SnapToRegionEnd:
- point = End;
+ interesting_points.push_back (End);
break;
case SnapToRegionSync:
- point = SyncPoint;
+ interesting_points.push_back (SyncPoint);
break;
case SnapToRegionBoundary:
- point = Start;
+ interesting_points.push_back (Start);
+ interesting_points.push_back (End);
break;
default:
fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
}
TimeAxisView *ontrack = 0;
+ TrackViewList tlist;
- while (pos < session->current_end_frame()) {
+ if (!selection->tracks.empty()) {
+ tlist = selection->tracks;
+ } else {
+ tlist = track_views;
+ }
- if (!selection->tracks.empty()) {
+ while (pos < session->current_end_frame() && !at_end) {
- if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
- break;
- }
+ nframes_t rpos;
+ nframes_t lpos = max_frames;
- } else if (clicked_trackview) {
+ for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
- TrackViewList t;
- t.push_back (clicked_trackview);
+ if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
+ if (*p == interesting_points.back()) {
+ at_end = true;
+ }
+ /* move to next point type */
+ continue;
+ }
- if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
+ switch (*p) {
+ case Start:
+ rpos = r->first_frame();
break;
- }
- } else {
+ case End:
+ rpos = r->last_frame();
+ break;
+
+ case SyncPoint:
+ rpos = r->adjust_to_sync (r->first_frame());
+ break;
- if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
+ 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();
+ }
+ }
+
+ rpos = track_frame_to_session_frame (rpos, speed);
- 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;
+ if (rpos < lpos) {
+ lpos = rpos;
+ }
- case SnapToRegionBoundary:
- rpos = r->last_frame();
- break;
- default:
- break;
- }
-
- float speed = 1.0f;
- AudioTimeAxisView *atav;
+ /* prevent duplicates, but we don't use set<> because we want to be able
+ to sort later.
+ */
- if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
- if (atav->get_diskstream() != 0) {
- speed = atav->get_diskstream()->speed();
+ vector<nframes_t>::iterator ri;
+
+ for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
+ if (*ri == rpos) {
+ break;
+ }
}
- }
- rpos = track_frame_to_session_frame(rpos, speed);
-
- if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
- if (snap_type == SnapToRegionBoundary) {
- region_boundary_cache.push_back (r->first_frame());
+ if (ri == region_boundary_cache.end()) {
+ region_boundary_cache.push_back (rpos);
}
- region_boundary_cache.push_back (rpos);
}
- pos = rpos + 1;
+ pos = lpos + 1;
}
+
+ /* finally sort to be sure that the order is correct */
+
+ sort (region_boundary_cache.begin(), region_boundary_cache.end());
}
-Region*
-Editor::find_next_region (jack_nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
+boost::shared_ptr<Region>
+Editor::find_next_region (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;
+ nframes_t closest = max_frames;
+ boost::shared_ptr<Region> ret;
+ nframes_t rpos = 0;
float track_speed;
- jack_nframes_t track_frame;
+ nframes_t track_frame;
AudioTimeAxisView *atav;
for (i = tracks.begin(); i != tracks.end(); ++i) {
- jack_nframes_t distance;
- Region* r;
-
+ nframes_t distance;
+ boost::shared_ptr<Region> r;
+
track_speed = 1.0f;
if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
if (atav->get_diskstream()!=0)
rpos = r->adjust_to_sync (r->first_frame());
break;
}
+
// rpos is a "track frame", converting it to "session frame"
rpos = track_frame_to_session_frame(rpos, track_speed);
return ret;
}
+nframes64_t
+Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackViewList& tracks)
+{
+ nframes64_t distance = max_frames;
+ nframes64_t current_nearest = -1;
+
+ for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
+ nframes64_t contender;
+ nframes64_t d;
+
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
+
+ if (!rtv) {
+ continue;
+ }
+
+ if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
+ continue;
+ }
+
+ d = ::llabs (pos - contender);
+
+ if (d < distance) {
+ current_nearest = contender;
+ distance = d;
+ }
+ }
+
+ return current_nearest;
+}
+
+void
+Editor::cursor_to_region_boundary (Cursor* cursor, int32_t dir)
+{
+ nframes64_t pos = cursor->current_frame;
+ nframes64_t target;
+
+ if (!session) {
+ return;
+ }
+
+ // so we don't find the current region again..
+ if (dir > 0 || pos > 0) {
+ pos += dir;
+ }
+
+ if (!selection->tracks.empty()) {
+
+ target = find_next_region_boundary (pos, dir, selection->tracks);
+
+ } else {
+
+ target = find_next_region_boundary (pos, dir, track_views);
+ }
+
+ if (target < 0) {
+ return;
+ }
+
+
+ if (cursor == playhead_cursor) {
+ session->request_locate (target);
+ } else {
+ cursor->set_position (target);
+ }
+}
+
+void
+Editor::cursor_to_next_region_boundary (Cursor* cursor)
+{
+ cursor_to_region_boundary (cursor, 1);
+}
+
+void
+Editor::cursor_to_previous_region_boundary (Cursor* cursor)
+{
+ cursor_to_region_boundary (cursor, -1);
+}
+
void
Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
{
- Region* r;
- jack_nframes_t pos = cursor->current_frame;
+ boost::shared_ptr<Region> r;
+ nframes_t pos = cursor->current_frame;
if (!session) {
return;
void
Editor::cursor_to_selection_start (Cursor *cursor)
{
- jack_nframes_t pos = 0;
+ nframes_t pos = 0;
switch (mouse_mode) {
case MouseObject:
- if (!selection->audio_regions.empty()) {
- pos = selection->audio_regions.start();
+ if (!selection->regions.empty()) {
+ pos = selection->regions.start();
}
break;
void
Editor::cursor_to_selection_end (Cursor *cursor)
{
- jack_nframes_t pos = 0;
+ nframes_t pos = 0;
switch (mouse_mode) {
case MouseObject:
- if (!selection->audio_regions.empty()) {
- pos = selection->audio_regions.end_frame();
+ if (!selection->regions.empty()) {
+ pos = selection->regions.end_frame();
}
break;
}
void
-Editor::playhead_backward ()
+Editor::selected_marker_to_region_boundary (int32_t dir)
{
- jack_nframes_t pos;
- jack_nframes_t cnt;
- float prefix;
- bool was_floating;
+ nframes64_t target;
+ Location* loc;
+ bool ignored;
- 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;
- }
+ if (!session) {
+ return;
}
- pos = playhead_cursor->current_frame;
+ if (selection->markers.empty()) {
+ nframes64_t mouse;
+ bool ignored;
- if ((jack_nframes_t) pos < cnt) {
- pos = 0;
- } else {
- pos -= cnt;
+ if (!mouse_frame (mouse, ignored)) {
+ return;
+ }
+
+ add_location_mark (mouse);
}
-
- /* 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);
-}
+ if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
+ return;
+ }
-void
-Editor::playhead_forward ()
-{
- jack_nframes_t pos;
- jack_nframes_t cnt;
- bool was_floating;
- float prefix;
+ nframes64_t pos = loc->start();
- 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);
- }
+ // so we don't find the current region again..
+ if (dir > 0 || pos > 0) {
+ pos += dir;
}
- pos = playhead_cursor->current_frame;
+ if (!selection->tracks.empty()) {
+
+ target = find_next_region_boundary (pos, dir, selection->tracks);
+
+ } else {
+
+ target = find_next_region_boundary (pos, dir, track_views);
+ }
- /* 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 !!!
- */
+ if (target < 0) {
+ return;
+ }
- session->request_locate (pos+cnt);
+ loc->move_to (target);
}
void
-Editor::cursor_align (bool playhead_to_edit)
+Editor::selected_marker_to_next_region_boundary ()
{
- if (playhead_to_edit) {
- if (session) {
- session->request_locate (edit_cursor->current_frame);
- }
- } else {
- edit_cursor->set_position (playhead_cursor->current_frame);
- }
+ selected_marker_to_region_boundary (1);
}
void
-Editor::edit_cursor_backward ()
+Editor::selected_marker_to_previous_region_boundary ()
{
- 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);
+ selected_marker_to_region_boundary (-1);
}
void
-Editor::edit_cursor_forward ()
+Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
{
- jack_nframes_t pos;
- jack_nframes_t cnt;
- bool was_floating;
- float prefix;
+ boost::shared_ptr<Region> r;
+ nframes_t pos;
+ Location* loc;
+ bool ignored;
- 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);
- }
+ if (!session || selection->markers.empty()) {
+ return;
}
- 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)) {
+ if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
return;
}
- if (was_floating) {
- frame = (jack_nframes_t) floor (prefix * session->frame_rate());
- } else {
- frame = (jack_nframes_t) floor (prefix);
- }
+ TimeAxisView *ontrack = 0;
- session->request_locate (frame);
-}
+ pos = loc->start();
-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);
- }
- }
+ // so we don't find the current region again..
+ if (dir>0 || pos>0)
+ pos+=dir;
- if (leftmost_frame < cnt) {
- frame = 0;
+ 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 {
- frame = leftmost_frame - cnt;
+
+ 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();
+ }
}
- reposition_x_origin (frame);
+ pos = track_frame_to_session_frame(pos, speed);
+
+ loc->move_to (pos);
}
void
-Editor::scroll_forward (float pages)
+Editor::selected_marker_to_next_region_point (RegionPoint point)
{
- jack_nframes_t frame;
- jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
- bool was_floating;
+ selected_marker_to_region_point (point, 1);
+}
+
+void
+Editor::selected_marker_to_previous_region_point (RegionPoint point)
+{
+ selected_marker_to_region_point (point, -1);
+}
+
+void
+Editor::selected_marker_to_selection_start ()
+{
+ nframes_t pos = 0;
+ Location* loc;
+ bool ignored;
+
+ if (!session || selection->markers.empty()) {
+ return;
+ }
+
+ if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
+ return;
+ }
+
+ switch (mouse_mode) {
+ case MouseObject:
+ if (!selection->regions.empty()) {
+ pos = selection->regions.start();
+ }
+ break;
+
+ case MouseRange:
+ if (!selection->time.empty()) {
+ pos = selection->time.start ();
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ loc->move_to (pos);
+}
+
+void
+Editor::selected_marker_to_selection_end ()
+{
+ nframes_t pos = 0;
+ Location* loc;
+ bool ignored;
+
+ if (!session || selection->markers.empty()) {
+ return;
+ }
+
+ if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
+ return;
+ }
+
+ switch (mouse_mode) {
+ case MouseObject:
+ if (!selection->regions.empty()) {
+ pos = selection->regions.end_frame();
+ }
+ break;
+
+ case MouseRange:
+ if (!selection->time.empty()) {
+ pos = selection->time.end_frame ();
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ loc->move_to (pos);
+}
+
+void
+Editor::scroll_playhead (bool forward)
+{
+ nframes_t pos = playhead_cursor->current_frame;
+ nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8);
+
+ if (forward) {
+ if (pos == max_frames) {
+ return;
+ }
+
+ if (pos < max_frames - delta) {
+ pos += delta ;
+ } else {
+ pos = max_frames;
+ }
+
+ } else {
+
+ if (pos == 0) {
+ return;
+ }
+
+ if (pos > delta) {
+ pos -= delta;
+ } else {
+ pos = 0;
+ }
+ }
+
+ session->request_locate (pos);
+}
+
+void
+Editor::playhead_backward ()
+{
+ nframes_t pos;
+ nframes_t cnt;
float prefix;
- jack_nframes_t cnt;
-
+ bool was_floating;
+
if (get_prefix (prefix, was_floating)) {
- cnt = (jack_nframes_t) floor (pages * one_page);
+ cnt = 1;
} else {
if (was_floating) {
- cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
+ cnt = (nframes_t) floor (prefix * session->frame_rate ());
} else {
- cnt = (jack_nframes_t) floor (prefix * one_page);
+ cnt = (nframes_t) prefix;
}
}
- if (ULONG_MAX - cnt < leftmost_frame) {
- frame = ULONG_MAX - cnt;
+ pos = playhead_cursor->current_frame;
+
+ if ((nframes_t) pos < cnt) {
+ pos = 0;
} else {
- frame = leftmost_frame + cnt;
+ 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 !!!
+ */
- reposition_x_origin (frame);
+ session->request_locate (pos);
}
void
-Editor::scroll_tracks_down ()
+Editor::playhead_forward ()
{
- float prefix;
+ nframes_t pos;
+ nframes_t cnt;
bool was_floating;
- int cnt;
+ float prefix;
if (get_prefix (prefix, was_floating)) {
cnt = 1;
} else {
- cnt = (int) floor (prefix);
+ if (was_floating) {
+ cnt = (nframes_t) floor (prefix * session->frame_rate ());
+ } else {
+ cnt = (nframes_t) floor (prefix);
+ }
}
- 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;
+ 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 (!session) {
+ return;
+ }
+
+ if (playhead_to_edit) {
+
+ if (selection->markers.empty()) {
+ return;
+ }
+
+ session->request_locate (selection->markers.front()->position(), session->transport_rolling());
+
+ } else {
+
+ /* move selected markers to playhead */
+
+ for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
+ bool ignored;
+
+ Location* loc = find_location_from_marker (*i, ignored);
+
+ if (loc->is_mark()) {
+ loc->set_start (playhead_cursor->current_frame);
+ } else {
+ loc->set (playhead_cursor->current_frame,
+ playhead_cursor->current_frame + loc->length());
+ }
+ }
}
- vertical_adjustment.set_value (vert_value);
}
void
-Editor::scroll_tracks_up ()
+Editor::edit_cursor_backward ()
{
+ nframes64_t pos;
+ nframes64_t cnt;
float prefix;
bool was_floating;
- int cnt;
if (get_prefix (prefix, was_floating)) {
cnt = 1;
} else {
- cnt = (int) floor (prefix);
+ if (was_floating) {
+ cnt = (nframes_t) floor (prefix * session->frame_rate ());
+ } else {
+ cnt = (nframes_t) prefix;
+ }
}
- vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
+ if ((pos = get_preferred_edit_position()) < 0) {
+ return;
+ }
+
+ if (pos < cnt) {
+ pos = 0;
+ } else {
+ pos -= cnt;
+ }
+
+ // EDIT CURSOR edit_cursor->set_position (pos);
+}
+
+void
+Editor::edit_cursor_forward ()
+{
+ //nframes_t pos;
+ nframes_t cnt;
+ bool was_floating;
+ float prefix;
+
+ if (get_prefix (prefix, was_floating)) {
+ cnt = 1;
+ } else {
+ if (was_floating) {
+ cnt = (nframes_t) floor (prefix * session->frame_rate ());
+ } else {
+ cnt = (nframes_t) floor (prefix);
+ }
+ }
+
+ // pos = edit_cursor->current_frame;
+ // EDIT CURSOR edit_cursor->set_position (pos+cnt);
}
-void
-Editor::scroll_tracks_down_line ()
-{
+void
+Editor::goto_frame ()
+{
+ float prefix;
+ bool was_floating;
+ nframes_t frame;
+
+ if (get_prefix (prefix, was_floating)) {
+ return;
+ }
+
+ if (was_floating) {
+ frame = (nframes_t) floor (prefix * session->frame_rate());
+ } else {
+ frame = (nframes_t) floor (prefix);
+ }
+
+ session->request_locate (frame);
+}
+
+void
+Editor::scroll_backward (float pages)
+{
+ nframes_t frame;
+ nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
+ bool was_floating;
+ float prefix;
+ nframes_t cnt;
+
+ if (get_prefix (prefix, was_floating)) {
+ cnt = (nframes_t) floor (pages * one_page);
+ } else {
+ if (was_floating) {
+ cnt = (nframes_t) floor (prefix * session->frame_rate());
+ } else {
+ cnt = (nframes_t) floor (prefix * one_page);
+ }
+ }
+
+ if (leftmost_frame < cnt) {
+ frame = 0;
+ } else {
+ frame = leftmost_frame - cnt;
+ }
+
+ reset_x_origin (frame);
+}
+
+void
+Editor::scroll_forward (float pages)
+{
+ nframes_t frame;
+ nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
+ bool was_floating;
+ float prefix;
+ nframes_t cnt;
+
+ if (get_prefix (prefix, was_floating)) {
+ cnt = (nframes_t) floor (pages * one_page);
+ } else {
+ if (was_floating) {
+ cnt = (nframes_t) floor (prefix * session->frame_rate());
+ } else {
+ cnt = (nframes_t) floor (prefix * one_page);
+ }
+ }
+
+ if (max_frames - cnt < leftmost_frame) {
+ frame = max_frames - cnt;
+ } else {
+ frame = leftmost_frame + cnt;
+ }
+
+ reset_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);
+ }
+
+ 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);
+}
+
+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);
+ }
+
+ vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
+}
+
+void
+Editor::scroll_tracks_down_line ()
+{
+
+ Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
+ 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);
+}
+
+void
+Editor::scroll_tracks_up_line ()
+{
+ Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
+ adj->set_value (adj->get_value() - 20);
+}
+
+/* ZOOM */
+
+void
+Editor::temporal_zoom_step (bool coarser)
+{
+ ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
+
+ double nfpu;
+
+ nfpu = frames_per_unit;
+
+ if (coarser) {
+ nfpu *= 1.61803399;
+ } else {
+ nfpu = max(1.0,(nfpu/1.61803399));
+ }
+
+ temporal_zoom (nfpu);
+}
+
+void
+Editor::temporal_zoom (gdouble fpu)
+{
+ if (!session) return;
+
+ nframes64_t current_page = current_page_frames();
+ nframes64_t current_leftmost = leftmost_frame;
+ nframes64_t current_rightmost;
+ nframes64_t current_center;
+ nframes64_t new_page;
+ nframes64_t leftmost_after_zoom = 0;
+ nframes64_t where;
+ bool in_track_canvas;
+ double nfpu;
+
+ nfpu = fpu;
+
+ new_page = (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 ZoomFocusMouse:
+ /* try to keep the mouse over the same point in the display */
+
+ if (!mouse_frame (where, in_track_canvas)) {
+ /* use playhead instead */
+ where = playhead_cursor->current_frame;
+
+ if (where > new_page/2) {
+ leftmost_after_zoom = where - (new_page/2);
+ } else {
+ leftmost_after_zoom = 0;
+ }
+
+ } else {
+
+ double l = - ((new_page * ((where - current_leftmost)/(double)current_page)) - where);
+
+ if (l < 0) {
+ leftmost_after_zoom = 0;
+ } else if (l > max_frames) {
+ leftmost_after_zoom = max_frames - new_page;
+ } else {
+ leftmost_after_zoom = (nframes64_t) l;
+ }
+ }
+
+ break;
+
+ case ZoomFocusEdit:
+ /* try to keep the edit point in the center */
+ if (get_preferred_edit_position() > new_page/2) {
+ leftmost_after_zoom = get_preferred_edit_position() - (new_page/2);
+ } else {
+ leftmost_after_zoom = 0;
+ }
+ break;
+
+ }
+
+ // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
+
+// begin_reversible_command (_("zoom"));
+// 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));
+// commit_reversible_command ();
+
+ // cerr << "repos & zoom to " << leftmost_after_zoom << " @ " << nfpu << endl;
+
+ reposition_and_zoom (leftmost_after_zoom, nfpu);
+}
+
+void
+Editor::temporal_zoom_region ()
+{
+
+ nframes64_t start = max_frames;
+ nframes64_t end = 0;
+
+ ensure_entered_region_selected (true);
+
+ if (selection->regions.empty()) {
+ info << _("cannot set loop: no region selected") << endmsg;
+ return;
+ }
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ if ((*i)->region()->position() < start) {
+ start = (*i)->region()->position();
+ }
+ if ((*i)->region()->last_frame() + 1 > end) {
+ end = (*i)->region()->last_frame() + 1;
+ }
+ }
+
+ /* now comes an "interesting" hack ... make sure we leave a little space
+ at each end of the editor so that the zoom doesn't fit the region
+ precisely to the screen.
+ */
+
+ GdkScreen* screen = gdk_screen_get_default ();
+ gint pixwidth = gdk_screen_get_width (screen);
+ gint mmwidth = gdk_screen_get_width_mm (screen);
+ double pix_per_mm = (double) pixwidth/ (double) mmwidth;
+ double one_centimeter_in_pixels = pix_per_mm * 10.0;
+ nframes_t extra_samples = unit_to_frame (one_centimeter_in_pixels);
+
+ if (start > extra_samples) {
+ start -= extra_samples;
+ } else {
+ start = 0;
+ }
+
+ if (max_frames - extra_samples > end) {
+ end += extra_samples;
+ } else {
+ end = max_frames;
+ }
+
+ temporal_zoom_by_frame (start, end, "zoom to region");
+ zoomed_to_region = true;
+}
+
+void
+Editor::toggle_zoom_region ()
+{
+ if (zoomed_to_region) {
+ swap_visual_state ();
+ } else {
+ temporal_zoom_region ();
+ }
+}
+
+void
+Editor::temporal_zoom_selection ()
+{
+ if (!selection) return;
+
+ if (selection->time.empty()) {
+ return;
+ }
+
+ nframes_t start = selection->time[clicked_selection].start;
+ nframes_t end = selection->time[clicked_selection].end;
+
+ temporal_zoom_by_frame (start, end, "zoom to selection");
+}
+
+void
+Editor::temporal_zoom_session ()
+{
+ ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
+
+ if (session) {
+ temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
+ }
+}
+
+void
+Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
+{
+ if (!session) return;
+
+ if ((start == 0 && end == 0) || end < start) {
+ return;
+ }
+
+ 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;
+
+ nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
+ nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
+ nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
+
+ if (new_leftmost > middle) new_leftmost = 0;
+
+// begin_reversible_command (op);
+// 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));
+// commit_reversible_command ();
+
+ reposition_and_zoom (new_leftmost, new_fpu);
+}
+
+void
+Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
+{
+ if (!session) return;
+
+ double range_before = frame - leftmost_frame;
+ double new_fpu;
+
+ new_fpu = frames_per_unit;
+
+ if (coarser) {
+ new_fpu *= 1.61803399;
+ range_before *= 1.61803399;
+ } else {
+ new_fpu = max(1.0,(new_fpu/1.61803399));
+ range_before /= 1.61803399;
+ }
+
+ if (new_fpu == frames_per_unit) return;
+
+ nframes_t new_leftmost = frame - (nframes_t)range_before;
+
+ if (new_leftmost > frame) new_leftmost = 0;
+
+// begin_reversible_command (_("zoom to frame"));
+// 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));
+// commit_reversible_command ();
+
+ reposition_and_zoom (new_leftmost, new_fpu);
+}
+
+void
+Editor::add_location_from_selection ()
+{
+ string rangename;
+
+ if (selection->time.empty()) {
+ return;
+ }
+
+ if (session == 0 || clicked_trackview == 0) {
+ return;
+ }
+
+ nframes_t start = selection->time[clicked_selection].start;
+ nframes_t end = selection->time[clicked_selection].end;
+
+ session->locations()->next_available_name(rangename,"selection");
+ Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
+
+ session->begin_reversible_command (_("add marker"));
+ XMLNode &before = session->locations()->get_state();
+ session->locations()->add (location, true);
+ XMLNode &after = session->locations()->get_state();
+ session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
+ session->commit_reversible_command ();
+}
+
+void
+Editor::add_location_mark (nframes64_t where)
+{
+ string markername;
+
+ select_new_marker = true;
+
+ session->locations()->next_available_name(markername,"mark");
+ Location *location = new Location (where, where, markername, Location::IsMark);
+ session->begin_reversible_command (_("add marker"));
+ XMLNode &before = session->locations()->get_state();
+ session->locations()->add (location, true);
+ XMLNode &after = session->locations()->get_state();
+ session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
+ session->commit_reversible_command ();
+}
+
+void
+Editor::add_location_from_playhead_cursor ()
+{
+ add_location_mark (session->audible_frame());
+}
+
+void
+Editor::add_location_from_audio_region ()
+{
+ if (selection->regions.empty()) {
+ return;
+ }
+
+ RegionView* rv = *(selection->regions.begin());
+ boost::shared_ptr<Region> region = rv->region();
+
+ Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
+ session->begin_reversible_command (_("add marker"));
+ XMLNode &before = session->locations()->get_state();
+ session->locations()->add (location, true);
+ XMLNode &after = session->locations()->get_state();
+ session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
+ session->commit_reversible_command ();
+}
+
+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 {
+ session->goto_start ();
+ }
+}
+
+void
+Editor::set_mark ()
+{
+ nframes_t pos;
+ float prefix;
+ bool was_floating;
+ string markername;
+
+ if (get_prefix (prefix, was_floating)) {
+ pos = session->audible_frame ();
+ } else {
+ if (was_floating) {
+ pos = (nframes_t) floor (prefix * session->frame_rate ());
+ } else {
+ pos = (nframes_t) floor (prefix);
+ }
+ }
+
+ session->locations()->next_available_name(markername,"mark");
+ session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
+}
+
+void
+Editor::clear_markers ()
+{
+ if (session) {
+ session->begin_reversible_command (_("clear markers"));
+ XMLNode &before = session->locations()->get_state();
+ session->locations()->clear_markers ();
+ XMLNode &after = session->locations()->get_state();
+ session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
+ session->commit_reversible_command ();
+ }
+}
+
+void
+Editor::clear_ranges ()
+{
+ if (session) {
+ session->begin_reversible_command (_("clear ranges"));
+ XMLNode &before = session->locations()->get_state();
+
+ 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);
+
+ XMLNode &after = session->locations()->get_state();
+ session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
+ session->commit_reversible_command ();
+ }
+}
+
+void
+Editor::clear_locations ()
+{
+ session->begin_reversible_command (_("clear locations"));
+ XMLNode &before = session->locations()->get_state();
+ session->locations()->clear ();
+ XMLNode &after = session->locations()->get_state();
+ session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
+ session->commit_reversible_command ();
+ session->locations()->clear ();
+}
+
+void
+Editor::unhide_markers ()
+{
+ for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
+ Location *l = (*i).first;
+ if (l->is_hidden() && l->is_mark()) {
+ l->set_hidden(false, this);
+ }
+ }
+}
+
+void
+Editor::unhide_ranges ()
+{
+ for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
+ Location *l = (*i).first;
+ if (l->is_hidden() && l->is_range_marker()) {
+ l->set_hidden(false, this);
+ }
+ }
+}
+
+/* INSERT/REPLACE */
+
+void
+Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
+{
+ double wx, wy;
+ double cx, cy;
+ TimeAxisView *tv;
+ nframes_t where;
+ AudioTimeAxisView *atv = 0;
+ boost::shared_ptr<Playlist> playlist;
+
+ track_canvas.window_to_world (x, y, wx, wy);
+ wx += horizontal_adjustment.get_value();
+ wy += vertical_adjustment.get_value();
+
+ 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"));
+ XMLNode &before = playlist->get_state();
+ playlist->add_region (RegionFactory::create (region), where, 1.0);
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
+ commit_reversible_command ();
+}
+
+void
+Editor::insert_region_list_selection (float times)
+{
+ RouteTimeAxisView *tv = 0;
+ boost::shared_ptr<Playlist> playlist;
+
+ if (clicked_audio_trackview != 0) {
+ tv = clicked_audio_trackview;
+ } else if (!selection->tracks.empty()) {
+ if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
+ return;
+ }
+ } else if (entered_track != 0) {
+ if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
+ return;
+ }
+ } else {
+ return;
+ }
+
+ if ((playlist = tv->playlist()) == 0) {
+ return;
+ }
+
+ Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
+
+ if (selected->count_selected_rows() != 1) {
+ return;
+ }
+
+ TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
+
+ /* only one row selected, so rows.begin() is it */
+
+ TreeIter iter;
+
+ if ((iter = region_list_model->get_iter (*rows.begin()))) {
+
+ boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
+
+ begin_reversible_command (_("insert region"));
+ XMLNode &before = playlist->get_state();
+ playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
+ commit_reversible_command ();
+ }
+}
+
+/* BUILT-IN EFFECTS */
+
+void
+Editor::reverse_selection ()
+{
+
+}
+
+/* GAIN ENVELOPE EDITING */
+
+void
+Editor::edit_envelope ()
+{
+}
+
+/* PLAYBACK */
+
+void
+Editor::transition_to_rolling (bool fwd)
+{
+ if (!session) {
+ return;
+ }
+
+ switch (Config->get_slave_source()) {
+ case None:
+ case JACK:
+ break;
+ default:
+ /* transport controlled by the master */
+ return;
+ }
+
+ if (session->is_auditioning()) {
+ session->cancel_audition ();
+ return;
+ }
+
+ session->request_transport_speed (fwd ? 1.0f : -1.0f);
+}
+
+void
+Editor::toggle_playback (bool with_abort)
+{
+ if (!session) {
+ return;
+ }
+
+ switch (Config->get_slave_source()) {
+ case None:
+ case JACK:
+ break;
+ default:
+ /* transport controlled by the master */
+ return;
+ }
+
+ if (session->is_auditioning()) {
+ session->cancel_audition ();
+ return;
+ }
+
+ if (session->transport_rolling()) {
+ session->request_stop (with_abort);
+ if (session->get_play_loop()) {
+ session->request_play_loop (false);
+ }
+ } else {
+ session->request_transport_speed (1.0f);
+ }
+}
+
+void
+Editor::play_from_start ()
+{
+ session->request_locate (session->current_start_frame(), true);
+}
+
+void
+Editor::play_from_edit_point ()
+{
+ session->request_locate (get_preferred_edit_position(), true);
+}
+
+void
+Editor::play_selection ()
+{
+ if (selection->time.empty()) {
+ return;
+ }
+
+ session->request_play_range (true);
+}
+
+void
+Editor::loop_selected_region ()
+{
+ if (!selection->regions.empty()) {
+ RegionView *rv = *(selection->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_play_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;
- Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
- double vert_value = adj->get_value() + 20;
+ if ((tll = transport_loop_location()) != 0) {
+ tll->set (location.start(), location.end());
- if (vert_value>adj->get_upper() - canvas_height) {
- vert_value = adj->get_upper() - canvas_height;
+ // enable looping, reposition and start rolling
+ session->request_play_loop (true);
+ session->request_locate (tll->start(), true);
}
- adj->set_value (vert_value);
}
void
-Editor::scroll_tracks_up_line ()
+Editor::raise_region ()
{
- Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
- adj->set_value (adj->get_value() - 20);
+ selection->foreach_region (&Region::raise);
}
-/* ZOOM */
+void
+Editor::raise_region_to_top ()
+{
+ selection->foreach_region (&Region::raise_to_top);
+}
void
-Editor::temporal_zoom_step (bool coarser)
+Editor::lower_region ()
{
- ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
+ selection->foreach_region (&Region::lower);
+}
- double nfpu;
+void
+Editor::lower_region_to_bottom ()
+{
+ selection->foreach_region (&Region::lower_to_bottom);
+}
- nfpu = frames_per_unit;
-
- if (coarser) {
- nfpu *= 2.0;
- } else {
- nfpu = max(1.0,(nfpu/2.0));
+void
+Editor::edit_region ()
+{
+ if (clicked_regionview == 0) {
+ return;
}
-
- temporal_zoom (nfpu);
-}
+
+ clicked_regionview->show_region_editor ();
+}
void
-Editor::temporal_zoom (gdouble fpu)
+Editor::rename_region()
{
- 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;
+ if (selection->regions.empty()) {
+ return;
+ }
- nfpu = fpu;
-
- new_page = (jack_nframes_t) floor (canvas_width * nfpu);
+ WindowTitle title (Glib::get_application_name());
+ title += _("Rename Region");
- 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;
+ ArdourDialog d (*this, title.get_string(), true, false);
+ Entry entry;
+ Label label (_("New name:"));
+ HBox hbox;
- 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());
+ hbox.set_spacing (6);
+ hbox.pack_start (label, false, false);
+ hbox.pack_start (entry, true, true);
-// begin_reversible_command (_("zoom"));
-// 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));
-// commit_reversible_command ();
+ d.get_vbox()->set_border_width (12);
+ d.get_vbox()->pack_start (hbox, false, false);
- reposition_and_zoom (leftmost_after_zoom, nfpu);
-}
+ d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
+ d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
-void
-Editor::temporal_zoom_selection ()
-{
- if (!selection) return;
+ d.set_size_request (300, -1);
+ d.set_position (Gtk::WIN_POS_MOUSE);
+
+ entry.set_text (selection->regions.front()->region()->name());
+ entry.select_region (0, -1);
+
+ entry.signal_activate().connect (bind (mem_fun (d, &Dialog::response), RESPONSE_OK));
- if (selection->time.empty()) {
- return;
- }
+ d.show_all ();
+
+ entry.grab_focus();
- jack_nframes_t start = selection->time[clicked_selection].start;
- jack_nframes_t end = selection->time[clicked_selection].end;
+ int ret = d.run();
- temporal_zoom_by_frame (start, end, "zoom to selection");
+ d.hide ();
+
+ if (ret == RESPONSE_OK) {
+ std::string str = entry.get_text();
+ strip_whitespace_edges (str);
+ if (!str.empty()) {
+ selection->regions.front()->region()->set_name (str);
+ redisplay_regions ();
+ }
+ }
}
void
-Editor::temporal_zoom_session ()
+Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
{
- ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
+ if (session->is_auditioning()) {
+ session->cancel_audition ();
+ }
- if (session) {
- temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
- }
+ // 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::temporal_zoom_by_frame (jack_nframes_t start, jack_nframes_t end, const string & op)
+Editor::play_selected_region ()
{
- if (!session) return;
+ nframes64_t start = max_frames;
+ nframes64_t end = 0;
- if ((start == 0 && end == 0) || end < start) {
+ ensure_entered_region_selected (true);
+
+ if (selection->regions.empty()) {
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;
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ if ((*i)->region()->position() < start) {
+ start = (*i)->region()->position();
+ }
+ if ((*i)->region()->last_frame() + 1 > end) {
+ end = (*i)->region()->last_frame() + 1;
+ }
+ }
-// begin_reversible_command (op);
-// 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));
-// commit_reversible_command ();
+ session->request_bounded_roll (start, end);
+}
- reposition_and_zoom (new_leftmost, new_fpu);
+void
+Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
+{
+ session->audition_region (region);
}
-void
-Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame)
+void
+Editor::build_interthread_progress_window ()
{
- if (!session) return;
-
- jack_nframes_t range_before = frame - leftmost_frame;
- double new_fpu;
-
- new_fpu = frames_per_unit;
+ interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
+
+ interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
- if (coarser) {
- new_fpu *= 2.0;
- range_before *= 2;
- } else {
- new_fpu = max(1.0,(new_fpu/2.0));
- range_before /= 2;
- }
+ interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
+ interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
- if (new_fpu == frames_per_unit) return;
+ // GTK2FIX: this button needs a modifiable label
- jack_nframes_t new_leftmost = frame - range_before;
+ Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
+ b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
- if (new_leftmost > frame) new_leftmost = 0;
+ interthread_cancel_button.add (interthread_cancel_label);
-// begin_reversible_command (_("zoom to frame"));
-// 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));
-// commit_reversible_command ();
+ interthread_progress_window->set_default_size (200, 100);
+}
- reposition_and_zoom (new_leftmost, new_fpu);
+void
+Editor::interthread_cancel_clicked ()
+{
+ if (current_interthread_info) {
+ current_interthread_info->cancel = true;
+ }
}
void
-Editor::add_location_from_selection ()
+Editor::region_from_selection ()
{
- if (selection->time.empty()) {
+ if (clicked_trackview == 0) {
return;
}
- if (session == 0 || clicked_trackview == 0) {
+ if (selection->time.empty()) {
return;
}
- jack_nframes_t start = selection->time[clicked_selection].start;
- jack_nframes_t end = selection->time[clicked_selection].end;
+ nframes_t start = selection->time[clicked_selection].start;
+ nframes_t end = selection->time[clicked_selection].end;
- Location *location = new Location (start, end, "selection");
+ nframes_t selection_cnt = end - start + 1;
+
+ for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ boost::shared_ptr<AudioRegion> current;
+ boost::shared_ptr<Region> current_r;
+ boost::shared_ptr<Playlist> pl;
- session->begin_reversible_command (_("add marker"));
- XMLNode &before = session->locations()->get_state();
- session->locations()->add (location, true);
- XMLNode &after = session->locations()->get_state();
- session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
- session->commit_reversible_command ();
-}
+ nframes_t internal_start;
+ string new_name;
-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"));
- XMLNode &before = session->locations()->get_state();
- session->locations()->add (location, true);
- XMLNode &after = session->locations()->get_state();
- session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
- session->commit_reversible_command ();
-}
+ if ((pl = (*i)->playlist()) == 0) {
+ continue;
+ }
+
+ if ((current_r = pl->top_region_at (start)) == 0) {
+ continue;
+ }
+
+ current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
+ // FIXME: audio only
+ if (current != 0) {
+ internal_start = start - current->position();
+ session->region_name (new_name, current->name(), true);
+ boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
+ }
+ }
+}
void
-Editor::add_location_from_audio_region ()
+Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
{
- if (selection->audio_regions.empty()) {
+ if (selection->time.empty() || selection->tracks.empty()) {
return;
}
- AudioRegionView* rv = *(selection->audio_regions.begin());
- Region& region = rv->region;
+ nframes_t start = selection->time[clicked_selection].start;
+ nframes_t end = selection->time[clicked_selection].end;
- Location *location = new Location (region.position(), region.last_frame(), region.name());
- session->begin_reversible_command (_("add marker"));
- XMLNode &before = session->locations()->get_state();
- session->locations()->add (location, true);
- XMLNode &after = session->locations()->get_state();
- session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
- session->commit_reversible_command ();
+ sort_track_selection ();
+
+ for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+
+ boost::shared_ptr<AudioRegion> current;
+ boost::shared_ptr<Region> current_r;
+ boost::shared_ptr<Playlist> playlist;
+ 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 = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
+ continue;
+ }
+
+ internal_start = start - current->position();
+ session->region_name (new_name, current->name(), true);
+
+ new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
+ }
}
void
-Editor::select_all_in_track (Selection::Operation op)
+Editor::split_multichannel_region ()
{
- list<Selectable *> touched;
-
- if (!clicked_trackview) {
+ if (selection->regions.empty()) {
return;
}
-
- clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
- switch (op) {
- case Selection::Toggle:
- selection->add (touched);
- break;
- case Selection::Set:
- selection->set (touched);
- break;
- case Selection::Extend:
- /* not defined yet */
- break;
- }
-}
+ vector<boost::shared_ptr<AudioRegion> > v;
-void
-Editor::select_all (Selection::Operation op)
-{
- list<Selectable *> touched;
-
- for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
- if ((*iter)->hidden()) {
+ for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
+
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
+
+ if (!arv || arv->audio_region()->n_channels() < 2) {
continue;
}
- (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
- }
- begin_reversible_command (_("select all"));
- switch (op) {
- case Selection::Toggle:
- selection->add (touched);
- break;
- case Selection::Set:
- selection->set (touched);
- break;
- case Selection::Extend:
- /* not defined yet */
- break;
+
+ (arv)->audio_region()->separate_by_channel (*session, v);
}
- commit_reversible_command ();
}
void
-Editor::invert_selection_in_track ()
+Editor::new_region_from_selection ()
{
- list<Selectable *> touched;
+ region_from_selection ();
+ cancel_selection ();
+}
- if (!clicked_trackview) {
- return;
+static void
+add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
+{
+ switch (rv->region()->coverage (ar->start, ar->end - 1)) {
+ case OverlapNone:
+ break;
+ default:
+ rs->push_back (rv);
}
-
- clicked_trackview->get_inverted_selectables (*selection, touched);
- selection->set (touched);
}
void
-Editor::invert_selection ()
+Editor::separate_regions_between (const TimeSelection& ts)
{
- 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);
- }
+ bool in_command = false;
+ boost::shared_ptr<Playlist> playlist;
+ RegionSelection new_selection;
+
+ sort_track_selection ();
- selection->set (touched);
-}
+ for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
-bool
-Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, Selection::Operation op)
-{
- 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);
- }
+ AudioTimeAxisView* atv;
- cerr << "select all within found " << touched.size() << endl;
+ if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
- begin_reversible_command (_("select all within"));
- switch (op) {
- case Selection::Toggle:
- cerr << "toggle\n";
- selection->add (touched);
- break;
- case Selection::Set:
- cerr << "set\n";
- selection->set (touched);
- break;
- case Selection::Extend:
- cerr << "extend\n";
- /* not defined yet */
- break;
- }
+ if (atv->is_audio_track()) {
- cerr << "selection now has " << selection->points.size() << endl;
+ /* no edits to destructive tracks */
- commit_reversible_command ();
- return !touched.empty();
-}
+ if (atv->audio_track()->audio_diskstream()->destructive()) {
+ continue;
+ }
+
+ if ((playlist = atv->playlist()) != 0) {
-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 ();
+ XMLNode *before;
+ bool got_some;
- set_mouse_mode (Editing::MouseRange, false);
-}
+ before = &(playlist->get_state());
+ got_some = false;
-void
-Editor::set_selection_from_punch()
-{
- Location* location;
+ /* XXX need to consider musical time selections here at some point */
- if ((location = session->locations()->auto_punch_location()) == 0) {
- return;
- }
+ double speed = atv->get_diskstream()->speed();
- set_selection_from_range (*location);
-}
-void
-Editor::set_selection_from_loop()
-{
- Location* location;
+ for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
- if ((location = session->locations()->auto_loop_location()) == 0) {
- return;
+ sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
+ latest_regionviews.clear ();
+
+ playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
+
+ c.disconnect ();
+
+ if (!latest_regionviews.empty()) {
+
+ got_some = true;
+
+ atv->view()->foreach_regionview (bind (sigc::ptr_fun (add_if_covered), &(*t), &new_selection));
+
+ if (!in_command) {
+ begin_reversible_command (_("separate"));
+ in_command = true;
+ }
+
+ session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
+
+ }
+ }
+
+ if (!got_some) {
+ delete before;
+ }
+ }
+ }
+ }
}
- set_selection_from_range (*location);
-}
-void
-Editor::set_selection_from_range (Location& loc)
-{
- begin_reversible_command (_("set selection from range"));
- selection->set (0, loc.start(), loc.end());
- commit_reversible_command ();
+ if (in_command) {
+ selection->set (new_selection);
+ set_mouse_mode (MouseObject);
- set_mouse_mode (Editing::MouseRange, false);
+ commit_reversible_command ();
+ }
}
void
-Editor::select_all_selectables_using_time_selection ()
+Editor::separate_region_from_selection ()
{
- list<Selectable *> touched;
+ /* preferentially use *all* ranges in the time selection if we're in range mode
+ to allow discontiguous operation, since get_edit_op_range() currently
+ returns a single range.
+ */
+ if (mouse_mode == MouseRange && !selection->time.empty()) {
- if (selection->time.empty()) {
- return;
- }
+ separate_regions_between (selection->time);
+
+ } else {
- jack_nframes_t start = selection->time[clicked_selection].start;
- jack_nframes_t end = selection->time[clicked_selection].end;
+ nframes64_t start;
+ nframes64_t end;
+
+ if (get_edit_op_range (start, end)) {
+
+ AudioRange ar (start, end, 1);
+ TimeSelection ts;
+ ts.push_back (ar);
- if (end - start < 1) {
- return;
- }
+ /* force track selection */
- for (TrackViewList::iterator iter = selection->tracks.begin(); iter != selection->tracks.end(); ++iter) {
- if ((*iter)->hidden()) {
- continue;
+ ensure_entered_region_selected ();
+
+ separate_regions_between (ts);
}
- (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
}
-
- begin_reversible_command (_("select all from range"));
- selection->set (touched);
- commit_reversible_command ();
}
-
void
-Editor::select_all_selectables_using_punch()
+Editor::separate_regions_using_location (Location& loc)
{
- Location* location = session->locations()->auto_punch_location();
- list<Selectable *> touched;
-
- if (location == 0 || (location->end() - location->start() <= 1)) {
+ if (loc.is_mark()) {
return;
}
- 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 punch"));
- selection->set (touched);
- commit_reversible_command ();
+ AudioRange ar (loc.start(), loc.end(), 1);
+ TimeSelection ts;
+
+ ts.push_back (ar);
+ separate_regions_between (ts);
}
void
-Editor::select_all_selectables_using_loop()
+Editor::crop_region_to_selection ()
{
- Location* location = session->locations()->auto_loop_location();
- list<Selectable *> touched;
+ ensure_entered_region_selected (true);
- if (location == 0 || (location->end() - location->start() <= 1)) {
- return;
- }
+ if (!selection->time.empty()) {
- for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
- if ((*iter)->hidden()) {
- continue;
+ crop_region_to (selection->time.start(), selection->time.end_frame());
+
+ } else {
+
+ nframes64_t start;
+ nframes64_t end;
+
+ if (get_edit_op_range (start, end)) {
+ crop_region_to (start, end);
}
- (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
}
- begin_reversible_command (_("select all from loop"));
- selection->set (touched);
- commit_reversible_command ();
-
-}
+
+}
void
-Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
+Editor::crop_region_to (nframes_t start, nframes_t end)
{
- jack_nframes_t start;
- jack_nframes_t end;
- list<Selectable *> touched;
+ vector<boost::shared_ptr<Playlist> > playlists;
+ boost::shared_ptr<Playlist> playlist;
+ TrackSelection* ts;
- if (after) {
- begin_reversible_command (_("select all after cursor"));
- start = cursor->current_frame ;
- end = session->current_end_frame();
+ if (selection->tracks.empty()) {
+ ts = &track_views;
} else {
- if (cursor->current_frame > 0) {
- begin_reversible_command (_("select all before cursor"));
- start = 0;
- end = cursor->current_frame - 1;
- } else {
- return;
+ sort_track_selection ();
+ ts = &selection->tracks;
+ }
+
+ for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
+
+ AudioTimeAxisView* atv;
+
+ if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
+
+ if (atv->is_audio_track()) {
+
+ /* no edits to destructive tracks */
+
+ if (atv->audio_track()->audio_diskstream()->destructive()) {
+ continue;
+ }
+
+ if ((playlist = atv->playlist()) != 0) {
+ playlists.push_back (playlist);
+ }
+ }
}
}
- for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
- if ((*iter)->hidden()) {
+ if (playlists.empty()) {
+ return;
+ }
+
+ nframes_t the_start;
+ nframes_t the_end;
+ nframes_t cnt;
+
+ begin_reversible_command (_("trim to selection"));
+
+ for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+
+ boost::shared_ptr<Region> region;
+
+ the_start = start;
+
+ if ((region = (*i)->top_region_at(the_start)) == 0) {
continue;
}
- (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
+
+ /* now adjust lengths to that we do the right thing
+ if the selection extends beyond the region
+ */
+
+ the_start = max (the_start, region->position());
+ if (max_frames - the_start < region->length()) {
+ the_end = the_start + region->length() - 1;
+ } else {
+ the_end = max_frames;
+ }
+ the_end = min (end, the_end);
+ cnt = the_end - the_start + 1;
+
+ XMLNode &before = (*i)->get_state();
+ region->trim_to (the_start, cnt, this);
+ XMLNode &after = (*i)->get_state();
+ session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
}
- selection->set (touched);
+
commit_reversible_command ();
-}
+}
void
-Editor::select_all_selectables_between_cursors (Cursor *cursor, Cursor *other_cursor)
+Editor::region_fill_track ()
{
- jack_nframes_t start;
- jack_nframes_t end;
- list<Selectable *> touched;
- bool other_cursor_is_first = cursor->current_frame > other_cursor->current_frame;
+ nframes_t end;
- if (cursor->current_frame == other_cursor->current_frame) {
+ if (!session || selection->regions.empty()) {
return;
}
- begin_reversible_command (_("select all between cursors"));
- if (other_cursor_is_first) {
- start = other_cursor->current_frame;
- end = cursor->current_frame - 1;
+ end = session->current_end_frame ();
+
+ begin_reversible_command (_("region fill"));
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+
+ boost::shared_ptr<Region> region ((*i)->region());
- } else {
- start = cursor->current_frame;
- end = other_cursor->current_frame - 1;
- }
-
- for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
- if ((*iter)->hidden()) {
+ // FIXME
+ boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
+ if (!ar)
continue;
+
+ boost::shared_ptr<Playlist> pl = region->playlist();
+
+ if (end <= region->last_frame()) {
+ return;
+ }
+
+ double times = (double) (end - region->last_frame()) / (double) region->length();
+
+ if (times == 0) {
+ return;
}
- (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
+
+ XMLNode &before = pl->get_state();
+ pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
+ session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
}
- selection->set (touched);
+
commit_reversible_command ();
}
void
-Editor::amplitude_zoom_step (bool in)
+Editor::region_fill_selection ()
{
- gdouble zoom = 1.0;
+ if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
+ return;
+ }
- if (in) {
- zoom *= 2.0;
- } else {
- if (zoom > 2.0) {
- zoom /= 2.0;
- } else {
- zoom = 1.0;
- }
+ if (selection->time.empty()) {
+ return;
}
-#ifdef FIX_FOR_CANVAS
- /* XXX DO SOMETHING */
-#endif
-}
+ Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
-/* DELETION */
+ if (selected->count_selected_rows() != 1) {
+ return;
+ }
+ TreeModel::iterator i = region_list_display.get_selection()->get_selected();
+ boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
-void
-Editor::delete_sample_forward ()
-{
+ nframes_t start = selection->time[clicked_selection].start;
+ nframes_t end = selection->time[clicked_selection].end;
+
+ boost::shared_ptr<Playlist> playlist;
+
+ if (selection->tracks.empty()) {
+ return;
+ }
+
+ 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;
+ }
+
+ XMLNode &before = playlist->get_state();
+ playlist->add_region (RegionFactory::create (region), start, times);
+ session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
+ }
+
+ commit_reversible_command ();
}
void
-Editor::delete_sample_backward ()
+Editor::set_region_sync_from_edit_point ()
{
+ nframes64_t where = get_preferred_edit_position ();
+ ensure_entered_region_selected (true);
+ set_sync_point (where, selection->regions);
}
void
-Editor::delete_screen ()
+Editor::set_sync_point (nframes64_t where, const RegionSelection& rs)
{
-}
+ bool in_command = false;
-/* SEARCH */
+ for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
+
+ if (!(*r)->region()->covers (where)) {
+ continue;
+ }
-void
-Editor::search_backwards ()
-{
- /* what ? */
-}
+ boost::shared_ptr<Region> region ((*r)->region());
-void
-Editor::search_forwards ()
-{
- /* what ? */
-}
+ if (!in_command) {
+ begin_reversible_command (_("set sync point"));
+ in_command = true;
+ }
-/* MARKS */
+ XMLNode &before = region->playlist()->get_state();
+ region->set_sync_position (get_preferred_edit_position());
+ XMLNode &after = region->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
+ }
-void
-Editor::jump_forward_to_mark ()
-{
- if (!session) {
- return;
+ if (in_command) {
+ commit_reversible_command ();
}
-
- 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::remove_region_sync ()
+{
+ if (clicked_regionview) {
+ boost::shared_ptr<Region> region (clicked_regionview->region());
+ begin_reversible_command (_("remove sync"));
+ XMLNode &before = region->playlist()->get_state();
+ region->clear_sync_position ();
+ XMLNode &after = region->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
+ commit_reversible_command ();
}
}
void
-Editor::jump_backward_to_mark ()
+Editor::naturalize ()
{
- if (!session) {
+ if (selection->regions.empty()) {
return;
}
-
- Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
-
- if (location) {
- session->request_locate (location->start(), session->transport_rolling());
- } else {
- session->goto_start ();
+ begin_reversible_command (_("naturalize"));
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ XMLNode &before = (*i)->region()->get_state();
+ (*i)->region()->move_to_natural_position (this);
+ XMLNode &after = (*i)->region()->get_state();
+ session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
}
+ commit_reversible_command ();
}
void
-Editor::set_mark ()
+Editor::align (RegionPoint what)
{
- jack_nframes_t pos;
- float prefix;
- bool was_floating;
+ ensure_entered_region_selected ();
- if (get_prefix (prefix, was_floating)) {
- pos = session->audible_frame ();
+ nframes64_t where = get_preferred_edit_position();
+
+ if (!selection->regions.empty()) {
+ align_selection (what, where, selection->regions);
} 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);
+ RegionSelection rs;
+ rs = get_regions_at (where, selection->tracks);
+ align_selection (what, where, rs);
+ }
}
void
-Editor::clear_markers ()
+Editor::align_relative (RegionPoint what)
{
- if (session) {
- session->begin_reversible_command (_("clear markers"));
- XMLNode &before = session->locations()->get_state();
- session->locations()->clear_markers ();
- XMLNode &after = session->locations()->get_state();
- session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
- session->commit_reversible_command ();
+ nframes64_t where = get_preferred_edit_position();
+
+ if (!selection->regions.empty()) {
+ align_selection_relative (what, where, selection->regions);
+ } else {
+
+ RegionSelection rs;
+ rs = get_regions_at (where, selection->tracks);
+ align_selection_relative (what, where, rs);
}
}
+struct RegionSortByTime {
+ bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
+ return a->region()->position() < b->region()->position();
+ }
+};
+
void
-Editor::clear_ranges ()
+Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs)
{
- if (session) {
- session->begin_reversible_command (_("clear ranges"));
- XMLNode &before = session->locations()->get_state();
-
- 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);
-
- XMLNode &after = session->locations()->get_state();
- session->add_command(MementoCommand<Locations>(*(session->locations()), before, after));
- session->commit_reversible_command ();
+ if (rs.empty()) {
+ return;
}
-}
-void
-Editor::clear_locations ()
-{
- session->begin_reversible_command (_("clear locations"));
- XMLNode &before = session->locations()->get_state();
- session->locations()->clear ();
- XMLNode &after = session->locations()->get_state();
- session->add_command(MementoCommand<Locations>(*(sessions->locations()), before, after));
- session->commit_reversible_command ();
- session->locations()->clear ();
-}
+ nframes_t distance;
+ nframes_t pos = 0;
+ int dir;
-/* INSERT/REPLACE */
+ list<RegionView*> sorted;
+ rs.by_position (sorted);
+ boost::shared_ptr<Region> r ((*sorted.begin())->region());
-void
-Editor::insert_region_list_drag (AudioRegion& region, int x, int y)
-{
- double wx, wy;
- double cx, cy;
- TimeAxisView *tv;
- jack_nframes_t where;
- AudioTimeAxisView *atv = 0;
- Playlist *playlist;
-
- track_canvas.window_to_world (x, y, wx, wy);
- wx += horizontal_adjustment.get_value();
- wy += vertical_adjustment.get_value();
+ switch (point) {
+ case Start:
+ pos = r->first_frame ();
+ break;
- GdkEvent event;
- event.type = GDK_BUTTON_RELEASE;
- event.button.x = wx;
- event.button.y = wy;
-
- where = event_frame (&event, &cx, &cy);
+ case End:
+ pos = r->last_frame();
+ break;
- if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
- /* clearly outside canvas area */
- return;
- }
-
- if ((tv = trackview_by_y_position (cy)) == 0) {
- return;
+ case SyncPoint:
+ pos = r->adjust_to_sync (r->first_frame());
+ break;
}
-
- if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
- return;
+
+ if (pos > position) {
+ distance = pos - position;
+ dir = -1;
+ } else {
+ distance = position - pos;
+ dir = 1;
}
- if ((playlist = atv->playlist()) == 0) {
- return;
+ begin_reversible_command (_("align selection (relative)"));
+
+ for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
+
+ boost::shared_ptr<Region> region ((*i)->region());
+
+ XMLNode &before = region->playlist()->get_state();
+
+ if (dir > 0) {
+ region->set_position (region->position() + distance, this);
+ } else {
+ region->set_position (region->position() - distance, this);
+ }
+
+ XMLNode &after = region->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
+
}
-
- snap_to (where);
-
- begin_reversible_command (_("insert dragged region"));
- XMLNode &before = playlist->get_state();
- playlist->add_region (*(new AudioRegion (region)), where, 1.0);
- session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
+
commit_reversible_command ();
}
void
-Editor::insert_region_list_selection (float times)
+Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs)
{
- 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 {
+ if (rs.empty()) {
return;
}
- if ((playlist = tv->playlist()) == 0) {
- return;
- }
-
- Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
-
- if (selected->count_selected_rows() != 1) {
- return;
+ begin_reversible_command (_("align selection"));
+
+ for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
+ align_region_internal ((*i)->region(), point, position);
}
-
- TreeModel::iterator i = region_list_display.get_selection()->get_selected();
- Region* region = (*i)[region_list_columns.region];
- begin_reversible_command (_("insert region"));
- XMLNode &before = playlist->get_state();
- playlist->add_region (*(createRegion (*region)), edit_cursor->current_frame, times);
- session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
commit_reversible_command ();
}
-
-/* BUILT-IN EFFECTS */
-
void
-Editor::reverse_selection ()
+Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
{
-
+ begin_reversible_command (_("align region"));
+ align_region_internal (region, point, position);
+ commit_reversible_command ();
}
-/* GAIN ENVELOPE EDITING */
-
void
-Editor::edit_envelope ()
+Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
{
-}
+ XMLNode &before = region->playlist()->get_state();
-/* PLAYBACK */
+ switch (point) {
+ case SyncPoint:
+ region->set_position (region->adjust_to_sync (position), this);
+ break;
-void
-Editor::toggle_playback (bool with_abort)
-{
- if (!session) {
- return;
- }
+ case End:
+ if (position > region->length()) {
+ region->set_position (position - region->length(), this);
+ }
+ break;
- switch (session->slave_source()) {
- case Session::None:
- case Session::JACK:
+ case Start:
+ region->set_position (position, this);
break;
- default:
- /* transport controlled by the master */
- return;
}
- if (session->is_auditioning()) {
- session->cancel_audition ();
+ XMLNode &after = region->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
+}
+
+void
+Editor::trim_region_to_loop ()
+{
+ Location* loc = session->locations()->auto_loop_location();
+ if (!loc) {
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);
- }
+ trim_region_to_location (*loc, _("trim to loop"));
}
void
-Editor::play_from_start ()
+Editor::trim_region_to_punch ()
{
- session->request_locate (session->current_start_frame(), true);
+ Location* loc = session->locations()->auto_punch_location();
+ if (!loc) {
+ return;
+ }
+ trim_region_to_location (*loc, _("trim to punch"));
}
void
-Editor::play_selection ()
+Editor::trim_region_to_location (const Location& loc, const char* str)
{
- if (selection->time.empty()) {
- return;
- }
+ ensure_entered_region_selected ();
- session->request_play_range (true);
+ RegionSelection& rs (get_regions_for_action ());
+
+ begin_reversible_command (str);
+
+ for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
+
+ if (!arv) {
+ continue;
+ }
+
+ /* require region to span proposed trim */
+
+ switch (arv->region()->coverage (loc.start(), loc.end())) {
+ case OverlapInternal:
+ break;
+ default:
+ continue;
+ }
+
+ AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
+
+ if (!atav) {
+ return;
+ }
+
+ float speed = 1.0;
+ nframes_t start;
+ nframes_t end;
+
+ if (atav->get_diskstream() != 0) {
+ speed = atav->get_diskstream()->speed();
+ }
+
+ start = session_frame_to_track_frame (loc.start(), speed);
+ end = session_frame_to_track_frame (loc.end(), speed);
+
+ XMLNode &before = arv->region()->playlist()->get_state();
+ arv->region()->trim_to (start, (end - start), this);
+ XMLNode &after = arv->region()->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
+ }
+
+ commit_reversible_command ();
}
void
-Editor::play_selected_region ()
+Editor::trim_region_to_edit_point ()
{
- if (!selection->audio_regions.empty()) {
- AudioRegionView *rv = *(selection->audio_regions.begin());
+ RegionSelection& rs (get_regions_for_action ());
+ nframes64_t where = get_preferred_edit_position();
+
+ begin_reversible_command (_("trim region start to edit point"));
+
+ for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
+
+ if (!arv) {
+ continue;
+ }
+
+ /* require region to cover trim */
+
+ if (!arv->region()->covers (where)) {
+ continue;
+ }
+
+ AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
+
+ if (!atav) {
+ return;
+ }
+
+ float speed = 1.0;
+
+ if (atav->get_diskstream() != 0) {
+ speed = atav->get_diskstream()->speed();
+ }
- session->request_bounded_roll (rv->region.position(), rv->region.last_frame());
+ XMLNode &before = arv->region()->playlist()->get_state();
+ arv->region()->trim_end( session_frame_to_track_frame(where, speed), this);
+ XMLNode &after = arv->region()->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
}
+
+ commit_reversible_command ();
}
void
-Editor::loop_selected_region ()
+Editor::trim_region_from_edit_point ()
{
- if (!selection->audio_regions.empty()) {
- AudioRegionView *rv = *(selection->audio_regions.begin());
- Location* tll;
+ RegionSelection& rs (get_regions_for_action ());
+ nframes64_t where = get_preferred_edit_position();
- if ((tll = transport_loop_location()) != 0) {
+ begin_reversible_command (_("trim region end to edit point"));
- tll->set (rv->region.position(), rv->region.last_frame());
-
- // enable looping, reposition and start rolling
+ for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
- session->request_auto_loop (true);
- session->request_locate (tll->start(), false);
- session->request_transport_speed (1.0f);
+ if (!arv) {
+ continue;
}
- }
-}
-void
-Editor::play_location (Location& location)
-{
- if (location.start() <= location.end()) {
- return;
- }
+ /* require region to cover trim */
- session->request_bounded_roll (location.start(), location.end());
-}
+ if (!arv->region()->covers (where)) {
+ continue;
+ }
-void
-Editor::loop_location (Location& location)
-{
- if (location.start() <= location.end()) {
- return;
- }
+ AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
- Location* tll;
+ if (!atav) {
+ return;
+ }
- if ((tll = transport_loop_location()) != 0) {
- tll->set (location.start(), location.end());
+ float speed = 1.0;
- // enable looping, reposition and start rolling
- session->request_auto_loop (true);
- session->request_locate (tll->start(), true);
- }
-}
+ if (atav->get_diskstream() != 0) {
+ speed = atav->get_diskstream()->speed();
+ }
-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);
+ XMLNode &before = arv->region()->playlist()->get_state();
+ arv->region()->trim_front ( session_frame_to_track_frame(where, speed), this);
+ XMLNode &after = arv->region()->playlist()->get_state();
+ session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
}
+
+ commit_reversible_command ();
}
void
-Editor::toggle_region_opaque ()
+Editor::unfreeze_route ()
{
- 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);
+ if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
+ return;
}
+
+ clicked_audio_trackview->audio_track()->unfreeze ();
}
-void
-Editor::raise_region ()
-{
- selection->foreach_audio_region (&Region::raise);
-}
-
-void
-Editor::raise_region_to_top ()
+void*
+Editor::_freeze_thread (void* arg)
{
- selection->foreach_audio_region (&Region::raise_to_top);
+ PBD::ThreadCreated (pthread_self(), X_("Freeze"));
+ return static_cast<Editor*>(arg)->freeze_thread ();
}
-void
-Editor::lower_region ()
+void*
+Editor::freeze_thread ()
{
- selection->foreach_audio_region (&Region::lower);
+ clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
+ return 0;
}
-void
-Editor::lower_region_to_bottom ()
+gint
+Editor::freeze_progress_timeout (void *arg)
{
- selection->foreach_audio_region (&Region::lower_to_bottom);
+ interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
+ return !(current_interthread_info->done || current_interthread_info->cancel);
}
void
-Editor::edit_region ()
+Editor::freeze_route ()
{
- if (clicked_regionview == 0) {
+ if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
return;
}
- clicked_regionview->show_region_editor ();
-}
-
-void
-Editor::rename_region ()
-{
- Dialog dialog;
- Entry entry;
- Button ok_button (_("OK"));
- Button cancel_button (_("Cancel"));
+ InterThreadInfo itt;
- if (selection->audio_regions.empty()) {
- return;
+ if (interthread_progress_window == 0) {
+ build_interthread_progress_window ();
}
- dialog.set_title (_("ardour: rename region"));
- dialog.set_name ("RegionRenameWindow");
- dialog.set_size_request (300, -1);
- dialog.set_position (Gtk::WIN_POS_MOUSE);
- 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);
+ WindowTitle title(Glib::get_application_name());
+ title += _("Freeze");
+ interthread_progress_window->set_title (title.get_string());
+ interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
+ interthread_progress_window->show_all ();
+ interthread_progress_bar.set_fraction (0.0f);
+ interthread_progress_label.set_text ("");
+ interthread_cancel_label.set_text (_("Cancel Freeze"));
+ current_interthread_info = &itt;
- entry.set_name ("RegionNameDisplay");
- ok_button.set_name ("EditorGTKButton");
- cancel_button.set_name ("EditorGTKButton");
+ interthread_progress_connection =
+ Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
- region_renamed = false;
+ itt.done = false;
+ itt.cancel = false;
+ itt.progress = 0.0f;
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 500000);
- entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
- 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));
+ pthread_create (&itt.thread, &attr, _freeze_thread, this);
- /* recurse */
+ pthread_attr_destroy(&attr);
- dialog.show_all ();
- Main::run ();
+ track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
- if (region_renamed) {
- (*selection->audio_regions.begin())->region.set_name (entry.get_text());
- redisplay_regions ();
+ while (!itt.done && !itt.cancel) {
+ gtk_main_iteration ();
}
-}
-void
-Editor::rename_region_finished (bool status)
-
-{
- region_renamed = status;
- Main::quit ();
+ interthread_progress_connection.disconnect ();
+ interthread_progress_window->hide_all ();
+ current_interthread_info = 0;
+ track_canvas.get_window()->set_cursor (*current_canvas_cursor);
}
void
-Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route)
+Editor::bounce_range_selection ()
{
- if (session->is_auditioning()) {
- session->cancel_audition ();
- }
+ if (selection->time.empty()) {
+ return;
+ }
- // note: some potential for creativity here, because region doesn't
- // have to belong to the playlist that Route is handling
+ TrackSelection views = selection->tracks;
- // bool was_soloed = route.soloed();
+ nframes_t start = selection->time[clicked_selection].start;
+ nframes_t end = selection->time[clicked_selection].end;
+ nframes_t cnt = end - start + 1;
- route.set_solo (true, this);
-
- session->request_bounded_roll (region.position(), region.position() + region.length());
+ 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;
+ }
+
+ boost::shared_ptr<Playlist> playlist;
+
+ if ((playlist = atv->playlist()) == 0) {
+ return;
+ }
+
+ InterThreadInfo itt;
+
+ itt.done = false;
+ itt.cancel = false;
+ itt.progress = false;
+
+ XMLNode &before = playlist->get_state();
+ atv->audio_track()->bounce_range (start, cnt, itt);
+ XMLNode &after = playlist->get_state();
+ session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
+ }
- /* XXX how to unset the solo state ? */
+ commit_reversible_command ();
}
void
-Editor::audition_selected_region ()
+Editor::cut ()
{
- if (!selection->audio_regions.empty()) {
- AudioRegionView* rv = *(selection->audio_regions.begin());
- session->audition_region (rv->region);
- }
+ cut_copy (Cut);
}
void
-Editor::audition_playlist_region_standalone (AudioRegion& region)
+Editor::copy ()
{
- session->audition_region (region);
+ cut_copy (Copy);
}
-void
-Editor::build_interthread_progress_window ()
+void
+Editor::cut_copy (CutCopyOp op)
{
- interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
+ /* only cancel selection if cut/copy is successful.*/
- interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
+ string opname;
+
+ switch (op) {
+ case Cut:
+ opname = _("cut");
+ break;
+ case Copy:
+ opname = _("copy");
+ break;
+ case Clear:
+ opname = _("clear");
+ break;
+ }
- interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
- interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
+ cut_buffer->clear ();
- // GTK2FIX: this button needs a modifiable label
+ if (entered_marker) {
- Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
- b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
+ /* cut/delete op while pointing at a marker */
- interthread_cancel_button.add (interthread_cancel_label);
+ bool ignored;
+ Location* loc = find_location_from_marker (entered_marker, ignored);
- interthread_progress_window->set_default_size (200, 100);
-}
+ if (session && loc) {
+ Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
+ }
-void
-Editor::interthread_cancel_clicked ()
-{
- if (current_interthread_info) {
- current_interthread_info->cancel = true;
+ return;
+ }
+
+ switch (current_mouse_mode()) {
+ case MouseObject:
+ cerr << "cutting in object mode\n";
+ if (!selection->regions.empty() || !selection->points.empty()) {
+
+ begin_reversible_command (opname + _(" objects"));
+
+ if (!selection->regions.empty()) {
+ cerr << "have regions to cut" << endl;
+ cut_copy_regions (op);
+
+ if (op == Cut) {
+ selection->clear_regions ();
+ }
+ }
+
+ if (!selection->points.empty()) {
+ cut_copy_points (op);
+
+ if (op == Cut) {
+ selection->clear_points ();
+ }
+ }
+
+ commit_reversible_command ();
+ break; // terminate case statement here
+ }
+ cerr << "nope, now cutting time range" << endl;
+ if (!selection->time.empty()) {
+ /* don't cause suprises */
+ break;
+ }
+ // fall thru if there was nothing selected
+
+ case MouseRange:
+ if (selection->time.empty()) {
+ nframes64_t start, end;
+ cerr << "no time selection, get edit op range" << endl;
+ if (!get_edit_op_range (start, end)) {
+ cerr << "no edit op range" << endl;
+ return;
+ }
+ selection->set ((TimeAxisView*) 0, start, end);
+ }
+
+ begin_reversible_command (opname + _(" range"));
+ cut_copy_ranges (op);
+ commit_reversible_command ();
+
+ if (op == Cut) {
+ selection->clear_time ();
+ }
+
+ break;
+
+ default:
+ break;
}
}
void
-Editor::region_from_selection ()
+Editor::cut_copy_points (CutCopyOp op)
{
- if (clicked_trackview == 0) {
- return;
- }
+ for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
- if (selection->time.empty()) {
- return;
+ AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
+
+ if (atv) {
+ atv->cut_copy_clear_objects (selection->points, op);
+ }
}
+}
+
+struct PlaylistState {
+ boost::shared_ptr<Playlist> playlist;
+ XMLNode* before;
+};
+
+struct lt_playlist {
+ bool operator () (const PlaylistState& a, const PlaylistState& b) {
+ return a.playlist < b.playlist;
+ }
+};
+
+struct PlaylistMapping {
+ TimeAxisView* tv;
+ boost::shared_ptr<AudioPlaylist> pl;
+
+ PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
+};
- jack_nframes_t start = selection->time[clicked_selection].start;
- jack_nframes_t end = selection->time[clicked_selection].end;
+void
+Editor::cut_copy_regions (CutCopyOp op)
+{
+ /* we can't use a std::map here because the ordering is important, and we can't trivially sort
+ a map when we want ordered access to both elements. i think.
+ */
- jack_nframes_t selection_cnt = end - start + 1;
+ vector<PlaylistMapping> pmap;
+
+ nframes_t first_position = max_frames;
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ set<PlaylistState, lt_playlist> freezelist;
+ pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
+
+ /* get ordering correct before we cut/copy */
+
+ selection->regions.sort_by_position_and_track ();
- AudioRegion *region;
- AudioRegion *current;
- Region* current_r;
- Playlist *pl;
+ for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
- jack_nframes_t internal_start;
- string new_name;
+ first_position = min ((*x)->region()->position(), first_position);
- if ((pl = (*i)->playlist()) == 0) {
- continue;
- }
+ if (op == Cut || op == Clear) {
+ boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
- if ((current_r = pl->top_region_at (start)) == 0) {
- continue;
- }
+ if (pl) {
- 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);
+ PlaylistState before;
+ before.playlist = pl;
+ before.before = &pl->get_state();
+
+ insert_result = freezelist.insert (before);
+
+ if (insert_result.second) {
+ pl->freeze ();
+ }
+ }
}
- }
-}
-void
-Editor::create_region_from_selection (vector<AudioRegion *>& new_regions)
-{
- if (selection->time.empty() || selection->tracks.empty()) {
- return;
- }
+ TimeAxisView* tv = &(*x)->get_trackview();
+ vector<PlaylistMapping>::iterator z;
- 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) {
+ for (z = pmap.begin(); z != pmap.end(); ++z) {
+ if ((*z).tv == tv) {
+ break;
+ }
+ }
+
+ if (z == pmap.end()) {
+ pmap.push_back (PlaylistMapping (tv));
+ }
+ }
- AudioRegion* current;
- Region* current_r;
- Playlist* playlist;
- jack_nframes_t internal_start;
- string new_name;
+ for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
- if ((playlist = (*i)->playlist()) == 0) {
+ boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
+
+ if (!pl) {
+ /* impossible, but this handles it for the future */
continue;
}
- if ((current_r = playlist->top_region_at(start)) == 0) {
- continue;
+ TimeAxisView& tv = (*x)->get_trackview();
+ boost::shared_ptr<AudioPlaylist> npl;
+ RegionSelection::iterator tmp;
+
+ tmp = x;
+ ++tmp;
+
+ vector<PlaylistMapping>::iterator z;
+
+ for (z = pmap.begin(); z != pmap.end(); ++z) {
+ if ((*z).tv == &tv) {
+ break;
+ }
+ }
+
+ assert (z != pmap.end());
+
+ if (!(*z).pl) {
+ npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
+ npl->freeze();
+ (*z).pl = npl;
+ } else {
+ npl = (*z).pl;
}
+
+ boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
+ boost::shared_ptr<Region> _xx;
+
+ switch (op) {
+ case Cut:
+ if (!ar) break;
+
+ _xx = RegionFactory::create ((*x)->region());
+ npl->add_region (_xx, (*x)->region()->position() - first_position);
+ pl->remove_region (((*x)->region()));
+ break;
+
+ case Copy:
+ if (!ar) break;
- if ((current = dynamic_cast<AudioRegion*>(current_r)) == 0) {
- continue;
+ /* copy region before adding, so we're not putting same object into two different playlists */
+ npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
+ break;
+
+ case Clear:
+ pl->remove_region (((*x)->region()));
+ break;
}
+
+ x = tmp;
+ }
- 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));
+ list<boost::shared_ptr<Playlist> > foo;
+
+ /* the pmap is in the same order as the tracks in which selected regions occured */
+
+ for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
+ (*i).pl->thaw();
+ foo.push_back ((*i).pl);
+ }
+
+
+ if (!foo.empty()) {
+ cut_buffer->set (foo);
+ }
+
+ for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
+ (*pl).playlist->thaw ();
+ session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
}
}
void
-Editor::split_multichannel_region ()
+Editor::cut_copy_ranges (CutCopyOp op)
{
- vector<AudioRegion*> v;
+ TrackSelection* ts;
- if (!clicked_regionview || clicked_regionview->region.n_channels() < 2) {
- return;
+ if (selection->tracks.empty()) {
+ ts = &track_views;
+ } else {
+ ts = &selection->tracks;
}
- clicked_regionview->region.separate_by_channel (*session, v);
+ for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
+ (*i)->cut_copy_clear (*selection, op);
+ }
+}
- /* nothing else to do, really */
+void
+Editor::paste (float times)
+{
+ paste_internal (get_preferred_edit_position(), times);
}
void
-Editor::new_region_from_selection ()
+Editor::mouse_paste ()
{
- region_from_selection ();
- cancel_selection ();
+ nframes64_t where;
+ bool ignored;
+
+ if (!mouse_frame (where, ignored)) {
+ return;
+ }
+
+ snap_to (where);
+ paste_internal (where, 1);
}
void
-Editor::separate_region_from_selection ()
+Editor::paste_internal (nframes_t position, float times)
{
- bool doing_undo = false;
+ bool commit = false;
- if (selection->time.empty()) {
+ if (cut_buffer->empty()) {
return;
}
- Playlist *playlist;
-
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ if (position == max_frames) {
+ position = get_preferred_edit_position();
+ }
- AudioTimeAxisView* atv;
+ begin_reversible_command (_("paste"));
- if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
+ TrackSelection ts;
+ TrackSelection::iterator i;
+ size_t nth;
- if (atv->is_audio_track()) {
-
- if ((playlist = atv->playlist()) != 0) {
- if (!doing_undo) {
- begin_reversible_command (_("separate"));
- doing_undo = true;
- }
- XMLNode &before, &after;
- if (doing_undo)
- before = playlist->get_state();
-
- /* XXX need to consider musical time selections here at some point */
+ /* get everything in the correct order */
- 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 (!selection->tracks.empty()) {
+ sort_track_selection ();
+ ts = selection->tracks;
+ } else if (entered_track) {
+ ts.push_back (entered_track);
+ }
- if (doing_undo)
- session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
- }
- }
+ for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
+
+ /* undo/redo is handled by individual tracks */
+
+ if ((*i)->paste (position, times, *cut_buffer, nth)) {
+ commit = true;
}
}
-
- if (doing_undo) commit_reversible_command ();
+
+ if (commit) {
+ commit_reversible_command ();
+ }
}
void
-Editor::separate_regions_using_location (Location& loc)
+Editor::paste_named_selection (float times)
{
- bool doing_undo = false;
+ TrackSelection::iterator t;
- if (loc.is_mark()) {
+ Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
+
+ if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
return;
}
- Playlist *playlist;
+ TreeModel::iterator i = selected->get_selected();
+ NamedSelection* ns = (*i)[named_selection_columns.selection];
- /* 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)
- */
+ list<boost::shared_ptr<Playlist> >::iterator chunk;
+ list<boost::shared_ptr<Playlist> >::iterator tmp;
- for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
- //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ chunk = ns->playlists.begin();
+
+ begin_reversible_command (_("paste chunk"));
+
+ sort_track_selection ();
+ for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
+
AudioTimeAxisView* atv;
+ boost::shared_ptr<Playlist> pl;
+ boost::shared_ptr<AudioPlaylist> apl;
- if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
+ if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
+ continue;
+ }
- if (atv->is_audio_track()) {
-
- if ((playlist = atv->playlist()) != 0) {
- XMLNode &before, &after;
- if (!doing_undo) {
- begin_reversible_command (_("separate"));
- doing_undo = true;
- }
- if (doing_undo)
- before = playlist->get_state();
-
-
- /* XXX need to consider musical time selections here at some point */
+ if ((pl = atv->playlist()) == 0) {
+ continue;
+ }
+
+ if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
+ continue;
+ }
- double speed = atv->get_diskstream()->speed();
+ tmp = chunk;
+ ++tmp;
+ XMLNode &before = apl->get_state();
+ apl->paste (*chunk, get_preferred_edit_position(), times);
+ session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
- playlist->partition ((jack_nframes_t)(loc.start() * speed), (jack_nframes_t)(loc.end() * speed), true);
- if (doing_undo)
- session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
- }
- }
+ if (tmp != ns->playlists.end()) {
+ chunk = tmp;
}
}
- if (doing_undo) commit_reversible_command ();
+ commit_reversible_command();
}
void
-Editor::crop_region_to_selection ()
+Editor::duplicate_some_regions (RegionSelection& regions, float times)
{
- if (selection->time.empty()) {
- return;
- }
+ boost::shared_ptr<Playlist> playlist;
+ RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
+ RegionSelection foo;
- vector<Playlist*> playlists;
- Playlist *playlist;
-
- if (clicked_trackview != 0) {
+ begin_reversible_command (_("duplicate region"));
- if ((playlist = clicked_trackview->playlist()) == 0) {
- return;
- }
+ selection->clear_regions ();
- playlists.push_back (playlist);
+ for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
- } else {
-
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ boost::shared_ptr<Region> r ((*i)->region());
- AudioTimeAxisView* atv;
+ TimeAxisView& tv = (*i)->get_time_axis_view();
+ AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
- if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
+ latest_regionviews.clear ();
+ sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
+
+ playlist = (*i)->region()->playlist();
+ XMLNode &before = playlist->get_state();
+ playlist->duplicate (r, r->last_frame() + 1, times);
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
- if (atv->is_audio_track()) {
-
- if ((playlist = atv->playlist()) != 0) {
- playlists.push_back (playlist);
- }
- }
- }
- }
+ c.disconnect ();
+
+ foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
}
- 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;
-
- XMLNode &before = (*i)->get_state();
- region->trim_to (start, cnt, this);
- XMLNode &after = (*i)->get_state();
- session->add_command (MementoCommand<Playlist>(*(*i), before, after));
- }
+ commit_reversible_command ();
- commit_reversible_command ();
+ if (!foo.empty()) {
+ selection->set (foo);
}
-}
+}
void
-Editor::region_fill_track ()
+Editor::duplicate_selection (float times)
{
- jack_nframes_t end;
-
- if (!session || selection->audio_regions.empty()) {
+ if (selection->time.empty() || selection->tracks.empty()) {
return;
}
- end = session->current_end_frame ();
+ boost::shared_ptr<Playlist> playlist;
+ vector<boost::shared_ptr<AudioRegion> > new_regions;
+ vector<boost::shared_ptr<AudioRegion> >::iterator ri;
+
+ create_region_from_selection (new_regions);
- begin_reversible_command (_("region fill"));
+ if (new_regions.empty()) {
+ return;
+ }
+
+ begin_reversible_command (_("duplicate selection"));
- for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
+ ri = new_regions.begin();
- AudioRegion& region ((*i)->region);
- Playlist* pl = region.playlist();
+ for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ if ((playlist = (*i)->playlist()) == 0) {
+ continue;
+ }
+ XMLNode &before = playlist->get_state();
+ playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
+ XMLNode &after = playlist->get_state();
+ session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
- if (end <= region.last_frame()) {
- return;
+ ++ri;
+ if (ri == new_regions.end()) {
+ --ri;
}
+ }
- double times = (double) (end - region.last_frame()) / (double) region.length();
+ commit_reversible_command ();
+}
- if (times == 0) {
- return;
- }
+void
+Editor::reset_point_selection ()
+{
+ /* reset all selected points to the relevant default value */
- XMLNode &before = pl->get_state();
- pl->add_region (*(new AudioRegion (region)), region.last_frame(), times);
- session->add_command (MementoCommand<Playlist>(*pl, before, pl->get_state()));
+ 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);
+ }
}
+}
- commit_reversible_command ();
+void
+Editor::center_playhead ()
+{
+ float page = canvas_width * frames_per_unit;
+ center_screen_internal (playhead_cursor->current_frame, page);
}
void
-Editor::region_fill_selection ()
+Editor::center_edit_point ()
{
- if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
- return;
- }
+ float page = canvas_width * frames_per_unit;
+ center_screen_internal (get_preferred_edit_position(), page);
+}
- if (selection->time.empty()) {
- return;
- }
+void
+Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
+{
+ begin_reversible_command (_("clear playlist"));
+ XMLNode &before = playlist->get_state();
+ playlist->clear ();
+ XMLNode &after = playlist->get_state();
+ session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
+ commit_reversible_command ();
+}
- Region *region;
+void
+Editor::nudge_track (bool use_edit, bool forwards)
+{
+ boost::shared_ptr<Playlist> playlist;
+ nframes_t distance;
+ nframes_t next_distance;
+ nframes_t start;
- Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
+ if (use_edit) {
+ start = get_preferred_edit_position();
+ } else {
+ start = 0;
+ }
- if (selected->count_selected_rows() != 1) {
+ if ((distance = get_nudge_distance (start, next_distance)) == 0) {
return;
}
-
- TreeModel::iterator i = region_list_display.get_selection()->get_selected();
- region = (*i)[region_list_columns.region];
-
- 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"));
+ begin_reversible_command (_("nudge track"));
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
}
XMLNode &before = playlist->get_state();
- playlist->add_region (*(createRegion (*region)), start, times);
- session->add_command (MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
+ playlist->nudge_after (start, distance, forwards);
+ XMLNode &after = playlist->get_state();
+ session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
}
commit_reversible_command ();
}
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"));
- XMLNode &before = region.playlist()->get_state();
- region.set_sync_position (position);
- XMLNode &after = region.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
- commit_reversible_command ();
-}
-
-void
-Editor::set_region_sync_from_edit_cursor ()
+Editor::remove_last_capture ()
{
- if (clicked_regionview == 0) {
+ vector<string> choices;
+ string prompt;
+
+ if (!session) {
return;
}
- if (!clicked_regionview->region.covers (edit_cursor->current_frame)) {
- error << _("Place the edit cursor at the desired sync point") << endmsg;
- 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)");
- Region& region (clicked_regionview->region);
- begin_reversible_command (_("set sync from edit cursor"));
- XMLNode &before = region.playlist()->get_state();
- region.set_sync_position (edit_cursor->current_frame);
- XMLNode &after = region.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
- commit_reversible_command ();
-}
+ choices.push_back (_("No, do nothing."));
+ choices.push_back (_("Yes, destroy it."));
+
+ Gtkmm2ext::Choice prompter (prompt, choices);
+
+ if (prompter.run () == 1) {
+ session->remove_last_capture ();
+ }
-void
-Editor::remove_region_sync ()
-{
- if (clicked_regionview) {
- Region& region (clicked_regionview->region);
- begin_reversible_command (_("remove sync"));
- XMLNode &before = region.playlist()->get_state();
- region.clear_sync_position ();
- XMLNode &after = region.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
- commit_reversible_command ();
+ } else {
+ session->remove_last_capture();
}
}
void
-Editor::naturalize ()
+Editor::normalize_region ()
{
- if (selection->audio_regions.empty()) {
+ if (!session) {
return;
}
- begin_reversible_command (_("naturalize"));
- for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
- XMLNode &before = (*i)->region.get_state();
- (*i)->region.move_to_natural_position (this);
- XMLNode &after = (*i)->region.get_state();
- session->add_command (MementoCommand<AudioRegion>((*i)->region, before, after));
- }
- 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()) {
+ if (selection->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);
-
- XMLNode &before = region.playlist()->get_state();
-
- if (dir > 0) {
- region.set_position (region.position() + distance, this);
- } else {
- region.set_position (region.position() - distance, this);
- }
+ begin_reversible_command (_("normalize"));
- XMLNode &after = region.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
+ track_canvas.get_window()->set_cursor (*wait_cursor);
+ gdk_flush ();
+ for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
+ if (!arv)
+ continue;
+ XMLNode &before = arv->region()->get_state();
+ arv->audio_region()->normalize_to (0.0f);
+ session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
}
commit_reversible_command ();
+ track_canvas.get_window()->set_cursor (*current_canvas_cursor);
}
+
void
-Editor::align_selection (RegionPoint point, jack_nframes_t position)
+Editor::denormalize_region ()
{
- if (selection->audio_regions.empty()) {
+ if (!session) {
return;
}
- begin_reversible_command (_("align selection"));
+ if (selection->regions.empty()) {
+ return;
+ }
+
+ begin_reversible_command ("denormalize");
- for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
- align_region_internal ((*i)->region, point, position);
+ for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
+ if (!arv)
+ continue;
+ XMLNode &before = arv->region()->get_state();
+ arv->audio_region()->set_scale_amplitude (1.0f);
+ session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
}
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)
+Editor::reverse_region ()
{
- XMLNode &before, &after;
- before = region.playlist()->get_state();
-
- 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;
+ if (!session) {
+ return;
}
- after = region.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
-}
+ Reverse rev (*session);
+ apply_filter (rev, _("reverse regions"));
+}
void
-Editor::trim_region_to_edit_cursor ()
+Editor::apply_filter (AudioFilter& filter, string command)
{
- if (clicked_regionview == 0) {
+ if (selection->regions.empty()) {
return;
}
- Region& region (clicked_regionview->region);
-
- float speed = 1.0f;
- AudioTimeAxisView *atav;
+ begin_reversible_command (command);
- if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
- if (atav->get_diskstream() != 0) {
- speed = atav->get_diskstream()->speed();
- }
- }
+ track_canvas.get_window()->set_cursor (*wait_cursor);
+ gdk_flush ();
- begin_reversible_command (_("trim to edit"));
- XMLNode &before = region.playlist()->get_state();
- region.trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
- XMLNode &after = region.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
- commit_reversible_command ();
-}
+ for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
+ if (!arv)
+ continue;
-void
-Editor::trim_region_from_edit_cursor ()
-{
- if (clicked_regionview == 0) {
- return;
- }
+ boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
- Region& region (clicked_regionview->region);
+ RegionSelection::iterator tmp;
+
+ tmp = r;
+ ++tmp;
- float speed = 1.0f;
- AudioTimeAxisView *atav;
+ if (arv->audio_region()->apply (filter) == 0) {
- if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
- if (atav->get_diskstream() != 0) {
- speed = atav->get_diskstream()->speed();
+ XMLNode &before = playlist->get_state();
+ playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
+ XMLNode &after = playlist->get_state();
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+ } else {
+ goto out;
}
+
+ r = tmp;
}
- begin_reversible_command (_("trim to edit"));
- XMLNode &before = region.playlist()->get_state();
- region.trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
- XMLNode &after = region.playlist()->get_state();
- session->add_command(MementoCommand<Playlist>(*(region.playlist()), before, after));
commit_reversible_command ();
+ selection->regions.clear ();
+
+ out:
+ track_canvas.get_window()->set_cursor (*current_canvas_cursor);
}
void
-Editor::unfreeze_route ()
+Editor::region_selection_op (void (Region::*pmf)(void))
{
- if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
- return;
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ Region* region = (*i)->region().get();
+ (region->*pmf)();
}
-
- 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 ()
+void
+Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
{
- clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
- return 0;
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ Region* region = (*i)->region().get();
+ (region->*pmf)(arg);
+ }
}
-gint
-Editor::freeze_progress_timeout (void *arg)
+void
+Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
{
- interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
- return !(current_interthread_info->done || current_interthread_info->cancel);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ Region* region = (*i)->region().get();
+ (region->*pmf)(yn);
+ }
}
void
-Editor::freeze_route ()
+Editor::external_edit_region ()
{
- 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"));
- interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
- interthread_progress_window->show_all ();
- interthread_progress_bar.set_fraction (0.0f);
- interthread_progress_label.set_text ("");
- interthread_cancel_label.set_text (_("Cancel Freeze"));
- current_interthread_info = &itt;
-
- interthread_progress_connection =
- Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
+ if (!clicked_regionview) {
+ return;
+ }
- itt.done = false;
- itt.cancel = false;
- itt.progress = 0.0f;
+ /* more to come */
+}
- pthread_create (&itt.thread, 0, _freeze_thread, this);
+void
+Editor::brush (nframes_t pos)
+{
+ RegionSelection sel;
+ snap_to (pos);
- track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
+ if (selection->regions.empty()) {
+ /* XXX get selection from region list */
+ } else {
+ sel = selection->regions;
+ }
- while (!itt.done && !itt.cancel) {
- gtk_main_iteration ();
+ if (sel.empty()) {
+ return;
}
- interthread_progress_connection.disconnect ();
- interthread_progress_window->hide_all ();
- current_interthread_info = 0;
- track_canvas.get_window()->set_cursor (*current_canvas_cursor);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ mouse_brush_insert_region ((*i), pos);
+ }
}
void
-Editor::bounce_range_selection ()
+Editor::reset_region_gain_envelopes ()
{
- if (selection->time.empty()) {
+ if (!session || selection->regions.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"));
+ session->begin_reversible_command (_("reset region gain"));
- for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
-
- AudioTimeAxisView* atv;
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+ if (arv) {
+ AutomationList& alist (arv->audio_region()->envelope());
+ XMLNode& before (alist.get_state());
- if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
- continue;
- }
-
- Playlist* playlist;
-
- if ((playlist = atv->playlist()) == 0) {
- return;
+ arv->audio_region()->set_default_envelope ();
+ session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
}
-
- InterThreadInfo itt;
-
- itt.done = false;
- itt.cancel = false;
- itt.progress = false;
-
- XMLNode &before = playlist->get_state();
- atv->audio_track()->bounce_range (start, cnt, itt);
- XMLNode &after = playlist->get_state();
- session->add_command (MementoCommand<Playlist> (*playlist, before, after));
}
-
- commit_reversible_command ();
-
- delete views;
+
+ session->commit_reversible_command ();
}
void
-Editor::cut ()
+Editor::toggle_gain_envelope_visibility ()
{
- cut_copy (Cut);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+ if (arv) {
+ bool x = region_envelope_visible_item->get_active();
+ if (x != arv->envelope_visible()) {
+ arv->set_envelope_visible (x);
+ }
+ }
+ }
}
void
-Editor::copy ()
+Editor::toggle_gain_envelope_active ()
{
- cut_copy (Copy);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+ if (arv) {
+ bool x = region_envelope_active_item->get_active();
+ if (x != arv->audio_region()->envelope_active()) {
+ arv->audio_region()->set_envelope_active (x);
+ }
+ }
+ }
}
-void
-Editor::cut_copy (CutCopyOp op)
+void
+Editor::toggle_region_lock ()
{
- /* 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 ();
- }
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+ if (arv) {
+ bool x = region_lock_item->get_active();
+ if (x != arv->audio_region()->locked()) {
+ arv->audio_region()->set_locked (x);
}
-
- 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 ();
+void
+Editor::toggle_region_mute ()
+{
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+ if (arv) {
+ bool x = region_mute_item->get_active();
+ if (x != arv->audio_region()->muted()) {
+ arv->audio_region()->set_muted (x);
}
-
}
- break;
-
- default:
- break;
}
}
void
-Editor::cut_copy_points (CutCopyOp op)
+Editor::toggle_region_opaque ()
{
- 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);
- }
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+ if (arv) {
+ bool x = region_opaque_item->get_active();
+ if (x != arv->audio_region()->opaque()) {
+ arv->audio_region()->set_opaque (x);
+ }
+ }
}
}
void
-Editor::cut_copy_regions (CutCopyOp op)
+Editor::set_fade_length (bool in)
{
- typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
- PlaylistMapping pmap;
- jack_nframes_t first_position = max_frames;
- set<Playlist*> freezelist;
- pair<set<Playlist*>::iterator,bool> insert_result;
+ ensure_entered_region_selected (true);
- for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) {
- first_position = min ((*x)->region.position(), first_position);
+ /* we need a region to measure the offset from the start */
- 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_command (MementoUndoCommand<Playlist>(*pl, pl->get_state()));
- }
- }
- }
- }
+ RegionView* rv;
- for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ) {
+ if (entered_regionview) {
+ rv = entered_regionview;
+ } else if (!selection->regions.empty()) {
+ rv = selection->regions.front();
+ } else {
+ return;
+ }
- AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
- AudioPlaylist* npl;
- AudioRegionSelection::iterator tmp;
-
- tmp = x;
- ++tmp;
+ nframes64_t pos = get_preferred_edit_position();
+ nframes_t len;
+ char* cmd;
- if (pl) {
+ if (in) {
+ if (pos <= rv->region()->position()) {
+ /* can't do it */
+ return;
+ }
+ len = pos - rv->region()->position();
+ cmd = _("set fade in length");
+ } else {
+ if (pos >= rv->region()->last_frame()) {
+ /* can't do it */
+ return;
+ }
+ len = rv->region()->last_frame() - pos;
+ cmd = _("set fade out length");
+ }
- 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;
- }
+ begin_reversible_command (cmd);
- switch (op) {
- case Cut:
- npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
- pl->remove_region (&((*x)->region));
- break;
+ RegionSelection& rs (get_regions_for_action());
- case Copy:
- npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
- break;
+ for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
- case Clear:
- pl->remove_region (&((*x)->region));
- break;
- }
+ if (!tmp) {
+ return;
}
- x = tmp;
- }
+ AutomationList& alist = tmp->audio_region()->fade_in();
+ XMLNode &before = alist.get_state();
- list<Playlist*> foo;
-
- for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
- foo.push_back (i->second);
+ if (in) {
+ tmp->audio_region()->set_fade_in_length (len);
+ } else {
+ tmp->audio_region()->set_fade_out_length (len);
+ }
+
+ XMLNode &after = alist.get_state();
+ session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
}
- if (!foo.empty()) {
- cut_buffer->set (foo);
- }
-
- for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
- (*pl)->thaw ();
- session->add_command (MementoRedoCommand<Playlist>(*(*pl), *(*pl)->get_state()));
- }
+ commit_reversible_command ();
}
+
void
-Editor::cut_copy_ranges (CutCopyOp op)
+Editor::toggle_fade_active (bool in)
{
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
- (*i)->cut_copy_clear (*selection, op);
+ ensure_entered_region_selected (true);
+
+ if (selection->regions.empty()) {
+ return;
}
-}
-void
-Editor::paste (float times)
-{
- paste_internal (edit_cursor->current_frame, times);
-}
+ const char* cmd = (in ? _("toggle fade in active") : _("toggle fade out active"));
-void
-Editor::mouse_paste ()
-{
- int x, y;
- double wx, wy;
+ begin_reversible_command (cmd);
- track_canvas.get_pointer (x, y);
- track_canvas.window_to_world (x, y, wx, wy);
- wx += horizontal_adjustment.get_value();
- wy += vertical_adjustment.get_value();
+ for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
- 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);
-}
+ if (!tmp) {
+ return;
+ }
-void
-Editor::paste_internal (jack_nframes_t position, float times)
-{
- bool commit = false;
+ boost::shared_ptr<AudioRegion> region (tmp->audio_region());
- if (cut_buffer->empty() || selection->tracks.empty()) {
- return;
- }
+ XMLNode &before = region->get_state();
- if (position == max_frames) {
- position = edit_cursor->current_frame;
+ if (in) {
+ region->set_fade_in_active (!region->fade_in_active());
+ } else {
+ region->set_fade_out_active (!region->fade_out_active());
+ }
+
+ XMLNode &after = region->get_state();
+ session->add_command(new MementoCommand<AudioRegion>(*region.get(), &before, &after));
}
- begin_reversible_command (_("paste"));
+ commit_reversible_command ();
+}
- TrackSelection::iterator i;
- size_t nth;
+void
+Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
+{
+ begin_reversible_command (_("set fade in shape"));
- for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
-
- /* undo/redo is handled by individual tracks */
+ for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
- if ((*i)->paste (position, times, *cut_buffer, nth)) {
- commit = true;
+ if (!tmp) {
+ return;
}
- }
- if (commit) {
- commit_reversible_command ();
+ AutomationList& alist = tmp->audio_region()->fade_in();
+ XMLNode &before = alist.get_state();
+
+ tmp->audio_region()->set_fade_in_shape (shape);
+
+ XMLNode &after = alist.get_state();
+ session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
}
+
+ commit_reversible_command ();
}
void
-Editor::paste_named_selection (float times)
+Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
{
- TrackSelection::iterator t;
-
- Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
+ begin_reversible_command (_("set fade out shape"));
- if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
- return;
- }
+ for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
- TreeModel::iterator i = selected->get_selected();
- NamedSelection* ns = (*i)[named_selection_columns.selection];
+ if (!tmp) {
+ return;
+ }
- list<Playlist*>::iterator chunk;
- list<Playlist*>::iterator tmp;
+ AutomationList& alist = tmp->audio_region()->fade_out();
+ XMLNode &before = alist.get_state();
- chunk = ns->playlists.begin();
+ tmp->audio_region()->set_fade_out_shape (shape);
- begin_reversible_command (_("paste chunk"));
+ XMLNode &after = alist.get_state();
+ session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+ }
- for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
-
- AudioTimeAxisView* atv;
- Playlist* pl;
- AudioPlaylist* apl;
+ commit_reversible_command ();
+}
- if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
- continue;
- }
+void
+Editor::set_fade_in_active (bool yn)
+{
+ begin_reversible_command (_("set fade in active"));
- if ((pl = atv->playlist()) == 0) {
- continue;
- }
+ for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
- if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
- continue;
+ if (!tmp) {
+ return;
}
- tmp = chunk;
- ++tmp;
- XMLNode &before = apl->get_state();
- apl->paste (**chunk, edit_cursor->current_frame, times);
- session->add_command(MementoCommand<AudioPlaylist>(*apl, before, apl->get_state()));
+ boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
- if (tmp != ns->playlists.end()) {
- chunk = tmp;
- }
- }
+ XMLNode &before = ar->get_state();
- commit_reversible_command();
+ ar->set_fade_in_active (yn);
+
+ XMLNode &after = ar->get_state();
+ session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
+ }
}
void
-Editor::duplicate_some_regions (AudioRegionSelection& regions, float times)
+Editor::set_fade_out_active (bool yn)
{
- Playlist *playlist;
- AudioRegionSelection sel = regions; // clear (below) will clear the argument list
-
- begin_reversible_command (_("duplicate region"));
+ begin_reversible_command (_("set fade out active"));
- selection->clear_audio_regions ();
+ for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
- for (AudioRegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
+ if (!tmp) {
+ return;
+ }
- Region& r ((*i)->region);
+ boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
- 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));
+ XMLNode &before = ar->get_state();
+
+ ar->set_fade_out_active (yn);
- playlist = (*i)->region.playlist();
- XMLNode &before = playlist->get_state();
- playlist->duplicate (r, r.last_frame(), times);
- session->add_command(MementoCommand<Playlist>(*playlist, before, playlist->get_state()));
+ XMLNode &after = ar->get_state();
+ session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
+ }
+}
- c.disconnect ();
- if (latest_regionview) {
- selection->add (latest_regionview);
+/** Update crossfade visibility after its configuration has been changed */
+void
+Editor::update_xfade_visibility ()
+{
+ _xfade_visibility = Config->get_xfades_visible ();
+
+ for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+ AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
+ if (v) {
+ if (_xfade_visibility) {
+ v->show_all_xfades ();
+ } else {
+ v->hide_all_xfades ();
+ }
}
}
-
-
- commit_reversible_command ();
}
void
-Editor::duplicate_selection (float times)
+Editor::set_edit_point ()
{
- if (selection->time.empty() || selection->tracks.empty()) {
+ nframes64_t where;
+ bool ignored;
+
+ if (!mouse_frame (where, ignored)) {
return;
}
+
+ snap_to (where);
- Playlist *playlist;
- vector<AudioRegion*> new_regions;
- vector<AudioRegion*>::iterator ri;
+ if (selection->markers.empty()) {
- create_region_from_selection (new_regions);
+ mouse_add_new_marker (where);
- if (new_regions.empty()) {
- return;
- }
-
- begin_reversible_command (_("duplicate selection"));
+ } else {
+ bool ignored;
- ri = new_regions.begin();
+ Location* loc = find_location_from_marker (selection->markers.front(), ignored);
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
- if ((playlist = (*i)->playlist()) == 0) {
- continue;
+ if (loc) {
+ loc->move_to (where);
}
- XMLNode &before = playlist->get_state();
- playlist->duplicate (**ri, selection->time[clicked_selection].end, times);
- XMLNode &after = playlist->get_state();
- session->add_command (MementoCommand<Playlist>(*playlist, before, after));
+ }
+}
- ++ri;
- if (ri == new_regions.end()) {
- --ri;
+void
+Editor::set_playhead_cursor ()
+{
+ if (entered_marker) {
+ session->request_locate (entered_marker->position(), session->transport_rolling());
+ } else {
+ nframes64_t where;
+ bool ignored;
+
+ if (!mouse_frame (where, ignored)) {
+ return;
+ }
+
+ snap_to (where);
+
+ if (session) {
+ session->request_locate (where, session->transport_rolling());
}
}
-
- commit_reversible_command ();
}
void
-Editor::reset_point_selection ()
+Editor::split ()
{
- /* reset all selected points to the relevant default value */
+ ensure_entered_region_selected ();
- cerr << "point selection has " << selection->points.size() << " entries\n";
-
- for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
+ nframes64_t where = get_preferred_edit_position();
+
+ if (!selection->regions.empty()) {
- AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
+ split_regions_at (where, selection->regions);
+
+ } else {
- if (atv) {
- atv->reset_objects (selection->points);
- }
+ RegionSelection rs;
+ rs = get_regions_at (where, selection->tracks);
+ split_regions_at (where, rs);
}
}
void
-Editor::center_playhead ()
+Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
{
- float page = canvas_width * frames_per_unit;
+ if (entered_track && mouse_mode == MouseObject) {
+ if (!selection->tracks.empty()) {
+ if (!selection->selected (entered_track)) {
+ selection->add (entered_track);
+ }
+ } else {
+ /* there is no selection, but this operation requires/prefers selected objects */
- center_screen_internal (playhead_cursor->current_frame, page);
+ if (op_really_wants_one_track_if_none_are_selected) {
+ selection->set (entered_track);
+ }
+ }
+ }
}
void
-Editor::center_edit_cursor ()
+Editor::ensure_entered_region_selected (bool op_really_wants_one_region_if_none_are_selected)
{
- float page = canvas_width * frames_per_unit;
+ if (entered_regionview && mouse_mode == MouseObject) {
+
+ /* heuristic:
+
+ - if there is no existing selection, don't change it. the operation will thus apply to "all"
+
+ - if there is an existing selection, but the entered regionview isn't in it, add it. this
+ avoids key-mouse ops on unselected regions from interfering with an existing selection,
+ but also means that the operation will apply to the pointed-at region.
+ */
- center_screen_internal (edit_cursor->current_frame, page);
+ if (!selection->regions.empty()) {
+ if (find (selection->regions.begin(), selection->regions.end(), entered_regionview) != selection->regions.end()) {
+ selection->add (entered_regionview);
+ }
+ } else {
+ /* there is no selection, but this operation requires/prefers selected objects */
+
+ if (op_really_wants_one_region_if_none_are_selected) {
+ selection->set (entered_regionview, false);
+ }
+ }
+ }
}
void
-Editor::clear_playlist (Playlist& playlist)
+Editor::trim_region_front ()
{
- begin_reversible_command (_("clear playlist"));
- XMLNode &before = playlist.get_state();
- playlist.clear ();
- XMLNode &after = playlist.get_state();
- session->add_command (MementoCommand<Playlist>(playlist, before, after));
- commit_reversible_command ();
+ trim_region (true);
}
void
-Editor::nudge_track (bool use_edit_cursor, bool forwards)
+Editor::trim_region_back ()
{
- Playlist *playlist;
- jack_nframes_t distance;
- jack_nframes_t next_distance;
- jack_nframes_t start;
+ trim_region (false);
+}
- if (use_edit_cursor) {
- start = edit_cursor->current_frame;
- } else {
- start = 0;
- }
+void
+Editor::trim_region (bool front)
+{
+ nframes64_t where = get_preferred_edit_position();
+ RegionSelection& rs = get_regions_for_action ();
- if ((distance = get_nudge_distance (start, next_distance)) == 0) {
- return;
- }
-
- if (selection->tracks.empty()) {
+ if (rs.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;
- }
-
- XMLNode &before = playlist->get_state();
- playlist->nudge_after (start, distance, forwards);
- XMLNode &after = playlist->get_state();
- session->add_command (MementoCommand<Playlist>(*playlist, before, after));
+ begin_reversible_command (front ? _("trim front") : _("trim back"));
+
+ for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
+ if (!(*i)->region()->locked()) {
+ boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
+ XMLNode &before = pl->get_state();
+ if (front) {
+ (*i)->region()->trim_front (where, this);
+ } else {
+ (*i)->region()->trim_end (where, this);
+ }
+ XMLNode &after = pl->get_state();
+ session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
+ }
}
-
- commit_reversible_command ();
+ commit_reversible_command ();
}
+struct EditorOrderRouteSorter {
+ bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
+ /* use of ">" forces the correct sort order */
+ return a->order_key ("editor") < b->order_key ("editor");
+ }
+};
+
void
-Editor::remove_last_capture ()
+Editor::select_next_route()
{
- vector<string> choices;
- string prompt;
-
- if (!session) {
+ if (selection->tracks.empty()) {
+ selection->set (track_views.front());
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)");
+ TimeAxisView* current = selection->tracks.front();
- choices.push_back (_("No, do nothing."));
- choices.push_back (_("Yes, destroy it."));
-
- Gtkmm2ext::Choice prompter (prompt, choices);
-
- if (prompter.run () == 1) {
- session->remove_last_capture ();
+ for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+ if (*i == current) {
+ ++i;
+ if (i != track_views.end()) {
+ selection->set (*i);
+ } else {
+ selection->set (*(track_views.begin()));
+ }
+ break;
}
-
- } else {
- session->remove_last_capture();
}
}
void
-Editor::normalize_region ()
+Editor::select_prev_route()
{
- if (!session) {
- return;
- }
-
- if (selection->audio_regions.empty()) {
+ if (selection->tracks.empty()) {
+ selection->set (track_views.front());
return;
}
- begin_reversible_command (_("normalize"));
-
- track_canvas.get_window()->set_cursor (*wait_cursor);
- gdk_flush ();
+ TimeAxisView* current = selection->tracks.front();
- for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
- XMLNode &before = (*r)->region.get_state();
- (*r)->region.normalize_to (0.0f);
- XMLNode &after = (*r)->region.get_state();
- session->add_command (MementoCommand<AudioRegion>((*r)->region, before, after));
+ for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
+ if (*i == current) {
+ ++i;
+ if (i != track_views.rend()) {
+ selection->set (*i);
+ } else {
+ selection->set (*(track_views.rbegin()));
+ }
+ break;
+ }
}
-
- commit_reversible_command ();
- track_canvas.get_window()->set_cursor (*current_canvas_cursor);
}
-
void
-Editor::denormalize_region ()
+Editor::set_loop_from_selection (bool play)
{
- if (!session) {
- return;
- }
-
- if (selection->audio_regions.empty()) {
+ if (session == 0 || selection->time.empty()) {
return;
}
- begin_reversible_command ("denormalize");
+ nframes_t start = selection->time[clicked_selection].start;
+ nframes_t end = selection->time[clicked_selection].end;
+
+ set_loop_range (start, end, _("set loop range from selection"));
- for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
- XMLNode &before = (*r)->region.get_state();
- (*r)->region.set_scale_amplitude (1.0f);
- XMLNode &after = (*r)->region.get_state();
- session->add_command (MementoCommand<AudioRegion>((*r)->region, before, after));
+ if (play) {
+ session->request_play_loop (true);
+ session->request_locate (start, true);
}
-
- commit_reversible_command ();
}
-
void
-Editor::reverse_region ()
+Editor::set_loop_from_edit_range (bool play)
{
- if (!session) {
+ if (session == 0) {
return;
}
- Reverse rev (*session);
- apply_filter (rev, _("reverse regions"));
-}
-
-void
-Editor::apply_filter (AudioFilter& filter, string command)
-{
- if (selection->audio_regions.empty()) {
+ nframes64_t start;
+ nframes64_t end;
+
+ if (!get_edit_op_range (start, end)) {
return;
}
- begin_reversible_command (command);
-
- track_canvas.get_window()->set_cursor (*wait_cursor);
- 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) {
-
- XMLNode &before = playlist->get_state();
- playlist->replace_region (region, *(filter.results.front()), region.position());
- XMLNode &after = playlist->get_state();
- session->add_command(MementoCommand<Playlist>(*playlist, before, after));
- } else {
- goto out;
- }
+ set_loop_range (start, end, _("set loop range from edit range"));
- r = tmp;
+ if (play) {
+ session->request_play_loop (true);
+ session->request_locate (start, true);
}
-
- commit_reversible_command ();
- selection->audio_regions.clear ();
-
- out:
- track_canvas.get_window()->set_cursor (*current_canvas_cursor);
}
void
-Editor::region_selection_op (void (Region::*pmf)(void))
+Editor::set_loop_from_region (bool play)
{
- for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
- ((*i)->region.*pmf)();
- }
-}
+ nframes64_t start = max_frames;
+ nframes64_t end = 0;
+ ensure_entered_region_selected (true);
-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);
+ if (selection->regions.empty()) {
+ info << _("cannot set loop: no region selected") << endmsg;
+ return;
}
-}
-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);
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ if ((*i)->region()->position() < start) {
+ start = (*i)->region()->position();
+ }
+ if ((*i)->region()->last_frame() + 1 > end) {
+ end = (*i)->region()->last_frame() + 1;
+ }
+ }
+
+ set_loop_range (start, end, _("set loop range from region"));
+
+ if (play) {
+ session->request_play_loop (true);
+ session->request_locate (start, true);
}
}
void
-Editor::external_edit_region ()
+Editor::set_punch_from_selection ()
{
- if (!clicked_regionview) {
+ if (session == 0 || selection->time.empty()) {
return;
}
- /* more to come */
+ nframes_t start = selection->time[clicked_selection].start;
+ nframes_t end = selection->time[clicked_selection].end;
+
+ set_punch_range (start, end, _("set punch range from selection"));
}
void
-Editor::brush (jack_nframes_t pos)
+Editor::set_punch_from_edit_range ()
{
- AudioRegionSelection sel;
- snap_to (pos);
-
- if (selection->audio_regions.empty()) {
- /* XXX get selection from region list */
- } else {
- sel = selection->audio_regions;
+ if (session == 0) {
+ return;
}
- if (sel.empty()) {
+ nframes64_t start;
+ nframes64_t end;
+
+ if (!get_edit_op_range (start, end)) {
return;
}
- for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
- mouse_brush_insert_region ((*i), pos);
- }
+ set_punch_range (start, end, _("set punch range from edit range"));
}
void
-Editor::toggle_gain_envelope_visibility ()
+Editor::pitch_shift_regions ()
{
- for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
- (*i)->set_envelope_visible (!(*i)->envelope_visible());
+ ensure_entered_region_selected (true);
+
+ if (selection->regions.empty()) {
+ return;
}
-}
-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);
- }
- }
+ pitch_shift (selection->regions, 1.2);
}
+