+XMLNode&
+MidiModel::NoteDiffCommand::marshal_note(const NotePtr note)
+{
+ XMLNode* xml_note = new XMLNode("note");
+
+ {
+ ostringstream id_str(ios::ate);
+ id_str << int(note->id());
+ xml_note->add_property("id", id_str.str());
+ }
+
+ {
+ ostringstream note_str(ios::ate);
+ note_str << int(note->note());
+ xml_note->add_property("note", note_str.str());
+ }
+
+ {
+ ostringstream channel_str(ios::ate);
+ channel_str << int(note->channel());
+ xml_note->add_property("channel", channel_str.str());
+ }
+
+ {
+ ostringstream time_str(ios::ate);
+ time_str << note->time();
+ xml_note->add_property("time", time_str.str());
+ }
+
+ {
+ ostringstream length_str(ios::ate);
+ length_str << note->length();
+ xml_note->add_property("length", length_str.str());
+ }
+
+ {
+ ostringstream velocity_str(ios::ate);
+ velocity_str << (unsigned int) note->velocity();
+ xml_note->add_property("velocity", velocity_str.str());
+ }
+
+ return *xml_note;
+}
+
+Evoral::Sequence<MidiModel::TimeType>::NotePtr
+MidiModel::NoteDiffCommand::unmarshal_note (XMLNode *xml_note)
+{
+ unsigned int note;
+ XMLProperty* prop;
+ unsigned int channel;
+ MidiModel::TimeType time;
+ MidiModel::TimeType length;
+ unsigned int velocity;
+ gint id;
+
+ if ((prop = xml_note->property("id")) != 0) {
+ istringstream id_str(prop->value());
+ id_str >> id;
+ } else {
+ error << "note information missing ID value" << endmsg;
+ id = -1;
+ }
+
+ if ((prop = xml_note->property("note")) != 0) {
+ istringstream note_str(prop->value());
+ note_str >> note;
+ } else {
+ warning << "note information missing note value" << endmsg;
+ note = 127;
+ }
+
+ if ((prop = xml_note->property("channel")) != 0) {
+ istringstream channel_str(prop->value());
+ channel_str >> channel;
+ } else {
+ warning << "note information missing channel" << endmsg;
+ channel = 0;
+ }
+
+ if ((prop = xml_note->property("time")) != 0) {
+ istringstream time_str(prop->value());
+ time_str >> time;
+ } else {
+ warning << "note information missing time" << endmsg;
+ time = 0;
+ }
+
+ if ((prop = xml_note->property("length")) != 0) {
+ istringstream length_str(prop->value());
+ length_str >> length;
+ } else {
+ warning << "note information missing length" << endmsg;
+ length = 1;
+ }
+
+ if ((prop = xml_note->property("velocity")) != 0) {
+ istringstream velocity_str(prop->value());
+ velocity_str >> velocity;
+ } else {
+ warning << "note information missing velocity" << endmsg;
+ velocity = 127;
+ }
+
+ NotePtr note_ptr(new Evoral::Note<TimeType>(channel, time, length, note, velocity));
+ note_ptr->set_id (id);
+
+ return note_ptr;
+}
+
+XMLNode&
+MidiModel::NoteDiffCommand::marshal_change (const NoteChange& change)
+{
+ XMLNode* xml_change = new XMLNode("Change");
+
+ /* first, the change itself */
+
+ xml_change->add_property ("property", enum_2_string (change.property));
+
+ {
+ ostringstream old_value_str (ios::ate);
+ if (change.property == StartTime || change.property == Length) {
+ old_value_str << change.old_time;
+ } else {
+ old_value_str << (unsigned int) change.old_value;
+ }
+ xml_change->add_property ("old", old_value_str.str());
+ }
+
+ {
+ ostringstream new_value_str (ios::ate);
+ if (change.property == StartTime || change.property == Length) {
+ new_value_str << change.new_time;
+ } else {
+ new_value_str << (unsigned int) change.new_value;
+ }
+ xml_change->add_property ("new", new_value_str.str());
+ }
+
+ ostringstream id_str;
+ id_str << change.note->id();
+ xml_change->add_property ("id", id_str.str());
+
+ return *xml_change;
+}
+
+MidiModel::NoteDiffCommand::NoteChange
+MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
+{
+ XMLProperty* prop;
+ NoteChange change;
+
+ if ((prop = xml_change->property("property")) != 0) {
+ change.property = (Property) string_2_enum (prop->value(), change.property);
+ } else {
+ fatal << "!!!" << endmsg;
+ /*NOTREACHED*/
+ }
+
+ if ((prop = xml_change->property ("id")) == 0) {
+ error << _("No NoteID found for note property change - ignored") << endmsg;
+ return change;
+ }
+
+ gint note_id = atoi (prop->value().c_str());
+
+ if ((prop = xml_change->property ("old")) != 0) {
+ istringstream old_str (prop->value());
+ if (change.property == StartTime || change.property == Length) {
+ old_str >> change.old_time;
+ } else {
+ int integer_value_so_that_istream_does_the_right_thing;
+ old_str >> integer_value_so_that_istream_does_the_right_thing;
+ change.old_value = integer_value_so_that_istream_does_the_right_thing;
+ }
+ } else {
+ fatal << "!!!" << endmsg;
+ /*NOTREACHED*/
+ }
+
+ if ((prop = xml_change->property ("new")) != 0) {
+ istringstream new_str (prop->value());
+ if (change.property == StartTime || change.property == Length) {
+ new_str >> change.new_time;
+ } else {
+ int integer_value_so_that_istream_does_the_right_thing;
+ new_str >> integer_value_so_that_istream_does_the_right_thing;
+ change.new_value = integer_value_so_that_istream_does_the_right_thing;
+ }
+ } else {
+ fatal << "!!!" << endmsg;
+ /*NOTREACHED*/
+ }
+
+ /* we must point at the instance of the note that is actually in the model.
+ 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);
+ change.note_id = note_id;
+
+ return change;
+}
+
+int
+MidiModel::NoteDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
+{
+ if (diff_command.name() != string (NOTE_DIFF_COMMAND_ELEMENT)) {
+ return 1;
+ }
+
+ /* additions */
+
+ _added_notes.clear();
+ XMLNode* added_notes = diff_command.child(ADDED_NOTES_ELEMENT);
+ if (added_notes) {
+ XMLNodeList notes = added_notes->children();
+ transform(notes.begin(), notes.end(), back_inserter(_added_notes),
+ boost::bind (&NoteDiffCommand::unmarshal_note, this, _1));
+ }
+
+
+ /* removals */
+
+ _removed_notes.clear();
+ XMLNode* removed_notes = diff_command.child(REMOVED_NOTES_ELEMENT);
+ if (removed_notes) {
+ XMLNodeList notes = removed_notes->children();
+ transform(notes.begin(), notes.end(), back_inserter(_removed_notes),
+ boost::bind (&NoteDiffCommand::unmarshal_note, this, _1));
+ }
+
+
+ /* changes */
+
+ _changes.clear();
+
+ XMLNode* changed_notes = diff_command.child(DIFF_NOTES_ELEMENT);
+
+ if (changed_notes) {
+ XMLNodeList notes = changed_notes->children();
+ transform (notes.begin(), notes.end(), back_inserter(_changes),
+ boost::bind (&NoteDiffCommand::unmarshal_change, this, _1));
+
+ }
+
+ /* side effect removals caused by changes */
+
+ side_effect_removals.clear();
+
+ XMLNode* side_effect_notes = diff_command.child(SIDE_EFFECT_REMOVALS_ELEMENT);
+
+ if (side_effect_notes) {
+ XMLNodeList notes = side_effect_notes->children();
+ for (XMLNodeList::iterator n = notes.begin(); n != notes.end(); ++n) {
+ side_effect_removals.insert (unmarshal_note (*n));
+ }
+ }
+
+ return 0;
+}
+
+XMLNode&
+MidiModel::NoteDiffCommand::get_state ()
+{
+ XMLNode* diff_command = new XMLNode (NOTE_DIFF_COMMAND_ELEMENT);
+ 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(),
+ boost::bind (
+ boost::bind (&XMLNode::add_child_nocopy, changes, _1),
+ boost::bind (&NoteDiffCommand::marshal_change, this, _1)));
+
+ XMLNode* added_notes = diff_command->add_child(ADDED_NOTES_ELEMENT);
+ for_each(_added_notes.begin(), _added_notes.end(),
+ boost::bind(
+ boost::bind (&XMLNode::add_child_nocopy, added_notes, _1),
+ boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
+
+ XMLNode* removed_notes = diff_command->add_child(REMOVED_NOTES_ELEMENT);
+ for_each(_removed_notes.begin(), _removed_notes.end(),
+ boost::bind (
+ boost::bind (&XMLNode::add_child_nocopy, removed_notes, _1),
+ boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
+
+ /* if this command had side-effects, store that state too
+ */
+
+ if (!side_effect_removals.empty()) {
+ XMLNode* side_effect_notes = diff_command->add_child(SIDE_EFFECT_REMOVALS_ELEMENT);
+ for_each(side_effect_removals.begin(), side_effect_removals.end(),
+ boost::bind (
+ boost::bind (&XMLNode::add_child_nocopy, side_effect_notes, _1),
+ boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
+ }
+
+ return *diff_command;
+}
+
+MidiModel::SysExDiffCommand::SysExDiffCommand (boost::shared_ptr<MidiModel> m, const XMLNode& node)
+ : DiffCommand (m, "")
+{
+ assert (_model);
+ set_state (node, Stateful::loading_state_version);
+}
+
+void
+MidiModel::SysExDiffCommand::change (boost::shared_ptr<Evoral::Event<TimeType> > s, TimeType new_time)
+{
+ Change change;
+
+ change.sysex = s;
+ change.property = Time;
+ change.old_time = s->time ();
+ change.new_time = new_time;
+
+ _changes.push_back (change);