Fix mute of MIDI tracks with channel forcing.
[ardour.git] / libs / ardour / midi_model.cc
index e68068de2b8f3beb3c103f5870590a8384546535..de5000669c46f84e287f83cdd8f6e165a40354af 100644 (file)
@@ -179,6 +179,24 @@ MidiModel::NoteDiffCommand::get_value (const NotePtr note, Property prop)
        case Length:
                return Variant(note->length());
        }
+
+       return Variant();
+}
+
+Variant::Type
+MidiModel::NoteDiffCommand::value_type(Property prop)
+{
+       switch (prop) {
+       case NoteNumber:
+       case Velocity:
+       case Channel:
+               return Variant::INT;
+       case StartTime:
+       case Length:
+               return Variant::BEATS;
+       }
+
+       return Variant::NOTHING;
 }
 
 void
@@ -564,8 +582,16 @@ MidiModel::NoteDiffCommand::marshal_change (const NoteChange& change)
        }
 
        ostringstream id_str;
-       id_str << change.note->id();
-       xml_change->add_property ("id", id_str.str());
+       if (change.note) {
+               id_str << change.note->id();
+               xml_change->add_property ("id", id_str.str());
+       } else if (change.note_id) {
+               warning << _("Change has no note, using note ID") << endmsg;
+               id_str << change.note_id;
+               xml_change->add_property ("id", id_str.str());
+       } else {
+               error << _("Change has no note or note ID") << endmsg;
+       }
 
        return *xml_change;
 }
@@ -575,6 +601,7 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
 {
        XMLProperty* prop;
        NoteChange change;
+       change.note_id = 0;
 
        if ((prop = xml_change->property("property")) != 0) {
                change.property = (Property) string_2_enum (prop->value(), change.property);
@@ -593,7 +620,7 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
        if ((prop = xml_change->property ("old")) != 0) {
                istringstream old_str (prop->value());
                if (change.property == StartTime || change.property == Length) {
-                       Evoral::MusicalTime old_time;
+                       Evoral::Beats old_time;
                        old_str >> old_time;
                        change.old_value = old_time;
                } else {
@@ -609,7 +636,7 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
        if ((prop = xml_change->property ("new")) != 0) {
                istringstream new_str (prop->value());
                if (change.property == StartTime || change.property == Length) {
-                       Evoral::MusicalTime new_time;
+                       Evoral::Beats new_time;
                        new_str >> new_time;
                        change.new_value = Variant(new_time);
                } else {
@@ -1209,14 +1236,15 @@ MidiModel::PatchChangePtr
 MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
 {
        XMLProperty* prop;
+       XMLProperty* prop_id;
        Evoral::event_id_t id = 0;
-       Evoral::MusicalTime time = Evoral::MusicalTime();
+       Evoral::Beats time = Evoral::Beats();
        int channel = 0;
        int program = 0;
        int bank = 0;
        
-       if ((prop = n->property ("id")) != 0) {
-               istringstream s (prop->value());
+       if ((prop_id = n->property ("id")) != 0) {
+               istringstream s (prop_id->value());
                s >> id;
        }
 
@@ -1241,7 +1269,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
        }
 
        PatchChangePtr p (new Evoral::PatchChange<TimeType> (time, channel, program, bank));
-       assert(id);
+       assert(prop_id);
        p->set_id (id);
        return p;
 }
@@ -1449,8 +1477,8 @@ MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock)
 bool
 MidiModel::write_section_to (boost::shared_ptr<MidiSource>     source,
                              const Glib::Threads::Mutex::Lock& source_lock,
-                             Evoral::MusicalTime               begin_time,
-                             Evoral::MusicalTime               end_time)
+                             Evoral::Beats                     begin_time,
+                             Evoral::Beats                     end_time)
 {
        ReadLock lock(read_lock());
        MidiStateTracker mst;
@@ -1462,12 +1490,12 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource>     source,
        source->mark_streaming_midi_write_started (source_lock, note_mode());
 
        for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
-               const Evoral::Event<Evoral::MusicalTime>& ev (*i);
+               const Evoral::Event<Evoral::Beats>& ev (*i);
 
                if (ev.time() >= begin_time && ev.time() < end_time) {
 
-                       const Evoral::MIDIEvent<Evoral::MusicalTime>* mev =
-                               static_cast<const Evoral::MIDIEvent<Evoral::MusicalTime>* > (&ev);
+                       const Evoral::MIDIEvent<Evoral::Beats>* mev =
+                               static_cast<const Evoral::MIDIEvent<Evoral::Beats>* > (&ev);
 
                        if (!mev) {
                                continue;
@@ -1584,25 +1612,19 @@ MidiModel::find_sysex (gint sysex_id)
 MidiModel::WriteLock
 MidiModel::edit_lock()
 {
-       boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
-       assert (ms);
+       boost::shared_ptr<MidiSource> ms          = _midi_source.lock();
+       Glib::Threads::Mutex::Lock*   source_lock = 0;
 
-       Glib::Threads::Mutex::Lock* source_lock = new Glib::Threads::Mutex::Lock (ms->mutex());
-       ms->invalidate(*source_lock); // 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()
-{
-       boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
-       assert (ms);
+       if (ms) {
+               /* Take source lock and invalidate iterator to release its lock on model.
+                  Add currently active notes to _active_notes so we can restore them
+                  if playback resumes at the same point after the edit. */
+               source_lock = new Glib::Threads::Mutex::Lock(ms->mutex());
+               ms->invalidate(*source_lock,
+                              ms->session().transport_rolling() ? &_active_notes : NULL);
+       }
 
-       assert (!ms->mutex().trylock ());
-       return WriteLock(new WriteLockImpl(0, _lock, _control_lock));
+       return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
 }
 
 int
@@ -1999,7 +2021,7 @@ MidiModel::transpose (TimeType from, TimeType to, int semitones)
 void
 MidiModel::control_list_marked_dirty ()
 {
-       AutomatableSequence<Evoral::MusicalTime>::control_list_marked_dirty ();
+       AutomatableSequence<Evoral::Beats>::control_list_marked_dirty ();
        
        ContentsChanged (); /* EMIT SIGNAL */
 }