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