1 /* This file is part of Evoral.
2 * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
3 * Copyright (C) 2000-2008 Paul Davis
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
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.
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
19 #define __STDC_LIMIT_MACROS 1
28 #include "pbd/compose.h"
30 #include "evoral/Control.hpp"
31 #include "evoral/ControlList.hpp"
32 #include "evoral/ControlSet.hpp"
33 #include "evoral/EventSink.hpp"
34 #include "evoral/MIDIParameters.hpp"
35 #include "evoral/Sequence.hpp"
36 #include "evoral/TypeMap.hpp"
37 #include "evoral/midi_util.h"
44 // Read iterator (const_iterator)
46 template<typename Time
>
47 Sequence
<Time
>::const_iterator::const_iterator()
50 , _control_iter(_control_iters
.end())
52 _event
= boost::shared_ptr
< Event
<Time
> >(new Event
<Time
>());
55 template<typename Time
>
56 Sequence
<Time
>::const_iterator::const_iterator(const Sequence
<Time
>& seq
, Time t
)
59 , _is_end((t
== DBL_MAX
) || seq
.empty())
60 , _note_iter(seq
.notes().end())
61 , _sysex_iter(seq
.sysexes().end())
62 , _control_iter(_control_iters
.end())
64 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Created Iterator @ %1 (is end: %2)\n)", t
, _is_end
));
67 _lock
= seq
.read_lock();
72 typename Sequence
<Time
>::ReadLock
lock(seq
.read_lock());
74 // Find first note which begins at or after t
75 _note_iter
= seq
.note_lower_bound(t
);
77 // Find first sysex event at or after t
78 for (typename Sequence
<Time
>::SysExes::const_iterator i
= seq
.sysexes().begin();
79 i
!= seq
.sysexes().end(); ++i
) {
80 if ((*i
)->time() >= t
) {
85 assert(_sysex_iter
== seq
.sysexes().end() || (*_sysex_iter
)->time() >= t
);
87 // Find first control event after t
88 ControlIterator
earliest_control(boost::shared_ptr
<ControlList
>(), DBL_MAX
, 0.0);
89 _control_iters
.reserve(seq
._controls
.size());
91 size_t earliest_control_index
= 0;
92 for (Controls::const_iterator i
= seq
._controls
.begin(); i
!= seq
._controls
.end(); ++i
) {
93 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Iterator: control: %1\n", seq
._type_map
.to_symbol(i
->first
)));
95 bool ret
= i
->second
->list()->rt_safe_earliest_event_unlocked(t
, DBL_MAX
, x
, y
, true);
97 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Iterator: CC %1 (size %2) has no events past %3\n",
98 i
->first
.id(), i
->second
->list()->size(), t
));
104 if (y
< i
->first
.min() || y
> i
->first
.max()) {
105 cerr
<< "ERROR: Controller value " << y
106 << " out of range [" << i
->first
.min() << "," << i
->first
.max()
107 << "], event ignored" << endl
;
111 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Iterator: CC %1 added (%2, %3)\n", i
->first
.id(), x
, y
));
113 const ControlIterator
new_iter(i
->second
->list(), x
, y
);
114 _control_iters
.push_back(new_iter
);
116 // Found a new earliest_control
117 if (x
< earliest_control
.x
) {
118 earliest_control
= new_iter
;
119 earliest_control_index
= _control_iters
.size() - 1;
125 _control_iter
= _control_iters
.begin() + earliest_control_index
;
126 assert(_control_iter
!= _control_iters
.end());
128 _control_iter
= _control_iters
.end();
131 // Now find the earliest event overall and point to it
134 if (_note_iter
!= seq
.notes().end()) {
136 earliest_t
= (*_note_iter
)->time();
139 if (_sysex_iter
!= seq
.sysexes().end()
140 && ((*_sysex_iter
)->time() < earliest_t
|| _type
== NIL
)) {
142 earliest_t
= (*_sysex_iter
)->time();
145 if (_control_iter
!= _control_iters
.end()
146 && earliest_control
.list
&& earliest_control
.x
>= t
147 && (earliest_control
.x
< earliest_t
|| _type
== NIL
)) {
149 earliest_t
= earliest_control
.x
;
154 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Starting at note on event @ %1\n", earliest_t
));
155 _event
= boost::shared_ptr
< Event
<Time
> >(
156 new Event
<Time
>((*_note_iter
)->on_event(), true));
157 _active_notes
.push(*_note_iter
);
160 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Starting at sysex event @ %1\n", earliest_t
));
161 _event
= boost::shared_ptr
< Event
<Time
> >(
162 new Event
<Time
>(*(*_sysex_iter
), true));
165 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Starting at control event @ %1\n", earliest_t
));
166 seq
.control_to_midi_event(_event
, earliest_control
);
172 if (_type
== NIL
|| !_event
|| _event
->size() == 0) {
173 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Starting at end @ %1\n", t
));
177 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("New iterator = 0x%x : 0x%x @ %f\n",
178 (int)_event
->event_type(),
179 (int)((MIDIEvent
<Time
>*)_event
.get())->type(),
181 assert(midi_event_is_valid(_event
->buffer(), _event
->size()));
185 template<typename Time
>
186 Sequence
<Time
>::const_iterator::~const_iterator()
190 template<typename Time
>
192 Sequence
<Time
>::const_iterator::invalidate()
194 while (!_active_notes
.empty()) {
200 _note_iter
= _seq
->notes().end();
201 _sysex_iter
= _seq
->sysexes().end();
203 _control_iter
= _control_iters
.end();
207 template<typename Time
>
208 const typename Sequence
<Time
>::const_iterator
&
209 Sequence
<Time
>::const_iterator::operator++()
212 throw std::logic_error("Attempt to iterate past end of Sequence");
215 DEBUG_TRACE(DEBUG::Sequence
, "Sequence::const_iterator++\n");
216 assert(_event
&& _event
->buffer() && _event
->size() > 0);
218 const MIDIEvent
<Time
>& ev
= *((MIDIEvent
<Time
>*)_event
.get());
222 || ev
.is_pgm_change()
223 || ev
.is_pitch_bender()
224 || ev
.is_channel_pressure()
225 || ev
.is_sysex()) ) {
226 cerr
<< "WARNING: Unknown event (type " << _type
<< "): " << hex
227 << int(ev
.buffer()[0]) << int(ev
.buffer()[1]) << int(ev
.buffer()[2]) << endl
;
234 // Increment past current event
242 // Increment current controller iterator
243 ret
= _control_iter
->list
->rt_safe_earliest_event_unlocked(
244 _control_iter
->x
, DBL_MAX
, x
, y
, false);
245 assert(!ret
|| x
> _control_iter
->x
);
247 _control_iter
->x
= x
;
248 _control_iter
->y
= y
;
250 _control_iter
->list
.reset();
251 _control_iter
->x
= DBL_MAX
;
252 _control_iter
->y
= DBL_MAX
;
255 // Find the controller with the next earliest event time
256 _control_iter
= _control_iters
.begin();
257 for (ControlIterators::iterator i
= _control_iters
.begin();
258 i
!= _control_iters
.end(); ++i
) {
259 if (i
->x
< _control_iter
->x
) {
271 // Now find the earliest event overall and point to it
273 Time earliest_t
= std::numeric_limits
<Time
>::max();
275 // Next earliest note on
276 if (_note_iter
!= _seq
->notes().end()) {
278 earliest_t
= (*_note_iter
)->time();
281 // Use the next note off iff it's earlier or the same time as the note on
282 if (!_seq
->percussive() && (!_active_notes
.empty())) {
283 if (_type
== NIL
|| _active_notes
.top()->end_time() <= earliest_t
) {
285 earliest_t
= _active_notes
.top()->end_time();
289 // Use the next earliest controller iff it's earlier than the note event
290 if (_control_iter
!= _control_iters
.end() && _control_iter
->x
!= DBL_MAX
) {
291 if (_type
== NIL
|| _control_iter
->x
< earliest_t
) {
293 earliest_t
= _control_iter
->x
;
297 // Use the next earliest SysEx iff it's earlier than the controller
298 if (_sysex_iter
!= _seq
->sysexes().end()) {
299 if (_type
== NIL
|| (*_sysex_iter
)->time() < earliest_t
) {
301 earliest_t
= (*_sysex_iter
)->time();
305 // Set event to reflect new position
308 DEBUG_TRACE(DEBUG::Sequence
, "iterator = note on\n");
309 *_event
= (*_note_iter
)->on_event();
310 _active_notes
.push(*_note_iter
);
313 DEBUG_TRACE(DEBUG::Sequence
, "iterator = note off\n");
314 assert(!_active_notes
.empty());
315 *_event
= _active_notes
.top()->off_event();
319 DEBUG_TRACE(DEBUG::Sequence
, "iterator = control\n");
320 _seq
->control_to_midi_event(_event
, *_control_iter
);
323 DEBUG_TRACE(DEBUG::Sequence
, "iterator = sysex\n");
324 *_event
= *(*_sysex_iter
);
327 DEBUG_TRACE(DEBUG::Sequence
, "iterator = end\n");
331 assert(_is_end
|| (_event
->size() > 0 && _event
->buffer() && _event
->buffer()[0] != '\0'));
336 template<typename Time
>
338 Sequence
<Time
>::const_iterator::operator==(const const_iterator
& other
) const
340 if (_seq
!= other
._seq
) {
342 } else if (_is_end
|| other
._is_end
) {
343 return (_is_end
== other
._is_end
);
344 } else if (_type
!= other
._type
) {
347 return (_event
== other
._event
);
351 template<typename Time
>
352 typename Sequence
<Time
>::const_iterator
&
353 Sequence
<Time
>::const_iterator::operator=(const const_iterator
& other
)
356 _event
= other
._event
;
357 _active_notes
= other
._active_notes
;
359 _is_end
= other
._is_end
;
360 _note_iter
= other
._note_iter
;
361 _sysex_iter
= other
._sysex_iter
;
362 _control_iters
= other
._control_iters
;
365 _lock
= _seq
->read_lock();
369 if (other
._control_iter
== other
._control_iters
.end()) {
370 _control_iter
= _control_iters
.end();
372 const size_t index
= other
._control_iter
- other
._control_iters
.begin();
373 _control_iter
= _control_iters
.begin() + index
;
381 template<typename Time
>
382 Sequence
<Time
>::Sequence(const TypeMap
& type_map
)
384 , _overlapping_pitches_accepted (true)
385 , _overlap_pitch_resolution (FirstOnFirstOff
)
386 , _type_map(type_map
)
388 , _end_iter(*this, DBL_MAX
)
393 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Sequence constructed: %1\n", this));
394 assert(_end_iter
._is_end
);
395 assert( ! _end_iter
._lock
);
398 template<typename Time
>
399 Sequence
<Time
>::Sequence(const Sequence
<Time
>& other
)
402 , _overlapping_pitches_accepted (other
._overlapping_pitches_accepted
)
403 , _overlap_pitch_resolution (other
._overlap_pitch_resolution
)
404 , _type_map(other
._type_map
)
406 , _end_iter(*this, DBL_MAX
)
407 , _percussive(other
._percussive
)
408 , _lowest_note(other
._lowest_note
)
409 , _highest_note(other
._highest_note
)
411 for (typename
Notes::const_iterator i
= other
._notes
.begin(); i
!= other
._notes
.end(); ++i
) {
412 boost::shared_ptr
<Note
<Time
> > n (new Note
<Time
> (**i
));
416 for (typename
SysExes::const_iterator i
= other
._sysexes
.begin(); i
!= other
._sysexes
.end(); ++i
) {
417 boost::shared_ptr
<Event
<Time
> > n (new Event
<Time
> (**i
, true));
418 _sysexes
.push_back (n
);
421 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Sequence copied: %1\n", this));
422 assert(_end_iter
._is_end
);
423 assert(! _end_iter
._lock
);
426 /** Write the controller event pointed to by \a iter to \a ev.
427 * The buffer of \a ev will be allocated or resized as necessary.
428 * The event_type of \a ev should be set to the expected output type.
429 * \return true on success
431 template<typename Time
>
433 Sequence
<Time
>::control_to_midi_event(
434 boost::shared_ptr
< Event
<Time
> >& ev
,
435 const ControlIterator
& iter
) const
437 assert(iter
.list
.get());
438 const uint32_t event_type
= iter
.list
->parameter().type();
440 // initialize the event pointer with a new event, if necessary
442 ev
= boost::shared_ptr
< Event
<Time
> >(new Event
<Time
>(event_type
, 0, 3, NULL
, true));
445 uint8_t midi_type
= _type_map
.parameter_midi_type(iter
.list
->parameter());
446 ev
->set_event_type(_type_map
.midi_event_type(midi_type
));
448 case MIDI_CMD_CONTROL
:
449 assert(iter
.list
.get());
450 assert(iter
.list
->parameter().channel() < 16);
451 assert(iter
.list
->parameter().id() <= INT8_MAX
);
452 assert(iter
.y
<= INT8_MAX
);
456 ev
->buffer()[0] = MIDI_CMD_CONTROL
+ iter
.list
->parameter().channel();
457 ev
->buffer()[1] = (uint8_t)iter
.list
->parameter().id();
458 ev
->buffer()[2] = (uint8_t)iter
.y
;
461 case MIDI_CMD_PGM_CHANGE
:
462 assert(iter
.list
.get());
463 assert(iter
.list
->parameter().channel() < 16);
464 assert(iter
.y
<= INT8_MAX
);
468 ev
->buffer()[0] = MIDI_CMD_PGM_CHANGE
+ iter
.list
->parameter().channel();
469 ev
->buffer()[1] = (uint8_t)iter
.y
;
472 case MIDI_CMD_BENDER
:
473 assert(iter
.list
.get());
474 assert(iter
.list
->parameter().channel() < 16);
475 assert(iter
.y
< (1<<14));
479 ev
->buffer()[0] = MIDI_CMD_BENDER
+ iter
.list
->parameter().channel();
480 ev
->buffer()[1] = uint16_t(iter
.y
) & 0x7F; // LSB
481 ev
->buffer()[2] = (uint16_t(iter
.y
) >> 7) & 0x7F; // MSB
484 case MIDI_CMD_CHANNEL_PRESSURE
:
485 assert(iter
.list
.get());
486 assert(iter
.list
->parameter().channel() < 16);
487 assert(iter
.y
<= INT8_MAX
);
491 ev
->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE
+ iter
.list
->parameter().channel();
492 ev
->buffer()[1] = (uint8_t)iter
.y
;
502 /** Clear all events from the model.
504 template<typename Time
>
506 Sequence
<Time
>::clear()
508 WriteLock
lock(write_lock());
510 for (Controls::iterator li
= _controls
.begin(); li
!= _controls
.end(); ++li
)
511 li
->second
->list()->clear();
514 /** Begin a write of events to the model.
516 * If \a mode is Sustained, complete notes with length are constructed as note
517 * on/off events are received. Otherwise (Percussive), only note on events are
518 * stored; note off events are discarded entirely and all contained notes will
521 template<typename Time
>
523 Sequence
<Time
>::start_write()
525 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1 : start_write (percussive = %2)\n", this, _percussive
));
526 WriteLock
lock(write_lock());
528 for (int i
= 0; i
< 16; ++i
) {
529 _write_notes
[i
].clear();
531 _dirty_controls
.clear();
534 /** Finish a write of events to the model.
536 * If \a delete_stuck is true and the current mode is Sustained, note on events
537 * that were never resolved with a corresonding note off will be deleted.
538 * Otherwise they will remain as notes with length 0.
540 template<typename Time
>
542 Sequence
<Time
>::end_write (bool delete_stuck
)
544 WriteLock
lock(write_lock());
550 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1 : end_write (%2 notes)\n", this, _notes
.size()));
552 if (!_percussive
&& delete_stuck
) {
553 for (typename
Notes::iterator n
= _notes
.begin(); n
!= _notes
.end() ;) {
554 typename
Notes::iterator next
= n
;
556 if ((*n
)->length() == 0) {
557 cerr
<< "WARNING: Stuck note lost: " << (*n
)->note() << endl
;
565 for (int i
= 0; i
< 16; ++i
) {
566 if (!_write_notes
[i
].empty()) {
567 cerr
<< "WARNING: Sequence<Time>::end_write: Channel " << i
<< " has "
568 << _write_notes
[i
].size() << " stuck notes" << endl
;
570 _write_notes
[i
].clear();
573 for (ControlLists::const_iterator i
= _dirty_controls
.begin(); i
!= _dirty_controls
.end(); ++i
) {
581 template<typename Time
>
583 Sequence
<Time
>::add_note_unlocked(const boost::shared_ptr
< Note
<Time
> > note
)
585 /* This is the core method to add notes to a Sequence
588 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1 add note %2 @ %3\n", this, (int)note
->note(), note
->time()));
590 if (!_overlapping_pitches_accepted
&& overlaps_unlocked (note
)) {
596 if (note
->note() < _lowest_note
)
597 _lowest_note
= note
->note();
598 if (note
->note() > _highest_note
)
599 _highest_note
= note
->note();
601 _notes
.insert (note
);
602 _pitches
[note
->channel()].insert (note
);
607 template<typename Time
>
609 Sequence
<Time
>::remove_note_unlocked(const boost::shared_ptr
< const Note
<Time
> > note
)
615 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1 remove note %2 @ %3\n", this, (int)note
->note(), note
->time()));
617 for (typename Sequence
<Time
>::Notes::iterator i
= note_lower_bound(note
->time());
618 i
!= _notes
.end() && (*i
)->time() == note
->time(); ++i
) {
622 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1\terasing note %2 @ %3\n", this, (int)(*i
)->note(), (*i
)->time()));
625 if ((*i
)->note() == _lowest_note
|| (*i
)->note() == _highest_note
) {
630 for (typename Sequence
<Time
>::Notes::iterator ii
= _notes
.begin(); ii
!= _notes
.end(); ++ii
) {
631 if ((*ii
)->note() < _lowest_note
)
632 _lowest_note
= (*ii
)->note();
633 if ((*ii
)->note() > _highest_note
)
634 _highest_note
= (*ii
)->note();
642 Pitches
& p (pitches (note
->channel()));
644 boost::shared_ptr
< Note
<Time
> > search_note(new Note
<Time
>(0, 0, 0, note
->note(), 0));
646 for (typename
Pitches::iterator i
= p
.lower_bound (search_note
);
647 i
!= p
.end() && (*i
)->note() == note
->note(); ++i
) {
649 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1\terasing pitch %2 @ %3\n", this, (int)(*i
)->note(), (*i
)->time()));
655 cerr
<< "Unable to find note to erase" << endl
;
659 /** Append \a ev to model. NOT realtime safe.
661 * The timestamp of event is expected to be relative to
662 * the start of this model (t=0) and MUST be monotonically increasing
663 * and MUST be >= the latest event currently in the model.
665 template<typename Time
>
667 Sequence
<Time
>::append(const Event
<Time
>& event
)
669 WriteLock
lock(write_lock());
672 const MIDIEvent
<Time
>& ev
= (const MIDIEvent
<Time
>&)event
;
674 assert(_notes
.empty() || ev
.time() >= (*_notes
.rbegin())->time());
677 if (!midi_event_is_valid(ev
.buffer(), ev
.size())) {
678 cerr
<< "WARNING: Sequence ignoring illegal MIDI event" << endl
;
682 if (ev
.is_note_on()) {
683 boost::shared_ptr
< Note
<Time
> > note(new Note
<Time
>(ev
.channel(), ev
.time(), 0, ev
.note(), ev
.velocity()));
684 append_note_on_unlocked (note
);
685 } else if (ev
.is_note_off()) {
686 boost::shared_ptr
< Note
<Time
> > note(new Note
<Time
>(ev
.channel(), ev
.time(), 0, ev
.note(), ev
.velocity()));
687 append_note_off_unlocked (note
);
688 } else if (ev
.is_sysex()) {
689 append_sysex_unlocked(ev
);
690 } else if (!_type_map
.type_is_midi(ev
.event_type())) {
691 printf("WARNING: Sequence: Unknown event type %X: ", ev
.event_type());
692 for (size_t i
=0; i
< ev
.size(); ++i
) {
693 printf("%X ", ev
.buffer()[i
]);
696 } else if (ev
.is_cc()) {
697 append_control_unlocked(
698 Evoral::MIDI::ContinuousController(ev
.event_type(), ev
.channel(), ev
.cc_number()),
699 ev
.time(), ev
.cc_value());
700 } else if (ev
.is_pgm_change()) {
701 append_control_unlocked(
702 Evoral::MIDI::ProgramChange(ev
.event_type(), ev
.channel()),
703 ev
.time(), ev
.pgm_number());
704 } else if (ev
.is_pitch_bender()) {
705 append_control_unlocked(
706 Evoral::MIDI::PitchBender(ev
.event_type(), ev
.channel()),
707 ev
.time(), double( (0x7F & ev
.pitch_bender_msb()) << 7
708 | (0x7F & ev
.pitch_bender_lsb()) ));
709 } else if (ev
.is_channel_pressure()) {
710 append_control_unlocked(
711 Evoral::MIDI::ChannelPressure(ev
.event_type(), ev
.channel()),
712 ev
.time(), ev
.channel_pressure());
714 printf("WARNING: Sequence: Unknown MIDI event type %X\n", ev
.type());
718 template<typename Time
>
720 Sequence
<Time
>::append_note_on_unlocked (boost::shared_ptr
< Note
<Time
> > note
)
722 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1 c=%2 note %3 on @ %4 v=%5\n", this,
723 (int) note
->channel(), (int) note
->note(),
724 note
->time(), (int) note
->velocity()));
725 assert(note
->note() <= 127);
726 assert(note
->channel() < 16);
729 if (note
->velocity() == 0) {
730 append_note_off_unlocked (note
);
734 add_note_unlocked (note
);
737 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("Sustained: Appending active note on %1 channel %2\n",
738 (unsigned)(uint8_t)note
->note(), note
->channel()));
739 _write_notes
[note
->channel()].insert (note
);
741 DEBUG_TRACE(DEBUG::Sequence
, "Percussive: NOT appending active note on\n");
745 template<typename Time
>
747 Sequence
<Time
>::append_note_off_unlocked (boost::shared_ptr
< Note
<Time
> > note
)
749 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1 c=%2 note %3 on @ %4 v=%5\n",
750 this, (int)note
->channel(),
751 (int)note
->note(), note
->time(), (int)note
->velocity()));
752 assert(note
->note() <= 127);
753 assert(note
->channel() < 16);
758 DEBUG_TRACE(DEBUG::Sequence
, "Sequence Ignoring note off (percussive mode)\n");
762 bool resolved
= false;
764 /* _write_notes is sorted earliest-latest, so this will find the first matching note (FIFO) that
765 matches this note (by pitch & channel). the MIDI specification doesn't provide any guidance
766 whether to use FIFO or LIFO for this matching process, so SMF is fundamentally a lossy
770 /* XXX use _overlap_pitch_resolution to determine FIFO/LIFO ... */
772 for (typename
WriteNotes::iterator n
= _write_notes
[note
->channel()].begin(); n
!= _write_notes
[note
->channel()].end(); ++n
) {
773 boost::shared_ptr
< Note
<Time
> > nn
= *n
;
774 if (note
->note() == nn
->note() && nn
->channel() == note
->channel()) {
775 assert(note
->time() >= nn
->time());
777 nn
->set_length (note
->time() - nn
->time());
778 nn
->set_off_velocity (note
->velocity());
780 _write_notes
[note
->channel()].erase(n
);
781 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("resolved note, length: %1\n", note
->length()));
788 cerr
<< this << " spurious note off chan " << (int)note
->channel()
789 << ", note " << (int)note
->note() << " @ " << note
->time() << endl
;
793 template<typename Time
>
795 Sequence
<Time
>::append_control_unlocked(const Parameter
& param
, Time time
, double value
)
797 DEBUG_TRACE (DEBUG::Sequence
, string_compose ("%1 %2 @ %3\t=\t%4 # controls: %5\n",
798 this, _type_map
.to_symbol(param
), time
, value
, _controls
.size()));
799 boost::shared_ptr
<Control
> c
= control(param
, true);
800 c
->list()->rt_add(time
, value
);
803 template<typename Time
>
805 Sequence
<Time
>::append_sysex_unlocked(const MIDIEvent
<Time
>& ev
)
807 #ifdef DEBUG_SEQUENCE
808 cerr
<< this << " SysEx @ " << ev
.time() << " \t= \t [ " << hex
;
809 for (size_t i
=0; i
< ev
.size(); ++i
) {
810 cerr
<< int(ev
.buffer()[i
]) << " ";
811 } cerr
<< "]" << endl
;
814 boost::shared_ptr
<MIDIEvent
<Time
> > event(new MIDIEvent
<Time
>(ev
, true));
815 _sysexes
.push_back(event
);
818 template<typename Time
>
820 Sequence
<Time
>::contains (const boost::shared_ptr
< Note
<Time
> >& note
) const
822 return contains_unlocked (note
);
825 template<typename Time
>
827 Sequence
<Time
>::contains_unlocked (const boost::shared_ptr
< Note
<Time
> >& note
) const
829 const Pitches
& p (pitches (note
->channel()));
830 boost::shared_ptr
< Note
<Time
> > search_note(new Note
<Time
>(0, 0, 0, 0, note
->note()));
832 for (typename
Pitches::const_iterator i
= p
.lower_bound (search_note
);
833 i
!= p
.end() && (*i
)->note() == note
->note(); ++i
) {
836 cerr
<< "Existing note matches: " << *i
<< endl
;
844 template<typename Time
>
846 Sequence
<Time
>::overlaps (const boost::shared_ptr
< Note
<Time
> >& note
) const
848 ReadLock
lock (read_lock());
849 return overlaps_unlocked (note
);
852 template<typename Time
>
854 Sequence
<Time
>::overlaps_unlocked (const boost::shared_ptr
< Note
<Time
> >& note
) const
856 Time sa
= note
->time();
857 Time ea
= note
->end_time();
859 const Pitches
& p (pitches (note
->channel()));
860 boost::shared_ptr
< Note
<Time
> > search_note(new Note
<Time
>(0, 0, 0, 0, note
->note()));
862 for (typename
Pitches::const_iterator i
= p
.lower_bound (search_note
);
863 i
!= p
.end() && (*i
)->note() == note
->note(); ++i
) {
865 Time sb
= (*i
)->time();
866 Time eb
= (*i
)->end_time();
868 if (((sb
> sa
) && (eb
<= ea
)) ||
869 ((eb
>= sa
) && (eb
<= ea
)) ||
870 ((sb
> sa
) && (sb
<= ea
)) ||
871 ((sa
>= sb
) && (sa
<= eb
) && (ea
<= eb
))) {
879 template<typename Time
>
881 Sequence
<Time
>::set_notes (const Sequence
<Time
>::Notes
& n
)
886 /** Return the earliest note with time >= t */
887 template<typename Time
>
888 typename Sequence
<Time
>::Notes::const_iterator
889 Sequence
<Time
>::note_lower_bound (Time t
) const
891 boost::shared_ptr
< Note
<Time
> > search_note(new Note
<Time
>(0, t
, 0, 0, 0));
892 typename Sequence
<Time
>::Notes::const_iterator i
= _notes
.lower_bound(search_note
);
893 assert(i
== _notes
.end() || (*i
)->time() >= t
);
897 template<typename Time
>
899 Sequence
<Time
>::get_notes (Notes
& n
, NoteOperator op
, uint8_t val
, int chan_mask
) const
904 case PitchLessThanOrEqual
:
906 case PitchGreaterThanOrEqual
:
907 get_notes_by_pitch (n
, op
, val
, chan_mask
);
911 case VelocityLessThan
:
912 case VelocityLessThanOrEqual
:
913 case VelocityGreater
:
914 case VelocityGreaterThanOrEqual
:
915 get_notes_by_velocity (n
, op
, val
, chan_mask
);
920 template<typename Time
>
922 Sequence
<Time
>::get_notes_by_pitch (Notes
& n
, NoteOperator op
, uint8_t val
, int chan_mask
) const
924 for (uint8_t c
= 0; c
< 16; ++c
) {
926 if (chan_mask
!= 0 && !((1<<c
) & chan_mask
)) {
930 const Pitches
& p (pitches (c
));
931 boost::shared_ptr
< Note
<Time
> > search_note(new Note
<Time
>(0, 0, 0, val
, 0));
932 typename
Pitches::const_iterator i
;
935 i
= p
.lower_bound (search_note
);
936 while (i
!= p
.end() && (*i
)->note() == val
) {
941 i
= p
.upper_bound (search_note
);
942 while (i
!= p
.end() && (*i
)->note() < val
) {
946 case PitchLessThanOrEqual
:
947 i
= p
.upper_bound (search_note
);
948 while (i
!= p
.end() && (*i
)->note() <= val
) {
953 i
= p
.lower_bound (search_note
);
954 while (i
!= p
.end() && (*i
)->note() > val
) {
958 case PitchGreaterThanOrEqual
:
959 i
= p
.lower_bound (search_note
);
960 while (i
!= p
.end() && (*i
)->note() >= val
) {
966 //fatal << string_compose (_("programming error: %1 %2", X_("get_notes_by_pitch() called with illegal operator"), op)) << endmsg;
973 template<typename Time
>
975 Sequence
<Time
>::get_notes_by_velocity (Notes
& n
, NoteOperator op
, uint8_t val
, int chan_mask
) const
977 ReadLock
lock (read_lock());
979 for (typename
Notes::const_iterator i
= _notes
.begin(); i
!= _notes
.end(); ++i
) {
981 if (chan_mask
!= 0 && !((1<<((*i
)->channel())) & chan_mask
)) {
987 if ((*i
)->velocity() == val
) {
991 case VelocityLessThan
:
992 if ((*i
)->velocity() < val
) {
996 case VelocityLessThanOrEqual
:
997 if ((*i
)->velocity() <= val
) {
1001 case VelocityGreater
:
1002 if ((*i
)->velocity() > val
) {
1006 case VelocityGreaterThanOrEqual
:
1007 if ((*i
)->velocity() >= val
) {
1012 // fatal << string_compose (_("programming error: %1 %2", X_("get_notes_by_velocity() called with illegal operator"), op)) << endmsg;
1020 template<typename Time
>
1022 Sequence
<Time
>::set_overlap_pitch_resolution (OverlapPitchResolution opr
)
1024 _overlap_pitch_resolution
= opr
;
1026 /* XXX todo: clean up existing overlaps in source data? */
1029 template class Sequence
<Evoral::MusicalTime
>;
1031 } // namespace Evoral