ardour
midi_model.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2007 Paul Davis
3  Author: David 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 <algorithm>
22 #include <iostream>
23 #include <set>
24 #include <stdexcept>
25 #include <stdint.h>
26 
27 #include "pbd/compose.h"
28 #include "pbd/enumwriter.h"
29 #include "pbd/error.h"
30 
31 #include "evoral/Control.hpp"
32 
33 #include "midi++/events.h"
34 
37 #include "ardour/midi_model.h"
38 #include "ardour/midi_source.h"
40 #include "ardour/session.h"
41 #include "ardour/types.h"
42 
43 #include "i18n.h"
44 
45 using namespace std;
46 using namespace ARDOUR;
47 using namespace PBD;
48 
49 MidiModel::MidiModel (boost::shared_ptr<MidiSource> s)
50  : AutomatableSequence<TimeType>(s->session())
51 {
52  set_midi_source (s);
53 }
54 
63 {
65  assert (ms);
66 
67  return new NoteDiffCommand (ms->model(), name);
68 }
69 
73 {
75  assert (ms);
76 
77  return new SysExDiffCommand (ms->model(), name);
78 }
79 
83 {
85  assert (ms);
86 
87  return new PatchChangeDiffCommand (ms->model(), name);
88 }
89 
90 
96 void
98 {
99  session.begin_reversible_command(cmd->name());
100  (*cmd)();
101  session.commit_reversible_command(cmd);
102  set_edited(true);
103 }
104 
110 void
112 {
113  (*cmd)();
114  session.add_command(cmd);
115  set_edited(true);
116 }
117 
118 /************** DIFF COMMAND ********************/
119 
120 #define NOTE_DIFF_COMMAND_ELEMENT "NoteDiffCommand"
121 #define DIFF_NOTES_ELEMENT "ChangedNotes"
122 #define ADDED_NOTES_ELEMENT "AddedNotes"
123 #define REMOVED_NOTES_ELEMENT "RemovedNotes"
124 #define SIDE_EFFECT_REMOVALS_ELEMENT "SideEffectRemovals"
125 #define SYSEX_DIFF_COMMAND_ELEMENT "SysExDiffCommand"
126 #define DIFF_SYSEXES_ELEMENT "ChangedSysExes"
127 #define PATCH_CHANGE_DIFF_COMMAND_ELEMENT "PatchChangeDiffCommand"
128 #define ADDED_PATCH_CHANGES_ELEMENT "AddedPatchChanges"
129 #define REMOVED_PATCH_CHANGES_ELEMENT "RemovedPatchChanges"
130 #define DIFF_PATCH_CHANGES_ELEMENT "ChangedPatchChanges"
131 
133  : Command (name)
134  , _model (m)
135  , _name (name)
136 {
137  assert(_model);
138 }
139 
141  : DiffCommand (m, "")
142 {
143  assert (_model);
145 }
146 
147 void
149 {
150  _removed_notes.remove(note);
151  _added_notes.push_back(note);
152 }
153 
154 void
156 {
157  _added_notes.remove(note);
158  _removed_notes.push_back(note);
159 }
160 
161 void
163 {
164  side_effect_removals.insert (note);
165 }
166 
167 Variant
169 {
170  switch (prop) {
171  case NoteNumber:
172  return Variant(note->note());
173  case Velocity:
174  return Variant(note->velocity());
175  case Channel:
176  return Variant(note->channel());
177  case StartTime:
178  return Variant(note->time());
179  case Length:
180  return Variant(note->length());
181  }
182 
183  return Variant();
184 }
185 
188 {
189  switch (prop) {
190  case NoteNumber:
191  case Velocity:
192  case Channel:
193  return Variant::INT;
194  case StartTime:
195  case Length:
196  return Variant::BEATS;
197  }
198 
199  return Variant::NOTHING;
200 }
201 
202 void
204  Property prop,
205  const Variant& new_value)
206 {
207  assert (note);
208 
209  const NoteChange change = {
210  prop, note, 0, get_value(note, prop), new_value
211  };
212 
213  if (change.old_value == new_value) {
214  return;
215  }
216 
217  _changes.push_back (change);
218 }
219 
222 {
223  if (this == &other) {
224  return *this;
225  }
226 
227  if (_model != other._model) {
228  return *this;
229  }
230 
231  _added_notes.insert (_added_notes.end(), other._added_notes.begin(), other._added_notes.end());
232  _removed_notes.insert (_removed_notes.end(), other._removed_notes.begin(), other._removed_notes.end());
233  side_effect_removals.insert (other.side_effect_removals.begin(), other.side_effect_removals.end());
234  _changes.insert (_changes.end(), other._changes.begin(), other._changes.end());
235 
236  return *this;
237 }
238 
239 void
241 {
242  {
243  MidiModel::WriteLock lock(_model->edit_lock());
244 
245  for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
246  if (!_model->add_note_unlocked(*i)) {
247  /* failed to add it, so don't leave it in the removed list, to
248  avoid apparent errors on undo.
249  */
250  _removed_notes.remove (*i);
251  }
252  }
253 
254  for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) {
255  _model->remove_note_unlocked(*i);
256  }
257 
258  /* notes we modify in a way that requires remove-then-add to maintain ordering */
259  set<NotePtr> temporary_removals;
260 
261  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
262  Property prop = i->property;
263 
264  if (!i->note) {
265  /* note found during deserialization, so try
266  again now that the model state is different.
267  */
268  i->note = _model->find_note (i->note_id);
269  assert (i->note);
270  }
271 
272  switch (prop) {
273  case NoteNumber:
274  if (temporary_removals.find (i->note) == temporary_removals.end()) {
275  _model->remove_note_unlocked (i->note);
276  temporary_removals.insert (i->note);
277  }
278  i->note->set_note (i->new_value.get_int());
279  break;
280 
281  case StartTime:
282  if (temporary_removals.find (i->note) == temporary_removals.end()) {
283  _model->remove_note_unlocked (i->note);
284  temporary_removals.insert (i->note);
285  }
286  i->note->set_time (i->new_value.get_beats());
287  break;
288 
289  case Channel:
290  if (temporary_removals.find (i->note) == temporary_removals.end()) {
291  _model->remove_note_unlocked (i->note);
292  temporary_removals.insert (i->note);
293  }
294  i->note->set_channel (i->new_value.get_int());
295  break;
296 
297  /* no remove-then-add required for these properties, since we do not index them
298  */
299 
300  case Velocity:
301  i->note->set_velocity (i->new_value.get_int());
302  break;
303 
304  case Length:
305  i->note->set_length (i->new_value.get_beats());
306  break;
307 
308  }
309  }
310 
311  for (set<NotePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
312  NoteDiffCommand side_effects (model(), "side effects");
313  if (_model->add_note_unlocked (*i, &side_effects)) {
314  /* The note was re-added ok */
315  *this += side_effects;
316  } else {
317  /* The note that we removed earlier could not be re-added. This change record
318  must say that the note was removed. We'll keep the changes we made, though,
319  as if the note is re-added by the undo the changes must also be undone.
320  */
321  _removed_notes.push_back (*i);
322  }
323  }
324 
325  if (!side_effect_removals.empty()) {
326  cerr << "SER: \n";
327  for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
328  cerr << "\t" << *i << ' ' << **i << endl;
329  }
330  }
331  }
332 
333  _model->ContentsChanged(); /* EMIT SIGNAL */
334 }
335 
336 void
338 {
339  {
340  MidiModel::WriteLock lock(_model->edit_lock());
341 
342  for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
343  _model->remove_note_unlocked(*i);
344  }
345 
346  /* Apply changes first; this is important in the case of a note change which
347  resulted in the note being removed by the overlap checker. If the overlap
348  checker removes a note, it will be in _removed_notes. We are going to re-add
349  it below, but first we must undo the changes we made so that the overlap
350  checker doesn't refuse the re-add.
351  */
352 
353  /* notes we modify in a way that requires remove-then-add to maintain ordering */
354  set<NotePtr> temporary_removals;
355 
356 
357  /* lazily discover any affected notes that were not discovered when
358  * loading the history because of deletions, etc.
359  */
360 
361  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
362  if (!i->note) {
363  i->note = _model->find_note (i->note_id);
364  assert (i->note);
365  }
366  }
367 
368  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
369  Property prop = i->property;
370 
371  switch (prop) {
372  case NoteNumber:
373  if (temporary_removals.find (i->note) == temporary_removals.end() &&
374  find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
375 
376  /* We only need to mark this note for re-add if (a) we haven't
377  already marked it and (b) it isn't on the _removed_notes
378  list (which means that it has already been removed and it
379  will be re-added anyway)
380  */
381 
382  _model->remove_note_unlocked (i->note);
383  temporary_removals.insert (i->note);
384  }
385  i->note->set_note (i->old_value.get_int());
386  break;
387 
388  case StartTime:
389  if (temporary_removals.find (i->note) == temporary_removals.end() &&
390  find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
391 
392  /* See above ... */
393 
394  _model->remove_note_unlocked (i->note);
395  temporary_removals.insert (i->note);
396  }
397  i->note->set_time (i->old_value.get_beats());
398  break;
399 
400  case Channel:
401  if (temporary_removals.find (i->note) == temporary_removals.end() &&
402  find (_removed_notes.begin(), _removed_notes.end(), i->note) == _removed_notes.end()) {
403 
404  /* See above ... */
405 
406  _model->remove_note_unlocked (i->note);
407  temporary_removals.insert (i->note);
408  }
409  i->note->set_channel (i->old_value.get_int());
410  break;
411 
412  /* no remove-then-add required for these properties, since we do not index them
413  */
414 
415  case Velocity:
416  i->note->set_velocity (i->old_value.get_int());
417  break;
418 
419  case Length:
420  i->note->set_length (i->old_value.get_beats());
421  break;
422  }
423  }
424 
425  for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) {
426  _model->add_note_unlocked(*i);
427  }
428 
429  for (set<NotePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
430  _model->add_note_unlocked (*i);
431  }
432 
433  /* finally add back notes that were removed by the "do". we don't care
434  about side effects here since the model should be back to its original
435  state once this is done.
436  */
437 
438  for (set<NotePtr>::iterator i = side_effect_removals.begin(); i != side_effect_removals.end(); ++i) {
439  _model->add_note_unlocked (*i);
440  }
441  }
442 
443  _model->ContentsChanged(); /* EMIT SIGNAL */
444 }
445 
446 XMLNode&
448 {
449  XMLNode* xml_note = new XMLNode("note");
450 
451  {
452  ostringstream id_str(ios::ate);
453  id_str << int(note->id());
454  xml_note->add_property("id", id_str.str());
455  }
456 
457  {
458  ostringstream note_str(ios::ate);
459  note_str << int(note->note());
460  xml_note->add_property("note", note_str.str());
461  }
462 
463  {
464  ostringstream channel_str(ios::ate);
465  channel_str << int(note->channel());
466  xml_note->add_property("channel", channel_str.str());
467  }
468 
469  {
470  ostringstream time_str(ios::ate);
471  time_str << note->time();
472  xml_note->add_property("time", time_str.str());
473  }
474 
475  {
476  ostringstream length_str(ios::ate);
477  length_str << note->length();
478  xml_note->add_property("length", length_str.str());
479  }
480 
481  {
482  ostringstream velocity_str(ios::ate);
483  velocity_str << (unsigned int) note->velocity();
484  xml_note->add_property("velocity", velocity_str.str());
485  }
486 
487  return *xml_note;
488 }
489 
492 {
493  unsigned int note;
494  XMLProperty* prop;
495  unsigned int channel;
496  MidiModel::TimeType time;
498  unsigned int velocity;
499  gint id;
500 
501  if ((prop = xml_note->property("id")) != 0) {
502  istringstream id_str(prop->value());
503  id_str >> id;
504  } else {
505  error << "note information missing ID value" << endmsg;
506  id = -1;
507  }
508 
509  if ((prop = xml_note->property("note")) != 0) {
510  istringstream note_str(prop->value());
511  note_str >> note;
512  } else {
513  warning << "note information missing note value" << endmsg;
514  note = 127;
515  }
516 
517  if ((prop = xml_note->property("channel")) != 0) {
518  istringstream channel_str(prop->value());
519  channel_str >> channel;
520  } else {
521  warning << "note information missing channel" << endmsg;
522  channel = 0;
523  }
524 
525  if ((prop = xml_note->property("time")) != 0) {
526  istringstream time_str(prop->value());
527  time_str >> time;
528  } else {
529  warning << "note information missing time" << endmsg;
530  time = MidiModel::TimeType();
531  }
532 
533  if ((prop = xml_note->property("length")) != 0) {
534  istringstream length_str(prop->value());
535  length_str >> length;
536  } else {
537  warning << "note information missing length" << endmsg;
538  length = MidiModel::TimeType(1);
539  }
540 
541  if ((prop = xml_note->property("velocity")) != 0) {
542  istringstream velocity_str(prop->value());
543  velocity_str >> velocity;
544  } else {
545  warning << "note information missing velocity" << endmsg;
546  velocity = 127;
547  }
548 
549  NotePtr note_ptr(new Evoral::Note<TimeType>(channel, time, length, note, velocity));
550  note_ptr->set_id (id);
551 
552  return note_ptr;
553 }
554 
555 XMLNode&
557 {
558  XMLNode* xml_change = new XMLNode("Change");
559 
560  /* first, the change itself */
561 
562  xml_change->add_property ("property", enum_2_string (change.property));
563 
564  {
565  ostringstream old_value_str (ios::ate);
566  if (change.property == StartTime || change.property == Length) {
567  old_value_str << change.old_value.get_beats();
568  } else {
569  old_value_str << change.old_value.get_int();
570  }
571  xml_change->add_property ("old", old_value_str.str());
572  }
573 
574  {
575  ostringstream new_value_str (ios::ate);
576  if (change.property == StartTime || change.property == Length) {
577  new_value_str << change.new_value.get_beats();
578  } else {
579  new_value_str << change.new_value.get_int();
580  }
581  xml_change->add_property ("new", new_value_str.str());
582  }
583 
584  ostringstream id_str;
585  if (change.note) {
586  id_str << change.note->id();
587  xml_change->add_property ("id", id_str.str());
588  } else if (change.note_id) {
589  warning << _("Change has no note, using note ID") << endmsg;
590  id_str << change.note_id;
591  xml_change->add_property ("id", id_str.str());
592  } else {
593  error << _("Change has no note or note ID") << endmsg;
594  }
595 
596  return *xml_change;
597 }
598 
601 {
602  XMLProperty* prop;
603  NoteChange change;
604  change.note_id = 0;
605 
606  if ((prop = xml_change->property("property")) != 0) {
607  change.property = (Property) string_2_enum (prop->value(), change.property);
608  } else {
609  fatal << "!!!" << endmsg;
610  abort(); /*NOTREACHED*/
611  }
612 
613  if ((prop = xml_change->property ("id")) == 0) {
614  error << _("No NoteID found for note property change - ignored") << endmsg;
615  return change;
616  }
617 
618  gint note_id = atoi (prop->value().c_str());
619 
620  if ((prop = xml_change->property ("old")) != 0) {
621  istringstream old_str (prop->value());
622  if (change.property == StartTime || change.property == Length) {
623  Evoral::Beats old_time;
624  old_str >> old_time;
625  change.old_value = old_time;
626  } else {
627  int integer_value_so_that_istream_does_the_right_thing;
628  old_str >> integer_value_so_that_istream_does_the_right_thing;
629  change.old_value = integer_value_so_that_istream_does_the_right_thing;
630  }
631  } else {
632  fatal << "!!!" << endmsg;
633  abort(); /*NOTREACHED*/
634  }
635 
636  if ((prop = xml_change->property ("new")) != 0) {
637  istringstream new_str (prop->value());
638  if (change.property == StartTime || change.property == Length) {
639  Evoral::Beats new_time;
640  new_str >> new_time;
641  change.new_value = Variant(new_time);
642  } else {
643  int integer_value_so_that_istream_does_the_right_thing;
644  new_str >> integer_value_so_that_istream_does_the_right_thing;
645  change.new_value = integer_value_so_that_istream_does_the_right_thing;
646  }
647  } else {
648  fatal << "!!!" << endmsg;
649  abort(); /*NOTREACHED*/
650  }
651 
652  /* we must point at the instance of the note that is actually in the model.
653  so go look for it ... it may not be there (it could have been
654  deleted in a later operation, so store the note id so that we can
655  look it up again later).
656  */
657 
658  change.note = _model->find_note (note_id);
659  change.note_id = note_id;
660 
661  return change;
662 }
663 
664 int
665 MidiModel::NoteDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
666 {
667  if (diff_command.name() != string (NOTE_DIFF_COMMAND_ELEMENT)) {
668  return 1;
669  }
670 
671  /* additions */
672 
673  _added_notes.clear();
674  XMLNode* added_notes = diff_command.child(ADDED_NOTES_ELEMENT);
675  if (added_notes) {
676  XMLNodeList notes = added_notes->children();
677  transform(notes.begin(), notes.end(), back_inserter(_added_notes),
678  boost::bind (&NoteDiffCommand::unmarshal_note, this, _1));
679  }
680 
681 
682  /* removals */
683 
684  _removed_notes.clear();
685  XMLNode* removed_notes = diff_command.child(REMOVED_NOTES_ELEMENT);
686  if (removed_notes) {
687  XMLNodeList notes = removed_notes->children();
688  transform(notes.begin(), notes.end(), back_inserter(_removed_notes),
689  boost::bind (&NoteDiffCommand::unmarshal_note, this, _1));
690  }
691 
692 
693  /* changes */
694 
695  _changes.clear();
696 
697  XMLNode* changed_notes = diff_command.child(DIFF_NOTES_ELEMENT);
698 
699  if (changed_notes) {
700  XMLNodeList notes = changed_notes->children();
701  transform (notes.begin(), notes.end(), back_inserter(_changes),
702  boost::bind (&NoteDiffCommand::unmarshal_change, this, _1));
703 
704  }
705 
706  /* side effect removals caused by changes */
707 
708  side_effect_removals.clear();
709 
710  XMLNode* side_effect_notes = diff_command.child(SIDE_EFFECT_REMOVALS_ELEMENT);
711 
712  if (side_effect_notes) {
713  XMLNodeList notes = side_effect_notes->children();
714  for (XMLNodeList::iterator n = notes.begin(); n != notes.end(); ++n) {
715  side_effect_removals.insert (unmarshal_note (*n));
716  }
717  }
718 
719  return 0;
720 }
721 
722 XMLNode&
724 {
725  XMLNode* diff_command = new XMLNode (NOTE_DIFF_COMMAND_ELEMENT);
726  diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
727 
728  XMLNode* changes = diff_command->add_child(DIFF_NOTES_ELEMENT);
729  for_each(_changes.begin(), _changes.end(),
730  boost::bind (
731  boost::bind (&XMLNode::add_child_nocopy, changes, _1),
732  boost::bind (&NoteDiffCommand::marshal_change, this, _1)));
733 
734  XMLNode* added_notes = diff_command->add_child(ADDED_NOTES_ELEMENT);
735  for_each(_added_notes.begin(), _added_notes.end(),
736  boost::bind(
737  boost::bind (&XMLNode::add_child_nocopy, added_notes, _1),
738  boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
739 
740  XMLNode* removed_notes = diff_command->add_child(REMOVED_NOTES_ELEMENT);
741  for_each(_removed_notes.begin(), _removed_notes.end(),
742  boost::bind (
743  boost::bind (&XMLNode::add_child_nocopy, removed_notes, _1),
744  boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
745 
746  /* if this command had side-effects, store that state too
747  */
748 
749  if (!side_effect_removals.empty()) {
750  XMLNode* side_effect_notes = diff_command->add_child(SIDE_EFFECT_REMOVALS_ELEMENT);
751  for_each(side_effect_removals.begin(), side_effect_removals.end(),
752  boost::bind (
753  boost::bind (&XMLNode::add_child_nocopy, side_effect_notes, _1),
754  boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
755  }
756 
757  return *diff_command;
758 }
759 
761  : DiffCommand (m, "")
762 {
763  assert (_model);
765 }
766 
767 void
769 {
770  Change change;
771 
772  change.sysex = s;
773  change.property = Time;
774  change.old_time = s->time ();
775  change.new_time = new_time;
776 
777  _changes.push_back (change);
778 }
779 
780 void
782 {
783  {
784  MidiModel::WriteLock lock (_model->edit_lock ());
785 
786  for (list<SysExPtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
787  _model->remove_sysex_unlocked (*i);
788  }
789 
790  /* find any sysex events that were missing when unmarshalling */
791 
792  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
793  if (!i->sysex) {
794  i->sysex = _model->find_sysex (i->sysex_id);
795  assert (i->sysex);
796  }
797  }
798 
799  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
800  switch (i->property) {
801  case Time:
802  i->sysex->set_time (i->new_time);
803  }
804  }
805  }
806 
807  _model->ContentsChanged (); /* EMIT SIGNAL */
808 }
809 
810 void
812 {
813  {
814  MidiModel::WriteLock lock (_model->edit_lock ());
815 
816  for (list<SysExPtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
817  _model->add_sysex_unlocked (*i);
818  }
819 
820  /* find any sysex events that were missing when unmarshalling */
821 
822  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
823  if (!i->sysex) {
824  i->sysex = _model->find_sysex (i->sysex_id);
825  assert (i->sysex);
826  }
827  }
828 
829  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
830  switch (i->property) {
831  case Time:
832  i->sysex->set_time (i->old_time);
833  break;
834  }
835  }
836 
837  }
838 
839  _model->ContentsChanged(); /* EMIT SIGNAL */
840 }
841 
842 void
844 {
845  _removed.push_back(sysex);
846 }
847 
848 XMLNode&
850 {
851  XMLNode* xml_change = new XMLNode ("Change");
852 
853  /* first, the change itself */
854 
855  xml_change->add_property ("property", enum_2_string (change.property));
856 
857  {
858  ostringstream old_value_str (ios::ate);
859  old_value_str << change.old_time;
860  xml_change->add_property ("old", old_value_str.str());
861  }
862 
863  {
864  ostringstream new_value_str (ios::ate);
865  new_value_str << change.new_time;
866  xml_change->add_property ("new", new_value_str.str());
867  }
868 
869  ostringstream id_str;
870  id_str << change.sysex->id();
871  xml_change->add_property ("id", id_str.str());
872 
873  return *xml_change;
874 }
875 
878 {
879  XMLProperty* prop;
880  Change change;
881 
882  if ((prop = xml_change->property ("property")) != 0) {
883  change.property = (Property) string_2_enum (prop->value(), change.property);
884  } else {
885  fatal << "!!!" << endmsg;
886  abort(); /*NOTREACHED*/
887  }
888 
889  if ((prop = xml_change->property ("id")) == 0) {
890  error << _("No SysExID found for sys-ex property change - ignored") << endmsg;
891  return change;
892  }
893 
894  gint sysex_id = atoi (prop->value().c_str());
895 
896  if ((prop = xml_change->property ("old")) != 0) {
897  istringstream old_str (prop->value());
898  old_str >> change.old_time;
899  } else {
900  fatal << "!!!" << endmsg;
901  abort(); /*NOTREACHED*/
902  }
903 
904  if ((prop = xml_change->property ("new")) != 0) {
905  istringstream new_str (prop->value());
906  new_str >> change.new_time;
907  } else {
908  fatal << "!!!" << endmsg;
909  abort(); /*NOTREACHED*/
910  }
911 
912  /* we must point at the instance of the sysex that is actually in the model.
913  so go look for it ...
914  */
915 
916  change.sysex = _model->find_sysex (sysex_id);
917  change.sysex_id = sysex_id;
918 
919  return change;
920 }
921 
922 int
923 MidiModel::SysExDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
924 {
925  if (diff_command.name() != string (SYSEX_DIFF_COMMAND_ELEMENT)) {
926  return 1;
927  }
928 
929  /* changes */
930 
931  _changes.clear();
932 
933  XMLNode* changed_sysexes = diff_command.child (DIFF_SYSEXES_ELEMENT);
934 
935  if (changed_sysexes) {
936  XMLNodeList sysexes = changed_sysexes->children();
937  transform (sysexes.begin(), sysexes.end(), back_inserter (_changes),
938  boost::bind (&SysExDiffCommand::unmarshal_change, this, _1));
939 
940  }
941 
942  return 0;
943 }
944 
945 XMLNode&
947 {
948  XMLNode* diff_command = new XMLNode (SYSEX_DIFF_COMMAND_ELEMENT);
949  diff_command->add_property ("midi-source", _model->midi_source()->id().to_s());
950 
951  XMLNode* changes = diff_command->add_child(DIFF_SYSEXES_ELEMENT);
952  for_each (_changes.begin(), _changes.end(),
953  boost::bind (
954  boost::bind (&XMLNode::add_child_nocopy, changes, _1),
955  boost::bind (&SysExDiffCommand::marshal_change, this, _1)));
956 
957  return *diff_command;
958 }
959 
961  : DiffCommand (m, name)
962 {
963  assert (_model);
964 }
965 
967  : DiffCommand (m, "")
968 {
969  assert (_model);
971 }
972 
973 void
975 {
976  _added.push_back (p);
977 }
978 
979 void
981 {
982  _removed.push_back (p);
983 }
984 
985 void
987 {
988  Change c;
989  c.property = Time;
990  c.patch = patch;
991  c.old_time = patch->time ();
992  c.new_time = t;
993 
994  _changes.push_back (c);
995 }
996 
997 void
999 {
1000  Change c;
1001  c.property = Channel;
1002  c.patch = patch;
1003  c.old_channel = patch->channel ();
1004  c.new_channel = channel;
1005  c.patch_id = patch->id();
1006 
1007  _changes.push_back (c);
1008 }
1009 
1010 void
1012 {
1013  Change c;
1014  c.property = Program;
1015  c.patch = patch;
1016  c.old_program = patch->program ();
1017  c.new_program = program;
1018  c.patch_id = patch->id();
1019 
1020  _changes.push_back (c);
1021 }
1022 
1023 void
1025 {
1026  Change c;
1027  c.property = Bank;
1028  c.patch = patch;
1029  c.old_bank = patch->bank ();
1030  c.new_bank = bank;
1031 
1032  _changes.push_back (c);
1033 }
1034 
1035 void
1037 {
1038  {
1039  MidiModel::WriteLock lock (_model->edit_lock ());
1040 
1041  for (list<PatchChangePtr>::iterator i = _added.begin(); i != _added.end(); ++i) {
1042  _model->add_patch_change_unlocked (*i);
1043  }
1044 
1045  for (list<PatchChangePtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
1046  _model->remove_patch_change_unlocked (*i);
1047  }
1048 
1049  /* find any patch change events that were missing when unmarshalling */
1050 
1051  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1052  if (!i->patch) {
1053  i->patch = _model->find_patch_change (i->patch_id);
1054  assert (i->patch);
1055  }
1056  }
1057 
1058  set<PatchChangePtr> temporary_removals;
1059 
1060  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1061  switch (i->property) {
1062  case Time:
1063  if (temporary_removals.find (i->patch) == temporary_removals.end()) {
1064  _model->remove_patch_change_unlocked (i->patch);
1065  temporary_removals.insert (i->patch);
1066  }
1067  i->patch->set_time (i->new_time);
1068  break;
1069 
1070  case Channel:
1071  i->patch->set_channel (i->new_channel);
1072  break;
1073 
1074  case Program:
1075  i->patch->set_program (i->new_program);
1076  break;
1077 
1078  case Bank:
1079  i->patch->set_bank (i->new_bank);
1080  break;
1081  }
1082  }
1083 
1084  for (set<PatchChangePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
1085  _model->add_patch_change_unlocked (*i);
1086  }
1087  }
1088 
1089  _model->ContentsChanged (); /* EMIT SIGNAL */
1090 }
1091 
1092 void
1094 {
1095  {
1096  MidiModel::WriteLock lock (_model->edit_lock());
1097 
1098  for (list<PatchChangePtr>::iterator i = _added.begin(); i != _added.end(); ++i) {
1099  _model->remove_patch_change_unlocked (*i);
1100  }
1101 
1102  for (list<PatchChangePtr>::iterator i = _removed.begin(); i != _removed.end(); ++i) {
1103  _model->add_patch_change_unlocked (*i);
1104  }
1105 
1106  /* find any patch change events that were missing when unmarshalling */
1107 
1108  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1109  if (!i->patch) {
1110  i->patch = _model->find_patch_change (i->patch_id);
1111  assert (i->patch);
1112  }
1113  }
1114 
1115  set<PatchChangePtr> temporary_removals;
1116 
1117  for (ChangeList::iterator i = _changes.begin(); i != _changes.end(); ++i) {
1118  switch (i->property) {
1119  case Time:
1120  if (temporary_removals.find (i->patch) == temporary_removals.end()) {
1121  _model->remove_patch_change_unlocked (i->patch);
1122  temporary_removals.insert (i->patch);
1123  }
1124  i->patch->set_time (i->old_time);
1125  break;
1126 
1127  case Channel:
1128  i->patch->set_channel (i->old_channel);
1129  break;
1130 
1131  case Program:
1132  i->patch->set_program (i->old_program);
1133  break;
1134 
1135  case Bank:
1136  i->patch->set_bank (i->old_bank);
1137  break;
1138  }
1139  }
1140 
1141  for (set<PatchChangePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
1142  _model->add_patch_change_unlocked (*i);
1143  }
1144 
1145  }
1146 
1147  _model->ContentsChanged (); /* EMIT SIGNAL */
1148 }
1149 
1150 XMLNode &
1152 {
1153  XMLNode* n = new XMLNode ("patch-change");
1154 
1155  {
1156  ostringstream s (ios::ate);
1157  s << int (p->id ());
1158  n->add_property ("id", s.str());
1159  }
1160 
1161  {
1162  ostringstream s (ios::ate);
1163  s << p->time ();
1164  n->add_property ("time", s.str ());
1165  }
1166 
1167  {
1168  ostringstream s (ios::ate);
1169  s << int (p->channel ());
1170  n->add_property ("channel", s.str ());
1171  }
1172 
1173  {
1174  ostringstream s (ios::ate);
1175  s << int (p->program ());
1176  n->add_property ("program", s.str ());
1177  }
1178 
1179  {
1180  ostringstream s (ios::ate);
1181  s << int (p->bank ());
1182  n->add_property ("bank", s.str ());
1183  }
1184 
1185  return *n;
1186 }
1187 
1188 XMLNode&
1190 {
1191  XMLNode* n = new XMLNode (X_("Change"));
1192 
1193  n->add_property (X_("property"), enum_2_string (c.property));
1194 
1195  {
1196  ostringstream s (ios::ate);
1197  if (c.property == Time) {
1198  s << c.old_time;
1199  } else if (c.property == Channel) {
1200  s << c.old_channel;
1201  } else if (c.property == Program) {
1202  s << int (c.old_program);
1203  } else if (c.property == Bank) {
1204  s << c.old_bank;
1205  }
1206 
1207  n->add_property (X_("old"), s.str ());
1208  }
1209 
1210  {
1211  ostringstream s (ios::ate);
1212 
1213  if (c.property == Time) {
1214  s << c.new_time;
1215  } else if (c.property == Channel) {
1216  s << c.new_channel;
1217  } else if (c.property == Program) {
1218  s << int (c.new_program);
1219  } else if (c.property == Bank) {
1220  s << c.new_bank;
1221  }
1222 
1223  n->add_property (X_("new"), s.str ());
1224  }
1225 
1226  {
1227  ostringstream s;
1228  s << c.patch->id ();
1229  n->add_property ("id", s.str ());
1230  }
1231 
1232  return *n;
1233 }
1234 
1237 {
1238  XMLProperty* prop;
1239  XMLProperty* prop_id;
1240  Evoral::event_id_t id = 0;
1241  Evoral::Beats time = Evoral::Beats();
1242  int channel = 0;
1243  int program = 0;
1244  int bank = 0;
1245 
1246  if ((prop_id = n->property ("id")) != 0) {
1247  istringstream s (prop_id->value());
1248  s >> id;
1249  }
1250 
1251  if ((prop = n->property ("time")) != 0) {
1252  istringstream s (prop->value ());
1253  s >> time;
1254  }
1255 
1256  if ((prop = n->property ("channel")) != 0) {
1257  istringstream s (prop->value ());
1258  s >> channel;
1259  }
1260 
1261  if ((prop = n->property ("program")) != 0) {
1262  istringstream s (prop->value ());
1263  s >> program;
1264  }
1265 
1266  if ((prop = n->property ("bank")) != 0) {
1267  istringstream s (prop->value ());
1268  s >> bank;
1269  }
1270 
1271  PatchChangePtr p (new Evoral::PatchChange<TimeType> (time, channel, program, bank));
1272  assert(prop_id);
1273  p->set_id (id);
1274  return p;
1275 }
1276 
1279 {
1280  XMLProperty* prop;
1281  Change c;
1282  int an_int;
1283 
1284  prop = n->property ("property");
1285  assert (prop);
1286  c.property = (Property) string_2_enum (prop->value(), c.property);
1287 
1288  prop = n->property ("id");
1289  assert (prop);
1290  Evoral::event_id_t const id = atoi (prop->value().c_str());
1291 
1292  /* we need to load via an int intermediate for all properties that are
1293  actually uint8_t (char/byte).
1294  */
1295 
1296  prop = n->property ("old");
1297  assert (prop);
1298  {
1299  istringstream s (prop->value ());
1300  if (c.property == Time) {
1301  s >> c.old_time;
1302  } else if (c.property == Channel) {
1303  s >> an_int;
1304  c.old_channel = an_int;
1305  } else if (c.property == Program) {
1306  s >> an_int;
1307  c.old_program = an_int;
1308  } else if (c.property == Bank) {
1309  s >> an_int;
1310  c.old_bank = an_int;
1311  }
1312  }
1313 
1314  prop = n->property ("new");
1315  assert (prop);
1316  {
1317  istringstream s (prop->value ());
1318 
1319  if (c.property == Time) {
1320  s >> c.new_time;
1321  } else if (c.property == Channel) {
1322  s >> an_int;
1323  c.new_channel = an_int;
1324  } else if (c.property == Program) {
1325  s >> an_int;
1326  c.new_program = an_int;
1327  } else if (c.property == Bank) {
1328  s >> an_int;
1329  c.new_bank = an_int;
1330  }
1331  }
1332 
1333  c.patch = _model->find_patch_change (id);
1334  c.patch_id = id;
1335 
1336  return c;
1337 }
1338 
1339 int
1340 MidiModel::PatchChangeDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
1341 {
1342  if (diff_command.name() != PATCH_CHANGE_DIFF_COMMAND_ELEMENT) {
1343  return 1;
1344  }
1345 
1346  _added.clear ();
1347  XMLNode* added = diff_command.child (ADDED_PATCH_CHANGES_ELEMENT);
1348  if (added) {
1349  XMLNodeList p = added->children ();
1350  transform (p.begin(), p.end(), back_inserter (_added), boost::bind (&PatchChangeDiffCommand::unmarshal_patch_change, this, _1));
1351  }
1352 
1353  _removed.clear ();
1354  XMLNode* removed = diff_command.child (REMOVED_PATCH_CHANGES_ELEMENT);
1355  if (removed) {
1356  XMLNodeList p = removed->children ();
1357  transform (p.begin(), p.end(), back_inserter (_removed), boost::bind (&PatchChangeDiffCommand::unmarshal_patch_change, this, _1));
1358  }
1359 
1360  _changes.clear ();
1361  XMLNode* changed = diff_command.child (DIFF_PATCH_CHANGES_ELEMENT);
1362  if (changed) {
1363  XMLNodeList p = changed->children ();
1364  transform (p.begin(), p.end(), back_inserter (_changes), boost::bind (&PatchChangeDiffCommand::unmarshal_change, this, _1));
1365  }
1366 
1367  return 0;
1368 }
1369 
1370 XMLNode &
1372 {
1373  XMLNode* diff_command = new XMLNode (PATCH_CHANGE_DIFF_COMMAND_ELEMENT);
1374  diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
1375 
1376  XMLNode* added = diff_command->add_child (ADDED_PATCH_CHANGES_ELEMENT);
1377  for_each (_added.begin(), _added.end(),
1378  boost::bind (
1379  boost::bind (&XMLNode::add_child_nocopy, added, _1),
1380  boost::bind (&PatchChangeDiffCommand::marshal_patch_change, this, _1)
1381  )
1382  );
1383 
1384  XMLNode* removed = diff_command->add_child (REMOVED_PATCH_CHANGES_ELEMENT);
1385  for_each (_removed.begin(), _removed.end(),
1386  boost::bind (
1387  boost::bind (&XMLNode::add_child_nocopy, removed, _1),
1388  boost::bind (&PatchChangeDiffCommand::marshal_patch_change, this, _1)
1389  )
1390  );
1391 
1392  XMLNode* changes = diff_command->add_child (DIFF_PATCH_CHANGES_ELEMENT);
1393  for_each (_changes.begin(), _changes.end(),
1394  boost::bind (
1395  boost::bind (&XMLNode::add_child_nocopy, changes, _1),
1396  boost::bind (&PatchChangeDiffCommand::marshal_change, this, _1)
1397  )
1398  );
1399 
1400  return *diff_command;
1401 }
1402 
1413 bool
1415  const Glib::Threads::Mutex::Lock& source_lock)
1416 {
1417  ReadLock lock(read_lock());
1418 
1419  const bool old_percussive = percussive();
1420  set_percussive(false);
1421 
1422  source->drop_model(source_lock);
1423  source->mark_streaming_midi_write_started (source_lock, note_mode());
1424 
1425  for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1426  source->append_event_beats(source_lock, *i);
1427  }
1428 
1429  set_percussive(old_percussive);
1430  source->mark_streaming_write_completed(source_lock);
1431 
1432  set_edited(false);
1433 
1434  return true;
1435 }
1436 
1442 bool
1444 {
1445  ReadLock lock(read_lock());
1446 
1447  const bool old_percussive = percussive();
1448  set_percussive(false);
1449 
1451  if (!ms) {
1452  error << "MIDI model has no source to sync to" << endmsg;
1453  return false;
1454  }
1455 
1456  /* Invalidate and store active notes, which will be picked up by the iterator
1457  on the next roll if time progresses linearly. */
1458  ms->invalidate(source_lock,
1459  ms->session().transport_rolling() ? &_active_notes : NULL);
1460 
1461  ms->mark_streaming_midi_write_started (source_lock, note_mode());
1462 
1463  for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1464  ms->append_event_beats(source_lock, *i);
1465  }
1466 
1467  set_percussive (old_percussive);
1468  ms->mark_streaming_write_completed (source_lock);
1469 
1470  set_edited (false);
1471 
1472  return true;
1473 }
1474 
1482 bool
1484  const Glib::Threads::Mutex::Lock& source_lock,
1485  Evoral::Beats begin_time,
1486  Evoral::Beats end_time)
1487 {
1488  ReadLock lock(read_lock());
1489  MidiStateTracker mst;
1490 
1491  const bool old_percussive = percussive();
1492  set_percussive(false);
1493 
1494  source->drop_model(source_lock);
1495  source->mark_streaming_midi_write_started (source_lock, note_mode());
1496 
1497  for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
1498  const Evoral::Event<Evoral::Beats>& ev (*i);
1499 
1500  if (ev.time() >= begin_time && ev.time() < end_time) {
1501 
1503  static_cast<const Evoral::MIDIEvent<Evoral::Beats>* > (&ev);
1504 
1505  if (!mev) {
1506  continue;
1507  }
1508 
1509 
1510  if (mev->is_note_off()) {
1511 
1512  if (!mst.active (mev->note(), mev->channel())) {
1513  /* the matching note-on was outside the
1514  time range we were given, so just
1515  ignore this note-off.
1516  */
1517  continue;
1518  }
1519 
1520  source->append_event_beats (source_lock, *i);
1521  mst.remove (mev->note(), mev->channel());
1522 
1523  } else if (mev->is_note_on()) {
1524  mst.add (mev->note(), mev->channel());
1525  source->append_event_beats(source_lock, *i);
1526  } else {
1527  source->append_event_beats(source_lock, *i);
1528  }
1529  }
1530  }
1531 
1532  mst.resolve_notes (*source, source_lock, end_time);
1533 
1534  set_percussive(old_percussive);
1535  source->mark_streaming_write_completed(source_lock);
1536 
1537  set_edited(false);
1538 
1539  return true;
1540 }
1541 
1542 XMLNode&
1544 {
1545  XMLNode *node = new XMLNode("MidiModel");
1546  return *node;
1547 }
1548 
1551 {
1552  Notes::iterator l = notes().lower_bound(other);
1553 
1554  if (l != notes().end()) {
1555  for (; (*l)->time() == other->time(); ++l) {
1556  /* NB: compare note contents, not note pointers.
1557  If "other" was a ptr to a note already in
1558  the model, we wouldn't be looking for it,
1559  would we now?
1560  */
1561  if (**l == *other) {
1562  return *l;
1563  }
1564  }
1565  }
1566 
1567  return NotePtr();
1568 }
1569 
1571 MidiModel::find_note (gint note_id)
1572 {
1573  /* used only for looking up notes when reloading history from disk,
1574  so we don't care about performance *too* much.
1575  */
1576 
1577  for (Notes::iterator l = notes().begin(); l != notes().end(); ++l) {
1578  if ((*l)->id() == note_id) {
1579  return *l;
1580  }
1581  }
1582 
1583  return NotePtr();
1584 }
1585 
1588 {
1589  for (PatchChanges::iterator i = patch_changes().begin(); i != patch_changes().end(); ++i) {
1590  if ((*i)->id() == id) {
1591  return *i;
1592  }
1593  }
1594 
1595  return PatchChangePtr ();
1596 }
1597 
1599 MidiModel::find_sysex (gint sysex_id)
1600 {
1601  /* used only for looking up notes when reloading history from disk,
1602  so we don't care about performance *too* much.
1603  */
1604 
1605  for (SysExes::iterator l = sysexes().begin(); l != sysexes().end(); ++l) {
1606  if ((*l)->id() == sysex_id) {
1607  return *l;
1608  }
1609  }
1610 
1612 }
1613 
1619 {
1621  Glib::Threads::Mutex::Lock* source_lock = 0;
1622 
1623  if (ms) {
1624  /* Take source lock and invalidate iterator to release its lock on model.
1625  Add currently active notes to _active_notes so we can restore them
1626  if playback resumes at the same point after the edit. */
1627  source_lock = new Glib::Threads::Mutex::Lock(ms->mutex());
1628  ms->invalidate(*source_lock,
1629  ms->session().transport_rolling() ? &_active_notes : NULL);
1630  }
1631 
1632  return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
1633 }
1634 
1635 int
1637 {
1638  using namespace Evoral;
1639 
1641  return 0;
1642  }
1643 
1644  NoteDiffCommand* cmd = static_cast<NoteDiffCommand*>(arg);
1645 
1646  TimeType sa = note->time();
1647  TimeType ea = note->end_time();
1648 
1649  const Pitches& p (pitches (note->channel()));
1650  NotePtr search_note(new Note<TimeType>(0, TimeType(), TimeType(), note->note()));
1651  set<NotePtr> to_be_deleted;
1652  bool set_note_length = false;
1653  bool set_note_time = false;
1654  TimeType note_time = note->time();
1655  TimeType note_length = note->length();
1656 
1657  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 checking overlaps for note %2 @ %3\n", this, (int)note->note(), note->time()));
1658 
1659  for (Pitches::const_iterator i = p.lower_bound (search_note);
1660  i != p.end() && (*i)->note() == note->note(); ++i) {
1661 
1662  TimeType sb = (*i)->time();
1663  TimeType eb = (*i)->end_time();
1664  OverlapType overlap = OverlapNone;
1665 
1666  if ((sb > sa) && (eb <= ea)) {
1667  overlap = OverlapInternal;
1668  } else if ((eb >= sa) && (eb <= ea)) {
1669  overlap = OverlapStart;
1670  } else if ((sb > sa) && (sb <= ea)) {
1671  overlap = OverlapEnd;
1672  } else if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
1673  overlap = OverlapExternal;
1674  } else {
1675  /* no overlap */
1676  continue;
1677  }
1678 
1680  "\toverlap is %1 for (%2,%3) vs (%4,%5)\n",
1681  enum_2_string(overlap), sa, ea, sb, eb));
1682 
1684  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 just reject\n", this));
1685  return -1;
1686  }
1687 
1688  switch (overlap) {
1689  case OverlapStart:
1690  cerr << "OverlapStart\n";
1691  /* existing note covers start of new note */
1692  switch (insert_merge_policy()) {
1693  case InsertMergeReplace:
1694  to_be_deleted.insert (*i);
1695  break;
1697  if (cmd) {
1698  cmd->change (*i, NoteDiffCommand::Length, (note->time() - (*i)->time()));
1699  }
1700  (*i)->set_length (note->time() - (*i)->time());
1701  break;
1703  set_note_time = true;
1704  set_note_length = true;
1705  note_time = (*i)->time() + (*i)->length();
1706  note_length = min (note_length, (*i)->length() - ((*i)->end_time() - note->time()));
1707  break;
1708  case InsertMergeExtend:
1709  if (cmd) {
1710  cmd->change ((*i), NoteDiffCommand::Length, note->end_time() - (*i)->time());
1711  }
1712  (*i)->set_length (note->end_time() - (*i)->time());
1713  return -1; /* do not add the new note */
1714  break;
1715  default:
1716  abort(); /*NOTREACHED*/
1717  /* stupid gcc */
1718  break;
1719  }
1720  break;
1721 
1722  case OverlapEnd:
1723  cerr << "OverlapEnd\n";
1724  /* existing note covers end of new note */
1725  switch (insert_merge_policy()) {
1726  case InsertMergeReplace:
1727  to_be_deleted.insert (*i);
1728  break;
1729 
1731  /* resetting the start time of the existing note
1732  is a problem because of time ordering.
1733  */
1734  break;
1735 
1737  set_note_length = true;
1738  note_length = min (note_length, ((*i)->time() - note->time()));
1739  break;
1740 
1741  case InsertMergeExtend:
1742  /* we can't reset the time of the existing note because
1743  that will corrupt time ordering. So remove the
1744  existing note and change the position/length
1745  of the new note (which has not been added yet)
1746  */
1747  to_be_deleted.insert (*i);
1748  set_note_length = true;
1749  note_length = min (note_length, (*i)->end_time() - note->time());
1750  break;
1751  default:
1752  abort(); /*NOTREACHED*/
1753  /* stupid gcc */
1754  break;
1755  }
1756  break;
1757 
1758  case OverlapExternal:
1759  cerr << "OverlapExt\n";
1760  /* existing note overlaps all the new note */
1761  switch (insert_merge_policy()) {
1762  case InsertMergeReplace:
1763  to_be_deleted.insert (*i);
1764  break;
1767  case InsertMergeExtend:
1768  /* cannot add in this case */
1769  return -1;
1770  default:
1771  abort(); /*NOTREACHED*/
1772  /* stupid gcc */
1773  break;
1774  }
1775  break;
1776 
1777  case OverlapInternal:
1778  cerr << "OverlapInt\n";
1779  /* new note fully overlaps an existing note */
1780  switch (insert_merge_policy()) {
1781  case InsertMergeReplace:
1784  case InsertMergeExtend:
1785  /* delete the existing note, the new one will cover it */
1786  to_be_deleted.insert (*i);
1787  break;
1788  default:
1789  abort(); /*NOTREACHED*/
1790  /* stupid gcc */
1791  break;
1792  }
1793  break;
1794 
1795  default:
1796  abort(); /*NOTREACHED*/
1797  /* stupid gcc */
1798  break;
1799  }
1800  }
1801 
1802  for (set<NotePtr>::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
1803  remove_note_unlocked (*i);
1804 
1805  if (cmd) {
1806  cmd->side_effect_remove (*i);
1807  }
1808  }
1809 
1810  if (set_note_time) {
1811  if (cmd) {
1812  cmd->change (note, NoteDiffCommand::StartTime, note_time);
1813  }
1814  note->set_time (note_time);
1815  }
1816 
1817  if (set_note_length) {
1818  if (cmd) {
1819  cmd->change (note, NoteDiffCommand::Length, note_length);
1820  }
1821  note->set_length (note_length);
1822  }
1823 
1824  return 0;
1825 }
1826 
1829 {
1830  /* XXX ultimately this should be a per-track or even per-model policy */
1832  assert (ms);
1833 
1834  return ms->session().config.get_insert_merge_policy ();
1835 }
1836 
1837 void
1839 {
1841 
1842  if (old) {
1843  Source::Lock lm(old->mutex());
1844  old->invalidate (lm);
1845  }
1846 
1848 
1849  _midi_source = s;
1850 
1851  s->InterpolationChanged.connect_same_thread (
1853  );
1854 
1855  s->AutomationStateChanged.connect_same_thread (
1857  );
1858 }
1859 
1867 void
1869 {
1871  control(p)->list()->set_interpolation (s);
1872 }
1873 
1877 void
1879 {
1881  assert (ms);
1882 
1883  ms->set_interpolation_of (p, s);
1884 }
1885 
1886 void
1888 {
1891  al->set_automation_state (s);
1892 }
1893 
1894 void
1896 {
1898  assert (ms);
1899  ms->set_automation_state_of (p, s);
1900 }
1901 
1904 {
1906 
1907  /* Set up newly created control's lists to the appropriate interpolation and
1908  automation state from our source.
1909  */
1910 
1912  assert (ms);
1913 
1914  c->list()->set_interpolation (ms->interpolation_of (p));
1915 
1917  assert (al);
1918 
1920 
1921  return c;
1922 }
1923 
1926 {
1927  return _midi_source.lock ();
1928 }
1929 
1933 void
1935 {
1937  assert (s);
1938 
1939  /* Notes */
1940 
1941  if (!notes().empty ()) {
1942  NoteDiffCommand* c = new_note_diff_command ("insert silence");
1943 
1944  for (Notes::const_iterator i = notes().begin(); i != notes().end(); ++i) {
1945  c->change (*i, NoteDiffCommand::StartTime, (*i)->time() + t);
1946  }
1947 
1949  }
1950 
1951  /* Patch changes */
1952 
1953  if (!patch_changes().empty ()) {
1954  PatchChangeDiffCommand* c = new_patch_change_diff_command ("insert silence");
1955 
1956  for (PatchChanges::const_iterator i = patch_changes().begin(); i != patch_changes().end(); ++i) {
1957  c->change_time (*i, (*i)->time() + t);
1958  }
1959 
1961  }
1962 
1963  /* Controllers */
1964 
1965  for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) {
1967  XMLNode& before = ac->alist()->get_state ();
1968  i->second->list()->shift (0, t.to_double());
1969  XMLNode& after = ac->alist()->get_state ();
1970  s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after));
1971  }
1972 
1973  /* Sys-ex */
1974 
1975  if (!sysexes().empty()) {
1976  SysExDiffCommand* c = new_sysex_diff_command ("insert silence");
1977 
1978  for (SysExes::iterator i = sysexes().begin(); i != sysexes().end(); ++i) {
1979  c->change (*i, (*i)->time() + t);
1980  }
1981 
1983  }
1984 }
1985 
1994 void
1995 MidiModel::transpose (TimeType from, TimeType to, int semitones)
1996 {
1998 
1999  NoteDiffCommand* c = new_note_diff_command (_("transpose"));
2000 
2001  for (Notes::iterator i = notes().begin(); i != notes().end(); ++i) {
2002 
2003  if ((*i)->time() >= to) {
2004 
2005  /* finished */
2006  break;
2007 
2008  } else if ((*i)->time() >= from) {
2009 
2010  int new_note = (*i)->note() + semitones;
2011 
2012  if (new_note < 0) {
2013  new_note = 0;
2014  } else if (new_note > 127) {
2015  new_note = 127;
2016  }
2017 
2018  c->change (*i, NoteDiffCommand::NoteNumber, (uint8_t) new_note);
2019 
2020  }
2021  }
2022 
2023  apply_command (s->session (), c);
2024 }
2025 
2026 void
2028 {
2030 
2031  ContentsChanged (); /* EMIT SIGNAL */
2032 }
bool transport_rolling() const
Definition: session.h:592
void set_automation_state(AutoState)
void apply_command(Session &session, Command *cmd)
Definition: midi_model.cc:97
LIBPBD_API Transmitter fatal
NoteMode note_mode() const
Definition: midi_model.h:61
int atoi(const string &s)
Definition: convert.cc:140
SysExDiffCommand::Property property
Definition: midi_model.h:180
virtual void mark_streaming_midi_write_started(const Lock &lock, NoteMode mode)
Definition: midi_source.cc:272
PBD::ScopedConnectionList _midi_source_connections
Definition: midi_model.h:322
boost::shared_ptr< Evoral::Control > control_factory(const Evoral::Parameter &id)
Definition: automatable.cc:405
int32_t event_id_t
Definition: types.hpp:40
void begin_reversible_command(const std::string &cmd_name)
void control_list_interpolation_changed(Evoral::Parameter, Evoral::ControlList::InterpolationStyle)
Definition: midi_model.cc:1878
NoteDiffCommand & operator+=(const NoteDiffCommand &other)
Definition: midi_model.cc:221
InsertMergePolicy
Definition: types.h:110
void change_channel(PatchChangePtr, uint8_t)
Definition: midi_model.cc:998
const std::string & value() const
Definition: xml++.h:159
bool is_note_off() const
Definition: MIDIEvent.hpp:69
std::multiset< NotePtr, NoteNumberComparator > Pitches
Definition: Sequence.hpp:326
Glib::Threads::Mutex::Lock Lock
Definition: source.h:54
uint8_t channel() const
Definition: MIDIEvent.hpp:64
uint8_t note() const
Definition: MIDIEvent.hpp:76
boost::shared_ptr< MidiModel > _model
Definition: midi_model.h:80
PBD::Signal2< void, Evoral::Parameter, AutoState > AutomationStateChanged
Definition: midi_source.h:187
bool write_section_to(boost::shared_ptr< MidiSource > source, const Glib::Threads::Mutex::Lock &source_lock, Evoral::Beats begin=Evoral::MinBeats, Evoral::Beats end=Evoral::MaxBeats)
Definition: midi_model.cc:1483
#define enum_2_string(e)
Definition: enumwriter.h:97
Session & session() const
#define NOTE_DIFF_COMMAND_ELEMENT
Definition: midi_model.cc:120
bool is_note_on() const
Definition: MIDIEvent.hpp:68
void change(boost::shared_ptr< Evoral::Event< TimeType > >, TimeType)
Definition: midi_model.cc:768
InsertMergePolicy insert_merge_policy() const
Definition: midi_model.cc:1828
void insert_silence_at_start(TimeType)
Definition: midi_model.cc:1934
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
void change_time(PatchChangePtr, TimeType)
Definition: midi_model.cc:986
const std::string & name() const
Definition: xml++.h:104
PatchChangeDiffCommand(boost::shared_ptr< MidiModel >, const std::string &)
void add_command(Command *const cmd)
Definition: session.h:787
virtual void mark_streaming_write_completed(const Lock &lock)
Definition: midi_source.cc:335
boost::shared_ptr< Control > control(const Parameter &id, bool create_if_missing=false)
Definition: ControlSet.cpp:73
NoteDiffCommand(boost::shared_ptr< MidiModel > m, const std::string &name)
Definition: midi_model.h:88
#define SYSEX_DIFF_COMMAND_ELEMENT
Definition: midi_model.cc:125
AutoState automation_state_of(Evoral::Parameter) const
Definition: midi_source.cc:442
PatchChangePtr unmarshal_patch_change(XMLNode *)
Definition: midi_model.cc:1236
void set_interpolation_of(Evoral::Parameter, Evoral::ControlList::InterpolationStyle)
Definition: midi_source.cc:460
void set_automation_state_of(Evoral::Parameter, AutoState)
Definition: midi_source.cc:477
XMLNode & get_state()
Definition: midi_model.cc:1543
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
PBD::Signal2< void, Evoral::Parameter, Evoral::ControlList::InterpolationStyle > InterpolationChanged
Definition: midi_source.h:185
#define DIFF_PATCH_CHANGES_ELEMENT
Definition: midi_model.cc:130
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
DiffCommand(boost::shared_ptr< MidiModel > m, const std::string &name)
Definition: midi_model.cc:132
void drop_model(const Glib::Threads::Mutex::Lock &lock)
Definition: midi_source.cc:415
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
PBD::Signal0< void > ContentsChanged
Definition: midi_model.h:274
SessionConfiguration config
Definition: session.h:866
#define SIDE_EFFECT_REMOVALS_ELEMENT
Definition: midi_model.cc:124
void change_bank(PatchChangePtr, int)
Definition: midi_model.cc:1024
LIBEVORAL_API uint64_t Sequence
Definition: debug.cpp:3
XMLNode * add_child(const char *)
Definition: xml++.cc:351
#define DIFF_NOTES_ELEMENT
Definition: midi_model.cc:121
MidiModel::SysExDiffCommand * new_sysex_diff_command(const std::string name="midi edit")
Definition: midi_model.cc:72
bool write_to(boost::shared_ptr< MidiSource > source, const Glib::Threads::Mutex::Lock &source_lock)
Definition: midi_model.cc:1414
XMLNode & marshal_patch_change(constPatchChangePtr)
Definition: midi_model.cc:1151
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
Glib::Threads::Mutex _control_lock
Definition: ControlSet.hpp:76
#define DIFF_SYSEXES_ELEMENT
Definition: midi_model.cc:126
#define ADDED_PATCH_CHANGES_ELEMENT
Definition: midi_model.cc:128
MidiModel::NoteDiffCommand * new_note_diff_command(const std::string name="midi edit")
Definition: midi_model.cc:62
void source_interpolation_changed(Evoral::Parameter, Evoral::ControlList::InterpolationStyle)
Definition: midi_model.cc:1868
#define _(Text)
Definition: i18n.h:11
void resolve_notes(MidiBuffer &buffer, framepos_t time)
int set_state(const XMLNode &, int version)
Definition: midi_model.cc:1340
boost::shared_ptr< MidiModel > model()
Definition: midi_source.h:168
XMLNode & marshal_note(const NotePtr note)
Definition: midi_model.cc:447
PatchChangePtr find_patch_change(Evoral::event_id_t)
Definition: midi_model.cc:1587
virtual void append_event_beats(const Lock &lock, const Evoral::Event< Evoral::Beats > &ev)=0
static Variant get_value(const NotePtr note, Property prop)
Definition: midi_model.cc:168
NoteChange unmarshal_change(XMLNode *xml_note)
Definition: midi_model.cc:600
#define X_(Text)
Definition: i18n.h:13
XMLProperty * property(const char *)
Definition: xml++.cc:413
boost::shared_ptr< const MidiSource > midi_source()
Definition: midi_model.cc:1925
#define string_2_enum(str, e)
Definition: enumwriter.h:98
const const_iterator & end() const
Definition: Sequence.hpp:280
Definition: amp.h:29
boost::shared_ptr< Evoral::Event< TimeType > > sysex
Definition: midi_model.h:178
Time time() const
Definition: Event.hpp:132
void change(const NotePtr note, Property prop, uint8_t new_value)
Definition: midi_model.h:109
void commit_reversible_command(Command *cmd=0)
void apply_command_as_subcommand(Session &session, Command *cmd)
Definition: midi_model.cc:111
boost::shared_ptr< Evoral::Note< Evoral::Beats > > NotePtr
Definition: Sequence.hpp:85
virtual ReadLock read_lock() const
Definition: Sequence.hpp:92
NotePtr unmarshal_note(XMLNode *xml_note)
Definition: midi_model.cc:491
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
#define ADDED_NOTES_ELEMENT
Definition: midi_model.cc:122
void automation_list_automation_state_changed(Evoral::Parameter, AutoState)
Definition: midi_model.cc:1895
bool sync_to_source(const Glib::Threads::Mutex::Lock &source_lock)
Definition: midi_model.cc:1443
Evoral::ControlList::InterpolationStyle interpolation_of(Evoral::Parameter) const
Definition: midi_source.cc:431
static int loading_state_version
Definition: stateful.h:90
const Evoral::Beats & get_beats() const
Definition: variant.h:173
Beats+ticks.
Definition: variant.h:41
void remove_note_unlocked(const constNotePtr note)
Evoral::Beats TimeType
Definition: midi_model.h:57
Pitches & pitches(uint8_t chan)
Definition: Sequence.hpp:327
#define REMOVED_PATCH_CHANGES_ELEMENT
Definition: midi_model.cc:129
XMLProperty * add_property(const char *name, const std::string &value)
Glib::Threads::Mutex & mutex()
Definition: source.h:105
void source_automation_state_changed(Evoral::Parameter, AutoState)
Definition: midi_model.cc:1887
const char * name
boost::shared_ptr< WriteLockImpl > WriteLock
Definition: Sequence.hpp:90
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
Signed 32-bit int.
Definition: variant.h:45
void control_list_marked_dirty()
Definition: midi_model.cc:2027
void remove(uint8_t note, uint8_t chn)
MidiModel::PatchChangeDiffCommand * new_patch_change_diff_command(const std::string name="midi edit")
Definition: midi_model.cc:82
Definition: xml++.h:95
boost::shared_ptr< ControlList > list()
Definition: Control.hpp:66
XMLNode & marshal_change(const NoteChange &)
Definition: midi_model.cc:556
Controls & controls()
Definition: ControlSet.hpp:58
const_iterator begin(Evoral::Beatst=Evoral::Beats(), bool force_discrete=false, const std::set< Evoral::Parameter > &f=std::set< Evoral::Parameter >(), const std::set< WeakNotePtr > *active_notes=NULL) const
Definition: Sequence.hpp:272
OverlapType
Definition: Range.hpp:31
boost::shared_ptr< Evoral::Note< TimeType > > find_note(NotePtr)
Definition: midi_model.cc:1550
Definition: debug.h:30
void change_program(PatchChangePtr, uint8_t)
Definition: midi_model.cc:1011
boost::shared_ptr< Evoral::Control > control_factory(const Evoral::Parameter &id)
Definition: midi_model.cc:1903
double to_double() const
Definition: Beats.hpp:185
std::set< NotePtr > side_effect_removals
Definition: midi_model.h:149
int get_int() const
Definition: variant.h:121
XMLNode & marshal_change(const Change &)
Definition: midi_model.cc:1189
void remove(const NotePtr note)
Definition: midi_model.cc:155
void transpose(TimeType, TimeType, int)
Definition: midi_model.cc:1995
Glib::Threads::RWLock _lock
Definition: Sequence.hpp:319
void side_effect_remove(const NotePtr note)
Definition: midi_model.cc:162
XMLNode * child(const char *) const
Definition: xml++.cc:309
XMLNode & marshal_change(const Change &)
Definition: midi_model.cc:849
int resolve_overlaps_unlocked(const NotePtr, void *arg=0)
Definition: midi_model.cc:1636
LIBEVORAL_API uint64_t Beats
void add(uint8_t note, uint8_t chn)
boost::shared_ptr< AutomationList > alist() const
const std::string & name() const
Definition: command.h:39
#define PATCH_CHANGE_DIFF_COMMAND_ELEMENT
Definition: midi_model.cc:127
Nothing (void)
Definition: variant.h:40
#define REMOVED_NOTES_ELEMENT
Definition: midi_model.cc:123
SysExDiffCommand(boost::shared_ptr< MidiModel > m, const XMLNode &node)
Definition: midi_model.cc:760
int set_state(const XMLNode &, int version)
Definition: midi_model.cc:923
WriteLock edit_lock()
Definition: midi_model.cc:1618
static LilvNode * get_value(LilvWorld *world, const LilvNode *subject, const LilvNode *predicate)
Definition: lv2_plugin.cc:971
boost::shared_ptr< Evoral::Event< TimeType > > find_sysex(gint)
Definition: midi_model.cc:1599
void set_midi_source(boost::shared_ptr< MidiSource >)
Definition: midi_model.cc:1838
boost::shared_ptr< PatchChange< Evoral::Beats > > PatchChangePtr
Definition: Sequence.hpp:201
std::set< WeakNotePtr > _active_notes
Definition: midi_model.h:328
void add(const NotePtr note)
Definition: midi_model.cc:148
static Variant::Type value_type(Property prop)
Definition: midi_model.cc:187
int set_state(const XMLNode &, int version)
Definition: midi_model.cc:665
bool active(uint8_t note, uint8_t channel)
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void invalidate(const Glib::Threads::Mutex::Lock &lock, std::set< Evoral::Sequence< Evoral::Beats >::WeakNotePtr > *notes=NULL)
Definition: midi_source.cc:181
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64
boost::weak_ptr< MidiSource > _midi_source
Definition: midi_model.h:325
AutoState
Definition: types.h:145
virtual void control_list_marked_dirty()