debug flag for session destruction and waf option for boost SP debug
[ardour.git] / libs / ardour / midi_model.cc
index fb09cda60f865c33b9ef7af63882c4bc792c8974..47bc14852c1cf1828521f98fbc57415bebff3938 100644 (file)
@@ -112,7 +112,7 @@ MidiModel::DeltaCommand::DeltaCommand(boost::shared_ptr<MidiModel> m, const XMLN
        : _model(m)
 {
        assert(_model);
-       set_state(node);
+       set_state(node, Stateful::loading_state_version);
 }
 
 void
@@ -135,9 +135,7 @@ MidiModel::DeltaCommand::operator()()
        // This could be made much faster by using a priority_queue for added and
        // removed notes (or sort here), and doing a single iteration over _model
 
-       Glib::Mutex::Lock lm (_model->_midi_source->mutex());
-       _model->_midi_source->invalidate(); // release model read lock
-       _model->write_lock();
+       MidiModel::WriteLock lock(_model->edit_lock());
 
        for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
                _model->add_note_unlocked(*i);
@@ -147,7 +145,7 @@ MidiModel::DeltaCommand::operator()()
                _model->remove_note_unlocked(*i);
        }
 
-       _model->write_unlock();
+       lock.reset();
        _model->ContentsChanged(); /* EMIT SIGNAL */
 }
 
@@ -157,9 +155,7 @@ MidiModel::DeltaCommand::undo()
        // This could be made much faster by using a priority_queue for added and
        // removed notes (or sort here), and doing a single iteration over _model
 
-       Glib::Mutex::Lock lm (_model->_midi_source->mutex());
-       _model->_midi_source->invalidate(); // release model read lock
-       _model->write_lock();
+       MidiModel::WriteLock lock(_model->edit_lock());;
 
        for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
                _model->remove_note_unlocked(*i);
@@ -169,7 +165,7 @@ MidiModel::DeltaCommand::undo()
                _model->add_note_unlocked(*i);
        }
 
-       _model->write_unlock();
+       lock.reset();
        _model->ContentsChanged(); /* EMIT SIGNAL */
 }
 
@@ -260,7 +256,7 @@ MidiModel::DeltaCommand::unmarshal_note(XMLNode *xml_note)
 #define DELTA_COMMAND_ELEMENT "DeltaCommand"
 
 int
-MidiModel::DeltaCommand::set_state(const XMLNode& delta_command)
+MidiModel::DeltaCommand::set_state (const XMLNode& delta_command, int /*version*/)
 {
        if (delta_command.name() != string(DELTA_COMMAND_ELEMENT)) {
                return 1;
@@ -321,7 +317,7 @@ MidiModel::DiffCommand::DiffCommand(boost::shared_ptr<MidiModel> m, const XMLNod
        : _model(m)
 {
        assert(_model);
-       set_state(node);
+       set_state(node, Stateful::loading_state_version);
 }
 
 void
@@ -387,9 +383,7 @@ MidiModel::DiffCommand::change(const boost::shared_ptr< Evoral::Note<TimeType> >
 void
 MidiModel::DiffCommand::operator()()
 {
-       Glib::Mutex::Lock lm (_model->_midi_source->mutex());
-       _model->_midi_source->invalidate(); // release model read lock
-       _model->write_lock();
+       MidiModel::WriteLock lock(_model->edit_lock());
 
        for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                Property prop = i->property;
@@ -412,16 +406,14 @@ MidiModel::DiffCommand::operator()()
                }
        }
 
-       _model->write_unlock();
+       lock.reset();
        _model->ContentsChanged(); /* EMIT SIGNAL */
 }
 
 void
 MidiModel::DiffCommand::undo()
 {
-       Glib::Mutex::Lock lm (_model->_midi_source->mutex());
-       _model->_midi_source->invalidate(); // release model read lock
-       _model->write_lock();
+       MidiModel::WriteLock lock(_model->edit_lock());
 
        for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                Property prop = i->property;
@@ -444,7 +436,7 @@ MidiModel::DiffCommand::undo()
                }
        }
 
-       _model->write_unlock();
+       lock.reset();
        _model->ContentsChanged(); /* EMIT SIGNAL */
 }
 
@@ -646,7 +638,7 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
 }
 
 int
-MidiModel::DiffCommand::set_state(const XMLNode& diff_command)
+MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
 {
        if (diff_command.name() != string(DIFF_COMMAND_ELEMENT)) {
                return 1;
@@ -690,20 +682,21 @@ MidiModel::DiffCommand::get_state ()
 bool
 MidiModel::write_to(boost::shared_ptr<MidiSource> source)
 {
-       read_lock();
+       ReadLock lock(read_lock());
 
        const bool old_percussive = percussive();
        set_percussive(false);
 
        source->drop_model();
+       source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position());
 
        for (Evoral::Sequence<TimeType>::const_iterator i = begin(); i != end(); ++i) {
                source->append_event_unlocked_beats(*i);
        }
 
        set_percussive(old_percussive);
+       source->mark_streaming_write_completed();
 
-       read_unlock();
        set_edited(false);
 
        return true;
@@ -719,15 +712,36 @@ MidiModel::get_state()
 boost::shared_ptr<Evoral::Note<MidiModel::TimeType> >
 MidiModel::find_note (boost::shared_ptr<Evoral::Note<TimeType> > other)
 {
-       for (Notes::iterator x = notes().begin(); x != notes().end(); ++x) {
-               if (**x == *other) {
-                       return *x;
-               }
+       Notes::iterator l = notes().lower_bound(other);
 
-               /* XXX optimize by using a stored iterator and break out
-                  when passed start time.
-               */
+       if (l != notes().end()) {
+               for (; (*l)->time() == other->time(); ++l) {
+                       if (*l == other) {
+                               return *l;
+                       }
+               }
        }
 
-       return boost::shared_ptr<Evoral::Note<TimeType> > ();
+       return boost::shared_ptr<Evoral::Note<TimeType> >();
+}
+
+/** Lock and invalidate the source.
+ * This should be used by commands and editing things
+ */
+MidiModel::WriteLock
+MidiModel::edit_lock()
+{
+       Glib::Mutex::Lock* source_lock = new Glib::Mutex::Lock(_midi_source->mutex());
+       _midi_source->invalidate(); // Release cached iterator's read lock on model
+       return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
+}
+
+/** Lock just the model, the source lock must already be held.
+ * This should only be called from libardour/evoral places
+ */
+MidiModel::WriteLock
+MidiModel::write_lock()
+{
+       assert(!_midi_source->mutex().trylock());
+       return WriteLock(new WriteLockImpl(NULL, _lock, _control_lock));
 }