add note IDs and use them for looking up notes during a history rebuild. NOTE: INVALI...
[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         {
386                 ostringstream id_str(ios::ate);
387                 id_str << int(note->id());
388                 xml_note->add_property("id", id_str.str());
389         }
390
391         {
392                 ostringstream note_str(ios::ate);
393                 note_str << int(note->note());
394                 xml_note->add_property("note", note_str.str());
395         }
396
397         {
398                 ostringstream channel_str(ios::ate);
399                 channel_str << int(note->channel());
400                 xml_note->add_property("channel", channel_str.str());
401         }
402
403         {
404                 ostringstream time_str(ios::ate);
405                 time_str << note->time();
406                 xml_note->add_property("time", time_str.str());
407         }
408
409         {
410                 ostringstream length_str(ios::ate);
411                 length_str << note->length();
412                 xml_note->add_property("length", length_str.str());
413         }
414
415         {
416                 ostringstream velocity_str(ios::ate);
417                 velocity_str << (unsigned int) note->velocity();
418                 xml_note->add_property("velocity", velocity_str.str());
419         }
420
421         return *xml_note;
422 }
423
424 Evoral::Sequence<MidiModel::TimeType>::NotePtr
425 MidiModel::DiffCommand::unmarshal_note(XMLNode *xml_note)
426 {
427         unsigned int note;
428         XMLProperty* prop;
429         unsigned int channel;
430         unsigned int time;
431         unsigned int length;
432         unsigned int velocity;
433         gint id;
434
435         if ((prop = xml_note->property("id")) != 0) {
436                 istringstream id_str(prop->value());
437                 id_str >> id;
438         } else {
439                 error << "note information missing ID value" << endmsg;
440                 id = -1;
441         }
442
443         if ((prop = xml_note->property("note")) != 0) {
444                 istringstream note_str(prop->value());
445                 note_str >> note;
446         } else {
447                 warning << "note information missing note value" << endmsg;
448                 note = 127;
449         }
450
451         if ((prop = xml_note->property("channel")) != 0) {
452                 istringstream channel_str(prop->value());
453                 channel_str >> channel;
454         } else {
455                 warning << "note information missing channel" << endmsg;
456                 channel = 0;
457         }
458
459         if ((prop = xml_note->property("time")) != 0) {
460                 istringstream time_str(prop->value());
461                 time_str >> time;
462         } else {
463                 warning << "note information missing time" << endmsg;
464                 time = 0;
465         }
466
467         if ((prop = xml_note->property("length")) != 0) {
468                 istringstream length_str(prop->value());
469                 length_str >> length;
470         } else {
471                 warning << "note information missing length" << endmsg;
472                 length = 1;
473         }
474
475         if ((prop = xml_note->property("velocity")) != 0) {
476                 istringstream velocity_str(prop->value());
477                 velocity_str >> velocity;
478         } else {
479                 warning << "note information missing velocity" << endmsg;
480                 velocity = 127;
481         }
482
483         NotePtr note_ptr(new Evoral::Note<TimeType>(channel, time, length, note, velocity));
484         note_ptr->set_id (id);
485
486         return note_ptr;
487 }
488
489 XMLNode&
490 MidiModel::DiffCommand::marshal_change(const NoteChange& change)
491 {
492         XMLNode* xml_change = new XMLNode("Change");
493
494         /* first, the change itself */
495
496         xml_change->add_property ("property", enum_2_string (change.property));
497
498         {
499                 ostringstream old_value_str (ios::ate);
500                 if (change.property == StartTime || change.property == Length) {
501                         old_value_str << change.old_time;
502                 } else {
503                         old_value_str << (unsigned int) change.old_value;
504                 }
505                 xml_change->add_property ("old", old_value_str.str());
506         }
507
508         {
509                 ostringstream new_value_str (ios::ate);
510                 if (change.property == StartTime || change.property == Length) {
511                         new_value_str << change.new_time;
512                 } else {
513                         new_value_str << (unsigned int) change.new_value;
514                 }
515                 xml_change->add_property ("new", new_value_str.str());
516         }
517
518         ostringstream id_str;
519         id_str << change.note->id();
520         xml_change->add_property ("id", id_str.str());
521
522         return *xml_change;
523 }
524
525 MidiModel::DiffCommand::NoteChange
526 MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
527 {
528         XMLProperty* prop;
529         NoteChange change;
530
531         if ((prop = xml_change->property("property")) != 0) {
532                 change.property = (Property) string_2_enum (prop->value(), change.property);
533         } else {
534                 fatal << "!!!" << endmsg;
535                 /*NOTREACHED*/
536         }
537
538         if ((prop = xml_change->property ("id")) == 0) {
539                 error << _("No NoteID found for note property change - ignored") << endmsg;
540                 return change;
541         }
542
543         gint note_id = atoi (prop->value().c_str());
544
545         if ((prop = xml_change->property ("old")) != 0) {
546                 istringstream old_str (prop->value());
547                 if (change.property == StartTime || change.property == Length) {
548                         old_str >> change.old_time;
549                 } else {
550                         int integer_value_so_that_istream_does_the_right_thing;
551                         old_str >> integer_value_so_that_istream_does_the_right_thing;
552                         change.old_value = integer_value_so_that_istream_does_the_right_thing;
553                 }
554         } else {
555                 fatal << "!!!" << endmsg;
556                 /*NOTREACHED*/
557         }
558
559         if ((prop = xml_change->property ("new")) != 0) {
560                 istringstream new_str (prop->value());
561                 if (change.property == StartTime || change.property == Length) {
562                         new_str >> change.new_time;
563                 } else {
564                         int integer_value_so_that_istream_does_the_right_thing;
565                         new_str >> integer_value_so_that_istream_does_the_right_thing;
566                         change.new_value = integer_value_so_that_istream_does_the_right_thing;
567                 }
568         } else {
569                 fatal << "!!!" << endmsg;
570                 /*NOTREACHED*/
571         }
572
573         /* we must point at the instance of the note that is actually in the model.
574            so go look for it ...
575         */
576
577         change.note = _model->find_note (note_id);
578
579         if (!change.note) {
580                 warning << "MIDI note #" << note_id << " not found in model - programmers should investigate this" << endmsg;
581                 return change;
582         }
583
584         return change;
585 }
586
587 int
588 MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
589 {
590         if (diff_command.name() != string(DIFF_COMMAND_ELEMENT)) {
591                 return 1;
592         }
593
594         /* additions */
595
596         _added_notes.clear();
597         XMLNode* added_notes = diff_command.child(ADDED_NOTES_ELEMENT);
598         if (added_notes) {
599                 XMLNodeList notes = added_notes->children();
600                 transform(notes.begin(), notes.end(), back_inserter(_added_notes),
601                           boost::bind (&DiffCommand::unmarshal_note, this, _1));
602         }
603
604
605         /* removals */
606
607         _removed_notes.clear();
608         XMLNode* removed_notes = diff_command.child(REMOVED_NOTES_ELEMENT);
609         if (removed_notes) {
610                 XMLNodeList notes = removed_notes->children();
611                 transform(notes.begin(), notes.end(), back_inserter(_removed_notes),
612                           boost::bind (&DiffCommand::unmarshal_note, this, _1));
613         }
614
615
616         /* changes */
617
618         _changes.clear();
619
620         XMLNode* changed_notes = diff_command.child(DIFF_NOTES_ELEMENT);
621
622         if (changed_notes) {
623                 XMLNodeList notes = changed_notes->children();
624                 transform (notes.begin(), notes.end(), back_inserter(_changes),
625                            boost::bind (&DiffCommand::unmarshal_change, this, _1));
626
627         }
628
629         /* side effect removals caused by changes */
630
631         side_effect_removals.clear();
632
633         XMLNode* side_effect_notes = diff_command.child(SIDE_EFFECT_REMOVALS_ELEMENT);
634
635         if (side_effect_notes) {
636                 XMLNodeList notes = side_effect_notes->children();
637                 for (XMLNodeList::iterator n = notes.begin(); n != notes.end(); ++n) {
638                         side_effect_removals.insert (unmarshal_note (*n));
639                 }
640         }
641
642         return 0;
643 }
644
645 XMLNode&
646 MidiModel::DiffCommand::get_state ()
647 {
648         XMLNode* diff_command = new XMLNode(DIFF_COMMAND_ELEMENT);
649         diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
650
651         XMLNode* changes = diff_command->add_child(DIFF_NOTES_ELEMENT);
652         for_each(_changes.begin(), _changes.end(), 
653                  boost::bind (
654                          boost::bind (&XMLNode::add_child_nocopy, changes, _1),
655                          boost::bind (&DiffCommand::marshal_change, this, _1)));
656
657         XMLNode* added_notes = diff_command->add_child(ADDED_NOTES_ELEMENT);
658         for_each(_added_notes.begin(), _added_notes.end(), 
659                  boost::bind(
660                          boost::bind (&XMLNode::add_child_nocopy, added_notes, _1),
661                          boost::bind (&DiffCommand::marshal_note, this, _1)));
662
663         XMLNode* removed_notes = diff_command->add_child(REMOVED_NOTES_ELEMENT);
664         for_each(_removed_notes.begin(), _removed_notes.end(), 
665                  boost::bind (
666                          boost::bind (&XMLNode::add_child_nocopy, removed_notes, _1),
667                          boost::bind (&DiffCommand::marshal_note, this, _1)));
668
669         /* if this command had side-effects, store that state too 
670          */
671
672         if (!side_effect_removals.empty()) {
673                 XMLNode* side_effect_notes = diff_command->add_child(SIDE_EFFECT_REMOVALS_ELEMENT);
674                 for_each(side_effect_removals.begin(), side_effect_removals.end(), 
675                          boost::bind (
676                                  boost::bind (&XMLNode::add_child_nocopy, side_effect_notes, _1),
677                                  boost::bind (&DiffCommand::marshal_note, this, _1)));
678         }
679
680         return *diff_command;
681 }
682
683
684 /** Write all of the model to a MidiSource (i.e. save the model).
685  * This is different from manually using read to write to a source in that
686  * note off events are written regardless of the track mode.  This is so the
687  * user can switch a recorded track (with note durations from some instrument)
688  * to percussive, save, reload, then switch it back to sustained without
689  * destroying the original note durations.
690  *
691  * Similarly, control events are written without interpolation (as with the
692  * `Discrete' mode).
693  */
694 bool
695 MidiModel::write_to (boost::shared_ptr<MidiSource> source)
696 {
697         ReadLock lock(read_lock());
698
699         const bool old_percussive = percussive();
700         set_percussive(false);
701
702         source->drop_model();
703         source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position());
704
705         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
706                 source->append_event_unlocked_beats(*i);
707         }
708
709         set_percussive(old_percussive);
710         source->mark_streaming_write_completed();
711
712         set_edited(false);
713         
714         return true;
715 }
716
717 /** very similar to ::write_to() but writes to the model's own
718     existing midi_source, without making it call MidiSource::drop_model().
719     the caller is a MidiSource that needs to catch up with the state
720     of the model.
721 */
722 bool
723 MidiModel::sync_to_source ()
724 {
725         ReadLock lock(read_lock());
726
727         const bool old_percussive = percussive();
728         set_percussive(false);
729
730         _midi_source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position());
731
732         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
733                 _midi_source->append_event_unlocked_beats(*i);
734         }
735
736         set_percussive (old_percussive);
737         _midi_source->mark_streaming_write_completed ();
738
739         set_edited (false);
740         
741         return true;
742 }
743
744 /** Write part or all of the model to a MidiSource (i.e. save the model).
745  * This is different from manually using read to write to a source in that
746  * note off events are written regardless of the track mode.  This is so the
747  * user can switch a recorded track (with note durations from some instrument)
748  * to percussive, save, reload, then switch it back to sustained without
749  * destroying the original note durations.
750  */
751 bool
752 MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::MusicalTime begin_time, Evoral::MusicalTime end_time)
753 {
754         ReadLock lock(read_lock());
755         MidiStateTracker mst;
756         Evoral::MusicalTime extra_note_on_time = end_time;
757
758         const bool old_percussive = percussive();
759         set_percussive(false);
760
761         source->drop_model();
762         source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position());
763
764         for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
765                 const Evoral::Event<Evoral::MusicalTime>& ev (*i);
766
767                 if (ev.time() >= begin_time && ev.time() < end_time) {
768
769                         const Evoral::MIDIEvent<Evoral::MusicalTime>* mev = 
770                                 static_cast<const Evoral::MIDIEvent<Evoral::MusicalTime>* > (&ev);
771
772                         if (!mev) {
773                                 continue;
774                         }
775
776
777                         if (mev->is_note_off()) {
778
779                                 if (!mst.active (mev->note(), mev->channel())) {
780
781                                         /* add a note-on at the start of the range we're writing
782                                            to the file. velocity is just an arbitary reasonable value.
783                                         */
784
785                                         Evoral::MIDIEvent<Evoral::MusicalTime> on (mev->event_type(), extra_note_on_time, 3, 0, true);
786                                         on.set_type (mev->type());
787                                         on.set_note (mev->note());
788                                         on.set_channel (mev->channel());
789                                         on.set_velocity (mev->velocity());
790
791                                         cerr << "Add note on for odd note off, note = " << (int) on.note() << endl;
792                                         source->append_event_unlocked_beats (on);
793                                         mst.add (on.note(), on.channel());
794                                         mst.dump (cerr);
795                                         extra_note_on_time += 1.0/128.0;
796                                 }
797
798                                 cerr << "MIDI Note off (note = " << (int) mev->note() << endl;
799                                 source->append_event_unlocked_beats (*i);
800                                 mst.remove (mev->note(), mev->channel());
801                                 mst.dump (cerr);
802
803                         } else if (mev->is_note_on()) {
804                                 cerr << "MIDI Note on (note = " << (int) mev->note() << endl;
805                                 mst.add (mev->note(), mev->channel());
806                                 source->append_event_unlocked_beats(*i);
807                                 mst.dump (cerr);
808                         } else {
809                                 cerr << "MIDI other event type\n";
810                                 source->append_event_unlocked_beats(*i);
811                         }
812                 }
813         }
814
815         mst.resolve_notes (*source, end_time);
816
817         set_percussive(old_percussive);
818         source->mark_streaming_write_completed();
819
820         set_edited(false);
821
822         return true;
823 }
824
825 XMLNode&
826 MidiModel::get_state()
827 {
828         XMLNode *node = new XMLNode("MidiModel");
829         return *node;
830 }
831
832 Evoral::Sequence<MidiModel::TimeType>::NotePtr
833 MidiModel::find_note (NotePtr other)
834 {
835         Notes::iterator l = notes().lower_bound(other);
836
837         if (l != notes().end()) {
838                 for (; (*l)->time() == other->time(); ++l) {
839                         /* NB: compare note contents, not note pointers.
840                            If "other" was a ptr to a note already in
841                            the model, we wouldn't be looking for it,
842                            would we now?
843                         */
844                         if (**l == *other) {
845                                 return *l;
846                         }
847                 }
848         }
849
850         return NotePtr();
851 }
852
853 Evoral::Sequence<MidiModel::TimeType>::NotePtr
854 MidiModel::find_note (gint note_id)
855 {
856         /* used only for looking up notes when reloading history from disk,
857            so we don't care about performance *too* much.
858         */
859
860         for (Notes::iterator l = notes().begin(); l != notes().end(); ++l) {
861                 if ((*l)->id() == note_id) {
862                         return *l;
863                 }
864         }
865
866         return NotePtr();
867 }
868
869 /** Lock and invalidate the source.
870  * This should be used by commands and editing things
871  */
872 MidiModel::WriteLock
873 MidiModel::edit_lock()
874 {
875         Glib::Mutex::Lock* source_lock = new Glib::Mutex::Lock(_midi_source->mutex());
876         _midi_source->invalidate(); // Release cached iterator's read lock on model
877         return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
878 }
879
880 /** Lock just the model, the source lock must already be held.
881  * This should only be called from libardour/evoral places
882  */
883 MidiModel::WriteLock
884 MidiModel::write_lock()
885 {
886         assert(!_midi_source->mutex().trylock());
887         return WriteLock(new WriteLockImpl(NULL, _lock, _control_lock));
888 }
889
890 int
891 MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
892 {
893         using namespace Evoral;
894
895         if (_writing || insert_merge_policy() == InsertMergeRelax) {
896                 return 0;
897         }
898
899         DiffCommand* cmd = static_cast<DiffCommand*>(arg);
900
901         TimeType sa = note->time();
902         TimeType ea  = note->end_time();
903
904         const Pitches& p (pitches (note->channel()));
905         NotePtr search_note(new Note<TimeType>(0, 0, 0, note->note()));
906         set<NotePtr> to_be_deleted;
907         bool set_note_length = false;
908         bool set_note_time = false;
909         TimeType note_time = note->time();
910         TimeType note_length = note->length();
911
912         for (Pitches::const_iterator i = p.lower_bound (search_note); 
913              i != p.end() && (*i)->note() == note->note(); ++i) {
914
915                 TimeType sb = (*i)->time();
916                 TimeType eb = (*i)->end_time();
917                 OverlapType overlap = OverlapNone;
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                 if (insert_merge_policy() == InsertMergeReject) {
933                         return -1;
934                 }
935
936                 switch (overlap) {
937                 case OverlapStart:
938                         cerr << "OverlapStart\n";
939                         /* existing note covers start of new note */
940                         switch (insert_merge_policy()) {
941                         case InsertMergeReplace:
942                                 to_be_deleted.insert (*i);
943                                 break;
944                         case InsertMergeTruncateExisting:
945                                 if (cmd) {
946                                         cmd->change (*i, DiffCommand::Length, (note->time() - (*i)->time()));
947                                 }
948                                 (*i)->set_length (note->time() - (*i)->time());
949                                 break;
950                         case InsertMergeTruncateAddition:
951                                 set_note_time = true;
952                                 set_note_length = true;
953                                 note_time = (*i)->time() + (*i)->length();
954                                 note_length = min (note_length, (*i)->length() - ((*i)->end_time() - note->time()));
955                                 break;
956                         case InsertMergeExtend:
957                                 if (cmd) {
958                                         cmd->change ((*i), DiffCommand::Length, note->end_time() - (*i)->time());
959                                 } 
960                                 (*i)->set_length (note->end_time() - (*i)->time());
961                                 return -1; /* do not add the new note */
962                                 break;
963                         default:
964                                 /*NOTREACHED*/
965                                 /* stupid gcc */
966                                 break;
967                         }
968                         break;
969
970                 case OverlapEnd:
971                         cerr << "OverlapEnd\n";
972                         /* existing note covers end of new note */
973                         switch (insert_merge_policy()) {
974                         case InsertMergeReplace:
975                                 to_be_deleted.insert (*i);
976                                 break;
977
978                         case InsertMergeTruncateExisting:
979                                 /* resetting the start time of the existing note
980                                    is a problem because of time ordering.
981                                 */
982                                 break;
983
984                         case InsertMergeTruncateAddition:
985                                 set_note_length = true;
986                                 note_length = min (note_length, ((*i)->time() - note->time()));
987                                 break;
988
989                         case InsertMergeExtend:
990                                 /* we can't reset the time of the existing note because
991                                    that will corrupt time ordering. So remove the
992                                    existing note and change the position/length
993                                    of the new note (which has not been added yet)
994                                 */
995                                 to_be_deleted.insert (*i);
996                                 set_note_length = true;
997                                 note_length = min (note_length, (*i)->end_time() - note->time());
998                                 break;
999                         default:
1000                                 /*NOTREACHED*/
1001                                 /* stupid gcc */
1002                                 break;
1003                         }
1004                         break;
1005
1006                 case OverlapExternal:
1007                         cerr << "OverlapExt\n";
1008                         /* existing note overlaps all the new note */
1009                         switch (insert_merge_policy()) {
1010                         case InsertMergeReplace:
1011                                 to_be_deleted.insert (*i);
1012                                 break;
1013                         case InsertMergeTruncateExisting:
1014                         case InsertMergeTruncateAddition:
1015                         case InsertMergeExtend:
1016                                 /* cannot add in this case */
1017                                 return -1;
1018                         default:
1019                                 /*NOTREACHED*/
1020                                 /* stupid gcc */
1021                                 break;
1022                         }
1023                         break;
1024
1025                 case OverlapInternal:
1026                         cerr << "OverlapInt\n";
1027                         /* new note fully overlaps an existing note */
1028                         switch (insert_merge_policy()) {
1029                         case InsertMergeReplace:
1030                         case InsertMergeTruncateExisting:
1031                         case InsertMergeTruncateAddition:
1032                         case InsertMergeExtend:
1033                                 /* delete the existing note, the new one will cover it */
1034                                 to_be_deleted.insert (*i);
1035                                 break;
1036                         default:
1037                                 /*NOTREACHED*/
1038                                 /* stupid gcc */
1039                                 break;
1040                         }
1041                         break;
1042
1043                 default:
1044                         /*NOTREACHED*/
1045                         /* stupid gcc */
1046                         break;
1047                 }
1048         }
1049
1050         for (set<NotePtr>::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
1051                 remove_note_unlocked (*i);
1052
1053                 if (cmd) {
1054                         cmd->side_effect_remove (*i);
1055                 }
1056         }
1057
1058         if (set_note_time) {
1059                 if (cmd) {
1060                         cmd->change (note, DiffCommand::StartTime, note_time);
1061                 } 
1062                 note->set_time (note_time);
1063         }
1064
1065         if (set_note_length) {
1066                 if (cmd) {
1067                         cmd->change (note, DiffCommand::Length, note_length);
1068                 } 
1069                 note->set_length (note_length);
1070         }
1071
1072         return 0;
1073 }
1074
1075 InsertMergePolicy
1076 MidiModel::insert_merge_policy () const 
1077 {
1078         /* XXX ultimately this should be a per-track or even per-model policy */
1079
1080         return _midi_source->session().config.get_insert_merge_policy();
1081 }
1082                         
1083 void
1084 MidiModel::set_midi_source (MidiSource* s)
1085 {
1086         if (_midi_source) {
1087                 _midi_source->invalidate ();
1088         }
1089
1090         _midi_source_connections.drop_connections ();
1091
1092         _midi_source = s;
1093
1094         _midi_source->InterpolationChanged.connect_same_thread (
1095                 _midi_source_connections, boost::bind (&MidiModel::source_interpolation_changed, this, _1, _2)
1096                 );
1097 }
1098
1099 /** The source has signalled that the interpolation style for a parameter has changed.  In order to
1100  *  keep MidiSource and ControlList interpolation state the same, we pass this change onto the
1101  *  appropriate ControlList.
1102  *
1103  *  The idea is that MidiSource and the MidiModel's ControlList states are kept in sync, and the
1104  *  MidiSource's InterpolationChanged signal is listened to by the GUI.
1105  */
1106 void
1107 MidiModel::source_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
1108 {
1109         Glib::Mutex::Lock lm (_control_lock);
1110         control(p)->list()->set_interpolation (s);
1111 }
1112
1113 /** A ControlList has signalled that its interpolation style has changed.  Again, in order to keep
1114  *  MidiSource and ControlList interpolation state in sync, we pass this change onto our MidiSource.
1115  */
1116 void
1117 MidiModel::control_list_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s)
1118 {
1119         _midi_source->set_interpolation_of (p, s);
1120 }
1121
1122 boost::shared_ptr<Evoral::Control>
1123 MidiModel::control_factory (Evoral::Parameter const & p)
1124 {
1125         boost::shared_ptr<Evoral::Control> c = Automatable::control_factory (p);
1126
1127         /* Set up newly created control's lists to the appropriate interpolation state
1128            from our source.
1129         */
1130
1131         assert (_midi_source);
1132
1133         c->list()->set_interpolation (_midi_source->interpolation_of (p));
1134
1135         return c;
1136 }