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