diff options
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 10 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 83 | ||||
-rw-r--r-- | libs/evoral/evoral/Sequence.hpp | 4 | ||||
-rw-r--r-- | libs/evoral/src/Sequence.cpp | 5 |
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; } |