fix scanning of VST shell plugins
[ardour.git] / libs / ardour / midi_model.cc
index e86b229c71585077d209eb6bdea7d80ee8ca47d0..ef9544589dcda716a02ff261b2b62a708236c3c8 100644 (file)
@@ -289,6 +289,15 @@ MidiModel::NoteDiffCommand::operator() ()
 
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                        Property prop = i->property;
+
+                       if (!i->note) {
+                               /* note found during deserialization, so try
+                                  again now that the model state is different.
+                               */
+                               i->note = _model->find_note (i->note_id);
+                               assert (i->note);
+                       }
+
                        switch (prop) {
                        case NoteNumber:
                                if (temporary_removals.find (i->note) == temporary_removals.end()) {
@@ -341,7 +350,7 @@ MidiModel::NoteDiffCommand::operator() ()
                                _removed_notes.push_back (*i);
                        }
                }
-
+               
                if (!side_effect_removals.empty()) {
                        cerr << "SER: \n";
                        for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
@@ -373,15 +382,25 @@ MidiModel::NoteDiffCommand::undo ()
                /* notes we modify in a way that requires remove-then-add to maintain ordering */
                set<NotePtr> temporary_removals;
 
+
+               /* lazily discover any affected notes that were not discovered when
+                * loading the history because of deletions, etc.
+                */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->note) {
+                               i->note = _model->find_note (i->note_id);
+                               assert (i->note);
+                       }
+               }
+                               
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                        Property prop = i->property;
-                       switch (prop) {
 
+                       switch (prop) {
                        case NoteNumber:
-                               if (
-                                       temporary_removals.find (i->note) == temporary_removals.end() &&
-                                       find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()
-                                       ) {
+                               if (temporary_removals.find (i->note) == temporary_removals.end() &&
+                                   find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
 
                                        /* We only need to mark this note for re-add if (a) we haven't
                                           already marked it and (b) it isn't on the _removed_notes
@@ -396,10 +415,8 @@ MidiModel::NoteDiffCommand::undo ()
                                break;
 
                        case StartTime:
-                               if (
-                                       temporary_removals.find (i->note) == temporary_removals.end() &&
-                                       find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()
-                                       ) {
+                               if (temporary_removals.find (i->note) == temporary_removals.end() &&
+                                   find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
 
                                        /* See above ... */
 
@@ -410,10 +427,8 @@ MidiModel::NoteDiffCommand::undo ()
                                break;
 
                        case Channel:
-                               if (
-                                       temporary_removals.find (i->note) == temporary_removals.end() &&
-                                       find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()
-                                       ) {
+                               if (temporary_removals.find (i->note) == temporary_removals.end() &&
+                                   find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
 
                                        /* See above ... */
 
@@ -453,7 +468,7 @@ MidiModel::NoteDiffCommand::undo ()
                        _model->add_note_unlocked (*i);
                }
        }
-
+       
        _model->ContentsChanged(); /* EMIT SIGNAL */
 }
 
@@ -651,15 +666,13 @@ MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
        }
 
        /* we must point at the instance of the note that is actually in the model.
-          so go look for it ...
+          so go look for it ... it may not be there (it could have been
+          deleted in a later operation, so store the note id so that we can
+          look it up again later).
        */
 
        change.note = _model->find_note (note_id);
-
-       if (!change.note) {
-               warning << "MIDI note #" << note_id << " not found in model - programmers should investigate this" << endmsg;
-               return change;
-       }
+       change.note_id = note_id;
 
        return change;
 }
@@ -786,6 +799,19 @@ MidiModel::SysExDiffCommand::operator() ()
        {
                MidiModel::WriteLock lock (_model->edit_lock ());
 
+               for (list<SysExPtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
+                       _model->remove_sysex_unlocked (*i);
+               }
+
+               /* find any sysex events that were missing when unmarshalling */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->sysex) {
+                               i->sysex = _model->find_sysex (i->sysex_id);
+                               assert (i->sysex);
+                       }
+               }
+
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                        switch (i->property) {
                        case Time:
@@ -803,6 +829,19 @@ MidiModel::SysExDiffCommand::undo ()
        {
                MidiModel::WriteLock lock (_model->edit_lock ());
 
+               for (list<SysExPtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
+                       _model->add_sysex_unlocked (*i);
+               }
+
+               /* find any sysex events that were missing when unmarshalling */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->sysex) {
+                               i->sysex = _model->find_sysex (i->sysex_id);
+                               assert (i->sysex);
+                       }
+               }
+
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
                        switch (i->property) {
                        case Time:
@@ -816,6 +855,12 @@ MidiModel::SysExDiffCommand::undo ()
        _model->ContentsChanged(); /* EMIT SIGNAL */
 }
 
+void
+MidiModel::SysExDiffCommand::remove (SysExPtr sysex)
+{
+       _removed.push_back(sysex);
+}
+
 XMLNode&
 MidiModel::SysExDiffCommand::marshal_change (const Change& change)
 {
@@ -885,11 +930,7 @@ MidiModel::SysExDiffCommand::unmarshal_change (XMLNode *xml_change)
        */
 
        change.sysex = _model->find_sysex (sysex_id);
-
-       if (!change.sysex) {
-               warning << "Sys-ex #" << sysex_id << " not found in model - programmers should investigate this" << endmsg;
-               return change;
-       }
+       change.sysex_id = sysex_id;
 
        return change;
 }
@@ -977,6 +1018,7 @@ MidiModel::PatchChangeDiffCommand::change_channel (PatchChangePtr patch, uint8_t
        c.patch = patch;
        c.old_channel = patch->channel ();
        c.new_channel = channel;
+       c.patch_id = patch->id();
 
        _changes.push_back (c);
 }
@@ -989,6 +1031,7 @@ MidiModel::PatchChangeDiffCommand::change_program (PatchChangePtr patch, uint8_t
        c.patch = patch;
        c.old_program = patch->program ();
        c.new_program = program;
+       c.patch_id = patch->id();
 
        _changes.push_back (c);
 }
@@ -1019,6 +1062,15 @@ MidiModel::PatchChangeDiffCommand::operator() ()
                        _model->remove_patch_change_unlocked (*i);
                }
 
+               /* find any patch change events that were missing when unmarshalling */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->patch) {
+                               i->patch = _model->find_patch_change (i->patch_id);
+                               assert (i->patch);
+                       }
+               }
+
                set<PatchChangePtr> temporary_removals;
 
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
@@ -1067,6 +1119,15 @@ MidiModel::PatchChangeDiffCommand::undo ()
                        _model->add_patch_change_unlocked (*i);
                }
 
+               /* find any patch change events that were missing when unmarshalling */
+
+               for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
+                       if (!i->patch) {
+                               i->patch = _model->find_patch_change (i->patch_id);
+                               assert (i->patch);
+                       }
+               }
+
                set<PatchChangePtr> temporary_removals;
 
                for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
@@ -1191,12 +1252,12 @@ MidiModel::PatchChangePtr
 MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
 {
        XMLProperty* prop;
-       Evoral::event_id_t id;
+       Evoral::event_id_t id = 0;
        Evoral::MusicalTime time = 0;
-       uint8_t channel = 0;
-       uint8_t program = 0;
+       int channel = 0;
+       int program = 0;
        int bank = 0;
-
+       
        if ((prop = n->property ("id")) != 0) {
                istringstream s (prop->value());
                s >> id;
@@ -1223,6 +1284,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
        }
 
        PatchChangePtr p (new Evoral::PatchChange<TimeType> (time, channel, program, bank));
+       assert(id);
        p->set_id (id);
        return p;
 }
@@ -1232,6 +1294,7 @@ MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
 {
        XMLProperty* prop;
        Change c;
+       int an_int;
 
        prop = n->property ("property");
        assert (prop);
@@ -1241,6 +1304,10 @@ MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
        assert (prop);
        Evoral::event_id_t const id = atoi (prop->value().c_str());
 
+       /* we need to load via an int intermediate for all properties that are 
+          actually uint8_t (char/byte).
+       */
+
        prop = n->property ("old");
        assert (prop);
        {
@@ -1248,11 +1315,14 @@ MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
                if (c.property == Time) {
                        s >> c.old_time;
                } else if (c.property == Channel) {
-                       s >> c.old_channel;
+                       s >> an_int;
+                       c.old_channel = an_int;
                } else if (c.property == Program) {
-                       s >> c.old_program;
+                       s >> an_int;
+                       c.old_program = an_int;
                } else if (c.property == Bank) {
-                       s >> c.old_bank;
+                       s >> an_int;
+                       c.old_bank = an_int;
                }
        }
 
@@ -1260,19 +1330,23 @@ MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
        assert (prop);
        {
                istringstream s (prop->value ());
+
                if (c.property == Time) {
                        s >> c.new_time;
                } else if (c.property == Channel) {
-                       s >> c.new_channel;
+                       s >> an_int;
+                       c.new_channel = an_int;
                } else if (c.property == Program) {
-                       s >> c.new_program;
+                       s >> an_int;
+                       c.new_program = an_int;
                } else if (c.property == Bank) {
-                       s >> c.new_bank;
+                       s >> an_int;
+                       c.new_bank = an_int;
                }
        }
 
        c.patch = _model->find_patch_change (id);
-       assert (c.patch);
+       c.patch_id = id;
 
        return c;
 }
@@ -1570,7 +1644,7 @@ MidiModel::write_lock()
        assert (ms);
 
        assert (!ms->mutex().trylock ());
-       return WriteLock(new WriteLockImpl(NULL, _lock, _control_lock));
+       return WriteLock(new WriteLockImpl(0, _lock, _control_lock));
 }
 
 int