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