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