A few fixes to interpolation of MIDI controller data. Don't interpolate
[ardour.git] / libs / ardour / midi_model.cc
1 /*
2     Copyright (C) 2007 Paul Davis
3     Author: Dave 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 #define __STDC_LIMIT_MACROS 1
22 #include <set>
23 #include <iostream>
24 #include <algorithm>
25 #include <stdexcept>
26 #include <stdint.h>
27 #include "pbd/error.h"
28 #include "pbd/enumwriter.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
38 using namespace std;
39 using namespace ARDOUR;
40 using namespace PBD;
41
42 MidiModel::MidiModel(MidiSource* s)
43         : AutomatableSequence<TimeType>(s->session())
44         , _midi_source (0)
45 {
46         set_midi_source (s);
47 }
48
49 /** Start a new Diff command.
50  *
51  * This has no side-effects on the model or Session, the returned command
52  * can be held on to for as long as the caller wishes, or discarded without
53  * formality, until apply_command is called and ownership is taken.
54  */
55 MidiModel::DiffCommand*
56 MidiModel::new_diff_command(const string name)
57 {
58         DiffCommand* cmd = new DiffCommand(_midi_source->model(), name);
59         return cmd;
60 }
61
62 /** Apply a command.
63  *
64  * Ownership of cmd is taken, it must not be deleted by the caller.
65  * The command will constitute one item on the undo stack.
66  */
67 void
68 MidiModel::apply_command(Session& session, Command* cmd)
69 {
70         session.begin_reversible_command(cmd->name());
71         (*cmd)();
72         session.commit_reversible_command(cmd);
73         set_edited(true);
74 }
75
76 /** Apply a command as part of a larger reversible transaction
77  *
78  * Ownership of cmd is taken, it must not be deleted by the caller.
79  * The command will constitute one item on the undo stack.
80  */
81 void
82 MidiModel::apply_command_as_subcommand(Session& session, Command* cmd)
83 {
84         (*cmd)();
85         session.add_command(cmd);
86         set_edited(true);
87 }
88
89 /************** DIFF COMMAND ********************/
90
91 #define DIFF_COMMAND_ELEMENT "DiffCommand"
92 #define DIFF_NOTES_ELEMENT "ChangedNotes"
93 #define ADDED_NOTES_ELEMENT "AddedNotes"
94 #define REMOVED_NOTES_ELEMENT "RemovedNotes"
95 #define SIDE_EFFECT_REMOVALS_ELEMENT "SideEffectRemovals"
96
97 MidiModel::DiffCommand::DiffCommand(boost::shared_ptr<MidiModel> m, const std::string& name)
98         : Command(name)
99         , _model(m)
100         , _name(name)
101 {
102         assert(_model);
103 }
104
105 MidiModel::DiffCommand::DiffCommand(boost::shared_ptr<MidiModel> m, const XMLNode& node)
106         : _model(m)
107 {
108         assert(_model);
109         set_state(node, Stateful::loading_state_version);
110 }
111
112 void
113 MidiModel::DiffCommand::add(const NotePtr note)
114 {
115         _removed_notes.remove(note);
116         _added_notes.push_back(note);
117 }
118
119 void
120 MidiModel::DiffCommand::remove(const NotePtr note)
121 {
122         _added_notes.remove(note);
123         _removed_notes.push_back(note);
124 }
125
126 void
127 MidiModel::DiffCommand::side_effect_remove(const NotePtr note)
128 {
129         side_effect_removals.insert (note);
130 }
131
132 void
133 MidiModel::DiffCommand::change(const NotePtr note, Property prop,
134                                uint8_t new_value)
135 {
136         NoteChange change;
137         
138         switch (prop) {
139         case NoteNumber:
140                 if (new_value == note->note()) {
141                         return;
142                 }
143                 change.old_value = note->note();
144                 break;
145         case Velocity:
146                 if (new_value == note->velocity()) {
147                         return;
148                 }
149                 change.old_value = note->velocity();
150                 break;
151         case Channel:
152                 if (new_value == note->channel()) {
153                         return;
154                 }
155                 change.old_value = note->channel();
156                 break;
157
158
159         case StartTime:
160                 fatal << "MidiModel::DiffCommand::change() with integer argument called for start time" << endmsg;
161                 /*NOTREACHED*/
162                 break;
163         case Length:
164                 fatal << "MidiModel::DiffCommand::change() with integer argument called for length" << endmsg;
165                 /*NOTREACHED*/
166                 break;
167         }
168
169         change.note = note;
170         change.property = prop;
171         change.new_value = new_value;
172
173         _changes.push_back (change);
174 }
175
176 void
177 MidiModel::DiffCommand::change(const NotePtr note, Property prop,
178                                TimeType new_time)
179 {
180         NoteChange change;
181
182         switch (prop) {
183         case NoteNumber:
184         case Channel:
185         case Velocity:
186                 fatal << "MidiModel::DiffCommand::change() with time argument called for note, channel or velocity" << endmsg;
187                 break;
188
189         case StartTime:
190                 if (Evoral::musical_time_equal (note->time(), new_time)) {
191                         return;
192                 }
193                 change.old_time = note->time();
194                 break;
195         case Length:
196                 if (Evoral::musical_time_equal (note->length(), new_time)) {
197                         return;
198                 }
199                 change.old_time = note->length();
200                 break;
201         }
202
203         change.note = note;
204         change.property = prop;
205         change.new_time = new_time;
206
207         _changes.push_back (change);
208 }
209
210 MidiModel::DiffCommand&
211 MidiModel::DiffCommand::operator+= (const DiffCommand& other)
212 {
213         if (this == &other) {
214                 return *this;
215         }
216
217         if (_model != other._model) {
218                 return *this;
219         }
220
221         _added_notes.insert (_added_notes.end(), other._added_notes.begin(), other._added_notes.end());
222         _removed_notes.insert (_removed_notes.end(), other._removed_notes.begin(), other._removed_notes.end());
223         side_effect_removals.insert (other.side_effect_removals.begin(), other.side_effect_removals.end());
224         _changes.insert (_changes.end(), other._changes.begin(), other._changes.end());
225
226         return *this;
227 }
228
229 void
230 MidiModel::DiffCommand::operator()()
231 {
232         {
233                 MidiModel::WriteLock lock(_model->edit_lock());
234
235                 for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
236                         if (!_model->add_note_unlocked(*i)) {
237                                 /* failed to add it, so don't leave it in the removed list, to
238                                    avoid apparent errors on undo.
239                                 */
240                                 _removed_notes.remove (*i);
241                         }
242                 }
243
244                 for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) {
245                         _model->remove_note_unlocked(*i);
246                 }
247
248                 /* notes we modify in a way that requires remove-then-add to maintain ordering */
249                 set<NotePtr> temporary_removals;
250
251                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
252                         Property prop = i->property;
253                         switch (prop) {
254                         case NoteNumber:
255                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
256                                         _model->remove_note_unlocked (i->note);
257                                         temporary_removals.insert (i->note);
258                                 }
259                                 i->note->set_note (i->new_value);
260                                 break;
261
262                         case StartTime:
263                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
264                                         _model->remove_note_unlocked (i->note);
265                                         temporary_removals.insert (i->note);
266
267                                 }
268                                 i->note->set_time (i->new_time);
269                                 break;
270
271                         case Channel:
272                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
273                                         _model->remove_note_unlocked (i->note);
274                                         temporary_removals.insert (i->note);
275                                 }
276                                 i->note->set_channel (i->new_value);
277                                 break;
278
279                                 /* no remove-then-add required for these properties, since we do not index them
280                                  */
281
282                         case Velocity:
283                                 i->note->set_velocity (i->new_value);
284                                 break;
285
286                         case Length:
287                                 i->note->set_length (i->new_time);
288                                 break;
289
290                         }
291                 }
292
293
294                 for (set<NotePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
295                         DiffCommand side_effects (model(), "side effects");
296                         _model->add_note_unlocked (*i, &side_effects);
297                         *this += side_effects;
298                 }
299
300                 if (!side_effect_removals.empty()) {
301                         cerr << "SER: \n";
302                         for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
303                                 cerr << "\t" << *i << ' ' << **i << endl;
304                         }
305                 }
306         }
307
308         _model->ContentsChanged(); /* EMIT SIGNAL */
309 }
310
311 void
312 MidiModel::DiffCommand::undo()
313 {
314         {
315                 MidiModel::WriteLock lock(_model->edit_lock());
316
317                 for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
318                         _model->remove_note_unlocked(*i);
319                 }
320
321                 for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) {
322                         _model->add_note_unlocked(*i);
323                 }
324
325                 /* notes we modify in a way that requires remove-then-add to maintain ordering */
326                 set<NotePtr> temporary_removals;
327
328                 for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
329                         Property prop = i->property;
330                         switch (prop) {
331                         case NoteNumber:
332                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
333                                         _model->remove_note_unlocked (i->note);
334                                         temporary_removals.insert (i->note);
335                                 }
336                                 i->note->set_note (i->old_value);
337                                 break;
338                         case Velocity:
339                                 i->note->set_velocity (i->old_value);
340                                 break;
341                         case StartTime:
342                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
343                                         _model->remove_note_unlocked (i->note);
344                                         temporary_removals.insert (i->note);
345                                 }
346                                 i->note->set_time (i->old_time);
347                                 break;
348                         case Length:
349                                 i->note->set_length (i->old_time);
350                                 break;
351                         case Channel:
352                                 if (temporary_removals.find (i->note) == temporary_removals.end()) {
353                                         _model->remove_note_unlocked (i->note);
354                                         temporary_removals.insert (i->note);
355                                 }
356                                 i->note->set_channel (i->old_value);
357                                 break;
358                         }
359                 }
360
361                 for (set<NotePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
362                         _model->add_note_unlocked (*i);
363                 }
364
365                 /* finally add back notes that were removed by the "do". we don't care
366                    about side effects here since the model should be back to its original
367                    state once this is done.
368                 */
369
370                 for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
371                         _model->add_note_unlocked (*i);
372                 }
373         }
374
375         _model->ContentsChanged(); /* EMIT SIGNAL */
376 }
377
378 XMLNode&
379 MidiModel::DiffCommand::marshal_note(const NotePtr note)
380 {
381         XMLNode* xml_note = new XMLNode("note");
382
383         cerr << "Marshalling note: " << *note << endl;
384
385         ostringstream note_str(ios::ate);
386         note_str << int(note->note());
387         xml_note->add_property("note", note_str.str());
388
389         ostringstream channel_str(ios::ate);
390         channel_str << int(note->channel());
391         xml_note->add_property("channel", channel_str.str());
392
393         ostringstream time_str(ios::ate);
394         time_str << note->time();
395         xml_note->add_property("time", time_str.str());
396
397         ostringstream length_str(ios::ate);
398         length_str << note->length();
399         xml_note->add_property("length", length_str.str());
400
401         ostringstream velocity_str(ios::ate);
402         velocity_str << (unsigned int) note->velocity();
403         xml_note->add_property("velocity", velocity_str.str());
404
405         return *xml_note;
406 }
407
408 Evoral::Sequence<MidiModel::TimeType>::NotePtr
409 MidiModel::DiffCommand::unmarshal_note(XMLNode *xml_note)
410 {
411         unsigned int note;
412         XMLProperty* prop;
413         unsigned int channel;
414         unsigned int time;
415         unsigned int length;
416         unsigned int velocity;
417
418         if ((prop = xml_note->property("note")) != 0) {
419                 istringstream note_str(prop->value());
420                 note_str >> note;
421         } else {
422                 warning << "note information missing note value" << endmsg;
423                 note = 127;
424         }
425
426         if ((prop = xml_note->property("channel")) != 0) {
427                 istringstream channel_str(prop->value());
428                 channel_str >> channel;
429         } else {
430                 warning << "note information missing channel" << endmsg;
431                 channel = 0;
432         }
433
434         if ((prop = xml_note->property("time")) != 0) {
435                 istringstream time_str(prop->value());
436                 time_str >> time;
437         } else {
438                 warning << "note information missing time" << endmsg;
439                 time = 0;
440         }
441
442         if ((prop = xml_note->property("length")) != 0) {
443                 istringstream length_str(prop->value());
444                 length_str >> length;
445         } else {
446                 warning << "note information missing length" << endmsg;
447                 length = 1;
448         }
449
450         if ((prop = xml_note->property("velocity")) != 0) {
451                 istringstream velocity_str(prop->value());
452                 velocity_str >> velocity;
453         } else {
454                 warning << "note information missing velocity" << endmsg;
455                 velocity = 127;
456         }
457
458         NotePtr note_ptr(new Evoral::Note<TimeType>(channel, time, length, note, velocity));
459
460         return note_ptr;
461 }
462
463 XMLNode&
464 MidiModel::DiffCommand::marshal_change(const NoteChange& change)
465 {
466         XMLNode* xml_change = new XMLNode("change");
467
468         /* first, the change itself */
469
470         xml_change->add_property ("property", enum_2_string (change.property));
471
472         {
473                 ostringstream old_value_str (ios::ate);
474                 if (change.property == StartTime || change.property == Length) {
475                         old_value_str << change.old_time;
476                 } else {
477                         old_value_str << (unsigned int) change.old_value;
478                 }
479                 xml_change->add_property ("old", old_value_str.str());
480         }
481
482         {
483                 ostringstream new_value_str (ios::ate);
484                 if (change.property == StartTime || change.property == Length) {
485                         new_value_str << change.new_time;
486                 } else {
487                         new_value_str << (unsigned int) change.new_value;
488                 }
489                 xml_change->add_property ("new", new_value_str.str());
490         }
491
492         /* now the rest of the note */
493
494         const SMFSource* smf = dynamic_cast<const SMFSource*> (_model->midi_source());
495
496         if (change.property != NoteNumber) {
497                 ostringstream note_str;
498                 note_str << int(change.note->note());
499                 xml_change->add_property("note", note_str.str());
500         }
501
502         if (change.property != Channel) {
503                 ostringstream channel_str;
504                 channel_str << int(change.note->channel());
505                 xml_change->add_property("channel", channel_str.str());
506         }
507
508         if (change.property != StartTime) {
509                 ostringstream time_str;
510                 if (smf) {
511                         time_str << smf->round_to_file_precision (change.note->time());
512                 } else {
513                         time_str << change.note->time();
514                 }
515                 xml_change->add_property("time", time_str.str());
516         }
517
518         if (change.property != Length) {
519                 ostringstream length_str;
520                 if (smf) {
521                         length_str << smf->round_to_file_precision (change.note->length());
522                 } else {
523                         length_str << change.note->length();
524                 }
525                 xml_change->add_property ("length", length_str.str());
526         }
527
528         if (change.property != Velocity) {
529                 ostringstream velocity_str;
530                 velocity_str << int (change.note->velocity());
531                 xml_change->add_property("velocity", velocity_str.str());
532         }
533
534         /* and now notes that were remove as a side-effect */
535
536         return *xml_change;
537 }
538
539 MidiModel::DiffCommand::NoteChange
540 MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
541 {
542         XMLProperty* prop;
543         NoteChange change;
544         unsigned int note;
545         unsigned int channel;
546         unsigned int velocity;
547         Evoral::MusicalTime time;
548         Evoral::MusicalTime length;
549
550         if ((prop = xml_change->property("property")) != 0) {
551                 change.property = (Property) string_2_enum (prop->value(), change.property);
552         } else {
553                 fatal << "!!!" << endmsg;
554                 /*NOTREACHED*/
555         }
556
557         if ((prop = xml_change->property ("old")) != 0) {
558                 istringstream old_str (prop->value());
559                 if (change.property == StartTime || change.property == Length) {
560                         old_str >> change.old_time;
561                 } else {
562                         int integer_value_so_that_istream_does_the_right_thing;
563                         old_str >> integer_value_so_that_istream_does_the_right_thing;
564                         change.old_value = integer_value_so_that_istream_does_the_right_thing;
565                 }
566         } else {
567                 fatal << "!!!" << endmsg;
568                 /*NOTREACHED*/
569         }
570
571         if ((prop = xml_change->property ("new")) != 0) {
572                 istringstream new_str (prop->value());
573                 if (change.property == StartTime || change.property == Length) {
574                         new_str >> change.new_time;
575                 } else {
576                         int integer_value_so_that_istream_does_the_right_thing;
577                         new_str >> integer_value_so_that_istream_does_the_right_thing;
578                         change.new_value = integer_value_so_that_istream_does_the_right_thing;
579                 }
580         } else {
581                 fatal << "!!!" << endmsg;
582                 /*NOTREACHED*/
583         }
584
585         if (change.property != NoteNumber) {
586                 if ((prop = xml_change->property("note")) != 0) {
587                         istringstream note_str(prop->value());
588                         note_str >> note;
589                 } else {
590                         warning << "note information missing note value" << endmsg;
591                         note = 127;
592                 }
593         } else {
594                 note = change.new_value;
595         }
596
597         if (change.property != Channel) {
598                 if ((prop = xml_change->property("channel")) != 0) {
599                         istringstream channel_str(prop->value());
600                         channel_str >> channel;
601                 } else {
602                         warning << "note information missing channel" << endmsg;
603                         channel = 0;
604                 }
605         } else {
606                 channel = change.new_value;
607         }
608
609         if (change.property != StartTime) {
610                 if ((prop = xml_change->property("time")) != 0) {
611                         istringstream time_str(prop->value());
612                         time_str >> time;
613                 } else {
614                         warning << "note information missing time" << endmsg;
615                         time = 0;
616                 }
617         } else {
618                 time = change.new_time;
619         }
620
621         if (change.property != Length) {
622                 if ((prop = xml_change->property("length")) != 0) {
623                         istringstream length_str(prop->value());
624                         length_str >> length;
625                 } else {
626                         warning << "note information missing length" << endmsg;
627                         length = 1;
628                 }
629         } else {
630                 length = change.new_time;
631         }
632
633         if (change.property != Velocity) {
634                 if ((prop = xml_change->property("velocity")) != 0) {
635                         istringstream velocity_str(prop->value());
636                         velocity_str >> velocity;
637                 } else {
638                         warning << "note information missing velocity" << endmsg;
639                         velocity = 127;
640                 }
641         } else {
642                 velocity = change.new_value;
643         }
644
645         /* we must point at the instance of the note that is actually in the model.
646            so go look for it ...
647         */
648
649         NotePtr new_note (new Evoral::Note<TimeType> (channel, time, length, note, velocity));
650
651         change.note = _model->find_note (new_note);
652
653         if (!change.note) {
654                 warning << "MIDI note " << *new_note << " not found in model - programmers should investigate this" << endmsg;
655                 /* use the actual new note */
656                 change.note = new_note;
657         }
658
659         return change;
660 }
661
662 int
663 MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
664 {
665         if (diff_command.name() != string(DIFF_COMMAND_ELEMENT)) {
666                 return 1;
667         }
668
669         /* additions */
670
671         _added_notes.clear();
672         XMLNode* added_notes = diff_command.child(ADDED_NOTES_ELEMENT);
673         if (added_notes) {
674                 XMLNodeList notes = added_notes->children();
675                 transform(notes.begin(), notes.end(), back_inserter(_added_notes),
676                           boost::bind (&DiffCommand::unmarshal_note, this, _1));
677         }
678
679
680         /* removals */
681
682         _removed_notes.clear();
683         XMLNode* removed_notes = diff_command.child(REMOVED_NOTES_ELEMENT);
684         if (removed_notes) {
685                 XMLNodeList notes = removed_notes->children();
686                 transform(notes.begin(), notes.end(), back_inserter(_removed_notes),
687                           boost::bind (&DiffCommand::unmarshal_note, this, _1));
688         }
689
690
691         /* changes */
692
693         _changes.clear();
694
695         XMLNode* changed_notes = diff_command.child(DIFF_NOTES_ELEMENT);
696
697         if (changed_notes) {
698                 XMLNodeList notes = changed_notes->children();
699                 transform (notes.begin(), notes.end(), back_inserter(_changes),
700                            boost::bind (&DiffCommand::unmarshal_change, this, _1));
701
702         }
703
704         /* side effect removals caused by changes */
705
706         side_effect_removals.clear();
707
708         XMLNode* side_effect_notes = diff_command.child(SIDE_EFFECT_REMOVALS_ELEMENT);
709
710         if (side_effect_notes) {
711                 XMLNodeList notes = side_effect_notes->children();
712                 for (XMLNodeList::iterator n = notes.begin(); n != notes.end(); ++n) {
713                         side_effect_removals.insert (unmarshal_note (*n));
714                 }
715         }
716
717         return 0;
718 }
719
720 XMLNode&
721 MidiModel::DiffCommand::get_state ()
722 {
723         XMLNode* diff_command = new XMLNode(DIFF_COMMAND_ELEMENT);
724         diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
725
726         XMLNode* changes = diff_command->add_child(DIFF_NOTES_ELEMENT);
727         for_each(_changes.begin(), _changes.end(), 
728                  boost::bind (
729                          boost::bind (&XMLNode::add_child_nocopy, changes, _1),
730                          boost::bind (&DiffCommand::marshal_change, this, _1)));
731
732         XMLNode* added_notes = diff_command->add_child(ADDED_NOTES_ELEMENT);
733         for_each(_added_notes.begin(), _added_notes.end(), 
734                  boost::bind(
735                          boost::bind (&XMLNode::add_child_nocopy, added_notes, _1),
736                          boost::bind (&DiffCommand::marshal_note, this, _1)));
737
738         XMLNode* removed_notes = diff_command->add_child(REMOVED_NOTES_ELEMENT);
739         for_each(_removed_notes.begin(), _removed_notes.end(), 
740                  boost::bind (
741                          boost::bind (&XMLNode::add_child_nocopy, removed_notes, _1),
742                          boost::bind (&DiffCommand::marshal_note, this, _1)));
743
744         /* if this command had side-effects, store that state too 
745          */
746
747         if (!side_effect_removals.empty()) {
748                 XMLNode* side_effect_notes = diff_command->add_child(SIDE_EFFECT_REMOVALS_ELEMENT);
749                 for_each(side_effect_removals.begin(), side_effect_removals.end(), 
750                          boost::bind (
751                                  boost::bind (&XMLNode::add_child_nocopy, side_effect_notes, _1),
752                                  boost::bind (&DiffCommand::marshal_note, this, _1)));
753         }
754
755         return *diff_command;
756 }
757
758
759 /** Write all of the model to a MidiSource (i.e. save the model).
760  * This is different from manually using read to write to a source in that
761  * note off events are written regardless of the track mode.  This is so the
762  * user can switch a recorded track (with note durations from some instrument)
763  * to percussive, save, reload, then switch it back to sustained without
764  * destroying the original note durations.
765  *
766  * Similarly, control events are written without interpolation (as with the
767  * `Discrete' mode).
768  */
769 bool
770 MidiModel::write_to (boost::shared_ptr<MidiSource> source)
771 {
772         ReadLock lock(read_lock());
773
774         const bool old_percussive = percussive();
775         set_percussive(false);
776
777         source->drop_model();
778         source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position());
779
780         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
781                 source->append_event_unlocked_beats(*i);
782         }
783
784         set_percussive(old_percussive);
785         source->mark_streaming_write_completed();
786
787         set_edited(false);
788         
789         return true;
790 }
791
792 /** very similar to ::write_to() but writes to the model's own
793     existing midi_source, without making it call MidiSource::drop_model().
794     the caller is a MidiSource that needs to catch up with the state
795     of the model.
796 */
797 bool
798 MidiModel::sync_to_source ()
799 {
800         ReadLock lock(read_lock());
801
802         const bool old_percussive = percussive();
803         set_percussive(false);
804
805         _midi_source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position());
806
807         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
808                 _midi_source->append_event_unlocked_beats(*i);
809         }
810
811         set_percussive (old_percussive);
812         _midi_source->mark_streaming_write_completed ();
813
814         set_edited (false);
815         
816         return true;
817 }
818
819 /** Write part or all of the model to a MidiSource (i.e. save the model).
820  * This is different from manually using read to write to a source in that
821  * note off events are written regardless of the track mode.  This is so the
822  * user can switch a recorded track (with note durations from some instrument)
823  * to percussive, save, reload, then switch it back to sustained without
824  * destroying the original note durations.
825  */
826 bool
827 MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::MusicalTime begin_time, Evoral::MusicalTime end_time)
828 {
829         ReadLock lock(read_lock());
830         MidiStateTracker mst;
831         Evoral::MusicalTime extra_note_on_time = end_time;
832
833         const bool old_percussive = percussive();
834         set_percussive(false);
835
836         source->drop_model();
837         source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position());
838
839         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
840                 const Evoral::Event<Evoral::MusicalTime>& ev (*i);
841
842                 if (ev.time() >= begin_time && ev.time() < end_time) {
843
844                         const Evoral::MIDIEvent<Evoral::MusicalTime>* mev = 
845                                 static_cast<const Evoral::MIDIEvent<Evoral::MusicalTime>* > (&ev);
846
847                         if (!mev) {
848                                 continue;
849                         }
850
851
852                         if (mev->is_note_off()) {
853
854                                 if (!mst.active (mev->note(), mev->channel())) {
855
856                                         /* add a note-on at the start of the range we're writing
857                                            to the file. velocity is just an arbitary reasonable value.
858                                         */
859
860                                         Evoral::MIDIEvent<Evoral::MusicalTime> on (mev->event_type(), extra_note_on_time, 3, 0, true);
861                                         on.set_type (mev->type());
862                                         on.set_note (mev->note());
863                                         on.set_channel (mev->channel());
864                                         on.set_velocity (mev->velocity());
865
866                                         cerr << "Add note on for odd note off, note = " << (int) on.note() << endl;
867                                         source->append_event_unlocked_beats (on);
868                                         mst.add (on.note(), on.channel());
869                                         mst.dump (cerr);
870                                         extra_note_on_time += 1.0/128.0;
871                                 }
872
873                                 cerr << "MIDI Note off (note = " << (int) mev->note() << endl;
874                                 source->append_event_unlocked_beats (*i);
875                                 mst.remove (mev->note(), mev->channel());
876                                 mst.dump (cerr);
877
878                         } else if (mev->is_note_on()) {
879                                 cerr << "MIDI Note on (note = " << (int) mev->note() << endl;
880                                 mst.add (mev->note(), mev->channel());
881                                 source->append_event_unlocked_beats(*i);
882                                 mst.dump (cerr);
883                         } else {
884                                 cerr << "MIDI other event type\n";
885                                 source->append_event_unlocked_beats(*i);
886                         }
887                 }
888         }
889
890         mst.resolve_notes (*source, end_time);
891
892         set_percussive(old_percussive);
893         source->mark_streaming_write_completed();
894
895         set_edited(false);
896
897         return true;
898 }
899
900 XMLNode&
901 MidiModel::get_state()
902 {
903         XMLNode *node = new XMLNode("MidiModel");
904         return *node;
905 }
906
907 Evoral::Sequence<MidiModel::TimeType>::NotePtr
908 MidiModel::find_note (NotePtr other)
909 {
910         Notes::iterator l = notes().lower_bound(other);
911
912         if (l != notes().end()) {
913                 for (; (*l)->time() == other->time(); ++l) {
914                         /* NB: compare note contents, not note pointers.
915                            If "other" was a ptr to a note already in
916                            the model, we wouldn't be looking for it,
917                            would we now?
918                         */
919                         if (**l == *other) {
920                                 return *l;
921                         }
922                 }
923         }
924
925         return NotePtr();
926 }
927
928 /** Lock and invalidate the source.
929  * This should be used by commands and editing things
930  */
931 MidiModel::WriteLock
932 MidiModel::edit_lock()
933 {
934         Glib::Mutex::Lock* source_lock = new Glib::Mutex::Lock(_midi_source->mutex());
935         _midi_source->invalidate(); // Release cached iterator's read lock on model
936         return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
937 }
938
939 /** Lock just the model, the source lock must already be held.
940  * This should only be called from libardour/evoral places
941  */
942 MidiModel::WriteLock
943 MidiModel::write_lock()
944 {
945         assert(!_midi_source->mutex().trylock());
946         return WriteLock(new WriteLockImpl(NULL, _lock, _control_lock));
947 }
948
949 int
950 MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
951 {
952         using namespace Evoral;
953
954         if (_writing || insert_merge_policy() == InsertMergeRelax) {
955                 return 0;
956         }
957
958         DiffCommand* cmd = static_cast<DiffCommand*>(arg);
959
960         TimeType sa = note->time();
961         TimeType ea  = note->end_time();
962
963         const Pitches& p (pitches (note->channel()));
964         NotePtr search_note(new Note<TimeType>(0, 0, 0, note->note()));
965         set<NotePtr> to_be_deleted;
966         bool set_note_length = false;
967         bool set_note_time = false;
968         TimeType note_time = note->time();
969         TimeType note_length = note->length();
970
971         for (Pitches::const_iterator i = p.lower_bound (search_note); 
972              i != p.end() && (*i)->note() == note->note(); ++i) {
973
974                 TimeType sb = (*i)->time();
975                 TimeType eb = (*i)->end_time();
976                 OverlapType overlap = OverlapNone;
977
978                 if ((sb > sa) && (eb <= ea)) {
979                         overlap = OverlapInternal;
980                 } else if ((eb >= sa) && (eb <= ea)) {
981                         overlap = OverlapStart;
982                 } else if ((sb > sa) && (sb <= ea)) {
983                         overlap = OverlapEnd;
984                 } else if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
985                         overlap = OverlapExternal;
986                 } else {
987                         /* no overlap */
988                         continue;
989                 }
990
991                 if (insert_merge_policy() == InsertMergeReject) {
992                         return -1;
993                 }
994
995                 switch (overlap) {
996                 case OverlapStart:
997                         cerr << "OverlapStart\n";
998                         /* existing note covers start of new note */
999                         switch (insert_merge_policy()) {
1000                         case InsertMergeReplace:
1001                                 to_be_deleted.insert (*i);
1002                                 break;
1003                         case InsertMergeTruncateExisting:
1004                                 if (cmd) {
1005                                         cmd->change (*i, DiffCommand::Length, (note->time() - (*i)->time()));
1006                                 }
1007                                 (*i)->set_length (note->time() - (*i)->time());
1008                                 break;
1009                         case InsertMergeTruncateAddition:
1010                                 set_note_time = true;
1011                                 set_note_length = true;
1012                                 note_time = (*i)->time() + (*i)->length();
1013                                 note_length = min (note_length, (*i)->length() - ((*i)->end_time() - note->time()));
1014                                 break;
1015                         case InsertMergeExtend:
1016                                 if (cmd) {
1017                                         cmd->change ((*i), DiffCommand::Length, note->end_time() - (*i)->time());
1018                                 } 
1019                                 (*i)->set_length (note->end_time() - (*i)->time());
1020                                 return -1; /* do not add the new note */
1021                                 break;
1022                         default:
1023                                 /*NOTREACHED*/
1024                                 /* stupid gcc */
1025                                 break;
1026                         }
1027                         break;
1028
1029                 case OverlapEnd:
1030                         cerr << "OverlapEnd\n";
1031                         /* existing note covers end of new note */
1032                         switch (insert_merge_policy()) {
1033                         case InsertMergeReplace:
1034                                 to_be_deleted.insert (*i);
1035                                 break;
1036
1037                         case InsertMergeTruncateExisting:
1038                                 /* resetting the start time of the existing note
1039                                    is a problem because of time ordering.
1040                                 */
1041                                 break;
1042
1043                         case InsertMergeTruncateAddition:
1044                                 set_note_length = true;
1045                                 note_length = min (note_length, ((*i)->time() - note->time()));
1046                                 break;
1047
1048                         case InsertMergeExtend:
1049                                 /* we can't reset the time of the existing note because
1050                                    that will corrupt time ordering. So remove the
1051                                    existing note and change the position/length
1052                                    of the new note (which has not been added yet)
1053                                 */
1054                                 to_be_deleted.insert (*i);
1055                                 set_note_length = true;
1056                                 note_length = min (note_length, (*i)->end_time() - note->time());
1057                                 break;
1058                         default:
1059                                 /*NOTREACHED*/
1060                                 /* stupid gcc */
1061                                 break;
1062                         }
1063                         break;
1064
1065                 case OverlapExternal:
1066                         cerr << "OverlapExt\n";
1067                         /* existing note overlaps all the new note */
1068                         switch (insert_merge_policy()) {
1069                         case InsertMergeReplace:
1070                                 to_be_deleted.insert (*i);
1071                                 break;
1072                         case InsertMergeTruncateExisting:
1073                         case InsertMergeTruncateAddition:
1074                         case InsertMergeExtend:
1075                                 /* cannot add in this case */
1076                                 return -1;
1077                         default:
1078                                 /*NOTREACHED*/
1079                                 /* stupid gcc */
1080                                 break;
1081                         }
1082                         break;
1083
1084                 case OverlapInternal:
1085                         cerr << "OverlapInt\n";
1086                         /* new note fully overlaps an existing note */
1087                         switch (insert_merge_policy()) {
1088                         case InsertMergeReplace:
1089                         case InsertMergeTruncateExisting:
1090                         case InsertMergeTruncateAddition:
1091                         case InsertMergeExtend:
1092                                 /* delete the existing note, the new one will cover it */
1093                                 to_be_deleted.insert (*i);
1094                                 break;
1095                         default:
1096                                 /*NOTREACHED*/
1097                                 /* stupid gcc */
1098                                 break;
1099                         }
1100                         break;
1101
1102                 default:
1103                         /*NOTREACHED*/
1104                         /* stupid gcc */
1105                         break;
1106                 }
1107         }
1108
1109         for (set<NotePtr>::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
1110                 remove_note_unlocked (*i);
1111
1112                 if (cmd) {
1113                         cmd->side_effect_remove (*i);
1114                 }
1115         }
1116
1117         if (set_note_time) {
1118                 if (cmd) {
1119                         cmd->change (note, DiffCommand::StartTime, note_time);
1120                 } 
1121                 note->set_time (note_time);
1122         }
1123
1124         if (set_note_length) {
1125                 if (cmd) {
1126                         cmd->change (note, DiffCommand::Length, note_length);
1127                 } 
1128                 note->set_length (note_length);
1129         }
1130
1131         return 0;
1132 }
1133
1134 InsertMergePolicy
1135 MidiModel::insert_merge_policy () const 
1136 {
1137         /* XXX ultimately this should be a per-track or even per-model policy */
1138
1139         return _midi_source->session().config.get_insert_merge_policy();
1140 }
1141                         
1142 void
1143 MidiModel::set_midi_source (MidiSource* s)
1144 {
1145         if (_midi_source) {
1146                 _midi_source->invalidate ();
1147         }
1148
1149         _midi_source_connections.drop_connections ();
1150
1151         _midi_source = s;
1152
1153         _midi_source->InterpolationChanged.connect_same_thread (
1154                 _midi_source_connections, boost::bind (&MidiModel::source_interpolation_changed, this, _1, _2)
1155                 );
1156 }
1157
1158 /** The source has signalled that the interpolation style for a parameter has changed.  In order to
1159  *  keep MidiSource and ControlList interpolation state the same, we pass this change onto the
1160  *  appropriate ControlList.
1161  *
1162  *  The idea is that MidiSource and the MidiModel's ControlList states are kept in sync, and the
1163  *  MidiSource's InterpolationChanged signal is listened to by the GUI.
1164  */
1165 void
1166 MidiModel::source_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
1167 {
1168         Glib::Mutex::Lock lm (_control_lock);
1169         control(p)->list()->set_interpolation (s);
1170 }
1171
1172 /** A ControlList has signalled that its interpolation style has changed.  Again, in order to keep
1173  *  MidiSource and ControlList interpolation state in sync, we pass this change onto our MidiSource.
1174  */
1175 void
1176 MidiModel::control_list_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
1177 {
1178         _midi_source->set_interpolation_of (p, s);
1179 }
1180
1181 boost::shared_ptr<Evoral::Control>
1182 MidiModel::control_factory (Evoral::Parameter const & p)
1183 {
1184         boost::shared_ptr<Evoral::Control> c = Automatable::control_factory (p);
1185
1186         /* Set up newly created control's lists to the appropriate interpolation state
1187            from our source.
1188         */
1189
1190         assert (_midi_source);
1191
1192         c->list()->set_interpolation (_midi_source->interpolation_of (p));
1193
1194         return c;
1195 }