MusicalTime => Beats.
[ardour.git] / libs / ardour / midi_model.cc
1 /*
2   Copyright (C) 2007 Paul Davis
3   Author: David Robillard
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include <algorithm>
22 #include <iostream>
23 #include <set>
24 #include <stdexcept>
25 #include <stdint.h>
26
27 #include "pbd/compose.h"
28 #include "pbd/enumwriter.h"
29 #include "pbd/error.h"
30
31 #include "evoral/Control.hpp"
32
33 #include "midi++/events.h"
34
35 #include "ardour/automation_control.h"
36 #include "ardour/midi_automation_list_binder.h"
37 #include "ardour/midi_model.h"
38 #include "ardour/midi_source.h"
39 #include "ardour/midi_state_tracker.h"
40 #include "ardour/session.h"
41 #include "ardour/types.h"
42
43 #include "i18n.h"
44
45 using namespace std;
46 using namespace ARDOUR;
47 using namespace PBD;
48
49 MidiModel::MidiModel (boost::shared_ptr<MidiSource> s)
50         : AutomatableSequence<TimeType>(s->session())
51 {
52         set_midi_source (s);
53 }
54
55 /** Start a new NoteDiff command.
56  *
57  * This has no side-effects on the model or Session, the returned command
58  * can be held on to for as long as the caller wishes, or discarded without
59  * formality, until apply_command is called and ownership is taken.
60  */
61 MidiModel::NoteDiffCommand*
62 MidiModel::new_note_diff_command (const string name)
63 {
64         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
65         assert (ms);
66
67         return new NoteDiffCommand (ms->model(), name);
68 }
69
70 /** Start a new SysExDiff command */
71 MidiModel::SysExDiffCommand*
72 MidiModel::new_sysex_diff_command (const string name)
73 {
74         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
75         assert (ms);
76
77         return new SysExDiffCommand (ms->model(), name);
78 }
79
80 /** Start a new PatchChangeDiff command */
81 MidiModel::PatchChangeDiffCommand*
82 MidiModel::new_patch_change_diff_command (const string name)
83 {
84         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
85         assert (ms);
86
87         return new PatchChangeDiffCommand (ms->model(), name);
88 }
89
90
91 /** Apply a command.
92  *
93  * Ownership of cmd is taken, it must not be deleted by the caller.
94  * The command will constitute one item on the undo stack.
95  */
96 void
97 MidiModel::apply_command(Session& session, Command* cmd)
98 {
99         session.begin_reversible_command(cmd->name());
100         (*cmd)();
101         session.commit_reversible_command(cmd);
102         set_edited(true);
103 }
104
105 /** Apply a command as part of a larger reversible transaction
106  *
107  * Ownership of cmd is taken, it must not be deleted by the caller.
108  * The command will constitute one item on the undo stack.
109  */
110 void
111 MidiModel::apply_command_as_subcommand(Session& session, Command* cmd)
112 {
113         (*cmd)();
114         session.add_command(cmd);
115         set_edited(true);
116 }
117
118 /************** DIFF COMMAND ********************/
119
120 #define NOTE_DIFF_COMMAND_ELEMENT "NoteDiffCommand"
121 #define DIFF_NOTES_ELEMENT "ChangedNotes"
122 #define ADDED_NOTES_ELEMENT "AddedNotes"
123 #define REMOVED_NOTES_ELEMENT "RemovedNotes"
124 #define SIDE_EFFECT_REMOVALS_ELEMENT "SideEffectRemovals"
125 #define SYSEX_DIFF_COMMAND_ELEMENT "SysExDiffCommand"
126 #define DIFF_SYSEXES_ELEMENT "ChangedSysExes"
127 #define PATCH_CHANGE_DIFF_COMMAND_ELEMENT "PatchChangeDiffCommand"
128 #define ADDED_PATCH_CHANGES_ELEMENT "AddedPatchChanges"
129 #define REMOVED_PATCH_CHANGES_ELEMENT "RemovedPatchChanges"
130 #define DIFF_PATCH_CHANGES_ELEMENT "ChangedPatchChanges"
131
132 MidiModel::DiffCommand::DiffCommand(boost::shared_ptr<MidiModel> m, const std::string& name)
133         : Command (name)
134         , _model (m)
135         , _name (name)
136 {
137         assert(_model);
138 }
139
140 MidiModel::NoteDiffCommand::NoteDiffCommand (boost::shared_ptr<MidiModel> m, const XMLNode& node)
141         : DiffCommand (m, "")
142 {
143         assert (_model);
144         set_state (node, Stateful::loading_state_version);
145 }
146
147 void
148 MidiModel::NoteDiffCommand::add (const NotePtr note)
149 {
150         _removed_notes.remove(note);
151         _added_notes.push_back(note);
152 }
153
154 void
155 MidiModel::NoteDiffCommand::remove (const NotePtr note)
156 {
157         _added_notes.remove(note);
158         _removed_notes.push_back(note);
159 }
160
161 void
162 MidiModel::NoteDiffCommand::side_effect_remove (const NotePtr note)
163 {
164         side_effect_removals.insert (note);
165 }
166
167 Variant
168 MidiModel::NoteDiffCommand::get_value (const NotePtr note, Property prop)
169 {
170         switch (prop) {
171         case NoteNumber:
172                 return Variant(note->note());
173         case Velocity:
174                 return Variant(note->velocity());
175         case Channel:
176                 return Variant(note->channel());
177         case StartTime:
178                 return Variant(note->time());
179         case Length:
180                 return Variant(note->length());
181         }
182
183         return Variant();
184 }
185
186 Variant::Type
187 MidiModel::NoteDiffCommand::value_type(Property prop)
188 {
189         switch (prop) {
190         case NoteNumber:
191         case Velocity:
192         case Channel:
193                 return Variant::INT;
194         case StartTime:
195         case Length:
196                 return Variant::BEATS;
197         }
198
199         return Variant::NOTHING;
200 }
201
202 void
203 MidiModel::NoteDiffCommand::change (const NotePtr  note,
204                                     Property       prop,
205                                     const Variant& new_value)
206 {
207         assert (note);
208
209         const NoteChange change = {
210                 prop, note, 0, get_value(note, prop), new_value
211         };
212
213         if (change.old_value == new_value) {
214                 return;
215         }
216
217         _changes.push_back (change);
218 }
219
220 MidiModel::NoteDiffCommand &
221 MidiModel::NoteDiffCommand::operator+= (const NoteDiffCommand& other)
222 {
223         if (this == &other) {
224                 return *this;
225         }
226
227         if (_model != other._model) {
228                 return *this;
229         }
230
231         _added_notes.insert (_added_notes.end(), other._added_notes.begin(), other._added_notes.end());
232         _removed_notes.insert (_removed_notes.end(), other._removed_notes.begin(), other._removed_notes.end());
233         side_effect_removals.insert (other.side_effect_removals.begin(), other.side_effect_removals.end());
234         _changes.insert (_changes.end(), other._changes.begin(), other._changes.end());
235
236         return *this;
237 }
238
239 void
240 MidiModel::NoteDiffCommand::operator() ()
241 {
242         {
243                 MidiModel::WriteLock lock(_model->edit_lock());
244
245                 for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
246                         if (!_model->add_note_unlocked(*i)) {
247                                 /* failed to add it, so don't leave it in the removed list, to
248                                    avoid apparent errors on undo.
249                                 */
250                                 _removed_notes.remove (*i);
251                         }
252                 }
253
254                 for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) {
255                         _model->remove_note_unlocked(*i);
256                 }
257
258                 /* notes we modify in a way that requires remove-then-add to maintain ordering */
259                 set<NotePtr> temporary_removals;
260
261                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
262                         Property prop = i->property;
263
264                         if (!i->note) {
265                                 /* note found during deserialization, so try
266                                    again now that the model state is different.
267                                 */
268                                 i->note = _model->find_note (i->note_id);
269                                 assert (i->note);
270                         }
271
272                         switch (prop) {
273                         case NoteNumber:
274                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
275                                         _model->remove_note_unlocked (i->note);
276                                         temporary_removals.insert (i->note);
277                                 }
278                                 i->note->set_note (i->new_value.get_int());
279                                 break;
280
281                         case StartTime:
282                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
283                                         _model->remove_note_unlocked (i->note);
284                                         temporary_removals.insert (i->note);
285                                 }
286                                 i->note->set_time (i->new_value.get_beats());
287                                 break;
288
289                         case Channel:
290                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
291                                         _model->remove_note_unlocked (i->note);
292                                         temporary_removals.insert (i->note);
293                                 }
294                                 i->note->set_channel (i->new_value.get_int());
295                                 break;
296
297                                 /* no remove-then-add required for these properties, since we do not index them
298                                  */
299
300                         case Velocity:
301                                 i->note->set_velocity (i->new_value.get_int());
302                                 break;
303
304                         case Length:
305                                 i->note->set_length (i->new_value.get_beats());
306                                 break;
307
308                         }
309                 }
310
311                 for (set<NotePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
312                         NoteDiffCommand side_effects (model(), "side effects");
313                         if (_model->add_note_unlocked (*i, &side_effects)) {
314                                 /* The note was re-added ok */
315                                 *this += side_effects;
316                         } else {
317                                 /* The note that we removed earlier could not be re-added.  This change record
318                                    must say that the note was removed.  We'll keep the changes we made, though,
319                                    as if the note is re-added by the undo the changes must also be undone.
320                                 */
321                                 _removed_notes.push_back (*i);
322                         }
323                 }
324                 
325                 if (!side_effect_removals.empty()) {
326                         cerr << "SER: \n";
327                         for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
328                                 cerr << "\t" << *i << ' ' << **i << endl;
329                         }
330                 }
331         }
332
333         _model->ContentsChanged(); /* EMIT SIGNAL */
334 }
335
336 void
337 MidiModel::NoteDiffCommand::undo ()
338 {
339         {
340                 MidiModel::WriteLock lock(_model->edit_lock());
341
342                 for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
343                         _model->remove_note_unlocked(*i);
344                 }
345
346                 /* Apply changes first; this is important in the case of a note change which
347                    resulted in the note being removed by the overlap checker.  If the overlap
348                    checker removes a note, it will be in _removed_notes.  We are going to re-add
349                    it below, but first we must undo the changes we made so that the overlap
350                    checker doesn't refuse the re-add.
351                 */
352
353                 /* notes we modify in a way that requires remove-then-add to maintain ordering */
354                 set<NotePtr> temporary_removals;
355
356
357                 /* lazily discover any affected notes that were not discovered when
358                  * loading the history because of deletions, etc.
359                  */
360
361                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
362                         if (!i->note) {
363                                 i->note = _model->find_note (i->note_id);
364                                 assert (i->note);
365                         }
366                 }
367                                 
368                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
369                         Property prop = i->property;
370
371                         switch (prop) {
372                         case NoteNumber:
373                                 if (temporary_removals.find (i->note) == temporary_removals.end() &&
374                                     find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
375
376                                         /* We only need to mark this note for re-add if (a) we haven't
377                                            already marked it and (b) it isn't on the _removed_notes
378                                            list (which means that it has already been removed and it
379                                            will be re-added anyway)
380                                         */
381
382                                         _model->remove_note_unlocked (i->note);
383                                         temporary_removals.insert (i->note);
384                                 }
385                                 i->note->set_note (i->old_value.get_int());
386                                 break;
387
388                         case StartTime:
389                                 if (temporary_removals.find (i->note) == temporary_removals.end() &&
390                                     find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
391
392                                         /* See above ... */
393
394                                         _model->remove_note_unlocked (i->note);
395                                         temporary_removals.insert (i->note);
396                                 }
397                                 i->note->set_time (i->old_value.get_beats());
398                                 break;
399
400                         case Channel:
401                                 if (temporary_removals.find (i->note) == temporary_removals.end() &&
402                                     find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
403
404                                         /* See above ... */
405
406                                         _model->remove_note_unlocked (i->note);
407                                         temporary_removals.insert (i->note);
408                                 }
409                                 i->note->set_channel (i->old_value.get_int());
410                                 break;
411
412                                 /* no remove-then-add required for these properties, since we do not index them
413                                  */
414
415                         case Velocity:
416                                 i->note->set_velocity (i->old_value.get_int());
417                                 break;
418
419                         case Length:
420                                 i->note->set_length (i->old_value.get_beats());
421                                 break;
422                         }
423                 }
424
425                 for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) {
426                         _model->add_note_unlocked(*i);
427                 }
428
429                 for (set<NotePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
430                         _model->add_note_unlocked (*i);
431                 }
432
433                 /* finally add back notes that were removed by the "do". we don't care
434                    about side effects here since the model should be back to its original
435                    state once this is done.
436                 */
437
438                 for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
439                         _model->add_note_unlocked (*i);
440                 }
441         }
442         
443         _model->ContentsChanged(); /* EMIT SIGNAL */
444 }
445
446 XMLNode&
447 MidiModel::NoteDiffCommand::marshal_note(const NotePtr note)
448 {
449         XMLNode* xml_note = new XMLNode("note");
450
451         {
452                 ostringstream id_str(ios::ate);
453                 id_str << int(note->id());
454                 xml_note->add_property("id", id_str.str());
455         }
456
457         {
458                 ostringstream note_str(ios::ate);
459                 note_str << int(note->note());
460                 xml_note->add_property("note", note_str.str());
461         }
462
463         {
464                 ostringstream channel_str(ios::ate);
465                 channel_str << int(note->channel());
466                 xml_note->add_property("channel", channel_str.str());
467         }
468
469         {
470                 ostringstream time_str(ios::ate);
471                 time_str << note->time();
472                 xml_note->add_property("time", time_str.str());
473         }
474
475         {
476                 ostringstream length_str(ios::ate);
477                 length_str << note->length();
478                 xml_note->add_property("length", length_str.str());
479         }
480
481         {
482                 ostringstream velocity_str(ios::ate);
483                 velocity_str << (unsigned int) note->velocity();
484                 xml_note->add_property("velocity", velocity_str.str());
485         }
486
487         return *xml_note;
488 }
489
490 Evoral::Sequence<MidiModel::TimeType>::NotePtr
491 MidiModel::NoteDiffCommand::unmarshal_note (XMLNode *xml_note)
492 {
493         unsigned int note;
494         XMLProperty* prop;
495         unsigned int channel;
496         MidiModel::TimeType time;
497         MidiModel::TimeType length;
498         unsigned int velocity;
499         gint id;
500
501         if ((prop = xml_note->property("id")) != 0) {
502                 istringstream id_str(prop->value());
503                 id_str >> id;
504         } else {
505                 error << "note information missing ID value" << endmsg;
506                 id = -1;
507         }
508
509         if ((prop = xml_note->property("note")) != 0) {
510                 istringstream note_str(prop->value());
511                 note_str >> note;
512         } else {
513                 warning << "note information missing note value" << endmsg;
514                 note = 127;
515         }
516
517         if ((prop = xml_note->property("channel")) != 0) {
518                 istringstream channel_str(prop->value());
519                 channel_str >> channel;
520         } else {
521                 warning << "note information missing channel" << endmsg;
522                 channel = 0;
523         }
524
525         if ((prop = xml_note->property("time")) != 0) {
526                 istringstream time_str(prop->value());
527                 time_str >> time;
528         } else {
529                 warning << "note information missing time" << endmsg;
530                 time = MidiModel::TimeType();
531         }
532
533         if ((prop = xml_note->property("length")) != 0) {
534                 istringstream length_str(prop->value());
535                 length_str >> length;
536         } else {
537                 warning << "note information missing length" << endmsg;
538                 length = MidiModel::TimeType(1);
539         }
540
541         if ((prop = xml_note->property("velocity")) != 0) {
542                 istringstream velocity_str(prop->value());
543                 velocity_str >> velocity;
544         } else {
545                 warning << "note information missing velocity" << endmsg;
546                 velocity = 127;
547         }
548
549         NotePtr note_ptr(new Evoral::Note<TimeType>(channel, time, length, note, velocity));
550         note_ptr->set_id (id);
551
552         return note_ptr;
553 }
554
555 XMLNode&
556 MidiModel::NoteDiffCommand::marshal_change (const NoteChange& change)
557 {
558         XMLNode* xml_change = new XMLNode("Change");
559
560         /* first, the change itself */
561
562         xml_change->add_property ("property", enum_2_string (change.property));
563
564         {
565                 ostringstream old_value_str (ios::ate);
566                 if (change.property == StartTime || change.property == Length) {
567                         old_value_str << change.old_value.get_beats();
568                 } else {
569                         old_value_str << change.old_value.get_int();
570                 }
571                 xml_change->add_property ("old", old_value_str.str());
572         }
573
574         {
575                 ostringstream new_value_str (ios::ate);
576                 if (change.property == StartTime || change.property == Length) {
577                         new_value_str << change.new_value.get_beats();
578                 } else {
579                         new_value_str << change.new_value.get_int();
580                 }
581                 xml_change->add_property ("new", new_value_str.str());
582         }
583
584         ostringstream id_str;
585         if (change.note) {
586                 id_str << change.note->id();
587                 xml_change->add_property ("id", id_str.str());
588         } else if (change.note_id) {
589                 warning << _("Change has no note, using note ID") << endmsg;
590                 id_str << change.note_id;
591                 xml_change->add_property ("id", id_str.str());
592         } else {
593                 error << _("Change has no note or note ID") << endmsg;
594         }
595
596         return *xml_change;
597 }
598
599 MidiModel::NoteDiffCommand::NoteChange
600 MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
601 {
602         XMLProperty* prop;
603         NoteChange change;
604         change.note_id = 0;
605
606         if ((prop = xml_change->property("property")) != 0) {
607                 change.property = (Property) string_2_enum (prop->value(), change.property);
608         } else {
609                 fatal << "!!!" << endmsg;
610                 abort(); /*NOTREACHED*/
611         }
612
613         if ((prop = xml_change->property ("id")) == 0) {
614                 error << _("No NoteID found for note property change - ignored") << endmsg;
615                 return change;
616         }
617
618         gint note_id = atoi (prop->value().c_str());
619
620         if ((prop = xml_change->property ("old")) != 0) {
621                 istringstream old_str (prop->value());
622                 if (change.property == StartTime || change.property == Length) {
623                         Evoral::Beats old_time;
624                         old_str >> old_time;
625                         change.old_value = old_time;
626                 } else {
627                         int integer_value_so_that_istream_does_the_right_thing;
628                         old_str >> integer_value_so_that_istream_does_the_right_thing;
629                         change.old_value = integer_value_so_that_istream_does_the_right_thing;
630                 }
631         } else {
632                 fatal << "!!!" << endmsg;
633                 abort(); /*NOTREACHED*/
634         }
635
636         if ((prop = xml_change->property ("new")) != 0) {
637                 istringstream new_str (prop->value());
638                 if (change.property == StartTime || change.property == Length) {
639                         Evoral::Beats new_time;
640                         new_str >> new_time;
641                         change.new_value = Variant(new_time);
642                 } else {
643                         int integer_value_so_that_istream_does_the_right_thing;
644                         new_str >> integer_value_so_that_istream_does_the_right_thing;
645                         change.new_value = integer_value_so_that_istream_does_the_right_thing;
646                 }
647         } else {
648                 fatal << "!!!" << endmsg;
649                 abort(); /*NOTREACHED*/
650         }
651
652         /* we must point at the instance of the note that is actually in the model.
653            so go look for it ... it may not be there (it could have been
654            deleted in a later operation, so store the note id so that we can
655            look it up again later).
656         */
657
658         change.note = _model->find_note (note_id);
659         change.note_id = note_id;
660
661         return change;
662 }
663
664 int
665 MidiModel::NoteDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
666 {
667         if (diff_command.name() != string (NOTE_DIFF_COMMAND_ELEMENT)) {
668                 return 1;
669         }
670
671         /* additions */
672
673         _added_notes.clear();
674         XMLNode* added_notes = diff_command.child(ADDED_NOTES_ELEMENT);
675         if (added_notes) {
676                 XMLNodeList notes = added_notes->children();
677                 transform(notes.begin(), notes.end(), back_inserter(_added_notes),
678                           boost::bind (&NoteDiffCommand::unmarshal_note, this, _1));
679         }
680
681
682         /* removals */
683
684         _removed_notes.clear();
685         XMLNode* removed_notes = diff_command.child(REMOVED_NOTES_ELEMENT);
686         if (removed_notes) {
687                 XMLNodeList notes = removed_notes->children();
688                 transform(notes.begin(), notes.end(), back_inserter(_removed_notes),
689                           boost::bind (&NoteDiffCommand::unmarshal_note, this, _1));
690         }
691
692
693         /* changes */
694
695         _changes.clear();
696
697         XMLNode* changed_notes = diff_command.child(DIFF_NOTES_ELEMENT);
698
699         if (changed_notes) {
700                 XMLNodeList notes = changed_notes->children();
701                 transform (notes.begin(), notes.end(), back_inserter(_changes),
702                            boost::bind (&NoteDiffCommand::unmarshal_change, this, _1));
703
704         }
705
706         /* side effect removals caused by changes */
707
708         side_effect_removals.clear();
709
710         XMLNode* side_effect_notes = diff_command.child(SIDE_EFFECT_REMOVALS_ELEMENT);
711
712         if (side_effect_notes) {
713                 XMLNodeList notes = side_effect_notes->children();
714                 for (XMLNodeList::iterator n = notes.begin(); n != notes.end(); ++n) {
715                         side_effect_removals.insert (unmarshal_note (*n));
716                 }
717         }
718
719         return 0;
720 }
721
722 XMLNode&
723 MidiModel::NoteDiffCommand::get_state ()
724 {
725         XMLNode* diff_command = new XMLNode (NOTE_DIFF_COMMAND_ELEMENT);
726         diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
727
728         XMLNode* changes = diff_command->add_child(DIFF_NOTES_ELEMENT);
729         for_each(_changes.begin(), _changes.end(),
730                  boost::bind (
731                          boost::bind (&XMLNode::add_child_nocopy, changes, _1),
732                          boost::bind (&NoteDiffCommand::marshal_change, this, _1)));
733
734         XMLNode* added_notes = diff_command->add_child(ADDED_NOTES_ELEMENT);
735         for_each(_added_notes.begin(), _added_notes.end(),
736                  boost::bind(
737                          boost::bind (&XMLNode::add_child_nocopy, added_notes, _1),
738                          boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
739
740         XMLNode* removed_notes = diff_command->add_child(REMOVED_NOTES_ELEMENT);
741         for_each(_removed_notes.begin(), _removed_notes.end(),
742                  boost::bind (
743                          boost::bind (&XMLNode::add_child_nocopy, removed_notes, _1),
744                          boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
745
746         /* if this command had side-effects, store that state too
747          */
748
749         if (!side_effect_removals.empty()) {
750                 XMLNode* side_effect_notes = diff_command->add_child(SIDE_EFFECT_REMOVALS_ELEMENT);
751                 for_each(side_effect_removals.begin(), side_effect_removals.end(),
752                          boost::bind (
753                                  boost::bind (&XMLNode::add_child_nocopy, side_effect_notes, _1),
754                                  boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
755         }
756
757         return *diff_command;
758 }
759
760 MidiModel::SysExDiffCommand::SysExDiffCommand (boost::shared_ptr<MidiModel> m, const XMLNode& node)
761         : DiffCommand (m, "")
762 {
763         assert (_model);
764         set_state (node, Stateful::loading_state_version);
765 }
766
767 void
768 MidiModel::SysExDiffCommand::change (boost::shared_ptr<Evoral::Event<TimeType> > s, TimeType new_time)
769 {
770         Change change;
771
772         change.sysex = s;
773         change.property = Time;
774         change.old_time = s->time ();
775         change.new_time = new_time;
776
777         _changes.push_back (change);
778 }
779
780 void
781 MidiModel::SysExDiffCommand::operator() ()
782 {
783         {
784                 MidiModel::WriteLock lock (_model->edit_lock ());
785
786                 for (list<SysExPtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
787                         _model->remove_sysex_unlocked (*i);
788                 }
789
790                 /* find any sysex events that were missing when unmarshalling */
791
792                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
793                         if (!i->sysex) {
794                                 i->sysex = _model->find_sysex (i->sysex_id);
795                                 assert (i->sysex);
796                         }
797                 }
798
799                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
800                         switch (i->property) {
801                         case Time:
802                                 i->sysex->set_time (i->new_time);
803                         }
804                 }
805         }
806
807         _model->ContentsChanged (); /* EMIT SIGNAL */
808 }
809
810 void
811 MidiModel::SysExDiffCommand::undo ()
812 {
813         {
814                 MidiModel::WriteLock lock (_model->edit_lock ());
815
816                 for (list<SysExPtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
817                         _model->add_sysex_unlocked (*i);
818                 }
819
820                 /* find any sysex events that were missing when unmarshalling */
821
822                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
823                         if (!i->sysex) {
824                                 i->sysex = _model->find_sysex (i->sysex_id);
825                                 assert (i->sysex);
826                         }
827                 }
828
829                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
830                         switch (i->property) {
831                         case Time:
832                                 i->sysex->set_time (i->old_time);
833                                 break;
834                         }
835                 }
836
837         }
838
839         _model->ContentsChanged(); /* EMIT SIGNAL */
840 }
841
842 void
843 MidiModel::SysExDiffCommand::remove (SysExPtr sysex)
844 {
845         _removed.push_back(sysex);
846 }
847
848 XMLNode&
849 MidiModel::SysExDiffCommand::marshal_change (const Change& change)
850 {
851         XMLNode* xml_change = new XMLNode ("Change");
852
853         /* first, the change itself */
854
855         xml_change->add_property ("property", enum_2_string (change.property));
856
857         {
858                 ostringstream old_value_str (ios::ate);
859                 old_value_str << change.old_time;
860                 xml_change->add_property ("old", old_value_str.str());
861         }
862
863         {
864                 ostringstream new_value_str (ios::ate);
865                 new_value_str << change.new_time;
866                 xml_change->add_property ("new", new_value_str.str());
867         }
868
869         ostringstream id_str;
870         id_str << change.sysex->id();
871         xml_change->add_property ("id", id_str.str());
872
873         return *xml_change;
874 }
875
876 MidiModel::SysExDiffCommand::Change
877 MidiModel::SysExDiffCommand::unmarshal_change (XMLNode *xml_change)
878 {
879         XMLProperty* prop;
880         Change change;
881
882         if ((prop = xml_change->property ("property")) != 0) {
883                 change.property = (Property) string_2_enum (prop->value(), change.property);
884         } else {
885                 fatal << "!!!" << endmsg;
886                 abort(); /*NOTREACHED*/
887         }
888
889         if ((prop = xml_change->property ("id")) == 0) {
890                 error << _("No SysExID found for sys-ex property change - ignored") << endmsg;
891                 return change;
892         }
893
894         gint sysex_id = atoi (prop->value().c_str());
895
896         if ((prop = xml_change->property ("old")) != 0) {
897                 istringstream old_str (prop->value());
898                 old_str >> change.old_time;
899         } else {
900                 fatal << "!!!" << endmsg;
901                 abort(); /*NOTREACHED*/
902         }
903
904         if ((prop = xml_change->property ("new")) != 0) {
905                 istringstream new_str (prop->value());
906                 new_str >> change.new_time;
907         } else {
908                 fatal << "!!!" << endmsg;
909                 abort(); /*NOTREACHED*/
910         }
911
912         /* we must point at the instance of the sysex that is actually in the model.
913            so go look for it ...
914         */
915
916         change.sysex = _model->find_sysex (sysex_id);
917         change.sysex_id = sysex_id;
918
919         return change;
920 }
921
922 int
923 MidiModel::SysExDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
924 {
925         if (diff_command.name() != string (SYSEX_DIFF_COMMAND_ELEMENT)) {
926                 return 1;
927         }
928
929         /* changes */
930
931         _changes.clear();
932
933         XMLNode* changed_sysexes = diff_command.child (DIFF_SYSEXES_ELEMENT);
934
935         if (changed_sysexes) {
936                 XMLNodeList sysexes = changed_sysexes->children();
937                 transform (sysexes.begin(), sysexes.end(), back_inserter (_changes),
938                            boost::bind (&SysExDiffCommand::unmarshal_change, this, _1));
939
940         }
941
942         return 0;
943 }
944
945 XMLNode&
946 MidiModel::SysExDiffCommand::get_state ()
947 {
948         XMLNode* diff_command = new XMLNode (SYSEX_DIFF_COMMAND_ELEMENT);
949         diff_command->add_property ("midi-source", _model->midi_source()->id().to_s());
950
951         XMLNode* changes = diff_command->add_child(DIFF_SYSEXES_ELEMENT);
952         for_each (_changes.begin(), _changes.end(),
953                   boost::bind (
954                           boost::bind (&XMLNode::add_child_nocopy, changes, _1),
955                           boost::bind (&SysExDiffCommand::marshal_change, this, _1)));
956
957         return *diff_command;
958 }
959
960 MidiModel::PatchChangeDiffCommand::PatchChangeDiffCommand (boost::shared_ptr<MidiModel> m, const string& name)
961         : DiffCommand (m, name)
962 {
963         assert (_model);
964 }
965
966 MidiModel::PatchChangeDiffCommand::PatchChangeDiffCommand (boost::shared_ptr<MidiModel> m, const XMLNode & node)
967         : DiffCommand (m, "")
968 {
969         assert (_model);
970         set_state (node, Stateful::loading_state_version);
971 }
972
973 void
974 MidiModel::PatchChangeDiffCommand::add (PatchChangePtr p)
975 {
976         _added.push_back (p);
977 }
978
979 void
980 MidiModel::PatchChangeDiffCommand::remove (PatchChangePtr p)
981 {
982         _removed.push_back (p);
983 }
984
985 void
986 MidiModel::PatchChangeDiffCommand::change_time (PatchChangePtr patch, TimeType t)
987 {
988         Change c;
989         c.property = Time;
990         c.patch = patch;
991         c.old_time = patch->time ();
992         c.new_time = t;
993
994         _changes.push_back (c);
995 }
996
997 void
998 MidiModel::PatchChangeDiffCommand::change_channel (PatchChangePtr patch, uint8_t channel)
999 {
1000         Change c;
1001         c.property = Channel;
1002         c.patch = patch;
1003         c.old_channel = patch->channel ();
1004         c.new_channel = channel;
1005         c.patch_id = patch->id();
1006
1007         _changes.push_back (c);
1008 }
1009
1010 void
1011 MidiModel::PatchChangeDiffCommand::change_program (PatchChangePtr patch, uint8_t program)
1012 {
1013         Change c;
1014         c.property = Program;
1015         c.patch = patch;
1016         c.old_program = patch->program ();
1017         c.new_program = program;
1018         c.patch_id = patch->id();
1019
1020         _changes.push_back (c);
1021 }
1022
1023 void
1024 MidiModel::PatchChangeDiffCommand::change_bank (PatchChangePtr patch, int bank)
1025 {
1026         Change c;
1027         c.property = Bank;
1028         c.patch = patch;
1029         c.old_bank = patch->bank ();
1030         c.new_bank = bank;
1031
1032         _changes.push_back (c);
1033 }
1034
1035 void
1036 MidiModel::PatchChangeDiffCommand::operator() ()
1037 {
1038         {
1039                 MidiModel::WriteLock lock (_model->edit_lock ());
1040
1041                 for (list<PatchChangePtr>::iterator i = _added.begin(); i != _added.end(); ++i) {
1042                         _model->add_patch_change_unlocked (*i);
1043                 }
1044
1045                 for (list<PatchChangePtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
1046                         _model->remove_patch_change_unlocked (*i);
1047                 }
1048
1049                 /* find any patch change events that were missing when unmarshalling */
1050
1051                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1052                         if (!i->patch) {
1053                                 i->patch = _model->find_patch_change (i->patch_id);
1054                                 assert (i->patch);
1055                         }
1056                 }
1057
1058                 set<PatchChangePtr> temporary_removals;
1059
1060                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1061                         switch (i->property) {
1062                         case Time:
1063                                 if (temporary_removals.find (i->patch) == temporary_removals.end()) {
1064                                         _model->remove_patch_change_unlocked (i->patch);
1065                                         temporary_removals.insert (i->patch);
1066                                 }
1067                                 i->patch->set_time (i->new_time);
1068                                 break;
1069
1070                         case Channel:
1071                                 i->patch->set_channel (i->new_channel);
1072                                 break;
1073
1074                         case Program:
1075                                 i->patch->set_program (i->new_program);
1076                                 break;
1077
1078                         case Bank:
1079                                 i->patch->set_bank (i->new_bank);
1080                                 break;
1081                         }
1082                 }
1083
1084                 for (set<PatchChangePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
1085                         _model->add_patch_change_unlocked (*i);
1086                 }
1087         }
1088
1089         _model->ContentsChanged (); /* EMIT SIGNAL */
1090 }
1091
1092 void
1093 MidiModel::PatchChangeDiffCommand::undo ()
1094 {
1095         {
1096                 MidiModel::WriteLock lock (_model->edit_lock());
1097
1098                 for (list<PatchChangePtr>::iterator i = _added.begin(); i != _added.end(); ++i) {
1099                         _model->remove_patch_change_unlocked (*i);
1100                 }
1101
1102                 for (list<PatchChangePtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
1103                         _model->add_patch_change_unlocked (*i);
1104                 }
1105
1106                 /* find any patch change events that were missing when unmarshalling */
1107
1108                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1109                         if (!i->patch) {
1110                                 i->patch = _model->find_patch_change (i->patch_id);
1111                                 assert (i->patch);
1112                         }
1113                 }
1114
1115                 set<PatchChangePtr> temporary_removals;
1116
1117                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1118                         switch (i->property) {
1119                         case Time:
1120                                 if (temporary_removals.find (i->patch) == temporary_removals.end()) {
1121                                         _model->remove_patch_change_unlocked (i->patch);
1122                                         temporary_removals.insert (i->patch);
1123                                 }
1124                                 i->patch->set_time (i->old_time);
1125                                 break;
1126
1127                         case Channel:
1128                                 i->patch->set_channel (i->old_channel);
1129                                 break;
1130
1131                         case Program:
1132                                 i->patch->set_program (i->old_program);
1133                                 break;
1134
1135                         case Bank:
1136                                 i->patch->set_bank (i->old_bank);
1137                                 break;
1138                         }
1139                 }
1140
1141                 for (set<PatchChangePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
1142                         _model->add_patch_change_unlocked (*i);
1143                 }
1144
1145         }
1146
1147         _model->ContentsChanged (); /* EMIT SIGNAL */
1148 }
1149
1150 XMLNode &
1151 MidiModel::PatchChangeDiffCommand::marshal_patch_change (constPatchChangePtr p)
1152 {
1153         XMLNode* n = new XMLNode ("patch-change");
1154
1155         {
1156                 ostringstream s (ios::ate);
1157                 s << int (p->id ());
1158                 n->add_property ("id", s.str());
1159         }
1160
1161         {
1162                 ostringstream s (ios::ate);
1163                 s << p->time ();
1164                 n->add_property ("time", s.str ());
1165         }
1166
1167         {
1168                 ostringstream s (ios::ate);
1169                 s << int (p->channel ());
1170                 n->add_property ("channel", s.str ());
1171         }
1172
1173         {
1174                 ostringstream s (ios::ate);
1175                 s << int (p->program ());
1176                 n->add_property ("program", s.str ());
1177         }
1178
1179         {
1180                 ostringstream s (ios::ate);
1181                 s << int (p->bank ());
1182                 n->add_property ("bank", s.str ());
1183         }
1184
1185         return *n;
1186 }
1187
1188 XMLNode&
1189 MidiModel::PatchChangeDiffCommand::marshal_change (const Change& c)
1190 {
1191         XMLNode* n = new XMLNode (X_("Change"));
1192
1193         n->add_property (X_("property"), enum_2_string (c.property));
1194
1195         {
1196                 ostringstream s (ios::ate);
1197                 if (c.property == Time) {
1198                         s << c.old_time;
1199                 } else if (c.property == Channel) {
1200                         s << c.old_channel;
1201                 } else if (c.property == Program) {
1202                         s << int (c.old_program);
1203                 } else if (c.property == Bank) {
1204                         s << c.old_bank;
1205                 }
1206
1207                 n->add_property (X_("old"), s.str ());
1208         }
1209
1210         {
1211                 ostringstream s (ios::ate);
1212
1213                 if (c.property == Time) {
1214                         s << c.new_time;
1215                 } else if (c.property == Channel) {
1216                         s << c.new_channel;
1217                 } else if (c.property == Program) {
1218                         s << int (c.new_program);
1219                 } else if (c.property == Bank) {
1220                         s << c.new_bank;
1221                 }
1222
1223                 n->add_property (X_("new"), s.str ());
1224         }
1225
1226         {
1227                 ostringstream s;
1228                 s << c.patch->id ();
1229                 n->add_property ("id", s.str ());
1230         }
1231
1232         return *n;
1233 }
1234
1235 MidiModel::PatchChangePtr
1236 MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
1237 {
1238         XMLProperty* prop;
1239         Evoral::event_id_t id = 0;
1240         Evoral::Beats time = Evoral::Beats();
1241         int channel = 0;
1242         int program = 0;
1243         int bank = 0;
1244         
1245         if ((prop = n->property ("id")) != 0) {
1246                 istringstream s (prop->value());
1247                 s >> id;
1248         }
1249
1250         if ((prop = n->property ("time")) != 0) {
1251                 istringstream s (prop->value ());
1252                 s >> time;
1253         }
1254
1255         if ((prop = n->property ("channel")) != 0) {
1256                 istringstream s (prop->value ());
1257                 s >> channel;
1258         }
1259
1260         if ((prop = n->property ("program")) != 0) {
1261                 istringstream s (prop->value ());
1262                 s >> program;
1263         }
1264
1265         if ((prop = n->property ("bank")) != 0) {
1266                 istringstream s (prop->value ());
1267                 s >> bank;
1268         }
1269
1270         PatchChangePtr p (new Evoral::PatchChange<TimeType> (time, channel, program, bank));
1271         assert(id);
1272         p->set_id (id);
1273         return p;
1274 }
1275
1276 MidiModel::PatchChangeDiffCommand::Change
1277 MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
1278 {
1279         XMLProperty* prop;
1280         Change c;
1281         int an_int;
1282
1283         prop = n->property ("property");
1284         assert (prop);
1285         c.property = (Property) string_2_enum (prop->value(), c.property);
1286
1287         prop = n->property ("id");
1288         assert (prop);
1289         Evoral::event_id_t const id = atoi (prop->value().c_str());
1290
1291         /* we need to load via an int intermediate for all properties that are 
1292            actually uint8_t (char/byte).
1293         */
1294
1295         prop = n->property ("old");
1296         assert (prop);
1297         {
1298                 istringstream s (prop->value ());
1299                 if (c.property == Time) {
1300                         s >> c.old_time;
1301                 } else if (c.property == Channel) {
1302                         s >> an_int;
1303                         c.old_channel = an_int;
1304                 } else if (c.property == Program) {
1305                         s >> an_int;
1306                         c.old_program = an_int;
1307                 } else if (c.property == Bank) {
1308                         s >> an_int;
1309                         c.old_bank = an_int;
1310                 }
1311         }
1312
1313         prop = n->property ("new");
1314         assert (prop);
1315         {
1316                 istringstream s (prop->value ());
1317
1318                 if (c.property == Time) {
1319                         s >> c.new_time;
1320                 } else if (c.property == Channel) {
1321                         s >> an_int;
1322                         c.new_channel = an_int;
1323                 } else if (c.property == Program) {
1324                         s >> an_int;
1325                         c.new_program = an_int;
1326                 } else if (c.property == Bank) {
1327                         s >> an_int;
1328                         c.new_bank = an_int;
1329                 }
1330         }
1331
1332         c.patch = _model->find_patch_change (id);
1333         c.patch_id = id;
1334
1335         return c;
1336 }
1337
1338 int
1339 MidiModel::PatchChangeDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
1340 {
1341         if (diff_command.name() != PATCH_CHANGE_DIFF_COMMAND_ELEMENT) {
1342                 return 1;
1343         }
1344
1345         _added.clear ();
1346         XMLNode* added = diff_command.child (ADDED_PATCH_CHANGES_ELEMENT);
1347         if (added) {
1348                 XMLNodeList p = added->children ();
1349                 transform (p.begin(), p.end(), back_inserter (_added), boost::bind (&PatchChangeDiffCommand::unmarshal_patch_change, this, _1));
1350         }
1351
1352         _removed.clear ();
1353         XMLNode* removed = diff_command.child (REMOVED_PATCH_CHANGES_ELEMENT);
1354         if (removed) {
1355                 XMLNodeList p = removed->children ();
1356                 transform (p.begin(), p.end(), back_inserter (_removed), boost::bind (&PatchChangeDiffCommand::unmarshal_patch_change, this, _1));
1357         }
1358
1359         _changes.clear ();
1360         XMLNode* changed = diff_command.child (DIFF_PATCH_CHANGES_ELEMENT);
1361         if (changed) {
1362                 XMLNodeList p = changed->children ();
1363                 transform (p.begin(), p.end(), back_inserter (_changes), boost::bind (&PatchChangeDiffCommand::unmarshal_change, this, _1));
1364         }
1365
1366         return 0;
1367 }
1368
1369 XMLNode &
1370 MidiModel::PatchChangeDiffCommand::get_state ()
1371 {
1372         XMLNode* diff_command = new XMLNode (PATCH_CHANGE_DIFF_COMMAND_ELEMENT);
1373         diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
1374
1375         XMLNode* added = diff_command->add_child (ADDED_PATCH_CHANGES_ELEMENT);
1376         for_each (_added.begin(), _added.end(),
1377                   boost::bind (
1378                           boost::bind (&XMLNode::add_child_nocopy, added, _1),
1379                           boost::bind (&PatchChangeDiffCommand::marshal_patch_change, this, _1)
1380                           )
1381                 );
1382
1383         XMLNode* removed = diff_command->add_child (REMOVED_PATCH_CHANGES_ELEMENT);
1384         for_each (_removed.begin(), _removed.end(),
1385                   boost::bind (
1386                           boost::bind (&XMLNode::add_child_nocopy, removed, _1),
1387                           boost::bind (&PatchChangeDiffCommand::marshal_patch_change, this, _1)
1388                           )
1389                 );
1390
1391         XMLNode* changes = diff_command->add_child (DIFF_PATCH_CHANGES_ELEMENT);
1392         for_each (_changes.begin(), _changes.end(),
1393                   boost::bind (
1394                           boost::bind (&XMLNode::add_child_nocopy, changes, _1),
1395                           boost::bind (&PatchChangeDiffCommand::marshal_change, this, _1)
1396                           )
1397                 );
1398
1399         return *diff_command;
1400 }
1401
1402 /** Write all of the model to a MidiSource (i.e. save the model).
1403  * This is different from manually using read to write to a source in that
1404  * note off events are written regardless of the track mode.  This is so the
1405  * user can switch a recorded track (with note durations from some instrument)
1406  * to percussive, save, reload, then switch it back to sustained without
1407  * destroying the original note durations.
1408  *
1409  * Similarly, control events are written without interpolation (as with the
1410  * `Discrete' mode).
1411  */
1412 bool
1413 MidiModel::write_to (boost::shared_ptr<MidiSource>     source,
1414                      const Glib::Threads::Mutex::Lock& source_lock)
1415 {
1416         ReadLock lock(read_lock());
1417
1418         const bool old_percussive = percussive();
1419         set_percussive(false);
1420
1421         source->drop_model(source_lock);
1422         source->mark_streaming_midi_write_started (source_lock, note_mode());
1423
1424         for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1425                 source->append_event_beats(source_lock, *i);
1426         }
1427
1428         set_percussive(old_percussive);
1429         source->mark_streaming_write_completed(source_lock);
1430
1431         set_edited(false);
1432
1433         return true;
1434 }
1435
1436 /** very similar to ::write_to() but writes to the model's own
1437     existing midi_source, without making it call MidiSource::drop_model().
1438     the caller is a MidiSource that needs to catch up with the state
1439     of the model.
1440 */
1441 bool
1442 MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock)
1443 {
1444         ReadLock lock(read_lock());
1445
1446         const bool old_percussive = percussive();
1447         set_percussive(false);
1448
1449         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1450         if (!ms) {
1451                 error << "MIDI model has no source to sync to" << endmsg;
1452                 return false;
1453         }
1454
1455         ms->mark_streaming_midi_write_started (source_lock, note_mode());
1456
1457         for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1458                 ms->append_event_beats(source_lock, *i);
1459         }
1460
1461         set_percussive (old_percussive);
1462         ms->mark_streaming_write_completed (source_lock);
1463
1464         set_edited (false);
1465
1466         return true;
1467 }
1468
1469 /** Write part or all of the model to a MidiSource (i.e. save the model).
1470  * This is different from manually using read to write to a source in that
1471  * note off events are written regardless of the track mode.  This is so the
1472  * user can switch a recorded track (with note durations from some instrument)
1473  * to percussive, save, reload, then switch it back to sustained without
1474  * destroying the original note durations.
1475  */
1476 bool
1477 MidiModel::write_section_to (boost::shared_ptr<MidiSource>     source,
1478                              const Glib::Threads::Mutex::Lock& source_lock,
1479                              Evoral::Beats                     begin_time,
1480                              Evoral::Beats                     end_time)
1481 {
1482         ReadLock lock(read_lock());
1483         MidiStateTracker mst;
1484
1485         const bool old_percussive = percussive();
1486         set_percussive(false);
1487
1488         source->drop_model(source_lock);
1489         source->mark_streaming_midi_write_started (source_lock, note_mode());
1490
1491         for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1492                 const Evoral::Event<Evoral::Beats>& ev (*i);
1493
1494                 if (ev.time() >= begin_time && ev.time() < end_time) {
1495
1496                         const Evoral::MIDIEvent<Evoral::Beats>* mev =
1497                                 static_cast<const Evoral::MIDIEvent<Evoral::Beats>* > (&ev);
1498
1499                         if (!mev) {
1500                                 continue;
1501                         }
1502
1503
1504                         if (mev->is_note_off()) {
1505
1506                                 if (!mst.active (mev->note(), mev->channel())) {
1507                                         /* the matching note-on was outside the
1508                                            time range we were given, so just
1509                                            ignore this note-off.
1510                                         */
1511                                         continue;
1512                                 }
1513
1514                                 source->append_event_beats (source_lock, *i);
1515                                 mst.remove (mev->note(), mev->channel());
1516
1517                         } else if (mev->is_note_on()) {
1518                                 mst.add (mev->note(), mev->channel());
1519                                 source->append_event_beats(source_lock, *i);
1520                         } else {
1521                                 source->append_event_beats(source_lock, *i);
1522                         }
1523                 }
1524         }
1525
1526         mst.resolve_notes (*source, source_lock, end_time);
1527
1528         set_percussive(old_percussive);
1529         source->mark_streaming_write_completed(source_lock);
1530
1531         set_edited(false);
1532
1533         return true;
1534 }
1535
1536 XMLNode&
1537 MidiModel::get_state()
1538 {
1539         XMLNode *node = new XMLNode("MidiModel");
1540         return *node;
1541 }
1542
1543 Evoral::Sequence<MidiModel::TimeType>::NotePtr
1544 MidiModel::find_note (NotePtr other)
1545 {
1546         Notes::iterator l = notes().lower_bound(other);
1547
1548         if (l != notes().end()) {
1549                 for (; (*l)->time() == other->time(); ++l) {
1550                         /* NB: compare note contents, not note pointers.
1551                            If "other" was a ptr to a note already in
1552                            the model, we wouldn't be looking for it,
1553                            would we now?
1554                         */
1555                         if (**l == *other) {
1556                                 return *l;
1557                         }
1558                 }
1559         }
1560
1561         return NotePtr();
1562 }
1563
1564 Evoral::Sequence<MidiModel::TimeType>::NotePtr
1565 MidiModel::find_note (gint note_id)
1566 {
1567         /* used only for looking up notes when reloading history from disk,
1568            so we don't care about performance *too* much.
1569         */
1570
1571         for (Notes::iterator l = notes().begin(); l != notes().end(); ++l) {
1572                 if ((*l)->id() == note_id) {
1573                         return *l;
1574                 }
1575         }
1576
1577         return NotePtr();
1578 }
1579
1580 MidiModel::PatchChangePtr
1581 MidiModel::find_patch_change (Evoral::event_id_t id)
1582 {
1583         for (PatchChanges::iterator i = patch_changes().begin(); i != patch_changes().end(); ++i) {
1584                 if ((*i)->id() == id) {
1585                         return *i;
1586                 }
1587         }
1588
1589         return PatchChangePtr ();
1590 }
1591
1592 boost::shared_ptr<Evoral::Event<MidiModel::TimeType> >
1593 MidiModel::find_sysex (gint sysex_id)
1594 {
1595         /* used only for looking up notes when reloading history from disk,
1596            so we don't care about performance *too* much.
1597         */
1598
1599         for (SysExes::iterator l = sysexes().begin(); l != sysexes().end(); ++l) {
1600                 if ((*l)->id() == sysex_id) {
1601                         return *l;
1602                 }
1603         }
1604
1605         return boost::shared_ptr<Evoral::Event<TimeType> > ();
1606 }
1607
1608 /** Lock and invalidate the source.
1609  * This should be used by commands and editing things
1610  */
1611 MidiModel::WriteLock
1612 MidiModel::edit_lock()
1613 {
1614         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1615         assert (ms);
1616
1617         Glib::Threads::Mutex::Lock* source_lock = new Glib::Threads::Mutex::Lock (ms->mutex());
1618         ms->invalidate(*source_lock); // Release cached iterator's read lock on model
1619         return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
1620 }
1621
1622 /** Lock just the model, the source lock must already be held.
1623  * This should only be called from libardour/evoral places
1624  */
1625 MidiModel::WriteLock
1626 MidiModel::write_lock()
1627 {
1628         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1629         assert (ms);
1630
1631         assert (!ms->mutex().trylock ());
1632         return WriteLock(new WriteLockImpl(0, _lock, _control_lock));
1633 }
1634
1635 int
1636 MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
1637 {
1638         using namespace Evoral;
1639
1640         if (_writing || insert_merge_policy() == InsertMergeRelax) {
1641                 return 0;
1642         }
1643
1644         NoteDiffCommand* cmd = static_cast<NoteDiffCommand*>(arg);
1645
1646         TimeType sa = note->time();
1647         TimeType ea  = note->end_time();
1648
1649         const Pitches& p (pitches (note->channel()));
1650         NotePtr search_note(new Note<TimeType>(0, TimeType(), TimeType(), note->note()));
1651         set<NotePtr> to_be_deleted;
1652         bool set_note_length = false;
1653         bool set_note_time = false;
1654         TimeType note_time = note->time();
1655         TimeType note_length = note->length();
1656
1657         DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 checking overlaps for note %2 @ %3\n", this, (int)note->note(), note->time()));
1658
1659         for (Pitches::const_iterator i = p.lower_bound (search_note);
1660              i != p.end() && (*i)->note() == note->note(); ++i) {
1661
1662                 TimeType sb = (*i)->time();
1663                 TimeType eb = (*i)->end_time();
1664                 OverlapType overlap = OverlapNone;
1665
1666                 if ((sb > sa) && (eb <= ea)) {
1667                         overlap = OverlapInternal;
1668                 } else if ((eb >= sa) && (eb <= ea)) {
1669                         overlap = OverlapStart;
1670                 } else if ((sb > sa) && (sb <= ea)) {
1671                         overlap = OverlapEnd;
1672                 } else if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
1673                         overlap = OverlapExternal;
1674                 } else {
1675                         /* no overlap */
1676                         continue;
1677                 }
1678
1679                 DEBUG_TRACE (DEBUG::Sequence, string_compose (
1680                                      "\toverlap is %1 for (%2,%3) vs (%4,%5)\n",
1681                                      enum_2_string(overlap), sa, ea, sb, eb));
1682
1683                 if (insert_merge_policy() == InsertMergeReject) {
1684                         DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 just reject\n", this));
1685                         return -1;
1686                 }
1687
1688                 switch (overlap) {
1689                 case OverlapStart:
1690                         cerr << "OverlapStart\n";
1691                         /* existing note covers start of new note */
1692                         switch (insert_merge_policy()) {
1693                         case InsertMergeReplace:
1694                                 to_be_deleted.insert (*i);
1695                                 break;
1696                         case InsertMergeTruncateExisting:
1697                                 if (cmd) {
1698                                         cmd->change (*i, NoteDiffCommand::Length, (note->time() - (*i)->time()));
1699                                 }
1700                                 (*i)->set_length (note->time() - (*i)->time());
1701                                 break;
1702                         case InsertMergeTruncateAddition:
1703                                 set_note_time = true;
1704                                 set_note_length = true;
1705                                 note_time = (*i)->time() + (*i)->length();
1706                                 note_length = min (note_length, (*i)->length() - ((*i)->end_time() - note->time()));
1707                                 break;
1708                         case InsertMergeExtend:
1709                                 if (cmd) {
1710                                         cmd->change ((*i), NoteDiffCommand::Length, note->end_time() - (*i)->time());
1711                                 }
1712                                 (*i)->set_length (note->end_time() - (*i)->time());
1713                                 return -1; /* do not add the new note */
1714                                 break;
1715                         default:
1716                                 abort(); /*NOTREACHED*/
1717                                 /* stupid gcc */
1718                                 break;
1719                         }
1720                         break;
1721
1722                 case OverlapEnd:
1723                         cerr << "OverlapEnd\n";
1724                         /* existing note covers end of new note */
1725                         switch (insert_merge_policy()) {
1726                         case InsertMergeReplace:
1727                                 to_be_deleted.insert (*i);
1728                                 break;
1729
1730                         case InsertMergeTruncateExisting:
1731                                 /* resetting the start time of the existing note
1732                                    is a problem because of time ordering.
1733                                 */
1734                                 break;
1735
1736                         case InsertMergeTruncateAddition:
1737                                 set_note_length = true;
1738                                 note_length = min (note_length, ((*i)->time() - note->time()));
1739                                 break;
1740
1741                         case InsertMergeExtend:
1742                                 /* we can't reset the time of the existing note because
1743                                    that will corrupt time ordering. So remove the
1744                                    existing note and change the position/length
1745                                    of the new note (which has not been added yet)
1746                                 */
1747                                 to_be_deleted.insert (*i);
1748                                 set_note_length = true;
1749                                 note_length = min (note_length, (*i)->end_time() - note->time());
1750                                 break;
1751                         default:
1752                                 abort(); /*NOTREACHED*/
1753                                 /* stupid gcc */
1754                                 break;
1755                         }
1756                         break;
1757
1758                 case OverlapExternal:
1759                         cerr << "OverlapExt\n";
1760                         /* existing note overlaps all the new note */
1761                         switch (insert_merge_policy()) {
1762                         case InsertMergeReplace:
1763                                 to_be_deleted.insert (*i);
1764                                 break;
1765                         case InsertMergeTruncateExisting:
1766                         case InsertMergeTruncateAddition:
1767                         case InsertMergeExtend:
1768                                 /* cannot add in this case */
1769                                 return -1;
1770                         default:
1771                                 abort(); /*NOTREACHED*/
1772                                 /* stupid gcc */
1773                                 break;
1774                         }
1775                         break;
1776
1777                 case OverlapInternal:
1778                         cerr << "OverlapInt\n";
1779                         /* new note fully overlaps an existing note */
1780                         switch (insert_merge_policy()) {
1781                         case InsertMergeReplace:
1782                         case InsertMergeTruncateExisting:
1783                         case InsertMergeTruncateAddition:
1784                         case InsertMergeExtend:
1785                                 /* delete the existing note, the new one will cover it */
1786                                 to_be_deleted.insert (*i);
1787                                 break;
1788                         default:
1789                                 abort(); /*NOTREACHED*/
1790                                 /* stupid gcc */
1791                                 break;
1792                         }
1793                         break;
1794
1795                 default:
1796                         abort(); /*NOTREACHED*/
1797                         /* stupid gcc */
1798                         break;
1799                 }
1800         }
1801
1802         for (set<NotePtr>::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
1803                 remove_note_unlocked (*i);
1804
1805                 if (cmd) {
1806                         cmd->side_effect_remove (*i);
1807                 }
1808         }
1809
1810         if (set_note_time) {
1811                 if (cmd) {
1812                         cmd->change (note, NoteDiffCommand::StartTime, note_time);
1813                 }
1814                 note->set_time (note_time);
1815         }
1816
1817         if (set_note_length) {
1818                 if (cmd) {
1819                         cmd->change (note, NoteDiffCommand::Length, note_length);
1820                 }
1821                 note->set_length (note_length);
1822         }
1823
1824         return 0;
1825 }
1826
1827 InsertMergePolicy
1828 MidiModel::insert_merge_policy () const
1829 {
1830         /* XXX ultimately this should be a per-track or even per-model policy */
1831         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1832         assert (ms);
1833
1834         return ms->session().config.get_insert_merge_policy ();
1835 }
1836
1837 void
1838 MidiModel::set_midi_source (boost::shared_ptr<MidiSource> s)
1839 {
1840         boost::shared_ptr<MidiSource> old = _midi_source.lock ();
1841
1842         if (old) {
1843                 Source::Lock lm(old->mutex());
1844                 old->invalidate (lm);
1845         }
1846
1847         _midi_source_connections.drop_connections ();
1848
1849         _midi_source = s;
1850
1851         s->InterpolationChanged.connect_same_thread (
1852                 _midi_source_connections, boost::bind (&MidiModel::source_interpolation_changed, this, _1, _2)
1853                 );
1854
1855         s->AutomationStateChanged.connect_same_thread (
1856                 _midi_source_connections, boost::bind (&MidiModel::source_automation_state_changed, this, _1, _2)
1857                 );
1858 }
1859
1860 /** The source has signalled that the interpolation style for a parameter has changed.  In order to
1861  *  keep MidiSource and ControlList interpolation state the same, we pass this change onto the
1862  *  appropriate ControlList.
1863  *
1864  *  The idea is that MidiSource and the MidiModel's ControlList states are kept in sync, and one
1865  *  or the other is listened to by the GUI.
1866  */
1867 void
1868 MidiModel::source_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
1869 {
1870         Glib::Threads::Mutex::Lock lm (_control_lock);
1871         control(p)->list()->set_interpolation (s);
1872 }
1873
1874 /** A ControlList has signalled that its interpolation style has changed.  Again, in order to keep
1875  *  MidiSource and ControlList interpolation state in sync, we pass this change onto our MidiSource.
1876  */
1877 void
1878 MidiModel::control_list_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
1879 {
1880         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1881         assert (ms);
1882
1883         ms->set_interpolation_of (p, s);
1884 }
1885
1886 void
1887 MidiModel::source_automation_state_changed (Evoral::Parameter p, AutoState s)
1888 {
1889         Glib::Threads::Mutex::Lock lm (_control_lock);
1890         boost::shared_ptr<AutomationList> al = boost::dynamic_pointer_cast<AutomationList> (control(p)->list ());
1891         al->set_automation_state (s);
1892 }
1893
1894 void
1895 MidiModel::automation_list_automation_state_changed (Evoral::Parameter p, AutoState s)
1896 {
1897         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1898         assert (ms);
1899         ms->set_automation_state_of (p, s);
1900 }
1901
1902 boost::shared_ptr<Evoral::Control>
1903 MidiModel::control_factory (Evoral::Parameter const & p)
1904 {
1905         boost::shared_ptr<Evoral::Control> c = Automatable::control_factory (p);
1906
1907         /* Set up newly created control's lists to the appropriate interpolation and
1908            automation state from our source.
1909         */
1910
1911         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1912         assert (ms);
1913
1914         c->list()->set_interpolation (ms->interpolation_of (p));
1915
1916         boost::shared_ptr<AutomationList> al = boost::dynamic_pointer_cast<AutomationList> (c->list ());
1917         assert (al);
1918
1919         al->set_automation_state (ms->automation_state_of (p));
1920
1921         return c;
1922 }
1923
1924 boost::shared_ptr<const MidiSource>
1925 MidiModel::midi_source ()
1926 {
1927         return _midi_source.lock ();
1928 }
1929
1930 /** Moves notes, patch changes, controllers and sys-ex to insert silence at the start of the model.
1931  *  Adds commands to the session's current undo stack to reflect the movements.
1932  */
1933 void
1934 MidiModel::insert_silence_at_start (TimeType t)
1935 {
1936         boost::shared_ptr<MidiSource> s = _midi_source.lock ();
1937         assert (s);
1938
1939         /* Notes */
1940
1941         if (!notes().empty ()) {
1942                 NoteDiffCommand* c = new_note_diff_command ("insert silence");
1943
1944                 for (Notes::const_iterator i = notes().begin(); i != notes().end(); ++i) {
1945                         c->change (*i, NoteDiffCommand::StartTime, (*i)->time() + t);
1946                 }
1947
1948                 apply_command_as_subcommand (s->session(), c);
1949         }
1950
1951         /* Patch changes */
1952
1953         if (!patch_changes().empty ()) {
1954                 PatchChangeDiffCommand* c = new_patch_change_diff_command ("insert silence");
1955
1956                 for (PatchChanges::const_iterator i = patch_changes().begin(); i != patch_changes().end(); ++i) {
1957                         c->change_time (*i, (*i)->time() + t);
1958                 }
1959
1960                 apply_command_as_subcommand (s->session(), c);
1961         }
1962
1963         /* Controllers */
1964
1965         for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) {
1966                 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second);
1967                 XMLNode& before = ac->alist()->get_state ();
1968                 i->second->list()->shift (0, t.to_double());
1969                 XMLNode& after = ac->alist()->get_state ();
1970                 s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after));
1971         }
1972
1973         /* Sys-ex */
1974
1975         if (!sysexes().empty()) {
1976                 SysExDiffCommand* c = new_sysex_diff_command ("insert silence");
1977
1978                 for (SysExes::iterator i = sysexes().begin(); i != sysexes().end(); ++i) {
1979                         c->change (*i, (*i)->time() + t);
1980                 }
1981
1982                 apply_command_as_subcommand (s->session(), c);
1983         }
1984 }
1985
1986 /** Transpose notes in a time range by a given number of semitones.  Notes
1987  *  will be clamped at 0 and 127 if the transposition would make them exceed
1988  *  that range.
1989  *
1990  *  @param from Start time.
1991  *  @param end End time.
1992  *  @param semitones Number of semitones to transpose by (+ve is higher, -ve is lower).
1993  */
1994 void
1995 MidiModel::transpose (TimeType from, TimeType to, int semitones)
1996 {
1997         boost::shared_ptr<const MidiSource> s = midi_source ();
1998
1999         NoteDiffCommand* c = new_note_diff_command (_("transpose"));
2000
2001         for (Notes::iterator i = notes().begin(); i != notes().end(); ++i) {
2002
2003                 if ((*i)->time() >= to) {
2004
2005                         /* finished */
2006                         break;
2007
2008                 } else if ((*i)->time() >= from) {
2009
2010                         int new_note = (*i)->note() + semitones;
2011
2012                         if (new_note < 0) {
2013                                 new_note = 0;
2014                         } else if (new_note > 127) {
2015                                 new_note = 127;
2016                         }
2017
2018                         c->change (*i, NoteDiffCommand::NoteNumber, (uint8_t) new_note);
2019
2020                 }
2021         }
2022
2023         apply_command (s->session (), c);
2024 }
2025
2026 void
2027 MidiModel::control_list_marked_dirty ()
2028 {
2029         AutomatableSequence<Evoral::Beats>::control_list_marked_dirty ();
2030         
2031         ContentsChanged (); /* EMIT SIGNAL */
2032 }