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