fix crash when copy'ing latent plugins
[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 "pbd/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 const * 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 const * 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 const * 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 const * prop;
1239         XMLProperty const * prop_id;
1240         Evoral::event_id_t id = 0;
1241         Evoral::Beats time = Evoral::Beats();
1242         int channel = 0;
1243         int program = 0;
1244         int bank = 0;
1245
1246         if ((prop_id = n->property ("id")) != 0) {
1247                 istringstream s (prop_id->value());
1248                 s >> id;
1249         }
1250
1251         if ((prop = n->property ("time")) != 0) {
1252                 istringstream s (prop->value ());
1253                 s >> time;
1254         }
1255
1256         if ((prop = n->property ("channel")) != 0) {
1257                 istringstream s (prop->value ());
1258                 s >> channel;
1259         }
1260
1261         if ((prop = n->property ("program")) != 0) {
1262                 istringstream s (prop->value ());
1263                 s >> program;
1264         }
1265
1266         if ((prop = n->property ("bank")) != 0) {
1267                 istringstream s (prop->value ());
1268                 s >> bank;
1269         }
1270
1271         PatchChangePtr p (new Evoral::PatchChange<TimeType> (time, channel, program, bank));
1272         assert(prop_id);
1273         p->set_id (id);
1274         return p;
1275 }
1276
1277 MidiModel::PatchChangeDiffCommand::Change
1278 MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
1279 {
1280         XMLProperty const * prop;
1281         Change c;
1282         int an_int;
1283
1284         prop = n->property ("property");
1285         assert (prop);
1286         c.property = (Property) string_2_enum (prop->value(), c.property);
1287
1288         prop = n->property ("id");
1289         assert (prop);
1290         Evoral::event_id_t const id = atoi (prop->value().c_str());
1291
1292         /* we need to load via an int intermediate for all properties that are
1293            actually uint8_t (char/byte).
1294         */
1295
1296         prop = n->property ("old");
1297         assert (prop);
1298         {
1299                 istringstream s (prop->value ());
1300                 if (c.property == Time) {
1301                         s >> c.old_time;
1302                 } else if (c.property == Channel) {
1303                         s >> an_int;
1304                         c.old_channel = an_int;
1305                 } else if (c.property == Program) {
1306                         s >> an_int;
1307                         c.old_program = an_int;
1308                 } else if (c.property == Bank) {
1309                         s >> an_int;
1310                         c.old_bank = an_int;
1311                 }
1312         }
1313
1314         prop = n->property ("new");
1315         assert (prop);
1316         {
1317                 istringstream s (prop->value ());
1318
1319                 if (c.property == Time) {
1320                         s >> c.new_time;
1321                 } else if (c.property == Channel) {
1322                         s >> an_int;
1323                         c.new_channel = an_int;
1324                 } else if (c.property == Program) {
1325                         s >> an_int;
1326                         c.new_program = an_int;
1327                 } else if (c.property == Bank) {
1328                         s >> an_int;
1329                         c.new_bank = an_int;
1330                 }
1331         }
1332
1333         c.patch = _model->find_patch_change (id);
1334         c.patch_id = id;
1335
1336         return c;
1337 }
1338
1339 int
1340 MidiModel::PatchChangeDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
1341 {
1342         if (diff_command.name() != PATCH_CHANGE_DIFF_COMMAND_ELEMENT) {
1343                 return 1;
1344         }
1345
1346         _added.clear ();
1347         XMLNode* added = diff_command.child (ADDED_PATCH_CHANGES_ELEMENT);
1348         if (added) {
1349                 XMLNodeList p = added->children ();
1350                 transform (p.begin(), p.end(), back_inserter (_added), boost::bind (&PatchChangeDiffCommand::unmarshal_patch_change, this, _1));
1351         }
1352
1353         _removed.clear ();
1354         XMLNode* removed = diff_command.child (REMOVED_PATCH_CHANGES_ELEMENT);
1355         if (removed) {
1356                 XMLNodeList p = removed->children ();
1357                 transform (p.begin(), p.end(), back_inserter (_removed), boost::bind (&PatchChangeDiffCommand::unmarshal_patch_change, this, _1));
1358         }
1359
1360         _changes.clear ();
1361         XMLNode* changed = diff_command.child (DIFF_PATCH_CHANGES_ELEMENT);
1362         if (changed) {
1363                 XMLNodeList p = changed->children ();
1364                 transform (p.begin(), p.end(), back_inserter (_changes), boost::bind (&PatchChangeDiffCommand::unmarshal_change, this, _1));
1365         }
1366
1367         return 0;
1368 }
1369
1370 XMLNode &
1371 MidiModel::PatchChangeDiffCommand::get_state ()
1372 {
1373         XMLNode* diff_command = new XMLNode (PATCH_CHANGE_DIFF_COMMAND_ELEMENT);
1374         diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
1375
1376         XMLNode* added = diff_command->add_child (ADDED_PATCH_CHANGES_ELEMENT);
1377         for_each (_added.begin(), _added.end(),
1378                   boost::bind (
1379                           boost::bind (&XMLNode::add_child_nocopy, added, _1),
1380                           boost::bind (&PatchChangeDiffCommand::marshal_patch_change, this, _1)
1381                           )
1382                 );
1383
1384         XMLNode* removed = diff_command->add_child (REMOVED_PATCH_CHANGES_ELEMENT);
1385         for_each (_removed.begin(), _removed.end(),
1386                   boost::bind (
1387                           boost::bind (&XMLNode::add_child_nocopy, removed, _1),
1388                           boost::bind (&PatchChangeDiffCommand::marshal_patch_change, this, _1)
1389                           )
1390                 );
1391
1392         XMLNode* changes = diff_command->add_child (DIFF_PATCH_CHANGES_ELEMENT);
1393         for_each (_changes.begin(), _changes.end(),
1394                   boost::bind (
1395                           boost::bind (&XMLNode::add_child_nocopy, changes, _1),
1396                           boost::bind (&PatchChangeDiffCommand::marshal_change, this, _1)
1397                           )
1398                 );
1399
1400         return *diff_command;
1401 }
1402
1403 /** Write all of the model to a MidiSource (i.e. save the model).
1404  * This is different from manually using read to write to a source in that
1405  * note off events are written regardless of the track mode.  This is so the
1406  * user can switch a recorded track (with note durations from some instrument)
1407  * to percussive, save, reload, then switch it back to sustained without
1408  * destroying the original note durations.
1409  *
1410  * Similarly, control events are written without interpolation (as with the
1411  * `Discrete' mode).
1412  */
1413 bool
1414 MidiModel::write_to (boost::shared_ptr<MidiSource>     source,
1415                      const Glib::Threads::Mutex::Lock& source_lock)
1416 {
1417         ReadLock lock(read_lock());
1418
1419         const bool old_percussive = percussive();
1420         set_percussive(false);
1421
1422         source->drop_model(source_lock);
1423         source->mark_streaming_midi_write_started (source_lock, note_mode());
1424
1425         for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1426                 source->append_event_beats(source_lock, *i);
1427         }
1428
1429         set_percussive(old_percussive);
1430         source->mark_streaming_write_completed(source_lock);
1431
1432         set_edited(false);
1433
1434         return true;
1435 }
1436
1437 /** very similar to ::write_to() but writes to the model's own
1438     existing midi_source, without making it call MidiSource::drop_model().
1439     the caller is a MidiSource that needs to catch up with the state
1440     of the model.
1441 */
1442 bool
1443 MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock)
1444 {
1445         ReadLock lock(read_lock());
1446
1447         const bool old_percussive = percussive();
1448         set_percussive(false);
1449
1450         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1451         if (!ms) {
1452                 error << "MIDI model has no source to sync to" << endmsg;
1453                 return false;
1454         }
1455
1456         /* Invalidate and store active notes, which will be picked up by the iterator
1457            on the next roll if time progresses linearly. */
1458         ms->invalidate(source_lock,
1459                        ms->session().transport_rolling() ? &_active_notes : NULL);
1460
1461         ms->mark_streaming_midi_write_started (source_lock, note_mode());
1462
1463         for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1464                 ms->append_event_beats(source_lock, *i);
1465         }
1466
1467         set_percussive (old_percussive);
1468         ms->mark_streaming_write_completed (source_lock);
1469
1470         set_edited (false);
1471
1472         return true;
1473 }
1474
1475 /** Write part or all of the model to a MidiSource (i.e. save the model).
1476  * This is different from manually using read to write to a source in that
1477  * note off events are written regardless of the track mode.  This is so the
1478  * user can switch a recorded track (with note durations from some instrument)
1479  * to percussive, save, reload, then switch it back to sustained without
1480  * destroying the original note durations.
1481  */
1482 bool
1483 MidiModel::write_section_to (boost::shared_ptr<MidiSource>     source,
1484                              const Glib::Threads::Mutex::Lock& source_lock,
1485                              TimeType                          begin_time,
1486                              TimeType                          end_time,
1487                              bool                              offset_events)
1488 {
1489         ReadLock lock(read_lock());
1490         MidiStateTracker mst;
1491
1492         const bool old_percussive = percussive();
1493         set_percussive(false);
1494
1495         source->drop_model(source_lock);
1496         source->mark_streaming_midi_write_started (source_lock, note_mode());
1497
1498         for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1499                 if (i->time() >= begin_time && i->time() < end_time) {
1500
1501                         Evoral::MIDIEvent<TimeType> mev (*i, true); /* copy the event */
1502
1503                         if (offset_events) {
1504                                 mev.set_time(mev.time() - begin_time);
1505                         }
1506
1507                         if (mev.is_note_off()) {
1508
1509                                 if (!mst.active (mev.note(), mev.channel())) {
1510                                         /* the matching note-on was outside the
1511                                            time range we were given, so just
1512                                            ignore this note-off.
1513                                         */
1514                                         continue;
1515                                 }
1516
1517                                 source->append_event_beats (source_lock, mev);
1518                                 mst.remove (mev.note(), mev.channel());
1519
1520                         } else if (mev.is_note_on()) {
1521                                 mst.add (mev.note(), mev.channel());
1522                                 source->append_event_beats(source_lock, mev);
1523                         } else {
1524                                 source->append_event_beats(source_lock, mev);
1525                         }
1526                 }
1527         }
1528
1529         if (offset_events) {
1530                 end_time -= begin_time;
1531         }
1532         mst.resolve_notes (*source, source_lock, end_time);
1533
1534         set_percussive(old_percussive);
1535         source->mark_streaming_write_completed(source_lock);
1536
1537         set_edited(false);
1538
1539         return true;
1540 }
1541
1542 XMLNode&
1543 MidiModel::get_state()
1544 {
1545         XMLNode *node = new XMLNode("MidiModel");
1546         return *node;
1547 }
1548
1549 Evoral::Sequence<MidiModel::TimeType>::NotePtr
1550 MidiModel::find_note (NotePtr other)
1551 {
1552         Notes::iterator l = notes().lower_bound(other);
1553
1554         if (l != notes().end()) {
1555                 for (; (*l)->time() == other->time(); ++l) {
1556                         /* NB: compare note contents, not note pointers.
1557                            If "other" was a ptr to a note already in
1558                            the model, we wouldn't be looking for it,
1559                            would we now?
1560                         */
1561                         if (**l == *other) {
1562                                 return *l;
1563                         }
1564                 }
1565         }
1566
1567         return NotePtr();
1568 }
1569
1570 Evoral::Sequence<MidiModel::TimeType>::NotePtr
1571 MidiModel::find_note (gint note_id)
1572 {
1573         /* used only for looking up notes when reloading history from disk,
1574            so we don't care about performance *too* much.
1575         */
1576
1577         for (Notes::iterator l = notes().begin(); l != notes().end(); ++l) {
1578                 if ((*l)->id() == note_id) {
1579                         return *l;
1580                 }
1581         }
1582
1583         return NotePtr();
1584 }
1585
1586 MidiModel::PatchChangePtr
1587 MidiModel::find_patch_change (Evoral::event_id_t id)
1588 {
1589         for (PatchChanges::iterator i = patch_changes().begin(); i != patch_changes().end(); ++i) {
1590                 if ((*i)->id() == id) {
1591                         return *i;
1592                 }
1593         }
1594
1595         return PatchChangePtr ();
1596 }
1597
1598 boost::shared_ptr<Evoral::Event<MidiModel::TimeType> >
1599 MidiModel::find_sysex (gint sysex_id)
1600 {
1601         /* used only for looking up notes when reloading history from disk,
1602            so we don't care about performance *too* much.
1603         */
1604
1605         for (SysExes::iterator l = sysexes().begin(); l != sysexes().end(); ++l) {
1606                 if ((*l)->id() == sysex_id) {
1607                         return *l;
1608                 }
1609         }
1610
1611         return boost::shared_ptr<Evoral::Event<TimeType> > ();
1612 }
1613
1614 /** Lock and invalidate the source.
1615  * This should be used by commands and editing things
1616  */
1617 MidiModel::WriteLock
1618 MidiModel::edit_lock()
1619 {
1620         boost::shared_ptr<MidiSource> ms          = _midi_source.lock();
1621         Glib::Threads::Mutex::Lock*   source_lock = 0;
1622
1623         if (ms) {
1624                 /* Take source lock and invalidate iterator to release its lock on model.
1625                    Add currently active notes to _active_notes so we can restore them
1626                    if playback resumes at the same point after the edit. */
1627                 source_lock = new Glib::Threads::Mutex::Lock(ms->mutex());
1628                 ms->invalidate(*source_lock,
1629                                ms->session().transport_rolling() ? &_active_notes : NULL);
1630         }
1631
1632         return WriteLock(new WriteLockImpl(source_lock, _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 void
1987 MidiModel::transpose (NoteDiffCommand* c, const NotePtr note_ptr, int semitones)
1988 {
1989         int new_note = note_ptr->note() + semitones;
1990
1991         if (new_note < 0) {
1992                 new_note = 0;
1993         } else if (new_note > 127) {
1994                 new_note = 127;
1995         }
1996
1997         c->change (note_ptr, NoteDiffCommand::NoteNumber, (uint8_t) new_note);
1998 }
1999
2000 void
2001 MidiModel::control_list_marked_dirty ()
2002 {
2003         AutomatableSequence<Evoral::Beats>::control_list_marked_dirty ();
2004
2005         ContentsChanged (); /* EMIT SIGNAL */
2006 }