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