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