ardour
Sequence.cpp
Go to the documentation of this file.
1 /* This file is part of Evoral.
2  * Copyright (C) 2008 David Robillard <http://drobilla.net>
3  * Copyright (C) 2000-2008 Paul Davis
4  *
5  * Evoral is free software; you can redistribute it and/or modify it under the
6  * terms of the GNU General Public License as published by the Free Software
7  * Foundation; either version 2 of the License, or (at your option) any later
8  * version.
9  *
10  * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <algorithm>
20 #include <cmath>
21 #include <iostream>
22 #include <limits>
23 #include <stdexcept>
24 #include <stdint.h>
25 #include <cstdio>
26 
27 #if __clang__
28 #include "evoral/Note.hpp"
29 #endif
30 
31 #include "pbd/compose.h"
32 #include "pbd/error.h"
33 
34 #include "evoral/Control.hpp"
35 #include "evoral/ControlList.hpp"
36 #include "evoral/ControlSet.hpp"
37 #include "evoral/EventSink.hpp"
39 #include "evoral/Sequence.hpp"
40 #include "evoral/TypeMap.hpp"
41 #include "evoral/midi_util.h"
42 
43 #include "i18n.h"
44 
45 using namespace std;
46 using namespace PBD;
47 
55 static double const time_between_interpolated_controller_outputs = 1.0 / 256;
56 
57 namespace Evoral {
58 
59 // Read iterator (const_iterator)
60 
61 template<typename Time>
63  : _seq(NULL)
64  , _event(boost::shared_ptr< Event<Time> >(new Event<Time>()))
65  , _active_patch_change_message (0)
66  , _type(NIL)
67  , _is_end(true)
68  , _control_iter(_control_iters.end())
69  , _force_discrete(false)
70 {
71 }
72 
74 template<typename Time>
76  Time t,
77  bool force_discrete,
78  const std::set<Evoral::Parameter>& filtered,
79  const std::set<WeakNotePtr>* active_notes)
80  : _seq(&seq)
81  , _active_patch_change_message (0)
82  , _type(NIL)
83  , _is_end((t == DBL_MAX) || seq.empty())
84  , _note_iter(seq.notes().end())
85  , _sysex_iter(seq.sysexes().end())
86  , _patch_change_iter(seq.patch_changes().end())
87  , _control_iter(_control_iters.end())
88  , _force_discrete (force_discrete)
89 {
90  DEBUG_TRACE (DEBUG::Sequence, string_compose ("Created Iterator @ %1 (is end: %2)\n)", t, _is_end));
91 
92  if (_is_end) {
93  return;
94  }
95 
96  _lock = seq.read_lock();
97 
98  // Add currently active notes, if given
99  if (active_notes) {
100  for (typename std::set<WeakNotePtr>::const_iterator i = active_notes->begin();
101  i != active_notes->end(); ++i) {
102  NotePtr note = i->lock();
103  if (note && note->time() <= t && note->end_time() > t) {
104  _active_notes.push(note);
105  }
106  }
107  }
108 
109  // Find first note which begins at or after t
110  _note_iter = seq.note_lower_bound(t);
111 
112  // Find first sysex event at or after t
113  for (typename Sequence<Time>::SysExes::const_iterator i = seq.sysexes().begin();
114  i != seq.sysexes().end(); ++i) {
115  if ((*i)->time() >= t) {
116  _sysex_iter = i;
117  break;
118  }
119  }
120  assert(_sysex_iter == seq.sysexes().end() || (*_sysex_iter)->time() >= t);
121 
122  // Find first patch event at or after t
123  for (typename Sequence<Time>::PatchChanges::const_iterator i = seq.patch_changes().begin(); i != seq.patch_changes().end(); ++i) {
124  if ((*i)->time() >= t) {
125  _patch_change_iter = i;
126  break;
127  }
128  }
129  assert (_patch_change_iter == seq.patch_changes().end() || (*_patch_change_iter)->time() >= t);
130 
131  // Find first control event after t
132  _control_iters.reserve(seq._controls.size());
133  bool found = false;
134  size_t earliest_control_index = 0;
135  double earliest_control_x = DBL_MAX;
136  for (Controls::const_iterator i = seq._controls.begin(); i != seq._controls.end(); ++i) {
137 
138  if (filtered.find (i->first) != filtered.end()) {
139  /* this parameter is filtered, so don't bother setting up an iterator for it */
140  continue;
141  }
142 
143  DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: control: %1\n", seq._type_map.to_symbol(i->first)));
144  double x, y;
145  bool ret;
146  if (_force_discrete || i->second->list()->interpolation() == ControlList::Discrete) {
147  ret = i->second->list()->rt_safe_earliest_event_discrete_unlocked (t.to_double(), x, y, true);
148  } else {
149  ret = i->second->list()->rt_safe_earliest_event_unlocked(t.to_double(), x, y, true);
150  }
151  if (!ret) {
152  DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: CC %1 (size %2) has no events past %3\n",
153  i->first.id(), i->second->list()->size(), t));
154  continue;
155  }
156 
157  assert(x >= 0);
158 
159  const ParameterDescriptor& desc = seq.type_map().descriptor(i->first);
160  if (y < desc.lower || y > desc.upper) {
161  cerr << "ERROR: Controller value " << y
162  << " out of range [" << desc.lower << "," << desc.upper
163  << "], event ignored" << endl;
164  continue;
165  }
166 
167  DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: CC %1 added (%2, %3)\n", i->first.id(), x, y));
168 
169  const ControlIterator new_iter(i->second->list(), x, y);
170  _control_iters.push_back(new_iter);
171 
172  // Found a new earliest_control
173  if (x < earliest_control_x) {
174  earliest_control_x = x;
175  earliest_control_index = _control_iters.size() - 1;
176  found = true;
177  }
178  }
179 
180  if (found) {
181  _control_iter = _control_iters.begin() + earliest_control_index;
182  assert(_control_iter != _control_iters.end());
183  assert(_control_iter->list);
184  } else {
186  }
187 
188  // Choose the earliest event overall to point to
189  choose_next(t);
190 
191  // Allocate a new event for storing the current event in MIDI format
193  new Event<Time>(0, Time(), 4, NULL, true));
194 
195  // Set event from chosen sub-iterator
196  set_event();
197 
198  if (_is_end) {
200  string_compose("Starting at end @ %1\n", t));
201  } else {
203  string_compose("Starting at type 0x%1 : 0x%2 @ %3\n",
204  (int)_event->event_type(),
205  (int)((MIDIEvent<Time>*)_event.get())->type(),
206  _event->time()));
207  }
208 }
209 
210 template<typename Time>
211 void
213 {
214  while (!_active_notes.empty()) {
215  if (notes) {
216  notes->insert(_active_notes.top());
217  }
218  _active_notes.pop();
219  }
220  _type = NIL;
221  _is_end = true;
222  if (_seq) {
223  _note_iter = _seq->notes().end();
224  _sysex_iter = _seq->sysexes().end();
225  _patch_change_iter = _seq->patch_changes().end();
226  _active_patch_change_message = 0;
227  }
228  _control_iters.clear();
229  _control_iter = _control_iters.end();
230  _lock.reset();
231 }
232 
233 template<typename Time>
234 Time
236 {
237  _type = NIL;
238 
239  // Next earliest note on
240  if (_note_iter != _seq->notes().end()) {
241  _type = NOTE_ON;
242  earliest_t = (*_note_iter)->time();
243  }
244 
245  // Use the next note off iff it's earlier or the same time as the note on
246  if ((!_active_notes.empty())) {
247  if (_type == NIL || _active_notes.top()->end_time() <= earliest_t) {
248  _type = NOTE_OFF;
249  earliest_t = _active_notes.top()->end_time();
250  }
251  }
252 
253  // Use the next earliest controller iff it's earlier than the note event
254  if (_control_iter != _control_iters.end() &&
255  _control_iter->list && _control_iter->x != DBL_MAX) {
256  if (_type == NIL || _control_iter->x < earliest_t.to_double()) {
257  _type = CONTROL;
258  earliest_t = Time(_control_iter->x);
259  }
260  }
261 
262  // Use the next earliest SysEx iff it's earlier than the controller
263  if (_sysex_iter != _seq->sysexes().end()) {
264  if (_type == NIL || (*_sysex_iter)->time() < earliest_t) {
265  _type = SYSEX;
266  earliest_t = (*_sysex_iter)->time();
267  }
268  }
269 
270  // Use the next earliest patch change iff it's earlier than the SysEx
271  if (_patch_change_iter != _seq->patch_changes().end()) {
272  if (_type == NIL || (*_patch_change_iter)->time() < earliest_t) {
273  _type = PATCH_CHANGE;
274  earliest_t = (*_patch_change_iter)->time();
275  }
276  }
277  return earliest_t;
278 }
279 
280 template<typename Time>
281 void
283 {
284  switch (_type) {
285  case NOTE_ON:
286  DEBUG_TRACE(DEBUG::Sequence, "iterator = note on\n");
287  *_event = (*_note_iter)->on_event();
288  _active_notes.push(*_note_iter);
289  break;
290  case NOTE_OFF:
291  DEBUG_TRACE(DEBUG::Sequence, "iterator = note off\n");
292  assert(!_active_notes.empty());
293  *_event = _active_notes.top()->off_event();
294  // We don't pop the active note until we increment past it
295  break;
296  case SYSEX:
297  DEBUG_TRACE(DEBUG::Sequence, "iterator = sysex\n");
298  *_event = *(*_sysex_iter);
299  break;
300  case CONTROL:
301  DEBUG_TRACE(DEBUG::Sequence, "iterator = control\n");
302  _seq->control_to_midi_event(_event, *_control_iter);
303  break;
304  case PATCH_CHANGE:
305  DEBUG_TRACE(DEBUG::Sequence, "iterator = program change\n");
306  *_event = (*_patch_change_iter)->message (_active_patch_change_message);
307  break;
308  default:
309  _is_end = true;
310  break;
311  }
312 
313  if (_type == NIL || !_event || _event->size() == 0) {
314  DEBUG_TRACE(DEBUG::Sequence, "iterator = end\n");
315  _type = NIL;
316  _is_end = true;
317  } else {
318  assert(midi_event_is_valid(_event->buffer(), _event->size()));
319  }
320 }
321 
322 template<typename Time>
323 const typename Sequence<Time>::const_iterator&
325 {
326  if (_is_end) {
327  throw std::logic_error("Attempt to iterate past end of Sequence");
328  }
329 
330  assert(_event && _event->buffer() && _event->size() > 0);
331 
332  const MIDIEvent<Time>& ev = *((MIDIEvent<Time>*)_event.get());
333 
334  if (!( ev.is_note()
335  || ev.is_cc()
336  || ev.is_pgm_change()
337  || ev.is_pitch_bender()
338  || ev.is_channel_pressure()
339  || ev.is_sysex()) ) {
340  cerr << "WARNING: Unknown event (type " << _type << "): " << hex
341  << int(ev.buffer()[0]) << int(ev.buffer()[1]) << int(ev.buffer()[2]) << endl;
342  }
343 
344  double x = 0.0;
345  double y = 0.0;
346  bool ret = false;
347 
348  // Increment past current event
349  switch (_type) {
350  case NOTE_ON:
351  ++_note_iter;
352  break;
353  case NOTE_OFF:
354  _active_notes.pop();
355  break;
356  case CONTROL:
357  // Increment current controller iterator
358  if (_force_discrete || _control_iter->list->interpolation() == ControlList::Discrete) {
359  ret = _control_iter->list->rt_safe_earliest_event_discrete_unlocked (
360  _control_iter->x, x, y, false);
361  } else {
362  ret = _control_iter->list->rt_safe_earliest_event_linear_unlocked (
363  _control_iter->x + time_between_interpolated_controller_outputs, x, y, false);
364  }
365  assert(!ret || x > _control_iter->x);
366  if (ret) {
367  _control_iter->x = x;
368  _control_iter->y = y;
369  } else {
370  _control_iter->list.reset();
371  _control_iter->x = DBL_MAX;
372  _control_iter->y = DBL_MAX;
373  }
374 
375  // Find the controller with the next earliest event time
376  _control_iter = _control_iters.begin();
377  for (ControlIterators::iterator i = _control_iters.begin();
378  i != _control_iters.end(); ++i) {
379  if (i->x < _control_iter->x) {
380  _control_iter = i;
381  }
382  }
383  break;
384  case SYSEX:
385  ++_sysex_iter;
386  break;
387  case PATCH_CHANGE:
388  ++_active_patch_change_message;
389  if (_active_patch_change_message == (*_patch_change_iter)->messages()) {
390  ++_patch_change_iter;
391  _active_patch_change_message = 0;
392  }
393  break;
394  default:
395  assert(false);
396  }
397 
398  // Choose the earliest event overall to point to
399  choose_next(std::numeric_limits<Time>::max());
400 
401  // Set event from chosen sub-iterator
402  set_event();
403 
404  assert(_is_end || (_event->size() > 0 && _event->buffer() && _event->buffer()[0] != '\0'));
405 
406  return *this;
407 }
408 
409 template<typename Time>
410 bool
412 {
413  if (_seq != other._seq) {
414  return false;
415  } else if (_is_end || other._is_end) {
416  return (_is_end == other._is_end);
417  } else if (_type != other._type) {
418  return false;
419  } else {
420  return (_event == other._event);
421  }
422 }
423 
424 template<typename Time>
427 {
428  _seq = other._seq;
429  _event = other._event;
430  _active_notes = other._active_notes;
431  _type = other._type;
432  _is_end = other._is_end;
433  _note_iter = other._note_iter;
434  _sysex_iter = other._sysex_iter;
435  _patch_change_iter = other._patch_change_iter;
436  _control_iters = other._control_iters;
437  _force_discrete = other._force_discrete;
438  _active_patch_change_message = other._active_patch_change_message;
439 
440  if (other._lock) {
441  _lock = _seq->read_lock();
442  } else {
443  _lock.reset();
444  }
445 
446  if (other._control_iter == other._control_iters.end()) {
447  _control_iter = _control_iters.end();
448  } else {
449  const size_t index = other._control_iter - other._control_iters.begin();
450  _control_iter = _control_iters.begin() + index;
451  }
452 
453  return *this;
454 }
455 
456 // Sequence
457 
458 template<typename Time>
460  : _edited(false)
463  , _writing(false)
464  , _type_map(type_map)
465  , _end_iter(*this, std::numeric_limits<Time>::max(), false, std::set<Evoral::Parameter> ())
466  , _percussive(false)
467  , _lowest_note(127)
468  , _highest_note(0)
469 {
470  DEBUG_TRACE (DEBUG::Sequence, string_compose ("Sequence constructed: %1\n", this));
471  assert(_end_iter._is_end);
472  assert( ! _end_iter._lock);
473 
474  for (int i = 0; i < 16; ++i) {
475  _bank[i] = 0;
476  }
477 }
478 
479 template<typename Time>
481  : ControlSet (other)
482  , _edited(false)
483  , _overlapping_pitches_accepted (other._overlapping_pitches_accepted)
484  , _overlap_pitch_resolution (other._overlap_pitch_resolution)
485  , _writing(false)
486  , _type_map(other._type_map)
487  , _end_iter(*this, std::numeric_limits<Time>::max(), false, std::set<Evoral::Parameter> ())
488  , _percussive(other._percussive)
489  , _lowest_note(other._lowest_note)
490  , _highest_note(other._highest_note)
491 {
492  for (typename Notes::const_iterator i = other._notes.begin(); i != other._notes.end(); ++i) {
493  NotePtr n (new Note<Time> (**i));
494  _notes.insert (n);
495  }
496 
497  for (typename SysExes::const_iterator i = other._sysexes.begin(); i != other._sysexes.end(); ++i) {
498  boost::shared_ptr<Event<Time> > n (new Event<Time> (**i, true));
499  _sysexes.insert (n);
500  }
501 
502  for (typename PatchChanges::const_iterator i = other._patch_changes.begin(); i != other._patch_changes.end(); ++i) {
503  PatchChangePtr n (new PatchChange<Time> (**i));
504  _patch_changes.insert (n);
505  }
506 
507  for (int i = 0; i < 16; ++i) {
508  _bank[i] = other._bank[i];
509  }
510 
511  DEBUG_TRACE (DEBUG::Sequence, string_compose ("Sequence copied: %1\n", this));
512  assert(_end_iter._is_end);
513  assert(! _end_iter._lock);
514 }
515 
521 template<typename Time>
522 bool
525  const ControlIterator& iter) const
526 {
527  assert(iter.list.get());
528  const uint32_t event_type = iter.list->parameter().type();
529 
530  // initialize the event pointer with a new event, if necessary
531  if (!ev) {
532  ev = boost::shared_ptr< Event<Time> >(new Event<Time>(event_type, Time(), 3, NULL, true));
533  }
534 
535  uint8_t midi_type = _type_map.parameter_midi_type(iter.list->parameter());
536  ev->set_event_type(_type_map.midi_event_type(midi_type));
537  switch (midi_type) {
538  case MIDI_CMD_CONTROL:
539  assert(iter.list.get());
540  assert(iter.list->parameter().channel() < 16);
541  assert(iter.list->parameter().id() <= INT8_MAX);
542  assert(iter.y <= INT8_MAX);
543 
544  ev->set_time(Time(iter.x));
545  ev->realloc(3);
546  ev->buffer()[0] = MIDI_CMD_CONTROL + iter.list->parameter().channel();
547  ev->buffer()[1] = (uint8_t)iter.list->parameter().id();
548  ev->buffer()[2] = (uint8_t)iter.y;
549  break;
550 
551  case MIDI_CMD_PGM_CHANGE:
552  assert(iter.list.get());
553  assert(iter.list->parameter().channel() < 16);
554  assert(iter.y <= INT8_MAX);
555 
556  ev->set_time(Time(iter.x));
557  ev->realloc(2);
558  ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.list->parameter().channel();
559  ev->buffer()[1] = (uint8_t)iter.y;
560  break;
561 
562  case MIDI_CMD_BENDER:
563  assert(iter.list.get());
564  assert(iter.list->parameter().channel() < 16);
565  assert(iter.y < (1<<14));
566 
567  ev->set_time(Time(iter.x));
568  ev->realloc(3);
569  ev->buffer()[0] = MIDI_CMD_BENDER + iter.list->parameter().channel();
570  ev->buffer()[1] = uint16_t(iter.y) & 0x7F; // LSB
571  ev->buffer()[2] = (uint16_t(iter.y) >> 7) & 0x7F; // MSB
572  break;
573 
575  assert(iter.list.get());
576  assert(iter.list->parameter().channel() < 16);
577  assert(iter.y <= INT8_MAX);
578 
579  ev->set_time(Time(iter.x));
580  ev->realloc(2);
581  ev->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.list->parameter().channel();
582  ev->buffer()[1] = (uint8_t)iter.y;
583  break;
584 
585  default:
586  return false;
587  }
588 
589  return true;
590 }
591 
594 template<typename Time>
595 void
597 {
598  WriteLock lock(write_lock());
599  _notes.clear();
600  for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li)
601  li->second->list()->clear();
602 }
603 
611 template<typename Time>
612 void
614 {
615  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 : start_write (percussive = %2)\n", this, _percussive));
616  WriteLock lock(write_lock());
617  _writing = true;
618  for (int i = 0; i < 16; ++i) {
619  _write_notes[i].clear();
620  }
621 }
622 
629 template<typename Time>
630 void
632 {
633  WriteLock lock(write_lock());
634 
635  if (!_writing) {
636  return;
637  }
638 
639  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 : end_write (%2 notes) delete stuck option %3 @ %4\n", this, _notes.size(), option, when));
640 
641  for (typename Notes::iterator n = _notes.begin(); n != _notes.end() ;) {
642  typename Notes::iterator next = n;
643  ++next;
644 
645  if (!(*n)->length()) {
646  switch (option) {
647  case Relax:
648  break;
649  case DeleteStuckNotes:
650  cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
651  _notes.erase(n);
652  break;
653  case ResolveStuckNotes:
654  if (when <= (*n)->time()) {
655  cerr << "WARNING: Stuck note resolution - end time @ "
656  << when << " is before note on: " << (**n) << endl;
657  _notes.erase (*n);
658  } else {
659  (*n)->set_length (when - (*n)->time());
660  cerr << "WARNING: resolved note-on with no note-off to generate " << (**n) << endl;
661  }
662  break;
663  }
664  }
665 
666  n = next;
667  }
668 
669  for (int i = 0; i < 16; ++i) {
670  _write_notes[i].clear();
671  }
672 
673  _writing = false;
674 }
675 
676 
677 template<typename Time>
678 bool
680 {
681  /* This is the core method to add notes to a Sequence
682  */
683 
684  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 add note %2 @ %3 dur %4\n", this, (int)note->note(), note->time(), note->length()));
685 
686  if (resolve_overlaps_unlocked (note, arg)) {
687  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 DISALLOWED: note %2 @ %3\n", this, (int)note->note(), note->time()));
688  return false;
689  }
690 
691  if (note->id() < 0) {
692  note->set_id (Evoral::next_event_id());
693  }
694 
695  if (note->note() < _lowest_note)
696  _lowest_note = note->note();
697  if (note->note() > _highest_note)
698  _highest_note = note->note();
699 
700  _notes.insert (note);
701  _pitches[note->channel()].insert (note);
702 
703  _edited = true;
704 
705  return true;
706 }
707 
708 template<typename Time>
709 void
711 {
712  bool erased = false;
713  bool id_matched = false;
714 
715  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 remove note #%2 %3 @ %4\n", this, note->id(), (int)note->note(), note->time()));
716 
717  /* first try searching for the note using the time index, which is
718  * faster since the container is "indexed" by time. (technically, this
719  * means that lower_bound() can do a binary search rather than linear)
720  *
721  * this may not work, for reasons explained below.
722  */
723 
725 
726  for (i = note_lower_bound(note->time()); i != _notes.end() && (*i)->time() == note->time(); ++i) {
727 
728  if (*i == note) {
729 
730  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing note #%2 %3 @ %4\n", this, (*i)->id(), (int)(*i)->note(), (*i)->time()));
731  _notes.erase (i);
732 
733  if (note->note() == _lowest_note || note->note() == _highest_note) {
734 
735  _lowest_note = 127;
736  _highest_note = 0;
737 
738  for (typename Sequence<Time>::Notes::iterator ii = _notes.begin(); ii != _notes.end(); ++ii) {
739  if ((*ii)->note() < _lowest_note)
740  _lowest_note = (*ii)->note();
741  if ((*ii)->note() > _highest_note)
742  _highest_note = (*ii)->note();
743  }
744  }
745 
746  erased = true;
747  break;
748  }
749  }
750 
751  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\ttime-based lookup did not find note #%2 %3 @ %4\n", this, note->id(), (int)note->note(), note->time()));
752 
753  if (!erased) {
754 
755  /* if the note's time property was changed in tandem with some
756  * other property as the next operation after it was added to
757  * the sequence, then at the point where we call this to undo
758  * the add, the note we are targetting currently has a
759  * different time property than the one we we passed via
760  * the argument.
761  *
762  * in this scenario, we have no choice other than to linear
763  * search the list of notes and find the note by ID.
764  */
765 
766  for (i = _notes.begin(); i != _notes.end(); ++i) {
767 
768  if ((*i)->id() == note->id()) {
769 
770  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\tID-based pass, erasing note #%2 %3 @ %4\n", this, (*i)->id(), (int)(*i)->note(), (*i)->time()));
771  _notes.erase (i);
772 
773  if (note->note() == _lowest_note || note->note() == _highest_note) {
774 
775  _lowest_note = 127;
776  _highest_note = 0;
777 
778  for (typename Sequence<Time>::Notes::iterator ii = _notes.begin(); ii != _notes.end(); ++ii) {
779  if ((*ii)->note() < _lowest_note)
780  _lowest_note = (*ii)->note();
781  if ((*ii)->note() > _highest_note)
782  _highest_note = (*ii)->note();
783  }
784  }
785 
786  erased = true;
787  id_matched = true;
788  break;
789  }
790  }
791  }
792 
793  if (erased) {
794 
795  Pitches& p (pitches (note->channel()));
796 
797  typename Pitches::iterator j;
798 
799  /* if we had to ID-match above, we can't expect to find it in
800  * pitches via note comparison either. so do another linear
801  * search to locate it. otherwise, we can use the note index
802  * to potentially speed things up.
803  */
804 
805  if (id_matched) {
806 
807  for (j = p.begin(); j != p.end(); ++j) {
808  if ((*j)->id() == note->id()) {
809  p.erase (j);
810  break;
811  }
812  }
813 
814  } else {
815 
816  /* Now find the same note in the "pitches" list (which indexes
817  * notes by channel+time. We care only about its note number
818  * so the search_note has all other properties unset.
819  */
820 
821  NotePtr search_note (new Note<Time>(0, Time(), Time(), note->note(), 0));
822 
823  for (j = p.lower_bound (search_note); j != p.end() && (*j)->note() == note->note(); ++j) {
824 
825  if ((*j) == note) {
826  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing pitch %2 @ %3\n", this, (int)(*j)->note(), (*j)->time()));
827  p.erase (j);
828  break;
829  }
830  }
831  }
832 
833  if (j == p.end()) {
834  warning << string_compose ("erased note %1 not found in pitches for channel %2", *note, (int) note->channel()) << endmsg;
835  }
836 
837  _edited = true;
838 
839  } else {
840  cerr << "Unable to find note to erase matching " << *note.get() << endmsg;
841  }
842 }
843 
844 template<typename Time>
845 void
847 {
848  typename Sequence<Time>::PatchChanges::iterator i = patch_change_lower_bound (p->time ());
849 
850  while (i != _patch_changes.end() && ((*i)->time() == p->time())) {
851 
853  ++tmp;
854 
855  if (**i == *p) {
856  _patch_changes.erase (i);
857  }
858 
859  i = tmp;
860  }
861 }
862 
863 template<typename Time>
864 void
866 {
867  typename Sequence<Time>::SysExes::iterator i = sysex_lower_bound (sysex->time ());
868  while (i != _sysexes.end() && (*i)->time() == sysex->time()) {
869 
870  typename Sequence<Time>::SysExes::iterator tmp = i;
871  ++tmp;
872 
873  if (*i == sysex) {
874  _sysexes.erase (i);
875  }
876 
877  i = tmp;
878  }
879 }
880 
887 template<typename Time>
888 void
890 {
891  WriteLock lock(write_lock());
892 
893  const MIDIEvent<Time>& ev = (const MIDIEvent<Time>&)event;
894 
895  assert(_notes.empty() || ev.time() >= (*_notes.rbegin())->time());
896  assert(_writing);
897 
898  if (!midi_event_is_valid(ev.buffer(), ev.size())) {
899  cerr << "WARNING: Sequence ignoring illegal MIDI event" << endl;
900  return;
901  }
902 
903  if (ev.is_note_on() && ev.velocity() > 0) {
904  append_note_on_unlocked (ev, evid);
905  } else if (ev.is_note_off() || (ev.is_note_on() && ev.velocity() == 0)) {
906  /* XXX note: event ID is discarded because we merge the on+off events into
907  a single note object
908  */
909  append_note_off_unlocked (ev);
910  } else if (ev.is_sysex()) {
911  append_sysex_unlocked(ev, evid);
912  } else if (ev.is_cc() && (ev.cc_number() == MIDI_CTL_MSB_BANK || ev.cc_number() == MIDI_CTL_LSB_BANK)) {
913  /* note bank numbers in our _bank[] array, so that we can write an event when the program change arrives */
914  if (ev.cc_number() == MIDI_CTL_MSB_BANK) {
915  _bank[ev.channel()] &= ~(0x7f << 7);
916  _bank[ev.channel()] |= ev.cc_value() << 7;
917  } else {
918  _bank[ev.channel()] &= ~0x7f;
919  _bank[ev.channel()] |= ev.cc_value();
920  }
921  } else if (ev.is_cc()) {
922  append_control_unlocked(
923  Parameter(ev.event_type(), ev.channel(), ev.cc_number()),
924  ev.time(), ev.cc_value(), evid);
925  } else if (ev.is_pgm_change()) {
926  /* write a patch change with this program change and any previously set-up bank number */
927  append_patch_change_unlocked (PatchChange<Time> (ev.time(), ev.channel(), ev.pgm_number(), _bank[ev.channel()]), evid);
928  } else if (ev.is_pitch_bender()) {
929  append_control_unlocked(
930  Parameter(ev.event_type(), ev.channel()),
931  ev.time(), double ((0x7F & ev.pitch_bender_msb()) << 7
932  | (0x7F & ev.pitch_bender_lsb())),
933  evid);
934  } else if (ev.is_channel_pressure()) {
935  append_control_unlocked(
936  Parameter(ev.event_type(), ev.channel()),
937  ev.time(), ev.channel_pressure(), evid);
938  } else if (!_type_map.type_is_midi(ev.event_type())) {
939  printf("WARNING: Sequence: Unknown event type %X: ", ev.event_type());
940  for (size_t i=0; i < ev.size(); ++i) {
941  printf("%X ", ev.buffer()[i]);
942  }
943  printf("\n");
944  } else {
945  printf("WARNING: Sequence: Unknown MIDI event type %X\n", ev.type());
946  }
947 
948  _edited = true;
949 }
950 
951 template<typename Time>
952 void
954 {
955  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 c=%2 note %3 on @ %4 v=%5\n", this,
956  (int)ev.channel(), (int)ev.note(),
957  ev.time(), (int)ev.velocity()));
958  assert(_writing);
959 
960  if (ev.note() > 127) {
961  error << string_compose (_("invalid note on number (%1) ignored"), (int) ev.note()) << endmsg;
962  return;
963  } else if (ev.channel() >= 16) {
964  error << string_compose (_("invalid note on channel (%1) ignored"), (int) ev.channel()) << endmsg;
965  return;
966  } else if (ev.velocity() == 0) {
967  // Note on with velocity 0 handled as note off by caller
968  error << string_compose (_("invalid note on velocity (%1) ignored"), (int) ev.velocity()) << endmsg;
969  return;
970  }
971 
972  NotePtr note(new Note<Time>(ev.channel(), ev.time(), Time(), ev.note(), ev.velocity()));
973  note->set_id (evid);
974 
975  add_note_unlocked (note);
976 
977  DEBUG_TRACE (DEBUG::Sequence, string_compose ("Appending active note on %1 channel %2\n",
978  (unsigned)(uint8_t)note->note(), note->channel()));
979  _write_notes[note->channel()].insert (note);
980 
981 }
982 
983 template<typename Time>
984 void
986 {
987  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 c=%2 note %3 OFF @ %4 v=%5\n",
988  this, (int)ev.channel(),
989  (int)ev.note(), ev.time(), (int)ev.velocity()));
990  assert(_writing);
991 
992  if (ev.note() > 127) {
993  error << string_compose (_("invalid note off number (%1) ignored"), (int) ev.note()) << endmsg;
994  return;
995  } else if (ev.channel() >= 16) {
996  error << string_compose (_("invalid note off channel (%1) ignored"), (int) ev.channel()) << endmsg;
997  return;
998  }
999 
1000  _edited = true;
1001 
1002  bool resolved = false;
1003 
1004  /* _write_notes is sorted earliest-latest, so this will find the first matching note (FIFO) that
1005  matches this note (by pitch & channel). the MIDI specification doesn't provide any guidance
1006  whether to use FIFO or LIFO for this matching process, so SMF is fundamentally a lossy
1007  format.
1008  */
1009 
1010  /* XXX use _overlap_pitch_resolution to determine FIFO/LIFO ... */
1011 
1012  for (typename WriteNotes::iterator n = _write_notes[ev.channel()].begin(); n != _write_notes[ev.channel()].end(); ) {
1013 
1014  typename WriteNotes::iterator tmp = n;
1015  ++tmp;
1016 
1017  NotePtr nn = *n;
1018  if (ev.note() == nn->note() && nn->channel() == ev.channel()) {
1019  assert(ev.time() >= nn->time());
1020 
1021  nn->set_length (ev.time() - nn->time());
1022  nn->set_off_velocity (ev.velocity());
1023 
1024  _write_notes[ev.channel()].erase(n);
1025  DEBUG_TRACE (DEBUG::Sequence, string_compose ("resolved note @ %2 length: %1\n", nn->length(), nn->time()));
1026  resolved = true;
1027  break;
1028  }
1029 
1030  n = tmp;
1031  }
1032 
1033  if (!resolved) {
1034  cerr << this << " spurious note off chan " << (int)ev.channel()
1035  << ", note " << (int)ev.note() << " @ " << ev.time() << endl;
1036  }
1037 }
1038 
1039 template<typename Time>
1040 void
1041 Sequence<Time>::append_control_unlocked(const Parameter& param, Time time, double value, event_id_t /* evid */)
1042 {
1043  DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 %2 @ %3 = %4 # controls: %5\n",
1044  this, _type_map.to_symbol(param), time, value, _controls.size()));
1045  boost::shared_ptr<Control> c = control(param, true);
1046  c->list()->add (time.to_double(), value);
1047  /* XXX control events should use IDs */
1048 }
1049 
1050 template<typename Time>
1051 void
1053 {
1054 #ifdef DEBUG_SEQUENCE
1055  cerr << this << " SysEx @ " << ev.time() << " \t= \t [ " << hex;
1056  for (size_t i=0; i < ev.size(); ++i) {
1057  cerr << int(ev.buffer()[i]) << " ";
1058  } cerr << "]" << endl;
1059 #endif
1060 
1061  boost::shared_ptr<MIDIEvent<Time> > event(new MIDIEvent<Time>(ev, true));
1062  /* XXX sysex events should use IDs */
1063  _sysexes.insert(event);
1064 }
1065 
1066 template<typename Time>
1067 void
1069 {
1070  PatchChangePtr p (new PatchChange<Time> (ev));
1071 
1072  if (p->id() < 0) {
1073  p->set_id (id);
1074  }
1075 
1076  _patch_changes.insert (p);
1077 }
1078 
1079 template<typename Time>
1080 void
1082 {
1083  if (p->id () < 0) {
1084  p->set_id (Evoral::next_event_id ());
1085  }
1086 
1087  _patch_changes.insert (p);
1088 }
1089 
1090 template<typename Time>
1091 void
1093 {
1094  if (s->id () < 0) {
1095  s->set_id (Evoral::next_event_id ());
1096  }
1097 
1098  _sysexes.insert (s);
1099 }
1100 
1101 template<typename Time>
1102 bool
1104 {
1105  ReadLock lock (read_lock());
1106  return contains_unlocked (note);
1107 }
1108 
1109 template<typename Time>
1110 bool
1112 {
1113  const Pitches& p (pitches (note->channel()));
1114  NotePtr search_note(new Note<Time>(0, Time(), Time(), note->note()));
1115 
1116  for (typename Pitches::const_iterator i = p.lower_bound (search_note);
1117  i != p.end() && (*i)->note() == note->note(); ++i) {
1118 
1119  if (**i == *note) {
1120  return true;
1121  }
1122  }
1123 
1124  return false;
1125 }
1126 
1127 template<typename Time>
1128 bool
1129 Sequence<Time>::overlaps (const NotePtr& note, const NotePtr& without) const
1130 {
1131  ReadLock lock (read_lock());
1132  return overlaps_unlocked (note, without);
1133 }
1134 
1135 template<typename Time>
1136 bool
1137 Sequence<Time>::overlaps_unlocked (const NotePtr& note, const NotePtr& without) const
1138 {
1139  Time sa = note->time();
1140  Time ea = note->end_time();
1141 
1142  const Pitches& p (pitches (note->channel()));
1143  NotePtr search_note(new Note<Time>(0, Time(), Time(), note->note()));
1144 
1145  for (typename Pitches::const_iterator i = p.lower_bound (search_note);
1146  i != p.end() && (*i)->note() == note->note(); ++i) {
1147 
1148  if (without && (**i) == *without) {
1149  continue;
1150  }
1151 
1152  Time sb = (*i)->time();
1153  Time eb = (*i)->end_time();
1154 
1155  if (((sb > sa) && (eb <= ea)) ||
1156  ((eb >= sa) && (eb <= ea)) ||
1157  ((sb > sa) && (sb <= ea)) ||
1158  ((sa >= sb) && (sa <= eb) && (ea <= eb))) {
1159  return true;
1160  }
1161  }
1162 
1163  return false;
1164 }
1165 
1166 template<typename Time>
1167 void
1169 {
1170  _notes = n;
1171 }
1172 
1173 // CONST iterator implementations (x3)
1174 
1176 template<typename Time>
1179 {
1180  NotePtr search_note(new Note<Time>(0, t, Time(), 0, 0));
1181  typename Sequence<Time>::Notes::const_iterator i = _notes.lower_bound(search_note);
1182  assert(i == _notes.end() || (*i)->time() >= t);
1183  return i;
1184 }
1185 
1187 template<typename Time>
1190 {
1191  PatchChangePtr search (new PatchChange<Time> (t, 0, 0, 0));
1192  typename Sequence<Time>::PatchChanges::const_iterator i = _patch_changes.lower_bound (search);
1193  assert (i == _patch_changes.end() || (*i)->time() >= t);
1194  return i;
1195 }
1196 
1198 template<typename Time>
1201 {
1202  SysExPtr search (new Event<Time> (0, t));
1203  typename Sequence<Time>::SysExes::const_iterator i = _sysexes.lower_bound (search);
1204  assert (i == _sysexes.end() || (*i)->time() >= t);
1205  return i;
1206 }
1207 
1208 // NON-CONST iterator implementations (x3)
1209 
1211 template<typename Time>
1214 {
1215  NotePtr search_note(new Note<Time>(0, t, Time(), 0, 0));
1216  typename Sequence<Time>::Notes::iterator i = _notes.lower_bound(search_note);
1217  assert(i == _notes.end() || (*i)->time() >= t);
1218  return i;
1219 }
1220 
1222 template<typename Time>
1225 {
1226  PatchChangePtr search (new PatchChange<Time> (t, 0, 0, 0));
1227  typename Sequence<Time>::PatchChanges::iterator i = _patch_changes.lower_bound (search);
1228  assert (i == _patch_changes.end() || (*i)->time() >= t);
1229  return i;
1230 }
1231 
1233 template<typename Time>
1236 {
1237  SysExPtr search (new Event<Time> (0, t));
1238  typename Sequence<Time>::SysExes::iterator i = _sysexes.lower_bound (search);
1239  assert (i == _sysexes.end() || (*i)->time() >= t);
1240  return i;
1241 }
1242 
1243 template<typename Time>
1244 void
1245 Sequence<Time>::get_notes (Notes& n, NoteOperator op, uint8_t val, int chan_mask) const
1246 {
1247  switch (op) {
1248  case PitchEqual:
1249  case PitchLessThan:
1250  case PitchLessThanOrEqual:
1251  case PitchGreater:
1252  case PitchGreaterThanOrEqual:
1253  get_notes_by_pitch (n, op, val, chan_mask);
1254  break;
1255 
1256  case VelocityEqual:
1257  case VelocityLessThan:
1258  case VelocityLessThanOrEqual:
1259  case VelocityGreater:
1260  case VelocityGreaterThanOrEqual:
1261  get_notes_by_velocity (n, op, val, chan_mask);
1262  break;
1263  }
1264 }
1265 
1266 template<typename Time>
1267 void
1268 Sequence<Time>::get_notes_by_pitch (Notes& n, NoteOperator op, uint8_t val, int chan_mask) const
1269 {
1270  for (uint8_t c = 0; c < 16; ++c) {
1271 
1272  if (chan_mask != 0 && !((1<<c) & chan_mask)) {
1273  continue;
1274  }
1275 
1276  const Pitches& p (pitches (c));
1277  NotePtr search_note(new Note<Time>(0, Time(), Time(), val, 0));
1278  typename Pitches::const_iterator i;
1279  switch (op) {
1280  case PitchEqual:
1281  i = p.lower_bound (search_note);
1282  while (i != p.end() && (*i)->note() == val) {
1283  n.insert (*i);
1284  }
1285  break;
1286  case PitchLessThan:
1287  i = p.upper_bound (search_note);
1288  while (i != p.end() && (*i)->note() < val) {
1289  n.insert (*i);
1290  }
1291  break;
1292  case PitchLessThanOrEqual:
1293  i = p.upper_bound (search_note);
1294  while (i != p.end() && (*i)->note() <= val) {
1295  n.insert (*i);
1296  }
1297  break;
1298  case PitchGreater:
1299  i = p.lower_bound (search_note);
1300  while (i != p.end() && (*i)->note() > val) {
1301  n.insert (*i);
1302  }
1303  break;
1304  case PitchGreaterThanOrEqual:
1305  i = p.lower_bound (search_note);
1306  while (i != p.end() && (*i)->note() >= val) {
1307  n.insert (*i);
1308  }
1309  break;
1310 
1311  default:
1312  //fatal << string_compose (_("programming error: %1 %2", X_("get_notes_by_pitch() called with illegal operator"), op)) << endmsg;
1313  abort(); /* NOTREACHED*/
1314  }
1315  }
1316 }
1317 
1318 template<typename Time>
1319 void
1320 Sequence<Time>::get_notes_by_velocity (Notes& n, NoteOperator op, uint8_t val, int chan_mask) const
1321 {
1322  ReadLock lock (read_lock());
1323 
1324  for (typename Notes::const_iterator i = _notes.begin(); i != _notes.end(); ++i) {
1325 
1326  if (chan_mask != 0 && !((1<<((*i)->channel())) & chan_mask)) {
1327  continue;
1328  }
1329 
1330  switch (op) {
1331  case VelocityEqual:
1332  if ((*i)->velocity() == val) {
1333  n.insert (*i);
1334  }
1335  break;
1336  case VelocityLessThan:
1337  if ((*i)->velocity() < val) {
1338  n.insert (*i);
1339  }
1340  break;
1341  case VelocityLessThanOrEqual:
1342  if ((*i)->velocity() <= val) {
1343  n.insert (*i);
1344  }
1345  break;
1346  case VelocityGreater:
1347  if ((*i)->velocity() > val) {
1348  n.insert (*i);
1349  }
1350  break;
1351  case VelocityGreaterThanOrEqual:
1352  if ((*i)->velocity() >= val) {
1353  n.insert (*i);
1354  }
1355  break;
1356  default:
1357  // fatal << string_compose (_("programming error: %1 %2", X_("get_notes_by_velocity() called with illegal operator"), op)) << endmsg;
1358  abort(); /* NOTREACHED*/
1359 
1360  }
1361  }
1362 }
1363 
1364 template<typename Time>
1365 void
1367 {
1368  _overlap_pitch_resolution = opr;
1369 
1370  /* XXX todo: clean up existing overlaps in source data? */
1371 }
1372 
1373 template<typename Time>
1374 void
1376 {
1377  set_edited (true);
1378 }
1379 
1380 template<typename Time>
1381 void
1382 Sequence<Time>::dump (ostream& str) const
1383 {
1384  typename Sequence<Time>::const_iterator i;
1385  str << "+++ dump\n";
1386  for (i = begin(); i != end(); ++i) {
1387  str << *i << endl;
1388  }
1389  str << "--- dump\n";
1390 }
1391 
1392 template class Sequence<Evoral::Beats>;
1393 
1394 } // namespace Evoral
const const_iterator & operator++()
Definition: Sequence.cpp:324
bool is_pgm_change() const
Definition: MIDIEvent.hpp:72
EventType event_type() const
Definition: Event.hpp:131
SysExes & sysexes()
Definition: Sequence.hpp:198
#define MIDI_CTL_MSB_BANK
Definition: midi_events.h:33
std::multiset< NotePtr, EarlierNoteComparator > Notes
Definition: Sequence.hpp:153
OverlapPitchResolution _overlap_pitch_resolution
Definition: Sequence.hpp:318
void remove_sysex_unlocked(const SysExPtr)
Definition: Sequence.cpp:865
float lower
Minimum value (in Hz, for frequencies)
bool overlaps_unlocked(const NotePtr &ev, const NotePtr &ignore_this_note) const
Definition: Sequence.cpp:1137
int32_t event_id_t
Definition: types.hpp:40
uint8_t velocity() const
Definition: MIDIEvent.hpp:78
bool is_note_off() const
Definition: MIDIEvent.hpp:69
std::multiset< NotePtr, NoteNumberComparator > Pitches
Definition: Sequence.hpp:326
uint8_t channel_pressure() const
Definition: MIDIEvent.hpp:96
uint8_t channel() const
Definition: MIDIEvent.hpp:64
uint8_t note() const
Definition: MIDIEvent.hpp:76
#define MIDI_CTL_LSB_BANK
Definition: midi_events.h:49
#define MIDI_CMD_CHANNEL_PRESSURE
Definition: midi_events.h:112
static bool midi_event_is_valid(const uint8_t *buffer, size_t len)
Definition: midi_util.h:113
bool is_note_on() const
Definition: MIDIEvent.hpp:68
uint8_t pitch_bender_lsb() const
Definition: MIDIEvent.hpp:89
void append_patch_change_unlocked(const PatchChange< Time > &, Evoral::event_id_t)
Definition: Sequence.cpp:1068
Time choose_next(Time earliest_t)
Definition: Sequence.cpp:235
#define MIDI_CMD_PGM_CHANGE
Definition: midi_events.h:111
boost::shared_ptr< Event< Time > > _event
Definition: Sequence.hpp:255
SysExes::const_iterator sysex_lower_bound(Time t) const
Definition: Sequence.cpp:1200
PatchChanges _patch_changes
Definition: Sequence.hpp:352
bool is_pitch_bender() const
Definition: MIDIEvent.hpp:71
void append_control_unlocked(const Parameter &param, Time time, double value, Evoral::event_id_t)
Definition: Sequence.cpp:1041
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
const TypeMap & _type_map
Definition: Sequence.hpp:347
#define MIDI_CMD_BENDER
Definition: midi_events.h:113
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
LIBEVORAL_API uint64_t Sequence
Definition: debug.cpp:3
bool contains_unlocked(const NotePtr &ev) const
Definition: Sequence.cpp:1111
void end_write(StuckNoteOption, Time when=Time())
Definition: Sequence.cpp:631
const const_iterator _end_iter
Definition: Sequence.hpp:363
uint8_t _lowest_note
Definition: Sequence.hpp:366
#define _(Text)
Definition: i18n.h:11
PatchChanges & patch_changes()
Definition: Sequence.hpp:211
void add_sysex_unlocked(const SysExPtr)
Definition: Sequence.cpp:1092
Notes::const_iterator _note_iter
Definition: Sequence.hpp:264
Definition: getopt.h:74
#define MIDI_CMD_CONTROL
Definition: midi_events.h:110
void add_patch_change_unlocked(const PatchChangePtr)
Definition: Sequence.cpp:1081
void start_write()
Definition: Sequence.cpp:613
float upper
Maximum value (in Hz, for frequencies)
const Sequence< Time > * _seq
Definition: Sequence.hpp:254
uint8_t cc_value() const
Definition: MIDIEvent.hpp:87
uint32_t size() const
Definition: Event.hpp:134
bool is_channel_pressure() const
Definition: MIDIEvent.hpp:75
bool control_to_midi_event(boost::shared_ptr< Event< Time > > &ev, const ControlIterator &iter) const
Definition: Sequence.cpp:523
void set_overlap_pitch_resolution(OverlapPitchResolution opr)
Definition: Sequence.cpp:1366
void get_notes(Notes &, NoteOperator, uint8_t val, int chan_mask=0) const
Definition: Sequence.cpp:1245
uint8_t pgm_number() const
Definition: MIDIEvent.hpp:93
const const_iterator & end() const
Definition: Sequence.hpp:280
Sequence(const TypeMap &type_map)
Definition: Sequence.cpp:459
bool overlaps(const NotePtr &ev, const NotePtr &ignore_this_note) const
Definition: Sequence.cpp:1129
bool add_note_unlocked(const NotePtr note, void *arg=0)
Definition: Sequence.cpp:679
void remove_patch_change_unlocked(const constPatchChangePtr)
Definition: Sequence.cpp:846
void append_sysex_unlocked(const MIDIEvent< Time > &ev, Evoral::event_id_t)
Definition: Sequence.cpp:1052
Time time() const
Definition: Event.hpp:132
SysExes::const_iterator _sysex_iter
Definition: Sequence.hpp:265
virtual ReadLock read_lock() const
Definition: Sequence.hpp:92
LIBEVORAL_API event_id_t next_event_id()
Definition: Event.cpp:39
void dump(std::ostream &) const
Definition: Sequence.cpp:1382
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
void get_notes_by_velocity(Notes &, NoteOperator, uint8_t val, int chan_mask=0) const
Definition: Sequence.cpp:1320
SysExes _sysexes
Definition: Sequence.hpp:351
uint8_t cc_number() const
Definition: MIDIEvent.hpp:85
T * get() const
Definition: shared_ptr.hpp:268
void remove_note_unlocked(const constNotePtr note)
Definition: Sequence.cpp:710
bool operator==(const const_iterator &other) const
Definition: Sequence.cpp:411
uint8_t type() const
Definition: MIDIEvent.hpp:60
bool _overlapping_pitches_accepted
Definition: Sequence.hpp:317
bool is_sysex() const
Definition: MIDIEvent.hpp:99
bool is_cc() const
Definition: MIDIEvent.hpp:70
PatchChanges::const_iterator patch_change_lower_bound(Time t) const
Definition: Sequence.cpp:1189
void append_note_on_unlocked(const MIDIEvent< Time > &event, Evoral::event_id_t)
Definition: Sequence.cpp:953
Notes & notes()
Definition: Sequence.hpp:154
void append(const Event< Time > &ev, Evoral::event_id_t evid)
Definition: Sequence.cpp:889
boost::shared_ptr< ControlList > list()
Definition: Control.hpp:66
const_iterator begin(Time t=Time(), 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
bool empty() const
Definition: Sequence.hpp:116
PatchChanges::const_iterator _patch_change_iter
Definition: Sequence.hpp:266
Definition: debug.h:30
ControlIterators::iterator _control_iter
Definition: Sequence.hpp:268
Glib::Threads::RWLock _lock
Definition: Sequence.hpp:319
boost::shared_ptr< const ControlList > list
Definition: Sequence.hpp:55
void append_note_off_unlocked(const MIDIEvent< Time > &event)
Definition: Sequence.cpp:985
bool contains(const NotePtr &ev) const
Definition: Sequence.cpp:1103
uint8_t pitch_bender_msb() const
Definition: MIDIEvent.hpp:90
const uint8_t * buffer() const
Definition: Event.hpp:135
void invalidate(std::set< WeakNotePtr > *notes)
Definition: Sequence.cpp:212
static double const time_between_interpolated_controller_outputs
Definition: Sequence.cpp:55
const TypeMap & type_map() const
Definition: Sequence.hpp:113
ControlIterators _control_iters
Definition: Sequence.hpp:267
Notes::const_iterator note_lower_bound(Time t) const
Definition: Sequence.cpp:1178
void get_notes_by_pitch(Notes &, NoteOperator, uint8_t val, int chan_mask=0) const
Definition: Sequence.cpp:1268
uint8_t _highest_note
Definition: Sequence.hpp:367
void set_notes(const typename Sequence< Time >::Notes &n)
Definition: Sequence.cpp:1168
const_iterator & operator=(const const_iterator &other)
Definition: Sequence.cpp:426
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
virtual void control_list_marked_dirty()
Definition: Sequence.cpp:1375