Inrease the export "chunk size" to speed it up over 10% at least in some situations
[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 (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
790                         switch (i->property) {
791                         case Time:
792                                 i->sysex->set_time (i->new_time);
793                         }
794                 }
795         }
796
797         _model->ContentsChanged (); /* EMIT SIGNAL */
798 }
799
800 void
801 MidiModel::SysExDiffCommand::undo ()
802 {
803         {
804                 MidiModel::WriteLock lock (_model->edit_lock ());
805
806                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
807                         switch (i->property) {
808                         case Time:
809                                 i->sysex->set_time (i->old_time);
810                                 break;
811                         }
812                 }
813
814         }
815
816         _model->ContentsChanged(); /* EMIT SIGNAL */
817 }
818
819 XMLNode&
820 MidiModel::SysExDiffCommand::marshal_change (const Change& change)
821 {
822         XMLNode* xml_change = new XMLNode ("Change");
823
824         /* first, the change itself */
825
826         xml_change->add_property ("property", enum_2_string (change.property));
827
828         {
829                 ostringstream old_value_str (ios::ate);
830                 old_value_str << change.old_time;
831                 xml_change->add_property ("old", old_value_str.str());
832         }
833
834         {
835                 ostringstream new_value_str (ios::ate);
836                 new_value_str << change.new_time;
837                 xml_change->add_property ("new", new_value_str.str());
838         }
839
840         ostringstream id_str;
841         id_str << change.sysex->id();
842         xml_change->add_property ("id", id_str.str());
843
844         return *xml_change;
845 }
846
847 MidiModel::SysExDiffCommand::Change
848 MidiModel::SysExDiffCommand::unmarshal_change (XMLNode *xml_change)
849 {
850         XMLProperty* prop;
851         Change change;
852
853         if ((prop = xml_change->property ("property")) != 0) {
854                 change.property = (Property) string_2_enum (prop->value(), change.property);
855         } else {
856                 fatal << "!!!" << endmsg;
857                 /*NOTREACHED*/
858         }
859
860         if ((prop = xml_change->property ("id")) == 0) {
861                 error << _("No SysExID found for sys-ex property change - ignored") << endmsg;
862                 return change;
863         }
864
865         gint sysex_id = atoi (prop->value().c_str());
866
867         if ((prop = xml_change->property ("old")) != 0) {
868                 istringstream old_str (prop->value());
869                 old_str >> change.old_time;
870         } else {
871                 fatal << "!!!" << endmsg;
872                 /*NOTREACHED*/
873         }
874
875         if ((prop = xml_change->property ("new")) != 0) {
876                 istringstream new_str (prop->value());
877                 new_str >> change.new_time;
878         } else {
879                 fatal << "!!!" << endmsg;
880                 /*NOTREACHED*/
881         }
882
883         /* we must point at the instance of the sysex that is actually in the model.
884            so go look for it ...
885         */
886
887         change.sysex = _model->find_sysex (sysex_id);
888
889         if (!change.sysex) {
890                 warning << "Sys-ex #" << sysex_id << " not found in model - programmers should investigate this" << endmsg;
891                 return change;
892         }
893
894         return change;
895 }
896
897 int
898 MidiModel::SysExDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
899 {
900         if (diff_command.name() != string (SYSEX_DIFF_COMMAND_ELEMENT)) {
901                 return 1;
902         }
903
904         /* changes */
905
906         _changes.clear();
907
908         XMLNode* changed_sysexes = diff_command.child (DIFF_SYSEXES_ELEMENT);
909
910         if (changed_sysexes) {
911                 XMLNodeList sysexes = changed_sysexes->children();
912                 transform (sysexes.begin(), sysexes.end(), back_inserter (_changes),
913                            boost::bind (&SysExDiffCommand::unmarshal_change, this, _1));
914
915         }
916
917         return 0;
918 }
919
920 XMLNode&
921 MidiModel::SysExDiffCommand::get_state ()
922 {
923         XMLNode* diff_command = new XMLNode (SYSEX_DIFF_COMMAND_ELEMENT);
924         diff_command->add_property ("midi-source", _model->midi_source()->id().to_s());
925
926         XMLNode* changes = diff_command->add_child(DIFF_SYSEXES_ELEMENT);
927         for_each (_changes.begin(), _changes.end(),
928                   boost::bind (
929                           boost::bind (&XMLNode::add_child_nocopy, changes, _1),
930                           boost::bind (&SysExDiffCommand::marshal_change, this, _1)));
931
932         return *diff_command;
933 }
934
935 MidiModel::PatchChangeDiffCommand::PatchChangeDiffCommand (boost::shared_ptr<MidiModel> m, const string& name)
936         : DiffCommand (m, name)
937 {
938         assert (_model);
939 }
940
941 MidiModel::PatchChangeDiffCommand::PatchChangeDiffCommand (boost::shared_ptr<MidiModel> m, const XMLNode & node)
942         : DiffCommand (m, "")
943 {
944         assert (_model);
945         set_state (node, Stateful::loading_state_version);
946 }
947
948 void
949 MidiModel::PatchChangeDiffCommand::add (PatchChangePtr p)
950 {
951         _added.push_back (p);
952 }
953
954 void
955 MidiModel::PatchChangeDiffCommand::remove (PatchChangePtr p)
956 {
957         _removed.push_back (p);
958 }
959
960 void
961 MidiModel::PatchChangeDiffCommand::change_time (PatchChangePtr patch, TimeType t)
962 {
963         Change c;
964         c.property = Time;
965         c.patch = patch;
966         c.old_time = patch->time ();
967         c.new_time = t;
968
969         _changes.push_back (c);
970 }
971
972 void
973 MidiModel::PatchChangeDiffCommand::change_channel (PatchChangePtr patch, uint8_t channel)
974 {
975         Change c;
976         c.property = Channel;
977         c.patch = patch;
978         c.old_channel = patch->channel ();
979         c.new_channel = channel;
980
981         _changes.push_back (c);
982 }
983
984 void
985 MidiModel::PatchChangeDiffCommand::change_program (PatchChangePtr patch, uint8_t program)
986 {
987         Change c;
988         c.property = Program;
989         c.patch = patch;
990         c.old_program = patch->program ();
991         c.new_program = program;
992
993         _changes.push_back (c);
994 }
995
996 void
997 MidiModel::PatchChangeDiffCommand::change_bank (PatchChangePtr patch, int bank)
998 {
999         Change c;
1000         c.property = Bank;
1001         c.patch = patch;
1002         c.old_bank = patch->bank ();
1003         c.new_bank = bank;
1004
1005         _changes.push_back (c);
1006 }
1007
1008 void
1009 MidiModel::PatchChangeDiffCommand::operator() ()
1010 {
1011         {
1012                 MidiModel::WriteLock lock (_model->edit_lock ());
1013
1014                 for (list<PatchChangePtr>::iterator i = _added.begin(); i != _added.end(); ++i) {
1015                         _model->add_patch_change_unlocked (*i);
1016                 }
1017
1018                 for (list<PatchChangePtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
1019                         _model->remove_patch_change_unlocked (*i);
1020                 }
1021
1022                 set<PatchChangePtr> temporary_removals;
1023
1024                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1025                         switch (i->property) {
1026                         case Time:
1027                                 if (temporary_removals.find (i->patch) == temporary_removals.end()) {
1028                                         _model->remove_patch_change_unlocked (i->patch);
1029                                         temporary_removals.insert (i->patch);
1030                                 }
1031                                 i->patch->set_time (i->new_time);
1032                                 break;
1033
1034                         case Channel:
1035                                 i->patch->set_channel (i->new_channel);
1036                                 break;
1037
1038                         case Program:
1039                                 i->patch->set_program (i->new_program);
1040                                 break;
1041
1042                         case Bank:
1043                                 i->patch->set_bank (i->new_bank);
1044                                 break;
1045                         }
1046                 }
1047
1048                 for (set<PatchChangePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
1049                         _model->add_patch_change_unlocked (*i);
1050                 }
1051         }
1052
1053         _model->ContentsChanged (); /* EMIT SIGNAL */
1054 }
1055
1056 void
1057 MidiModel::PatchChangeDiffCommand::undo ()
1058 {
1059         {
1060                 MidiModel::WriteLock lock (_model->edit_lock());
1061
1062                 for (list<PatchChangePtr>::iterator i = _added.begin(); i != _added.end(); ++i) {
1063                         _model->remove_patch_change_unlocked (*i);
1064                 }
1065
1066                 for (list<PatchChangePtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
1067                         _model->add_patch_change_unlocked (*i);
1068                 }
1069
1070                 set<PatchChangePtr> temporary_removals;
1071
1072                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1073                         switch (i->property) {
1074                         case Time:
1075                                 if (temporary_removals.find (i->patch) == temporary_removals.end()) {
1076                                         _model->remove_patch_change_unlocked (i->patch);
1077                                         temporary_removals.insert (i->patch);
1078                                 }
1079                                 i->patch->set_time (i->old_time);
1080                                 break;
1081
1082                         case Channel:
1083                                 i->patch->set_channel (i->old_channel);
1084                                 break;
1085
1086                         case Program:
1087                                 i->patch->set_program (i->old_program);
1088                                 break;
1089
1090                         case Bank:
1091                                 i->patch->set_bank (i->old_bank);
1092                                 break;
1093                         }
1094                 }
1095
1096                 for (set<PatchChangePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
1097                         _model->add_patch_change_unlocked (*i);
1098                 }
1099
1100         }
1101
1102         _model->ContentsChanged (); /* EMIT SIGNAL */
1103 }
1104
1105 XMLNode &
1106 MidiModel::PatchChangeDiffCommand::marshal_patch_change (constPatchChangePtr p)
1107 {
1108         XMLNode* n = new XMLNode ("patch-change");
1109
1110         {
1111                 ostringstream s (ios::ate);
1112                 s << int (p->id ());
1113                 n->add_property ("id", s.str());
1114         }
1115
1116         {
1117                 ostringstream s (ios::ate);
1118                 s << p->time ();
1119                 n->add_property ("time", s.str ());
1120         }
1121
1122         {
1123                 ostringstream s (ios::ate);
1124                 s << int (p->channel ());
1125                 n->add_property ("channel", s.str ());
1126         }
1127
1128         {
1129                 ostringstream s (ios::ate);
1130                 s << int (p->program ());
1131                 n->add_property ("program", s.str ());
1132         }
1133
1134         {
1135                 ostringstream s (ios::ate);
1136                 s << int (p->bank ());
1137                 n->add_property ("bank", s.str ());
1138         }
1139
1140         return *n;
1141 }
1142
1143 XMLNode&
1144 MidiModel::PatchChangeDiffCommand::marshal_change (const Change& c)
1145 {
1146         XMLNode* n = new XMLNode (X_("Change"));
1147
1148         n->add_property (X_("property"), enum_2_string (c.property));
1149
1150         {
1151                 ostringstream s (ios::ate);
1152                 if (c.property == Time) {
1153                         s << c.old_time;
1154                 } else if (c.property == Channel) {
1155                         s << c.old_channel;
1156                 } else if (c.property == Program) {
1157                         s << int (c.old_program);
1158                 } else if (c.property == Bank) {
1159                         s << c.old_bank;
1160                 }
1161
1162                 n->add_property (X_("old"), s.str ());
1163         }
1164
1165         {
1166                 ostringstream s (ios::ate);
1167
1168                 if (c.property == Time) {
1169                         s << c.new_time;
1170                 } else if (c.property == Channel) {
1171                         s << c.new_channel;
1172                 } else if (c.property == Program) {
1173                         s << int (c.new_program);
1174                 } else if (c.property == Bank) {
1175                         s << c.new_bank;
1176                 }
1177
1178                 n->add_property (X_("new"), s.str ());
1179         }
1180
1181         {
1182                 ostringstream s;
1183                 s << c.patch->id ();
1184                 n->add_property ("id", s.str ());
1185         }
1186
1187         return *n;
1188 }
1189
1190 MidiModel::PatchChangePtr
1191 MidiModel::PatchChangeDiffCommand::unmarshal_patch_change (XMLNode* n)
1192 {
1193         XMLProperty* prop;
1194         Evoral::event_id_t id;
1195         Evoral::MusicalTime time = 0;
1196         uint8_t channel = 0;
1197         uint8_t program = 0;
1198         int bank = 0;
1199
1200         if ((prop = n->property ("id")) != 0) {
1201                 istringstream s (prop->value());
1202                 s >> id;
1203         }
1204
1205         if ((prop = n->property ("time")) != 0) {
1206                 istringstream s (prop->value ());
1207                 s >> time;
1208         }
1209
1210         if ((prop = n->property ("channel")) != 0) {
1211                 istringstream s (prop->value ());
1212                 s >> channel;
1213         }
1214
1215         if ((prop = n->property ("program")) != 0) {
1216                 istringstream s (prop->value ());
1217                 s >> program;
1218         }
1219
1220         if ((prop = n->property ("bank")) != 0) {
1221                 istringstream s (prop->value ());
1222                 s >> bank;
1223         }
1224
1225         PatchChangePtr p (new Evoral::PatchChange<TimeType> (time, channel, program, bank));
1226         p->set_id (id);
1227         return p;
1228 }
1229
1230 MidiModel::PatchChangeDiffCommand::Change
1231 MidiModel::PatchChangeDiffCommand::unmarshal_change (XMLNode* n)
1232 {
1233         XMLProperty* prop;
1234         Change c;
1235
1236         prop = n->property ("property");
1237         assert (prop);
1238         c.property = (Property) string_2_enum (prop->value(), c.property);
1239
1240         prop = n->property ("id");
1241         assert (prop);
1242         Evoral::event_id_t const id = atoi (prop->value().c_str());
1243
1244         prop = n->property ("old");
1245         assert (prop);
1246         {
1247                 istringstream s (prop->value ());
1248                 if (c.property == Time) {
1249                         s >> c.old_time;
1250                 } else if (c.property == Channel) {
1251                         s >> c.old_channel;
1252                 } else if (c.property == Program) {
1253                         s >> c.old_program;
1254                 } else if (c.property == Bank) {
1255                         s >> c.old_bank;
1256                 }
1257         }
1258
1259         prop = n->property ("new");
1260         assert (prop);
1261         {
1262                 istringstream s (prop->value ());
1263                 if (c.property == Time) {
1264                         s >> c.new_time;
1265                 } else if (c.property == Channel) {
1266                         s >> c.new_channel;
1267                 } else if (c.property == Program) {
1268                         s >> c.new_program;
1269                 } else if (c.property == Bank) {
1270                         s >> c.new_bank;
1271                 }
1272         }
1273
1274         c.patch = _model->find_patch_change (id);
1275         assert (c.patch);
1276
1277         return c;
1278 }
1279
1280 int
1281 MidiModel::PatchChangeDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
1282 {
1283         if (diff_command.name() != PATCH_CHANGE_DIFF_COMMAND_ELEMENT) {
1284                 return 1;
1285         }
1286
1287         _added.clear ();
1288         XMLNode* added = diff_command.child (ADDED_PATCH_CHANGES_ELEMENT);
1289         if (added) {
1290                 XMLNodeList p = added->children ();
1291                 transform (p.begin(), p.end(), back_inserter (_added), boost::bind (&PatchChangeDiffCommand::unmarshal_patch_change, this, _1));
1292         }
1293
1294         _removed.clear ();
1295         XMLNode* removed = diff_command.child (REMOVED_PATCH_CHANGES_ELEMENT);
1296         if (removed) {
1297                 XMLNodeList p = removed->children ();
1298                 transform (p.begin(), p.end(), back_inserter (_removed), boost::bind (&PatchChangeDiffCommand::unmarshal_patch_change, this, _1));
1299         }
1300
1301         _changes.clear ();
1302         XMLNode* changed = diff_command.child (DIFF_PATCH_CHANGES_ELEMENT);
1303         if (changed) {
1304                 XMLNodeList p = changed->children ();
1305                 transform (p.begin(), p.end(), back_inserter (_changes), boost::bind (&PatchChangeDiffCommand::unmarshal_change, this, _1));
1306         }
1307
1308         return 0;
1309 }
1310
1311 XMLNode &
1312 MidiModel::PatchChangeDiffCommand::get_state ()
1313 {
1314         XMLNode* diff_command = new XMLNode (PATCH_CHANGE_DIFF_COMMAND_ELEMENT);
1315         diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
1316
1317         XMLNode* added = diff_command->add_child (ADDED_PATCH_CHANGES_ELEMENT);
1318         for_each (_added.begin(), _added.end(),
1319                   boost::bind (
1320                           boost::bind (&XMLNode::add_child_nocopy, added, _1),
1321                           boost::bind (&PatchChangeDiffCommand::marshal_patch_change, this, _1)
1322                           )
1323                 );
1324
1325         XMLNode* removed = diff_command->add_child (REMOVED_PATCH_CHANGES_ELEMENT);
1326         for_each (_removed.begin(), _removed.end(),
1327                   boost::bind (
1328                           boost::bind (&XMLNode::add_child_nocopy, removed, _1),
1329                           boost::bind (&PatchChangeDiffCommand::marshal_patch_change, this, _1)
1330                           )
1331                 );
1332
1333         XMLNode* changes = diff_command->add_child (DIFF_PATCH_CHANGES_ELEMENT);
1334         for_each (_changes.begin(), _changes.end(),
1335                   boost::bind (
1336                           boost::bind (&XMLNode::add_child_nocopy, changes, _1),
1337                           boost::bind (&PatchChangeDiffCommand::marshal_change, this, _1)
1338                           )
1339                 );
1340
1341         return *diff_command;
1342 }
1343
1344 /** Write all of the model to a MidiSource (i.e. save the model).
1345  * This is different from manually using read to write to a source in that
1346  * note off events are written regardless of the track mode.  This is so the
1347  * user can switch a recorded track (with note durations from some instrument)
1348  * to percussive, save, reload, then switch it back to sustained without
1349  * destroying the original note durations.
1350  *
1351  * Similarly, control events are written without interpolation (as with the
1352  * `Discrete' mode).
1353  */
1354 bool
1355 MidiModel::write_to (boost::shared_ptr<MidiSource> source)
1356 {
1357         ReadLock lock(read_lock());
1358
1359         const bool old_percussive = percussive();
1360         set_percussive(false);
1361
1362         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1363         assert (ms);
1364
1365         source->drop_model();
1366         source->mark_streaming_midi_write_started (note_mode());
1367
1368         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
1369                 source->append_event_unlocked_beats(*i);
1370         }
1371
1372         set_percussive(old_percussive);
1373         source->mark_streaming_write_completed();
1374
1375         set_edited(false);
1376
1377         return true;
1378 }
1379
1380 /** very similar to ::write_to() but writes to the model's own
1381     existing midi_source, without making it call MidiSource::drop_model().
1382     the caller is a MidiSource that needs to catch up with the state
1383     of the model.
1384 */
1385 bool
1386 MidiModel::sync_to_source ()
1387 {
1388         ReadLock lock(read_lock());
1389
1390         const bool old_percussive = percussive();
1391         set_percussive(false);
1392
1393         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1394         assert (ms);
1395
1396         ms->mark_streaming_midi_write_started (note_mode());
1397
1398         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
1399                 ms->append_event_unlocked_beats(*i);
1400         }
1401
1402         set_percussive (old_percussive);
1403         ms->mark_streaming_write_completed ();
1404
1405         set_edited (false);
1406
1407         return true;
1408 }
1409
1410 /** Write part or all of the model to a MidiSource (i.e. save the model).
1411  * This is different from manually using read to write to a source in that
1412  * note off events are written regardless of the track mode.  This is so the
1413  * user can switch a recorded track (with note durations from some instrument)
1414  * to percussive, save, reload, then switch it back to sustained without
1415  * destroying the original note durations.
1416  */
1417 bool
1418 MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::MusicalTime begin_time, Evoral::MusicalTime end_time)
1419 {
1420         ReadLock lock(read_lock());
1421         MidiStateTracker mst;
1422
1423         const bool old_percussive = percussive();
1424         set_percussive(false);
1425
1426         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1427         assert (ms);
1428
1429         source->drop_model();
1430         source->mark_streaming_midi_write_started (note_mode());
1431
1432         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
1433                 const Evoral::Event<Evoral::MusicalTime>& ev (*i);
1434
1435                 if (ev.time() >= begin_time && ev.time() < end_time) {
1436
1437                         const Evoral::MIDIEvent<Evoral::MusicalTime>* mev =
1438                                 static_cast<const Evoral::MIDIEvent<Evoral::MusicalTime>* > (&ev);
1439
1440                         if (!mev) {
1441                                 continue;
1442                         }
1443
1444
1445                         if (mev->is_note_off()) {
1446
1447                                 if (!mst.active (mev->note(), mev->channel())) {
1448                                         /* the matching note-on was outside the
1449                                            time range we were given, so just
1450                                            ignore this note-off.
1451                                         */
1452                                         continue;
1453                                 }
1454
1455                                 source->append_event_unlocked_beats (*i);
1456                                 mst.remove (mev->note(), mev->channel());
1457
1458                         } else if (mev->is_note_on()) {
1459                                 mst.add (mev->note(), mev->channel());
1460                                 source->append_event_unlocked_beats(*i);
1461                         } else {
1462                                 source->append_event_unlocked_beats(*i);
1463                         }
1464                 }
1465         }
1466
1467         mst.resolve_notes (*source, end_time);
1468
1469         set_percussive(old_percussive);
1470         source->mark_streaming_write_completed();
1471
1472         set_edited(false);
1473
1474         return true;
1475 }
1476
1477 XMLNode&
1478 MidiModel::get_state()
1479 {
1480         XMLNode *node = new XMLNode("MidiModel");
1481         return *node;
1482 }
1483
1484 Evoral::Sequence<MidiModel::TimeType>::NotePtr
1485 MidiModel::find_note (NotePtr other)
1486 {
1487         Notes::iterator l = notes().lower_bound(other);
1488
1489         if (l != notes().end()) {
1490                 for (; (*l)->time() == other->time(); ++l) {
1491                         /* NB: compare note contents, not note pointers.
1492                            If "other" was a ptr to a note already in
1493                            the model, we wouldn't be looking for it,
1494                            would we now?
1495                         */
1496                         if (**l == *other) {
1497                                 return *l;
1498                         }
1499                 }
1500         }
1501
1502         return NotePtr();
1503 }
1504
1505 Evoral::Sequence<MidiModel::TimeType>::NotePtr
1506 MidiModel::find_note (gint note_id)
1507 {
1508         /* used only for looking up notes when reloading history from disk,
1509            so we don't care about performance *too* much.
1510         */
1511
1512         for (Notes::iterator l = notes().begin(); l != notes().end(); ++l) {
1513                 if ((*l)->id() == note_id) {
1514                         return *l;
1515                 }
1516         }
1517
1518         return NotePtr();
1519 }
1520
1521 MidiModel::PatchChangePtr
1522 MidiModel::find_patch_change (Evoral::event_id_t id)
1523 {
1524         for (PatchChanges::iterator i = patch_changes().begin(); i != patch_changes().end(); ++i) {
1525                 if ((*i)->id() == id) {
1526                         return *i;
1527                 }
1528         }
1529
1530         return PatchChangePtr ();
1531 }
1532
1533 boost::shared_ptr<Evoral::Event<MidiModel::TimeType> >
1534 MidiModel::find_sysex (gint sysex_id)
1535 {
1536         /* used only for looking up notes when reloading history from disk,
1537            so we don't care about performance *too* much.
1538         */
1539
1540         for (SysExes::iterator l = sysexes().begin(); l != sysexes().end(); ++l) {
1541                 if ((*l)->id() == sysex_id) {
1542                         return *l;
1543                 }
1544         }
1545
1546         return boost::shared_ptr<Evoral::Event<TimeType> > ();
1547 }
1548
1549 /** Lock and invalidate the source.
1550  * This should be used by commands and editing things
1551  */
1552 MidiModel::WriteLock
1553 MidiModel::edit_lock()
1554 {
1555         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1556         assert (ms);
1557
1558         Glib::Mutex::Lock* source_lock = new Glib::Mutex::Lock (ms->mutex());
1559         ms->invalidate(); // Release cached iterator's read lock on model
1560         return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
1561 }
1562
1563 /** Lock just the model, the source lock must already be held.
1564  * This should only be called from libardour/evoral places
1565  */
1566 MidiModel::WriteLock
1567 MidiModel::write_lock()
1568 {
1569         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1570         assert (ms);
1571
1572         assert (!ms->mutex().trylock ());
1573         return WriteLock(new WriteLockImpl(NULL, _lock, _control_lock));
1574 }
1575
1576 int
1577 MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
1578 {
1579         using namespace Evoral;
1580
1581         if (_writing || insert_merge_policy() == InsertMergeRelax) {
1582                 return 0;
1583         }
1584
1585         NoteDiffCommand* cmd = static_cast<NoteDiffCommand*>(arg);
1586
1587         TimeType sa = note->time();
1588         TimeType ea  = note->end_time();
1589
1590         const Pitches& p (pitches (note->channel()));
1591         NotePtr search_note(new Note<TimeType>(0, 0, 0, note->note()));
1592         set<NotePtr> to_be_deleted;
1593         bool set_note_length = false;
1594         bool set_note_time = false;
1595         TimeType note_time = note->time();
1596         TimeType note_length = note->length();
1597
1598         DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 checking overlaps for note %2 @ %3\n", this, (int)note->note(), note->time()));
1599
1600         for (Pitches::const_iterator i = p.lower_bound (search_note);
1601              i != p.end() && (*i)->note() == note->note(); ++i) {
1602
1603                 TimeType sb = (*i)->time();
1604                 TimeType eb = (*i)->end_time();
1605                 OverlapType overlap = OverlapNone;
1606
1607                 if ((sb > sa) && (eb <= ea)) {
1608                         overlap = OverlapInternal;
1609                 } else if ((eb >= sa) && (eb <= ea)) {
1610                         overlap = OverlapStart;
1611                 } else if ((sb > sa) && (sb <= ea)) {
1612                         overlap = OverlapEnd;
1613                 } else if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
1614                         overlap = OverlapExternal;
1615                 } else {
1616                         /* no overlap */
1617                         continue;
1618                 }
1619
1620                 DEBUG_TRACE (DEBUG::Sequence, string_compose (
1621                                      "\toverlap is %1 for (%2,%3) vs (%4,%5)\n",
1622                                      enum_2_string(overlap), sa, ea, sb, eb));
1623
1624                 if (insert_merge_policy() == InsertMergeReject) {
1625                         DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 just reject\n", this));
1626                         return -1;
1627                 }
1628
1629                 switch (overlap) {
1630                 case OverlapStart:
1631                         cerr << "OverlapStart\n";
1632                         /* existing note covers start of new note */
1633                         switch (insert_merge_policy()) {
1634                         case InsertMergeReplace:
1635                                 to_be_deleted.insert (*i);
1636                                 break;
1637                         case InsertMergeTruncateExisting:
1638                                 if (cmd) {
1639                                         cmd->change (*i, NoteDiffCommand::Length, (note->time() - (*i)->time()));
1640                                 }
1641                                 (*i)->set_length (note->time() - (*i)->time());
1642                                 break;
1643                         case InsertMergeTruncateAddition:
1644                                 set_note_time = true;
1645                                 set_note_length = true;
1646                                 note_time = (*i)->time() + (*i)->length();
1647                                 note_length = min (note_length, (*i)->length() - ((*i)->end_time() - note->time()));
1648                                 break;
1649                         case InsertMergeExtend:
1650                                 if (cmd) {
1651                                         cmd->change ((*i), NoteDiffCommand::Length, note->end_time() - (*i)->time());
1652                                 }
1653                                 (*i)->set_length (note->end_time() - (*i)->time());
1654                                 return -1; /* do not add the new note */
1655                                 break;
1656                         default:
1657                                 /*NOTREACHED*/
1658                                 /* stupid gcc */
1659                                 break;
1660                         }
1661                         break;
1662
1663                 case OverlapEnd:
1664                         cerr << "OverlapEnd\n";
1665                         /* existing note covers end of new note */
1666                         switch (insert_merge_policy()) {
1667                         case InsertMergeReplace:
1668                                 to_be_deleted.insert (*i);
1669                                 break;
1670
1671                         case InsertMergeTruncateExisting:
1672                                 /* resetting the start time of the existing note
1673                                    is a problem because of time ordering.
1674                                 */
1675                                 break;
1676
1677                         case InsertMergeTruncateAddition:
1678                                 set_note_length = true;
1679                                 note_length = min (note_length, ((*i)->time() - note->time()));
1680                                 break;
1681
1682                         case InsertMergeExtend:
1683                                 /* we can't reset the time of the existing note because
1684                                    that will corrupt time ordering. So remove the
1685                                    existing note and change the position/length
1686                                    of the new note (which has not been added yet)
1687                                 */
1688                                 to_be_deleted.insert (*i);
1689                                 set_note_length = true;
1690                                 note_length = min (note_length, (*i)->end_time() - note->time());
1691                                 break;
1692                         default:
1693                                 /*NOTREACHED*/
1694                                 /* stupid gcc */
1695                                 break;
1696                         }
1697                         break;
1698
1699                 case OverlapExternal:
1700                         cerr << "OverlapExt\n";
1701                         /* existing note overlaps all the new note */
1702                         switch (insert_merge_policy()) {
1703                         case InsertMergeReplace:
1704                                 to_be_deleted.insert (*i);
1705                                 break;
1706                         case InsertMergeTruncateExisting:
1707                         case InsertMergeTruncateAddition:
1708                         case InsertMergeExtend:
1709                                 /* cannot add in this case */
1710                                 return -1;
1711                         default:
1712                                 /*NOTREACHED*/
1713                                 /* stupid gcc */
1714                                 break;
1715                         }
1716                         break;
1717
1718                 case OverlapInternal:
1719                         cerr << "OverlapInt\n";
1720                         /* new note fully overlaps an existing note */
1721                         switch (insert_merge_policy()) {
1722                         case InsertMergeReplace:
1723                         case InsertMergeTruncateExisting:
1724                         case InsertMergeTruncateAddition:
1725                         case InsertMergeExtend:
1726                                 /* delete the existing note, the new one will cover it */
1727                                 to_be_deleted.insert (*i);
1728                                 break;
1729                         default:
1730                                 /*NOTREACHED*/
1731                                 /* stupid gcc */
1732                                 break;
1733                         }
1734                         break;
1735
1736                 default:
1737                         /*NOTREACHED*/
1738                         /* stupid gcc */
1739                         break;
1740                 }
1741         }
1742
1743         for (set<NotePtr>::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
1744                 remove_note_unlocked (*i);
1745
1746                 if (cmd) {
1747                         cmd->side_effect_remove (*i);
1748                 }
1749         }
1750
1751         if (set_note_time) {
1752                 if (cmd) {
1753                         cmd->change (note, NoteDiffCommand::StartTime, note_time);
1754                 }
1755                 note->set_time (note_time);
1756         }
1757
1758         if (set_note_length) {
1759                 if (cmd) {
1760                         cmd->change (note, NoteDiffCommand::Length, note_length);
1761                 }
1762                 note->set_length (note_length);
1763         }
1764
1765         return 0;
1766 }
1767
1768 InsertMergePolicy
1769 MidiModel::insert_merge_policy () const
1770 {
1771         /* XXX ultimately this should be a per-track or even per-model policy */
1772         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1773         assert (ms);
1774
1775         return ms->session().config.get_insert_merge_policy ();
1776 }
1777
1778 void
1779 MidiModel::set_midi_source (boost::shared_ptr<MidiSource> s)
1780 {
1781         boost::shared_ptr<MidiSource> old = _midi_source.lock ();
1782
1783         if (old) {
1784                 old->invalidate ();
1785         }
1786
1787         _midi_source_connections.drop_connections ();
1788
1789         _midi_source = s;
1790
1791         s->InterpolationChanged.connect_same_thread (
1792                 _midi_source_connections, boost::bind (&MidiModel::source_interpolation_changed, this, _1, _2)
1793                 );
1794
1795         s->AutomationStateChanged.connect_same_thread (
1796                 _midi_source_connections, boost::bind (&MidiModel::source_automation_state_changed, this, _1, _2)
1797                 );
1798 }
1799
1800 /** The source has signalled that the interpolation style for a parameter has changed.  In order to
1801  *  keep MidiSource and ControlList interpolation state the same, we pass this change onto the
1802  *  appropriate ControlList.
1803  *
1804  *  The idea is that MidiSource and the MidiModel's ControlList states are kept in sync, and one
1805  *  or the other is listened to by the GUI.
1806  */
1807 void
1808 MidiModel::source_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
1809 {
1810         Glib::Mutex::Lock lm (_control_lock);
1811         control(p)->list()->set_interpolation (s);
1812 }
1813
1814 /** A ControlList has signalled that its interpolation style has changed.  Again, in order to keep
1815  *  MidiSource and ControlList interpolation state in sync, we pass this change onto our MidiSource.
1816  */
1817 void
1818 MidiModel::control_list_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
1819 {
1820         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1821         assert (ms);
1822
1823         ms->set_interpolation_of (p, s);
1824 }
1825
1826 void
1827 MidiModel::source_automation_state_changed (Evoral::Parameter p, AutoState s)
1828 {
1829         Glib::Mutex::Lock lm (_control_lock);
1830         boost::shared_ptr<AutomationList> al = boost::dynamic_pointer_cast<AutomationList> (control(p)->list ());
1831         al->set_automation_state (s);
1832 }
1833
1834 void
1835 MidiModel::automation_list_automation_state_changed (Evoral::Parameter p, AutoState s)
1836 {
1837         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1838         assert (ms);
1839         ms->set_automation_state_of (p, s);
1840 }
1841
1842 boost::shared_ptr<Evoral::Control>
1843 MidiModel::control_factory (Evoral::Parameter const & p)
1844 {
1845         boost::shared_ptr<Evoral::Control> c = Automatable::control_factory (p);
1846
1847         /* Set up newly created control's lists to the appropriate interpolation and
1848            automation state from our source.
1849         */
1850
1851         boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
1852         assert (ms);
1853
1854         c->list()->set_interpolation (ms->interpolation_of (p));
1855
1856         boost::shared_ptr<AutomationList> al = boost::dynamic_pointer_cast<AutomationList> (c->list ());
1857         assert (al);
1858
1859         al->set_automation_state (ms->automation_state_of (p));
1860
1861         return c;
1862 }
1863
1864 boost::shared_ptr<const MidiSource>
1865 MidiModel::midi_source ()
1866 {
1867         return _midi_source.lock ();
1868 }
1869
1870 /** Moves notes, patch changes, controllers and sys-ex to insert silence at the start of the model.
1871  *  Adds commands to the session's current undo stack to reflect the movements.
1872  */
1873 void
1874 MidiModel::insert_silence_at_start (TimeType t)
1875 {
1876         boost::shared_ptr<MidiSource> s = _midi_source.lock ();
1877         assert (s);
1878
1879         /* Notes */
1880
1881         if (!notes().empty ()) {
1882                 NoteDiffCommand* c = new_note_diff_command ("insert silence");
1883
1884                 for (Notes::const_iterator i = notes().begin(); i != notes().end(); ++i) {
1885                         c->change (*i, NoteDiffCommand::StartTime, (*i)->time() + t);
1886                 }
1887
1888                 apply_command_as_subcommand (s->session(), c);
1889         }
1890
1891         /* Patch changes */
1892
1893         if (!patch_changes().empty ()) {
1894                 PatchChangeDiffCommand* c = new_patch_change_diff_command ("insert silence");
1895
1896                 for (PatchChanges::const_iterator i = patch_changes().begin(); i != patch_changes().end(); ++i) {
1897                         c->change_time (*i, (*i)->time() + t);
1898                 }
1899
1900                 apply_command_as_subcommand (s->session(), c);
1901         }
1902
1903         /* Controllers */
1904
1905         for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) {
1906                 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second);
1907                 XMLNode& before = ac->alist()->get_state ();
1908                 i->second->list()->shift (0, t);
1909                 XMLNode& after = ac->alist()->get_state ();
1910                 s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after));
1911         }
1912
1913         /* Sys-ex */
1914
1915         if (!sysexes().empty()) {
1916                 SysExDiffCommand* c = new_sysex_diff_command ("insert silence");
1917
1918                 for (SysExes::iterator i = sysexes().begin(); i != sysexes().end(); ++i) {
1919                         c->change (*i, (*i)->time() + t);
1920                 }
1921
1922                 apply_command_as_subcommand (s->session(), c);
1923         }
1924 }
1925
1926 /** Transpose notes in a time range by a given number of semitones.  Notes
1927  *  will be clamped at 0 and 127 if the transposition would make them exceed
1928  *  that range.
1929  *
1930  *  @param from Start time.
1931  *  @param end End time.
1932  *  @param semitones Number of semitones to transpose by (+ve is higher, -ve is lower).
1933  */
1934 void
1935 MidiModel::transpose (TimeType from, TimeType to, int semitones)
1936 {
1937         boost::shared_ptr<const MidiSource> s = midi_source ();
1938
1939         NoteDiffCommand* c = new_note_diff_command (_("transpose"));
1940
1941         for (Notes::iterator i = notes().begin(); i != notes().end(); ++i) {
1942
1943                 if ((*i)->time() >= to) {
1944
1945                         /* finished */
1946                         break;
1947
1948                 } else if ((*i)->time() >= from) {
1949
1950                         int new_note = (*i)->note() + semitones;
1951
1952                         if (new_note < 0) {
1953                                 new_note = 0;
1954                         } else if (new_note > 127) {
1955                                 new_note = 127;
1956                         }
1957
1958                         c->change (*i, NoteDiffCommand::NoteNumber, (uint8_t) new_note);
1959
1960                 }
1961         }
1962
1963         apply_command (s->session (), c);
1964 }
1965
1966 void
1967 MidiModel::control_list_marked_dirty ()
1968 {
1969         AutomatableSequence<Evoral::MusicalTime>::control_list_marked_dirty ();
1970         
1971         ContentsChanged (); /* EMIT SIGNAL */
1972 }