From fddb3778120e25b3b8e8134084e260dac07c1365 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 12 Jun 2010 13:55:22 +0000 Subject: introduce the notion that note additions and property changes can cause the removal of other notes because of overlaps; merge Diff and Delta commands in MidiModel; fix marshalling of notes to avoid float->int conversion of length+time properties; initial implementation (not tested much so far) of different policies for how to handle note overlaps git-svn-id: svn://localhost/ardour2/branches/3.0@7254 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/midi_model.h | 82 ++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 51 deletions(-) (limited to 'libs/ardour/ardour/midi_model.h') diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index b3a4d746a1..ac578dc5a9 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -49,53 +49,13 @@ class MidiSource; */ class MidiModel : public AutomatableSequence { public: - typedef double TimeType; + typedef Evoral::MusicalTime TimeType; MidiModel(MidiSource* s); NoteMode note_mode() const { return (percussive() ? Percussive : Sustained); } void set_note_mode(NoteMode mode) { set_percussive(mode == Percussive); }; - /** Add/Remove notes. - * Technically all note operations can be implemented as one of these, but - * a custom command can be more efficient. - */ - class DeltaCommand : public Command { - public: - DeltaCommand (boost::shared_ptr m, const std::string& name); - DeltaCommand (boost::shared_ptr m, const XMLNode& node); - - const std::string& name() const { return _name; } - - void operator()(); - void undo(); - - int set_state (const XMLNode&, int version); - XMLNode& get_state (); - - void add(const boost::shared_ptr< Evoral::Note > note); - void remove(const boost::shared_ptr< Evoral::Note > note); - - private: - XMLNode &marshal_note(const boost::shared_ptr< Evoral::Note > note); - boost::shared_ptr< Evoral::Note > unmarshal_note(XMLNode *xml_note); - - boost::shared_ptr _model; - const std::string _name; - - typedef std::list< boost::shared_ptr< Evoral::Note > > NoteList; - - NoteList _added_notes; - NoteList _removed_notes; - }; - - - /** Change note properties. - * More efficient than DeltaCommand and has the important property that - * it leaves the objects in the MidiModel (Notes) the same, thus - * enabling selection and other state to persist across command - * do/undo/redo. - */ class DiffCommand : public Command { public: enum Property { @@ -117,18 +77,23 @@ public: int set_state (const XMLNode&, int version); XMLNode& get_state (); - void change (const boost::shared_ptr > note, - Property prop, uint8_t new_value); - void change (const boost::shared_ptr > note, - Property prop, TimeType new_time); + void add(const NotePtr note); + void 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); + + bool adds_or_removes() const { + return !_added_notes.empty() || !_removed_notes.empty(); + } - private: + private: boost::shared_ptr _model; const std::string _name; struct NoteChange { DiffCommand::Property property; - boost::shared_ptr< Evoral::Note > note; + NotePtr note; union { uint8_t old_value; TimeType old_time; @@ -142,11 +107,19 @@ public: typedef std::list ChangeList; ChangeList _changes; + typedef std::list< boost::shared_ptr< Evoral::Note > > NoteList; + NoteList _added_notes; + NoteList _removed_notes; + + std::set side_effect_removals; + XMLNode &marshal_change(const NoteChange&); NoteChange unmarshal_change(XMLNode *xml_note); + + XMLNode &marshal_note(const NotePtr note); + NotePtr unmarshal_note(XMLNode *xml_note); }; - MidiModel::DeltaCommand* new_delta_command(const std::string name="midi edit"); MidiModel::DiffCommand* new_diff_command(const std::string name="midi edit"); void apply_command(Session& session, Command* cmd); void apply_command_as_subcommand(Session& session, Command* cmd); @@ -165,12 +138,18 @@ public: const MidiSource* midi_source() const { return _midi_source; } void set_midi_source(MidiSource* source) { _midi_source = source; } - boost::shared_ptr > find_note (boost::shared_ptr >); + boost::shared_ptr > find_note (NotePtr); + + InsertMergePolicy insert_merge_policy () const; + void set_insert_merge_policy (InsertMergePolicy); + +protected: + int resolve_overlaps_unlocked (const NotePtr, std::set* removed = 0); private: - struct WriteLockImpl : public AutomatableSequence::WriteLockImpl { + struct WriteLockImpl : public AutomatableSequence::WriteLockImpl { WriteLockImpl(Glib::Mutex::Lock* source_lock, Glib::RWLock& s, Glib::Mutex& c) - : AutomatableSequence::WriteLockImpl(s, c) + : AutomatableSequence::WriteLockImpl(s, c) , source_lock(source_lock) {} ~WriteLockImpl() { @@ -188,6 +167,7 @@ private: // We cannot use a boost::shared_ptr here to avoid a retain cycle MidiSource* _midi_source; + InsertMergePolicy _insert_merge_policy; }; } /* namespace ARDOUR */ -- cgit v1.2.3