MidiClock_SlaveTest: add basic framework
[ardour.git] / libs / ardour / midi_model.cc
index 851ee49b46551c7a51d69118390ca9b1cb1da4cc..baa3c2c7c016d4c54b408de7cf38e48c6d78e126 100644 (file)
@@ -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, int version)
+MidiModel::DeltaCommand::set_state (const XMLNode& delta_command, int /*version*/)
 {
        if (delta_command.name() != string(DELTA_COMMAND_ELEMENT)) {
                return 1;
@@ -271,7 +267,7 @@ MidiModel::DeltaCommand::set_state (const XMLNode& delta_command, int version)
        if (added_notes) {
                XMLNodeList notes = added_notes->children();
                transform(notes.begin(), notes.end(), back_inserter(_added_notes),
-                         sigc::mem_fun(*this, &DeltaCommand::unmarshal_note));
+                         boost::bind (&DeltaCommand::unmarshal_note, this, _1));
        }
 
        _removed_notes.clear();
@@ -279,7 +275,7 @@ MidiModel::DeltaCommand::set_state (const XMLNode& delta_command, int version)
        if (removed_notes) {
                XMLNodeList notes = removed_notes->children();
                transform(notes.begin(), notes.end(), back_inserter(_removed_notes),
-                         sigc::mem_fun(*this, &DeltaCommand::unmarshal_note));
+                         boost::bind (&DeltaCommand::unmarshal_note, this, _1));
        }
 
        return 0;
@@ -292,14 +288,16 @@ MidiModel::DeltaCommand::get_state()
        delta_command->add_property("midi-source", _model->midi_source()->id().to_s());
 
        XMLNode* added_notes = delta_command->add_child(ADDED_NOTES_ELEMENT);
-       for_each(_added_notes.begin(), _added_notes.end(), sigc::compose(
-                       sigc::mem_fun(*added_notes, &XMLNode::add_child_nocopy),
-                       sigc::mem_fun(*this, &DeltaCommand::marshal_note)));
+       for_each(_added_notes.begin(), _added_notes.end(), 
+                boost::bind(
+                        boost::bind (&XMLNode::add_child_nocopy, *added_notes, _1),
+                        boost::bind (&DeltaCommand::marshal_note, this, _1)));
 
        XMLNode* removed_notes = delta_command->add_child(REMOVED_NOTES_ELEMENT);
-       for_each(_removed_notes.begin(), _removed_notes.end(), sigc::compose(
-                       sigc::mem_fun(*removed_notes, &XMLNode::add_child_nocopy),
-                       sigc::mem_fun(*this, &DeltaCommand::marshal_note)));
+       for_each(_removed_notes.begin(), _removed_notes.end(), 
+                boost::bind (
+                        boost::bind (&XMLNode::add_child_nocopy, *removed_notes, _1),
+                        boost::bind (&DeltaCommand::marshal_note, this, _1)));
 
        return *delta_command;
 }
@@ -387,9 +385,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 +408,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 +438,7 @@ MidiModel::DiffCommand::undo()
                }
        }
 
-       _model->write_unlock();
+       lock.reset();
        _model->ContentsChanged(); /* EMIT SIGNAL */
 }
 
@@ -646,7 +640,7 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
 }
 
 int
-MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int version)
+MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
 {
        if (diff_command.name() != string(DIFF_COMMAND_ELEMENT)) {
                return 1;
@@ -658,9 +652,9 @@ MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int version)
 
        if (changed_notes) {
                XMLNodeList notes = changed_notes->children();
-
                transform (notes.begin(), notes.end(), back_inserter(_changes),
-                          sigc::mem_fun(*this, &DiffCommand::unmarshal_change));
+                          boost::bind (&DiffCommand::unmarshal_change, this, _1));
+
        }
 
        return 0;
@@ -673,9 +667,10 @@ MidiModel::DiffCommand::get_state ()
        diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
 
        XMLNode* changes = diff_command->add_child(DIFF_NOTES_ELEMENT);
-       for_each(_changes.begin(), _changes.end(), sigc::compose(
-                        sigc::mem_fun(*changes, &XMLNode::add_child_nocopy),
-                        sigc::mem_fun(*this, &DiffCommand::marshal_change)));
+       for_each(_changes.begin(), _changes.end(), 
+                boost::bind (
+                        boost::bind (&XMLNode::add_child_nocopy, *changes, _1),
+                        boost::bind (&DiffCommand::marshal_change, this, _1)));
 
        return *diff_command;
 }
@@ -690,20 +685,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;
@@ -731,3 +727,24 @@ MidiModel::find_note (boost::shared_ptr<Evoral::Note<TimeType> > other)
 
        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));
+}