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