summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/midi_model.h10
-rw-r--r--libs/ardour/midi_model.cc83
-rw-r--r--libs/evoral/evoral/Sequence.hpp4
-rw-r--r--libs/evoral/src/Sequence.cpp5
4 files changed, 78 insertions, 24 deletions
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
index ac578dc5a9..5d1d605c95 100644
--- a/libs/ardour/ardour/midi_model.h
+++ b/libs/ardour/ardour/midi_model.h
@@ -77,8 +77,9 @@ public:
int set_state (const XMLNode&, int version);
XMLNode& get_state ();
- void add(const NotePtr note);
- void remove(const NotePtr note);
+ void add (const NotePtr note);
+ void remove (const NotePtr note);
+ void side_effect_remove (const NotePtr note);
void change (const NotePtr note, Property prop, uint8_t new_value);
void change (const NotePtr note, Property prop, TimeType new_time);
@@ -87,6 +88,9 @@ public:
return !_added_notes.empty() || !_removed_notes.empty();
}
+ DiffCommand& operator+= (const DiffCommand& other);
+ boost::shared_ptr<MidiModel> model() const { return _model; }
+
private:
boost::shared_ptr<MidiModel> _model;
const std::string _name;
@@ -144,7 +148,7 @@ public:
void set_insert_merge_policy (InsertMergePolicy);
protected:
- int resolve_overlaps_unlocked (const NotePtr, std::set<NotePtr>* removed = 0);
+ int resolve_overlaps_unlocked (const NotePtr, void* arg = 0);
private:
struct WriteLockImpl : public AutomatableSequence<TimeType>::WriteLockImpl {
diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc
index c4c989d362..bac630bb14 100644
--- a/libs/ardour/midi_model.cc
+++ b/libs/ardour/midi_model.cc
@@ -123,6 +123,12 @@ MidiModel::DiffCommand::remove(const NotePtr note)
}
void
+MidiModel::DiffCommand::side_effect_remove(const NotePtr note)
+{
+ side_effect_removals.insert (note);
+}
+
+void
MidiModel::DiffCommand::change(const NotePtr note, Property prop,
uint8_t new_value)
{
@@ -200,12 +206,31 @@ MidiModel::DiffCommand::change(const NotePtr note, Property prop,
_changes.push_back (change);
}
+MidiModel::DiffCommand&
+MidiModel::DiffCommand::operator+= (const DiffCommand& other)
+{
+ if (this == &other) {
+ return *this;
+ }
+
+ if (_model != other._model) {
+ return *this;
+ }
+
+ _added_notes.insert (_added_notes.end(), other._added_notes.begin(), other._added_notes.end());
+ _removed_notes.insert (_removed_notes.end(), other._removed_notes.begin(), other._removed_notes.end());
+ side_effect_removals.insert (other.side_effect_removals.begin(), other.side_effect_removals.end());
+ _changes.insert (_changes.end(), other._changes.begin(), other._changes.end());
+
+ return *this;
+}
+
void
MidiModel::DiffCommand::operator()()
{
{
MidiModel::WriteLock lock(_model->edit_lock());
-
+
for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
_model->add_note_unlocked(*i);
}
@@ -228,10 +253,6 @@ MidiModel::DiffCommand::operator()()
i->note->set_note (i->new_value);
break;
- case Velocity:
- i->note->set_velocity (i->new_value);
- break;
-
case StartTime:
if (temporary_removals.find (i->note) == temporary_removals.end()) {
_model->remove_note_unlocked (i->note);
@@ -241,10 +262,6 @@ MidiModel::DiffCommand::operator()()
i->note->set_time (i->new_time);
break;
- case Length:
- i->note->set_length (i->new_time);
- break;
-
case Channel:
if (temporary_removals.find (i->note) == temporary_removals.end()) {
_model->remove_note_unlocked (i->note);
@@ -252,11 +269,26 @@ MidiModel::DiffCommand::operator()()
}
i->note->set_channel (i->new_value);
break;
+
+ /* no remove-then-add required for these properties, since we do not index them
+ */
+
+ case Velocity:
+ i->note->set_velocity (i->new_value);
+ break;
+
+ case Length:
+ i->note->set_length (i->new_time);
+ break;
+
}
}
+
for (set<NotePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
- _model->add_note_unlocked (*i, &side_effect_removals);
+ DiffCommand side_effects (model(), "side effects");
+ _model->add_note_unlocked (*i, &side_effects);
+ *this += side_effects;
}
if (!side_effect_removals.empty()) {
@@ -329,7 +361,7 @@ MidiModel::DiffCommand::undo()
state once this is done.
*/
- cerr << "This undo has " << side_effect_removals.size() << " SER's\n";
+ cerr << "This undo has " << side_effect_removals.size() << " SER's to be re-added\n";
for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
_model->add_note_unlocked (*i);
}
@@ -880,15 +912,16 @@ MidiModel::write_lock()
}
int
-MidiModel::resolve_overlaps_unlocked (const NotePtr note, set<NotePtr>* removed)
-
+MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
{
using namespace Evoral;
-
+
if (_writing || insert_merge_policy() == InsertMergeRelax) {
return 0;
}
+ DiffCommand* cmd = static_cast<DiffCommand*>(arg);
+
TimeType sa = note->time();
TimeType ea = note->end_time();
@@ -926,19 +959,28 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, set<NotePtr>* removed)
switch (overlap) {
case OverlapStart:
+ cerr << "OverlapStart\n";
/* existing note covers start of new note */
switch (insert_merge_policy()) {
case InsertMergeReplace:
to_be_deleted.insert (*i);
break;
case InsertMergeTruncateExisting:
+ if (cmd) {
+ cmd->change (*i, DiffCommand::Length, (note->time() - (*i)->time()));
+ }
(*i)->set_length (note->time() - (*i)->time());
break;
case InsertMergeTruncateAddition:
set_note_time = true;
+ set_note_length = true;
note_time = (*i)->time() + (*i)->length();
+ note_length = min (note_length, (*i)->length() - ((*i)->end_time() - note->time()));
break;
case InsertMergeExtend:
+ if (cmd) {
+ cmd->change ((*i), DiffCommand::Length, note->end_time() - (*i)->time());
+ }
(*i)->set_length (note->end_time() - (*i)->time());
return -1; /* do not add the new note */
break;
@@ -950,6 +992,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, set<NotePtr>* removed)
break;
case OverlapEnd:
+ cerr << "OverlapEnd\n";
/* existing note covers end of new note */
switch (insert_merge_policy()) {
case InsertMergeReplace:
@@ -985,6 +1028,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, set<NotePtr>* removed)
break;
case OverlapExternal:
+ cerr << "OverlapExt\n";
/* existing note overlaps all the new note */
switch (insert_merge_policy()) {
case InsertMergeReplace:
@@ -1003,6 +1047,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, set<NotePtr>* removed)
break;
case OverlapInternal:
+ cerr << "OverlapInt\n";
/* new note fully overlaps an existing note */
switch (insert_merge_policy()) {
case InsertMergeReplace:
@@ -1029,16 +1074,22 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, set<NotePtr>* removed)
for (set<NotePtr>::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
remove_note_unlocked (*i);
- if (removed) {
- removed->insert (*i);
+ if (cmd) {
+ cmd->side_effect_remove (*i);
}
}
if (set_note_time) {
+ if (cmd) {
+ cmd->change (note, DiffCommand::StartTime, note_time);
+ }
note->set_time (note_time);
}
if (set_note_length) {
+ if (cmd) {
+ cmd->change (note, DiffCommand::Length, note_length);
+ }
note->set_length (note_length);
}
diff --git a/libs/evoral/evoral/Sequence.hpp b/libs/evoral/evoral/Sequence.hpp
index e3b0a3636e..79a4181f67 100644
--- a/libs/evoral/evoral/Sequence.hpp
+++ b/libs/evoral/evoral/Sequence.hpp
@@ -236,7 +236,7 @@ public:
const NotePtr& ignore_this_note) const;
bool contains (const NotePtr& ev) const;
- bool add_note_unlocked (const NotePtr note, std::set<NotePtr>* removed = 0);
+ bool add_note_unlocked (const NotePtr note, void* arg = 0);
void remove_note_unlocked(const constNotePtr note);
uint8_t lowest_note() const { return _lowest_note; }
@@ -250,7 +250,7 @@ protected:
mutable Glib::RWLock _lock;
bool _writing;
- virtual int resolve_overlaps_unlocked (const NotePtr, std::set<NotePtr>* removed = 0) {
+ virtual int resolve_overlaps_unlocked (const NotePtr, void* arg = 0) {
return 0;
}
diff --git a/libs/evoral/src/Sequence.cpp b/libs/evoral/src/Sequence.cpp
index dba79a556a..ddd978fefa 100644
--- a/libs/evoral/src/Sequence.cpp
+++ b/libs/evoral/src/Sequence.cpp
@@ -580,15 +580,14 @@ Sequence<Time>::end_write (bool delete_stuck)
template<typename Time>
bool
-Sequence<Time>::add_note_unlocked(const NotePtr note,
- set<NotePtr >* removed)
+Sequence<Time>::add_note_unlocked(const NotePtr note, void* arg)
{
/* This is the core method to add notes to a Sequence
*/
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 add note %2 @ %3\n", this, (int)note->note(), note->time()));
- if (resolve_overlaps_unlocked (note, removed)) {
+ if (resolve_overlaps_unlocked (note, arg)) {
return false;
}