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