#include "ardour/playlist_factory.h"
#include "ardour/profile.h"
#include "ardour/quantize.h"
+#include "ardour/legatize.h"
#include "ardour/region_factory.h"
#include "ardour/reverse.h"
#include "ardour/session.h"
#include "mixer_strip.h"
#include "mouse_cursors.h"
#include "normalize_dialog.h"
+#include "note.h"
+#include "paste_context.h"
#include "patch_change_dialog.h"
#include "quantize_dialog.h"
#include "region_gain_line.h"
a = tmp;
}
+ latest_regionviews.clear ();
+
vector<sigc::connection> region_added_connections;
for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
}
- latest_regionviews.clear ();
-
while (used_playlists.size() > 0) {
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
(*i)->thaw();
for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
(*c).disconnect ();
}
-
- commit_reversible_command ();
if (frozen){
EditorThaw(); /* Emit Signal */
selection->add (latest_regionviews); //these are the new regions created after the split
}
_ignore_follow_edits = false;
+ } else {
+ _ignore_follow_edits = true;
+ if( working_on_selection ) {
+ selection->add (latest_regionviews); //these are the new regions created after the split
+ }
+ _ignore_follow_edits = false;
}
+
+ commit_reversible_command ();
}
/** Move one extreme of the current range selection. If more than one range is selected,
_session->locations()->next_available_name(rangename,"selection");
Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
- _session->begin_reversible_command (_("add marker"));
+ 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 ();
+
+ commit_reversible_command ();
}
void
return;
}
Location *location = new Location (*_session, where, where, markername, Location::IsMark);
- _session->begin_reversible_command (_("add marker"));
+ 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 ();
+
+ commit_reversible_command ();
}
void
if (_session) {
//set up for undo
- _session->begin_reversible_command (_("remove marker"));
+ begin_reversible_command (_("remove marker"));
+
XMLNode &before = _session->locations()->get_state();
bool removed = false;
if (removed) {
XMLNode &after = _session->locations()->get_state();
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
}
}
return;
}
- _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
+ begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
+
XMLNode &before = _session->locations()->get_state();
for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
XMLNode &after = _session->locations()->get_state();
_session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
/** Add a single range marker around all selected regions */
return;
}
- _session->begin_reversible_command (_("add marker"));
+ begin_reversible_command (_("add marker"));
+
XMLNode &before = _session->locations()->get_state();
string markername;
XMLNode &after = _session->locations()->get_state();
_session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
/* MARKS */
Editor::clear_markers ()
{
if (_session) {
- _session->begin_reversible_command (_("clear markers"));
+ 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 ();
+
+ commit_reversible_command ();
}
}
Editor::clear_ranges ()
{
if (_session) {
- _session->begin_reversible_command (_("clear ranges"));
+ begin_reversible_command (_("clear ranges"));
+
XMLNode &before = _session->locations()->get_state();
_session->locations()->clear_ranges ();
XMLNode &after = _session->locations()->get_state();
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
}
void
Editor::clear_locations ()
{
- _session->begin_reversible_command (_("clear locations"));
+ 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 ();
+
+ commit_reversible_command ();
}
void
add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
{
switch (rv->region()->coverage (ar->start, ar->end - 1)) {
+ // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
case Evoral::OverlapNone:
break;
default:
return;
}
- if (internal_editing()) {
-
- switch (effective_mouse_mode()) {
- case MouseObject:
- case MouseRange:
- begin_reversible_command (opname + ' ' + X_("MIDI"));
- cut_copy_midi (op);
- commit_reversible_command ();
- break;
- default:
- break;
- }
-
+ switch (mouse_mode) {
+ case MouseDraw:
+ case MouseContent:
+ begin_reversible_command (opname + ' ' + X_("MIDI"));
+ cut_copy_midi (op);
+ commit_reversible_command ();
return;
+ default:
+ break;
}
bool did_edit = false;
* @param op Operation (Cut, Copy or Clear)
*/
void
-Editor::cut_copy_points (CutCopyOp op)
+Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
{
if (selection->points.empty ()) {
return;
/* This operation will involve putting things in the cut buffer, so create an empty
ControlList for each of our source lists to put the cut buffer data in.
*/
- framepos_t start = std::numeric_limits<framepos_t>::max();
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
- i->second.copy = i->first->create (i->first->parameter ());
-
- /* Calculate earliest start position of any point in selection. */
- start = std::min(start, i->second.line->session_position(i->first->begin()));
+ i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
}
/* Add all selected points to the relevant copy ControlLists */
+ framepos_t start = std::numeric_limits<framepos_t>::max();
for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
- AutomationList::const_iterator j = (*i)->model ();
+ AutomationList::const_iterator j = (*i)->model();
+
lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
+ if (midi) {
+ /* Update earliest MIDI start time in beats */
+ earliest = std::min(earliest, Evoral::MusicalTime((*j)->when));
+ } else {
+ /* Update earliest session start time in frames */
+ start = std::min(start, (*i)->line().session_position(j));
+ }
}
/* Snap start time backwards, so copy/paste is snap aligned. */
- snap_to(start, RoundDownMaybe);
+ if (midi) {
+ if (earliest == Evoral::MusicalTime::max()) {
+ earliest = Evoral::MusicalTime(); // Weird... don't offset
+ }
+ earliest.round_down_to_beat();
+ } else {
+ if (start == std::numeric_limits<double>::max()) {
+ start = 0; // Weird... don't offset
+ }
+ snap_to(start, RoundDownMaybe);
+ }
+ const double line_offset = midi ? earliest.to_double() : start;
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
/* Correct this copy list so that it is relative to the earliest
start time, so relative ordering between points is preserved
- when copying from several lists. */
- const AutomationLine* line = i->second.line;
- const double line_offset = line->time_converter().from(start);
-
+ when copying from several lists and the paste starts at the
+ earliest copied piece of data. */
for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
(*j)->when -= line_offset;
}
void
Editor::cut_copy_midi (CutCopyOp op)
{
+ Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
if (mrv) {
+ if (!mrv->selection().empty()) {
+ earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
+ }
mrv->cut_copy_clear (op);
/* XXX: not ideal, as there may be more than one track involved in the selection */
}
if (!selection->points.empty()) {
- cut_copy_points (op);
+ cut_copy_points (op, earliest, true);
if (op == Cut || op == Delete) {
selection->clear_points ();
}
return;
}
+ begin_reversible_command (_("remove region"));
+
boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
playlist->clear_changes ();
R1.A1, R1.A2, R2, R2.A1, ... */
}
- if (internal_editing ()) {
+ if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
+ dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
+ /* Only one line copied, and one automation track selected. Do a
+ "greedy" paste from one automation type to another. */
+
+ begin_reversible_command (Operations::paste);
+
+ PasteContext ctx(paste_count, times, ItemCounts(), true);
+ ts.front()->paste (position, *cut_buffer, ctx);
+
+ commit_reversible_command ();
+
+ } else if (internal_editing ()) {
/* undo/redo is handled by individual tracks/regions */
RegionSelection rs;
get_regions_at (rs, position, ts);
- ItemCounts counts;
+ PasteContext ctx(paste_count, times, ItemCounts(), false);
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
if (mrv) {
- mrv->paste (position, paste_count, times, *cut_buffer, counts);
+ mrv->paste (position, *cut_buffer, ctx);
}
}
begin_reversible_command (Operations::paste);
- ItemCounts counts;
+ PasteContext ctx(paste_count, times, ItemCounts(), false);
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
- (*i)->paste (position, paste_count, times, *cut_buffer, counts);
+ (*i)->paste (position, *cut_buffer, ctx);
}
commit_reversible_command ();
foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
}
- commit_reversible_command ();
-
if (!foo.empty()) {
selection->set (foo);
}
+
+ commit_reversible_command ();
}
void
}
}
+void
+Editor::legatize_region (bool shrink_only)
+{
+ int selected_midi_region_cnt = 0;
+
+ if (!_session) {
+ return;
+ }
+
+ RegionSelection rs = get_regions_from_selection_and_entered ();
+
+ if (rs.empty()) {
+ return;
+ }
+
+ for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
+ MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
+ if (mrv) {
+ selected_midi_region_cnt++;
+ }
+ }
+
+ if (selected_midi_region_cnt == 0) {
+ return;
+ }
+
+ Legatize legatize(shrink_only);
+ apply_midi_note_edit_op (legatize);
+}
+
void
Editor::insert_patch_change (bool from_context)
{
return;
}
- _session->begin_reversible_command (_("reset region gain"));
-
+ begin_reversible_command (_("reset region gain"));
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
_session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
}
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
void
return;
}
- _session->begin_reversible_command (_("region gain envelope active"));
-
+ begin_reversible_command (_("region gain envelope active"));
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
_session->add_command (new StatefulDiffCommand (arv->region()));
}
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
void
return;
}
- _session->begin_reversible_command (_("toggle region lock"));
-
+ begin_reversible_command (_("toggle region lock"));
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
(*i)->region()->clear_changes ();
(*i)->region()->set_locked (!(*i)->region()->locked());
_session->add_command (new StatefulDiffCommand ((*i)->region()));
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
void
return;
}
- _session->begin_reversible_command (_("Toggle Video Lock"));
-
+ begin_reversible_command (_("Toggle Video Lock"));
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
(*i)->region()->clear_changes ();
(*i)->region()->set_video_locked (!(*i)->region()->video_locked());
_session->add_command (new StatefulDiffCommand ((*i)->region()));
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
void
return;
}
- _session->begin_reversible_command (_("region lock style"));
-
+ begin_reversible_command (_("region lock style"));
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
(*i)->region()->clear_changes ();
PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
(*i)->region()->set_position_lock_style (ns);
_session->add_command (new StatefulDiffCommand ((*i)->region()));
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
void
return;
}
- _session->begin_reversible_command (_("change region opacity"));
-
+ begin_reversible_command (_("change region opacity"));
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
(*i)->region()->clear_changes ();
(*i)->region()->set_opaque (!(*i)->region()->opaque());
_session->add_command (new StatefulDiffCommand ((*i)->region()));
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
void
set_punch_range (start, end, _("set punch range from selection"));
}
+void
+Editor::set_session_extents_from_selection ()
+{
+ if (_session == 0 || selection->time.empty()) {
+ return;
+ }
+
+ begin_reversible_command (_("set session start/stop from selection"));
+
+ framepos_t start = selection->time[clicked_selection].start;
+ framepos_t end = selection->time[clicked_selection].end;
+
+ Location* loc;
+ if ((loc = _session->locations()->session_range_location()) == 0) {
+ _session->set_session_extents ( start, end ); // this will create a new session range; no need for UNDO
+ } else {
+ XMLNode &before = loc->get_state();
+
+ _session->set_session_extents ( start, end );
+
+ XMLNode &after = loc->get_state();
+
+ _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
+
+ commit_reversible_command ();
+ }
+}
+
void
Editor::set_punch_from_edit_range ()
{
return;
}
- _session->begin_reversible_command (_("split regions"));
-
+ begin_reversible_command (_("split regions"));
+
for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
RegionSelection::iterator tmp;
i = tmp;
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
framepos_t where = get_preferred_edit_position();
- _session->begin_reversible_command (_("place transient"));
-
+ 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 ();
+
+ commit_reversible_command ();
}
void
return;
}
- _session->begin_reversible_command (_("snap regions to grid"));
-
+ 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();
(*i)->thaw();
used_playlists.pop_front();
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
void
/* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
- _session->begin_reversible_command (_("close region gaps"));
-
+ begin_reversible_command (_("close region gaps"));
+
int idx = 0;
boost::shared_ptr<Region> last_region;
(*i)->thaw();
used_playlists.pop_front();
}
-
- _session->commit_reversible_command ();
+
+ commit_reversible_command ();
}
void
(*i)->region()->playlist()->clear_changes ();
(*i)->region()->set_muted (!(*i)->region()->muted ());
- _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
+ _session->add_command (new StatefulDiffCommand ((*i)->region()));
}