#include "ardour/operations.h"
#include "ardour_ui.h"
+#include "debug.h"
#include "editor.h"
#include "time_axis_view.h"
#include "route_time_axis.h"
#include "editor_cursors.h"
#include "mouse_cursors.h"
#include "patch_change_dialog.h"
+#include "transpose_dialog.h"
#include "i18n.h"
}
} else {
snap_to (where);
-
+
frozen = true;
EditorFreeze(); /* Emit Signal */
}
}
commit_reversible_command ();
-
+
if (frozen){
EditorThaw(); /* Emit Signal */
}
}
-boost::shared_ptr<Region>
-Editor::select_region_for_operation (int /*dir*/, TimeAxisView **tv)
+/** Move one extreme of the current range selection. If more than one range is selected,
+ * the start of the earliest range or the end of the latest range is moved.
+ *
+ * @param move_end true to move the end of the current range selection, false to move
+ * the start.
+ * @param next true to move the extreme to the next region boundary, false to move to
+ * the previous.
+ */
+void
+Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
{
- RegionView* rv;
- boost::shared_ptr<Region> region;
- framepos_t start = 0;
-
- if (selection->time.start () == selection->time.end_frame ()) {
-
- /* no current selection-> is there a selected regionview? */
-
- if (selection->regions.empty()) {
- return region;
- }
-
+ if (selection->time.start() == selection->time.end_frame()) {
+ return;
}
- if (!selection->regions.empty()) {
-
- rv = *(selection->regions.begin());
- (*tv) = &rv->get_time_axis_view();
- region = rv->region();
-
- } else if (!selection->tracks.empty()) {
-
- (*tv) = selection->tracks.front();
-
- RouteTimeAxisView* rtv;
+ framepos_t start = selection->time.start ();
+ framepos_t end = selection->time.end_frame ();
- if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
- boost::shared_ptr<Playlist> pl;
+ /* the position of the thing we may move */
+ framepos_t pos = move_end ? end : start;
+ int dir = next ? 1 : -1;
- if ((pl = rtv->playlist()) == 0) {
- return region;
- }
-
- region = pl->top_region_at (start);
- }
+ /* so we don't find the current region again */
+ if (dir > 0 || pos > 0) {
+ pos += dir;
}
- return region;
-}
-
-void
-Editor::extend_selection_to_end_of_region (bool next)
-{
- TimeAxisView *tv;
- boost::shared_ptr<Region> region;
- framepos_t start;
-
- if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
+ framepos_t const target = get_region_boundary (pos, dir, true, false);
+ if (target < 0) {
return;
}
- if (region && selection->time.start () == selection->time.end_frame ()) {
- start = region->position();
+ if (move_end) {
+ end = target;
} else {
- start = selection->time.start ();
+ start = target;
}
- begin_reversible_command (_("extend selection"));
- selection->set (start, region->position() + region->length());
- commit_reversible_command ();
-}
-
-void
-Editor::extend_selection_to_start_of_region (bool previous)
-{
- TimeAxisView *tv;
- boost::shared_ptr<Region> region;
- framepos_t end;
-
- if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
+ if (end < start) {
return;
}
- if (region && selection->time.start () == selection->time.end_frame ()) {
- end = region->position() + region->length();
- } else {
- end = selection->time.end_frame ();
- }
-
- /* Try to leave the selection with the same route if possible */
-
- begin_reversible_command (_("extend selection"));
- selection->set (region->position(), end);
+ begin_reversible_command (_("alter selection"));
+ selection->set_preserving_all_ranges (start, end);
commit_reversible_command ();
}
}
r->clear_changes ();
- r->set_position (r->position() + distance, this);
+ r->set_position (r->position() + distance);
_session->add_command (new StatefulDiffCommand (r));
}
if (next) {
distance = next_distance;
}
-
+
r->clear_changes ();
if (r->position() > distance) {
- r->set_position (r->position() - distance, this);
+ r->set_position (r->position() - distance);
} else {
- r->set_position (0, this);
+ r->set_position (0);
}
_session->add_command (new StatefulDiffCommand (r));
}
Editor::nudge_forward_capture_offset ()
{
RegionSelection rs = get_regions_from_selection_and_entered ();
-
+
if (!_session || rs.empty()) {
return;
}
begin_reversible_command (_("nudge forward"));
-
+
framepos_t const distance = _session->worst_output_latency();
-
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
boost::shared_ptr<Region> r ((*i)->region());
-
+
r->clear_changes ();
- r->set_position (r->position() + distance, this);
+ r->set_position (r->position() + distance);
_session->add_command(new StatefulDiffCommand (r));
}
-
+
commit_reversible_command ();
}
}
begin_reversible_command (_("nudge forward"));
-
+
framepos_t const distance = _session->worst_output_latency();
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
boost::shared_ptr<Region> r ((*i)->region());
-
+
r->clear_changes ();
-
+
if (r->position() > distance) {
- r->set_position (r->position() - distance, this);
+ r->set_position (r->position() - distance);
} else {
- r->set_position (0, this);
+ r->set_position (0);
}
_session->add_command(new StatefulDiffCommand (r));
}
-
+
commit_reversible_command ();
}
for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
framepos_t contender;
framecnt_t d;
-
+
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
if (!rtv) {
_session->request_locate (pos);
}
-void
-Editor::playhead_backward ()
-{
- framepos_t pos;
- framepos_t cnt;
- float prefix;
- bool was_floating;
-
- if (get_prefix (prefix, was_floating)) {
- cnt = 1;
- } else {
- if (was_floating) {
- cnt = (framepos_t) floor (prefix * _session->frame_rate ());
- } else {
- cnt = (framepos_t) prefix;
- }
- }
-
- pos = playhead_cursor->current_frame;
-
- if ((framepos_t) pos < cnt) {
- pos = 0;
- } else {
- pos -= cnt;
- }
-
- /* XXX this is completely insane. with the current buffering
- design, we'll force a complete track buffer flush and
- reload, just to move 1 sample !!!
- */
-
- _session->request_locate (pos);
-}
-
-void
-Editor::playhead_forward ()
-{
- framepos_t pos;
- framepos_t cnt;
- bool was_floating;
- float prefix;
-
- if (get_prefix (prefix, was_floating)) {
- cnt = 1;
- } else {
- if (was_floating) {
- cnt = (framepos_t) floor (prefix * _session->frame_rate ());
- } else {
- cnt = (framepos_t) floor (prefix);
- }
- }
-
- pos = playhead_cursor->current_frame;
-
- /* XXX this is completely insane. with the current buffering
- design, we'll force a complete track buffer flush and
- reload, just to move 1 sample !!!
- */
-
- _session->request_locate (pos+cnt);
-}
-
void
Editor::cursor_align (bool playhead_to_edit)
{
}
}
-void
-Editor::edit_cursor_backward ()
-{
- framepos_t pos;
- framepos_t cnt;
- float prefix;
- bool was_floating;
-
- if (get_prefix (prefix, was_floating)) {
- cnt = 1;
- } else {
- if (was_floating) {
- cnt = (framepos_t) floor (prefix * _session->frame_rate ());
- } else {
- cnt = (framepos_t) prefix;
- }
- }
-
- 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 ()
-{
- //framepos_t pos;
- framepos_t cnt;
- bool was_floating;
- float prefix;
-
- if (get_prefix (prefix, was_floating)) {
- cnt = 1;
- } else {
- if (was_floating) {
- cnt = (framepos_t) floor (prefix * _session->frame_rate ());
- } else {
- cnt = (framepos_t) floor (prefix);
- }
- }
-
- // pos = edit_cursor->current_frame;
- // EDIT CURSOR edit_cursor->set_position (pos+cnt);
-}
-
-void
-Editor::goto_frame ()
-{
- float prefix;
- bool was_floating;
- framepos_t frame;
-
- if (get_prefix (prefix, was_floating)) {
- return;
- }
-
- if (was_floating) {
- frame = (framepos_t) floor (prefix * _session->frame_rate());
- } else {
- frame = (framepos_t) floor (prefix);
- }
-
- _session->request_locate (frame);
-}
-
void
Editor::scroll_backward (float pages)
{
- framepos_t frame;
- framepos_t one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
- bool was_floating;
- float prefix;
- framepos_t cnt;
-
- if (get_prefix (prefix, was_floating)) {
- cnt = (framepos_t) floor (pages * one_page);
- } else {
- if (was_floating) {
- cnt = (framepos_t) floor (prefix * _session->frame_rate());
- } else {
- cnt = (framepos_t) floor (prefix * one_page);
- }
- }
+ framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
+ framepos_t const cnt = (framepos_t) floor (pages * one_page);
+ framepos_t frame;
if (leftmost_frame < cnt) {
frame = 0;
} else {
void
Editor::scroll_forward (float pages)
{
- framepos_t frame;
- framepos_t one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
- bool was_floating;
- float prefix;
- framepos_t cnt;
-
- if (get_prefix (prefix, was_floating)) {
- cnt = (framepos_t) floor (pages * one_page);
- } else {
- if (was_floating) {
- cnt = (framepos_t) floor (prefix * _session->frame_rate());
- } else {
- cnt = (framepos_t) floor (prefix * one_page);
- }
- }
+ framepos_t const one_page = (framepos_t) rint (_canvas_width * frames_per_unit);
+ framepos_t const cnt = (framepos_t) floor (pages * one_page);
+ framepos_t frame;
if (max_framepos - cnt < leftmost_frame) {
frame = max_framepos - cnt;
} else {
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());
+ double vert_value = vertical_adjustment.get_value() + 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()));
+ vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
}
void
if (vert_value > vertical_adjustment.get_upper() - _canvas_height) {
vert_value = vertical_adjustment.get_upper() - _canvas_height;
}
-
+
vertical_adjustment.set_value (vert_value);
}
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
- hide_track_in_display (*i, true);
+ hide_track_in_display (*i);
}
}
if (new_leftmost > frame) {
new_leftmost = 0;
}
-// begin_reversible_command (_("zoom to frame"));
-// _session->add_undo (sigc::bind (sigc::mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
-// _session->add_redo (sigc::bind (sigc::mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
-// commit_reversible_command ();
+
+ if (new_leftmost < 0) {
+ new_leftmost = 0;
+ }
reposition_and_zoom (new_leftmost, new_fpu);
}
Editor::add_locations_from_region ()
{
RegionSelection rs = get_regions_from_selection_and_entered ();
-
+
if (rs.empty()) {
return;
}
Editor::add_location_from_region ()
{
RegionSelection rs = get_regions_from_selection_and_entered ();
-
+
if (rs.empty()) {
return;
}
_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
void
Editor::set_mark ()
{
- framepos_t pos;
- float prefix;
- bool was_floating;
- string markername;
+ framepos_t const pos = _session->audible_frame ();
- if (get_prefix (prefix, was_floating)) {
- pos = _session->audible_frame ();
- } else {
- if (was_floating) {
- pos = (framepos_t) floor (prefix * _session->frame_rate ());
- } else {
- pos = (framepos_t) floor (prefix);
- }
- }
+ string markername;
+ _session->locations()->next_available_name (markername, "mark");
- _session->locations()->next_available_name(markername,"mark");
- if (!choose_new_marker_name(markername)) {
+ if (!choose_new_marker_name (markername)) {
return;
}
+
_session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
}
Editor::rename_region ()
{
RegionSelection rs = get_regions_from_selection_and_entered ();
-
+
if (rs.empty()) {
return;
}
if (ret != RESPONSE_OK) {
return;
}
-
+
std::string str = entry.get_text();
strip_whitespace_edges (str);
if (!str.empty()) {
framepos_t end = 0;
RegionSelection rs = get_regions_from_selection_and_entered ();
-
+
if (rs.empty()) {
return;
}
internal_start = start - current->position();
RegionFactory::region_name (new_name, current->name(), true);
- PropertyList plist;
-
+ PropertyList plist;
+
plist.add (ARDOUR::Properties::start, current->start() + internal_start);
plist.add (ARDOUR::Properties::length, selection_cnt);
plist.add (ARDOUR::Properties::name, new_name);
internal_start = start - current->position();
RegionFactory::region_name (new_name, current->name(), true);
- PropertyList plist;
-
+ PropertyList plist;
+
plist.add (ARDOUR::Properties::start, current->start() + internal_start);
plist.add (ARDOUR::Properties::length, end - start + 1);
plist.add (ARDOUR::Properties::name, new_name);
Editor::split_multichannel_region ()
{
RegionSelection rs = get_regions_from_selection_and_entered ();
-
+
if (rs.empty()) {
return;
}
rtv->view()->foreach_regionview (sigc::bind (
sigc::ptr_fun (add_if_covered),
&(*t), &new_selection));
-
+
if (!in_command) {
begin_reversible_command (_("separate"));
in_command = true;
}
-
+
/* pick up changes to existing regions */
vector<Command*> cmds;
vector<PlaylistState> playlists;
RegionSelection rs;
-
+
rs = get_regions_from_selection_and_entered();
if (!_session || rs.empty()) {
//Partition on the region bounds
playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
-
+
//Re-add region that was just removed due to the partition operation
playlist->add_region( (*rl), (*rl)->first_frame() );
}
cnt = the_end - the_start + 1;
region->clear_changes ();
- region->trim_to (the_start, cnt, this);
+ region->trim_to (the_start, cnt);
_session->add_command (new StatefulDiffCommand (region));
}
Editor::remove_region_sync ()
{
RegionSelection rs = get_regions_from_selection_and_entered ();
-
+
if (rs.empty()) {
return;
}
begin_reversible_command (_("remove region sync"));
-
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
(*i)->region()->clear_changes ();
(*i)->region()->clear_sync_position ();
_session->add_command(new StatefulDiffCommand ((*i)->region()));
}
-
+
commit_reversible_command ();
}
} else {
begin_reversible_command (_("move region to original position"));
}
-
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
(*i)->region()->clear_changes ();
- (*i)->region()->move_to_natural_position (this);
+ (*i)->region()->move_to_natural_position ();
_session->add_command (new StatefulDiffCommand ((*i)->region()));
}
-
+
commit_reversible_command ();
}
Editor::align_regions (RegionPoint what)
{
RegionSelection const rs = get_regions_from_selection_and_edit_point ();
-
+
if (rs.empty()) {
return;
}
Editor::align_regions_relative (RegionPoint point)
{
RegionSelection const rs = get_regions_from_selection_and_edit_point ();
-
+
if (rs.empty()) {
return;
}
/* move first one specially */
r->clear_changes ();
- r->set_position (pos, this);
+ r->set_position (pos);
_session->add_command(new StatefulDiffCommand (r));
/* move rest by the same amount */
region->clear_changes ();
if (dir > 0) {
- region->set_position (region->position() + distance, this);
+ region->set_position (region->position() + distance);
} else {
- region->set_position (region->position() - distance, this);
+ region->set_position (region->position() - distance);
}
-
+
_session->add_command(new StatefulDiffCommand (region));
}
switch (point) {
case SyncPoint:
- region->set_position (region->adjust_to_sync (position), this);
+ region->set_position (region->adjust_to_sync (position));
break;
case End:
if (position > region->length()) {
- region->set_position (position - region->length(), this);
+ region->set_position (position - region->length());
}
break;
case Start:
- region->set_position (position, this);
+ region->set_position (position);
break;
}
for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
if (!(*i)->region()->locked()) {
-
+
(*i)->region()->clear_changes ();
-
+
if (front) {
- (*i)->region()->trim_front (where, this);
+ (*i)->region()->trim_front (where);
} else {
- (*i)->region()->trim_end (where, this);
+ (*i)->region()->trim_end (where);
}
-
+
_session->add_command (new StatefulDiffCommand ((*i)->region()));
}
}
start = session_frame_to_track_frame (loc.start(), speed);
end = session_frame_to_track_frame (loc.end(), speed);
-
+
rv->region()->clear_changes ();
- rv->region()->trim_to (start, (end - start), this);
+ rv->region()->trim_to (start, (end - start));
_session->add_command(new StatefulDiffCommand (rv->region()));
}
continue;
}
- region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed), this);
+ region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
arv->region_changed (PropertyChange (ARDOUR::Properties::length));
}
else {
continue;
}
- region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed), this);
+ region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
arv->region_changed (ARDOUR::bounds_change);
}
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
- if (rtv && !rtv->track()->bounceable()) {
+ if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable()) {
MessageDialog d (
- _("One or more selected tracks cannot be bounced because it has more outputs than inputs. "
- "You can fix this by increasing the number of inputs on that track.")
+ _("You can't perform this operation because the processing of the signal "
+ "will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
+ "You can do this without processing, which is a different operation.")
);
d.set_title (_("Cannot bounce"));
d.run ();
playlist->clear_changes ();
playlist->clear_owned_changes ();
-
+
boost::shared_ptr<Region> r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing);
if (replace) {
commit_reversible_command ();
}
+/** Delete selected regions, automation points or a time range */
+void
+Editor::delete_ ()
+{
+ cut_copy (Delete);
+}
+
/** Cut selected regions, automation points or a time range */
void
Editor::cut ()
string opname;
switch (op) {
+ case Delete:
+ opname = _("delete");
+ break;
case Cut:
opname = _("cut");
break;
this function.
*/
- if (op == Cut || op == Clear) {
+ if (op == Delete || op == Cut || op == Clear) {
if (_drags->active ()) {
_drags->abort ();
}
if (!rs.empty()) {
cut_copy_regions (op, rs);
- if (op == Cut) {
+ if (op == Cut || op == Delete) {
selection->clear_regions ();
}
}
if (!selection->points.empty()) {
cut_copy_points (op);
- if (op == Cut) {
+ if (op == Cut || op == Delete) {
selection->clear_points ();
}
}
cut_copy_ranges (op);
commit_reversible_command ();
- if (op == Cut) {
+ if (op == Cut || op == Delete) {
selection->clear_time ();
}
}
}
- if (op == Cut || op == Clear) {
+ if (op == Delete || op == Cut || op == Clear) {
_drags->abort ();
}
}
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track);
+ _last_cut_copy_source_track = atv;
if (atv) {
atv->cut_copy_clear_objects (selection->points, op);
first_position = min ((framepos_t) (*x)->region()->position(), first_position);
- if (op == Cut || op == Clear) {
+ if (op == Cut || op == Clear || op == Delete) {
boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
if (pl) {
FreezeList::iterator fl;
- //only take state if this is a new playlist.
+ // only take state if this is a new playlist.
for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
if ((*fl) == pl) {
break;
tmp = x;
++tmp;
- vector<PlaylistMapping>::iterator z;
+ if (op != Delete) {
- for (z = pmap.begin(); z != pmap.end(); ++z) {
- if ((*z).tv == &tv) {
- break;
+ vector<PlaylistMapping>::iterator z;
+
+ for (z = pmap.begin(); z != pmap.end(); ++z) {
+ if ((*z).tv == &tv) {
+ break;
+ }
+ }
+
+ assert (z != pmap.end());
+
+ if (!(*z).pl) {
+ npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
+ npl->freeze();
+ (*z).pl = npl;
+ } else {
+ npl = (*z).pl;
}
- }
-
- assert (z != pmap.end());
-
- if (!(*z).pl) {
- npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
- npl->freeze();
- (*z).pl = npl;
- } else {
- npl = (*z).pl;
}
boost::shared_ptr<Region> r = (*x)->region();
assert (r != 0);
switch (op) {
+ case Delete:
+ pl->remove_region (r);
+ break;
+
case Cut:
_xx = RegionFactory::create (r);
npl->add_region (_xx, r->position() - first_position);
case Copy:
/* copy region before adding, so we're not putting same object into two different playlists */
npl->add_region (RegionFactory::create (r), r->position() - first_position);
- break;
-
- case Clear:
+ case Clear:
pl->remove_region (r);
break;
}
x = tmp;
}
- list<boost::shared_ptr<Playlist> > foo;
-
- /* the pmap is in the same order as the tracks in which selected regions occured */
+ if (op != Delete) {
- for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
- if ((*i).pl) {
- (*i).pl->thaw();
- foo.push_back ((*i).pl);
+ list<boost::shared_ptr<Playlist> > foo;
+
+ /* the pmap is in the same order as the tracks in which selected regions occured */
+
+ for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
+ if ((*i).pl) {
+ (*i).pl->thaw();
+ foo.push_back ((*i).pl);
+ }
+ }
+
+ if (!foo.empty()) {
+ cut_buffer->set (foo);
+ }
+
+ if (pmap.empty()) {
+ _last_cut_copy_source_track = 0;
+ } else {
+ _last_cut_copy_source_track = pmap.front().tv;
}
}
- if (!foo.empty()) {
- cut_buffer->set (foo);
- }
-
- if (pmap.empty()) {
- _last_cut_copy_source_track = 0;
- } else {
- _last_cut_copy_source_track = pmap.front().tv;
- }
-
for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
(*pl)->thaw ();
_session->add_command (new StatefulDiffCommand (*pl));
TrackViewList* ts;
TrackViewList entered;
+ /* Sort the track selection now, so that it if is used, the playlists
+ selected by the calls below to cut_copy_clear are in the order that
+ their tracks appear in the editor. This makes things like paste
+ of ranges work properly.
+ */
+ sort_track_selection (&selection->tracks);
+
if (selection->tracks.empty()) {
if (!entered_track) {
return;
void
Editor::paste (float times)
{
+ DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
paste_internal (get_preferred_edit_position(), times);
}
void
Editor::paste_internal (framepos_t position, float times)
{
- bool commit = false;
+ DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
if (internal_editing()) {
if (cut_buffer->midi_notes.empty()) {
if (position == max_framepos) {
position = get_preferred_edit_position();
+ DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
}
- begin_reversible_command (Operations::paste);
-
TrackViewList ts;
TrackViewList::iterator i;
size_t nth;
ts = selection->tracks;
} else if (_last_cut_copy_source_track) {
/* otherwise paste to the track that the cut/copy came from;
- see discussion in mants #3333.
+ see discussion in mantis #3333.
*/
ts.push_back (_last_cut_copy_source_track);
}
- for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
+ if (internal_editing ()) {
/* undo/redo is handled by individual tracks/regions */
- if (internal_editing()) {
+ for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
RegionSelection rs;
RegionSelection::iterator r;
++cb;
}
}
+ }
- } else {
+ } else {
- if ((*i)->paste (position, times, *cut_buffer, nth)) {
- commit = true;
- }
+ /* we do redo (do you do voodoo?) */
+
+ begin_reversible_command (Operations::paste);
+
+ for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
+ (*i)->paste (position, times, *cut_buffer, nth);
}
- }
- if (commit) {
commit_reversible_command ();
}
}
playlist->clear_owned_changes ();
playlist->nudge_after (start, distance, forwards);
-
+
vector<Command*> cmds;
-
+
playlist->rdiff (cmds);
_session->add_commands (cmds);
-
+
_session->add_command (new StatefulDiffCommand (playlist));
}
}
RegionSelection rs = get_regions_from_selection_and_entered ();
-
+
if (rs.empty()) {
return;
}
set_canvas_cursor (current_canvas_cursor);
return;
}
-
+
max_amps.push_back (a);
max_amp = max (max_amp, a);
dialog.ascend ();
begin_reversible_command (_("normalize"));
list<double>::const_iterator a = max_amps.begin ();
-
+
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
if (!arv) {
arv->region()->clear_changes ();
double const amp = dialog.normalize_individually() ? *a : max_amp;
-
+
arv->audio_region()->normalize (amp, dialog.target ());
_session->add_command (new StatefulDiffCommand (arv->region()));
int const r = d.run ();
d.drop_rects ();
-
+
if (r == Gtk::RESPONSE_OK) {
ARDOUR::AudioIntervalMap silences;
d.silences (silences);
StripSilence s (*_session, silences, d.fade_length());
apply_filter (s, _("strip silence"), &d);
- }
+ }
}
Command*
vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
v.push_back (selected);
- return op (mrv.midi_region()->model(), v);
+ framepos_t pos_frames = mrv.midi_region()->position();
+ double pos_beats = _session->tempo_map().framewalk_to_beats(0, pos_frames);
+
+ return op (mrv.midi_region()->model(), pos_beats, v);
}
void
if (mrv) {
boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
-
+
playlist->clear_changes ();
playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
_session->add_command(new StatefulDiffCommand (playlist));
Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
PatchChangeDialog d (0, _session, empty, Gtk::Stock::ADD);
-
+
if (d.run() == RESPONSE_CANCEL) {
return;
}
int n = 0;
int const N = rs.size ();
-
+
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
RegionSelection::iterator tmp = r;
++tmp;
/* more to come */
}
-void
-Editor::brush (framepos_t pos)
-{
- snap_to (pos);
-
- RegionSelection rs = get_regions_from_selection_and_entered ();
-
- if (rs.empty()) {
- return;
- }
-
- for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
- mouse_brush_insert_region ((*i), pos);
- }
-}
-
void
Editor::reset_region_gain_envelopes ()
{
if (_ignore_region_action) {
return;
}
-
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
if (_ignore_region_action) {
return;
}
-
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
if (_ignore_region_action) {
return;
}
-
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
if (_ignore_region_action) {
return;
}
-
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
-
+
ar->clear_changes ();
ar->set_fade_in_active (yn);
_session->add_command (new StatefulDiffCommand (ar));
return;
}
- RegionSelection::iterator i;
+ RegionSelection::iterator i;
for (i = rs.begin(); i != rs.end(); ++i) {
if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
if (dir == -1) {
void
Editor::split_region ()
{
- if (((mouse_mode == MouseRange) ||
- (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) &&
+ if (((mouse_mode == MouseRange) ||
+ (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) &&
!selection->time.empty()) {
separate_regions_between (selection->time);
return;
- }
+ }
RegionSelection rs = get_regions_from_selection_and_edit_point ();
{
RegionSelection rs = get_regions_from_selection_and_entered ();
- if (rs.empty()) {
+ RegionSelection audio_rs;
+ for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
+ if (dynamic_cast<AudioRegionView*> (*i)) {
+ audio_rs.push_back (*i);
+ }
+ }
+
+ if (audio_rs.empty()) {
return;
}
- pitch_shift (rs, 1.2);
+ pitch_shift (audio_rs, 1.2);
+}
+
+void
+Editor::transpose_region ()
+{
+ RegionSelection rs = get_regions_from_selection_and_entered ();
+
+ list<MidiRegionView*> midi_region_views;
+ for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
+ MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
+ if (mrv) {
+ midi_region_views.push_back (mrv);
+ }
+ }
+
+ TransposeDialog d;
+ int const r = d.run ();
+ if (r != RESPONSE_ACCEPT) {
+ return;
+ }
+
+ for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
+ (*i)->midi_region()->transpose (d.semitones ());
+ }
}
void
_("Do you want to set the global tempo or add a new tempo marker?"),
options
);
-
+
c.set_default_response (2);
switch (c.run()) {
Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
{
bool use_rhythmic_rodent = false;
-
+
boost::shared_ptr<Playlist> pl = r->playlist();
-
+
list<boost::shared_ptr<Region> > new_regions;
if (!pl) {
int response = msg.run();
msg.hide ();
-
+
switch (response) {
case RESPONSE_OK:
break;
framepos_t pos = 0;
while (x != positions.end()) {
-
+
/* deal with positons that are out of scope of present region bounds */
if (*x <= 0 || *x > r->length()) {
++x;
*/
framepos_t len = (*x) - pos;
-
+
/* XXX we do we really want to allow even single-sample regions?
shouldn't we have some kind of lower limit on region size?
*/
/* do NOT announce new regions 1 by one, just wait till they are all done */
- PropertyList plist;
-
+ PropertyList plist;
+
plist.add (ARDOUR::Properties::start, file_start);
plist.add (ARDOUR::Properties::length, len);
plist.add (ARDOUR::Properties::name, new_name);
string new_name;
RegionFactory::region_name (new_name, r->name());
-
+
/* Add the final region */
- PropertyList plist;
-
+ PropertyList plist;
+
plist.add (ARDOUR::Properties::start, r->start() + pos);
plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
plist.add (ARDOUR::Properties::name, new_name);
boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
pl->add_region (nr, r->position() + pos);
-
+
if (select_new) {
new_regions.push_front(nr);
}
pl->thaw ();
_session->add_command (new StatefulDiffCommand (pl));
-
+
if (select_new) {
for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
if (rs.empty()) {
return;
}
-
+
framepos_t where = get_preferred_edit_position();
_session->begin_reversible_command (_("place transient"));
-
+
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
framepos_t position = (*r)->region()->position();
(*r)->region()->add_transient(where - position);
}
-
+
_session->commit_reversible_command ();
}
Editor::snap_regions_to_grid ()
{
list <boost::shared_ptr<Playlist > > used_playlists;
-
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
return;
}
-
+
_session->begin_reversible_command (_("snap regions to grid"));
-
+
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
-
+
boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
-
+
if (!pl->frozen()) {
/* we haven't seen this playlist before */
framepos_t start_frame = (*r)->region()->first_frame ();
snap_to (start_frame);
- (*r)->region()->set_position (start_frame, this);
+ (*r)->region()->set_position (start_frame);
}
-
+
while (used_playlists.size() > 0) {
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
(*i)->thaw();
Editor::close_region_gaps ()
{
list <boost::shared_ptr<Playlist > > used_playlists;
-
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
Label* l = manage (new Label (_("Crossfade length")));
l->set_alignment (0, 0.5);
table.attach (*l, 0, 1, 0, 1);
-
+
SpinButton spin_crossfade (1, 0);
spin_crossfade.set_range (0, 15);
spin_crossfade.set_increments (1, 1);
l = manage (new Label (_("Pull-back length")));
l->set_alignment (0, 0.5);
table.attach (*l, 0, 1, 1, 2);
-
+
SpinButton spin_pullback (1, 0);
spin_pullback.set_range (0, 100);
spin_pullback.set_increments (1, 1);
table.attach (spin_pullback, 1, 2, 1, 2);
table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
-
+
dialog.get_vbox()->pack_start (table);
dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
return;
}
- framepos_t crossfade_len = spin_crossfade.get_value();
+ framepos_t crossfade_len = spin_crossfade.get_value();
framepos_t pull_back_frames = spin_pullback.get_value();
crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
/* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
-
+
_session->begin_reversible_command (_("close region gaps"));
int idx = 0;
boost::shared_ptr<Region> last_region;
-
+
rs.sort_by_position_and_track();
-
+
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
-
+
boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
-
+
if (!pl->frozen()) {
/* we haven't seen this playlist before */
}
framepos_t position = (*r)->region()->position();
-
+
if (idx == 0 || position < last_region->position()){
last_region = (*r)->region();
idx++;
continue;
}
-
- (*r)->region()->trim_front( (position - pull_back_frames), this );
- last_region->trim_end( (position - pull_back_frames + crossfade_len), this );
-
+
+ (*r)->region()->trim_front( (position - pull_back_frames));
+ last_region->trim_end( (position - pull_back_frames + crossfade_len));
+
last_region = (*r)->region();
-
+
idx++;
}
-
+
while (used_playlists.size() > 0) {
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
(*i)->thaw();
vector<Command*> cmds;
pl->rdiff (cmds);
_session->add_commands (cmds);
-
+
_session->add_command (new StatefulDiffCommand (pl));
commit = true;
}
}
moved = true;
}
-
+
}
if (was_locked) {
void
Editor::fit_selected_tracks ()
{
- fit_tracks (selection->tracks);
+ if (!selection->tracks.empty()) {
+ fit_tracks (selection->tracks);
+ } else {
+ TrackViewList tvl;
+
+ /* no selected tracks - use tracks with selected regions */
+
+ if (!selection->regions.empty()) {
+ for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
+ tvl.push_back (&(*r)->get_time_axis_view ());
+ }
+
+ if (!tvl.empty()) {
+ fit_tracks (tvl);
+ }
+ } else if (internal_editing()) {
+ /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
+ the entered track
+ */
+ if (entered_track) {
+ tvl.push_back (entered_track);
+ fit_tracks (tvl);
+ }
+ }
+ }
}
void
if (_ignore_region_action) {
return;
}
-
+
RegionSelection rs = get_regions_from_selection_and_entered ();
if (rs.empty ()) {
} else {
begin_reversible_command (_("mute region"));
}
-
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
-
+
(*i)->region()->playlist()->clear_changes ();
(*i)->region()->set_muted (!(*i)->region()->muted ());
_session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
-
+
+ }
+
+ commit_reversible_command ();
+}
+
+void
+Editor::combine_regions ()
+{
+ /* foreach track with selected regions, take all selected regions
+ and join them into a new region containing the subregions (as a
+ playlist)
+ */
+
+ typedef set<RouteTimeAxisView*> RTVS;
+ RTVS tracks;
+
+ if (selection->regions.empty()) {
+ return;
+ }
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
+
+ if (rtv) {
+ tracks.insert (rtv);
+ }
}
-
+
+ begin_reversible_command (_("combine regions"));
+
+ vector<RegionView*> new_selection;
+
+ for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
+ RegionView* rv;
+
+ if ((rv = (*i)->combine_regions ()) != 0) {
+ new_selection.push_back (rv);
+ }
+ }
+
+ selection->clear_regions ();
+ for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
+ selection->add (*i);
+ }
+
+ commit_reversible_command ();
+}
+
+void
+Editor::uncombine_regions ()
+{
+ typedef set<RouteTimeAxisView*> RTVS;
+ RTVS tracks;
+
+ if (selection->regions.empty()) {
+ return;
+ }
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
+
+ if (rtv) {
+ tracks.insert (rtv);
+ }
+ }
+
+ begin_reversible_command (_("uncombine regions"));
+
+ for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
+ (*i)->uncombine_regions ();
+ }
+
commit_reversible_command ();
}