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