Fix crash on iteration over an empty sequence and/or recording controllers only.
[ardour.git] / libs / evoral / src / Sequence.cpp
1 /* This file is part of Evoral.
2  * Copyright (C) 2008 Dave 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 #define __STDC_LIMIT_MACROS 1
20 #include <algorithm>
21 #include <cmath>
22 #include <iostream>
23 #include <limits>
24 #include <stdexcept>
25 #include <stdint.h>
26 #include "evoral/Control.hpp"
27 #include "evoral/ControlList.hpp"
28 #include "evoral/ControlSet.hpp"
29 #include "evoral/EventSink.hpp"
30 #include "evoral/MIDIParameters.hpp"
31 #include "evoral/Sequence.hpp"
32 #include "evoral/TypeMap.hpp"
33 #include "evoral/midi_util.h"
34
35 //#define DEBUG_SEQUENCE 1
36 #ifdef DEBUG_SEQUENCE
37         #include <boost/format.hpp>
38         using boost::format;
39         #define DUMP(x) cerr << (x);
40 #else
41         #define DUMP(x)
42 #endif
43
44 using namespace std;
45
46 namespace Evoral {
47
48 template<typename Time>
49 void Sequence<Time>::write_lock() {
50         _lock.writer_lock();
51         _control_lock.lock();
52 }
53
54 template<typename Time>
55 void Sequence<Time>::write_unlock() {
56         _lock.writer_unlock();
57         _control_lock.unlock();
58 }
59
60 template<typename Time>
61 void Sequence<Time>::read_lock() const {
62         _lock.reader_lock();
63 }
64
65 template<typename Time>
66 void Sequence<Time>::read_unlock() const {
67         _lock.reader_unlock();
68 }
69
70
71 // Read iterator (const_iterator)
72
73 template<typename Time>
74 Sequence<Time>::const_iterator::const_iterator()
75         : _seq(NULL)
76         , _is_end(true)
77         , _locked(false)
78 {
79         _event = boost::shared_ptr< Event<Time> >(new Event<Time>());
80 }
81
82 template<typename Time>
83 Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t)
84         : _seq(&seq)
85         , _type(NIL)
86         , _is_end((t == DBL_MAX) || seq.empty())
87         , _locked(!_is_end)
88 {
89         DUMP(format("Created Iterator @ %1% (is end: %2%)\n)") % t % _is_end);
90         
91         if (_is_end) {
92                 return;
93         }
94
95         seq.read_lock();
96
97         // Find first note which begins after t
98         _note_iter = seq.notes().end();
99         for (typename Sequence<Time>::Notes::const_iterator i = seq.notes().begin();
100                         i != seq.notes().end(); ++i) {
101                 if ((*i)->time() >= t) {
102                         _note_iter = i;
103                         break;
104                 }
105         }
106         assert(_note_iter == seq.notes().end() || (*_note_iter)->time() >= t);
107         
108         // Find first sysex event after t
109         _sysex_iter = seq.sysexes().end();
110         for (typename Sequence<Time>::SysExes::const_iterator i = seq.sysexes().begin();
111                         i != seq.sysexes().end(); ++i) {
112                 if ((*i)->time() >= t) {
113                         _sysex_iter = i;
114                         break;
115                 }
116         }
117         assert(_sysex_iter == seq.sysexes().end() || (*_sysex_iter)->time() >= t);
118
119         // Find first control event after t
120         ControlIterator earliest_control(boost::shared_ptr<ControlList>(), DBL_MAX, 0.0);
121         _control_iters.reserve(seq._controls.size());
122         for (Controls::const_iterator i = seq._controls.begin(); i != seq._controls.end(); ++i) {
123                 DUMP(format("Iterator: control: %1%\n") % seq._type_map.to_symbol(i->first));
124                 double x, y;
125                 bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
126                 if (!ret) {
127                         DUMP(format("Iterator: CC %1% (size %2%) has no events past %3%\n")
128                                         % i->first.id() % i->second->list()->size() % t);
129                         continue;
130                 }
131
132                 assert(x >= 0);
133
134                 if (y < i->first.min() || y > i->first.max()) {
135                         cerr << "ERROR: Controller value " << y
136                                 << " out of range [" << i->first.min() << "," << i->first.max()
137                                 << "], event ignored" << endl;
138                         continue;
139                 }
140                 
141                 DUMP(format("Iterator: CC %1% added (%2%, %3%)\n") % i->first.id() % x % y);
142
143                 const ControlIterator new_iter(i->second->list(), x, y);
144                 _control_iters.push_back(new_iter);
145
146                 // Found a new earliest_control
147                 if (x < earliest_control.x) {
148                         earliest_control = new_iter;
149                         _control_iter = _control_iters.end();
150                         --_control_iter; // now points to the last element in _control_iters
151                 }
152         }
153         
154         // Now find the earliest event overall and point to it
155         Time earliest_t = t;
156
157         if (_note_iter != seq.notes().end()) {
158                 _type = NOTE_ON;
159                 earliest_t = (*_note_iter)->time();
160         }
161         
162         if (_sysex_iter != seq.sysexes().end() && (*_sysex_iter)->time() < earliest_t) {
163                 _type = SYSEX;
164                 earliest_t = (*_sysex_iter)->time();
165         }
166
167         if (earliest_control.list && earliest_control.x >= t && earliest_control.x < earliest_t) {
168                 _type = CONTROL;
169                 earliest_t = earliest_control.x;
170         }
171         
172         switch (_type) {
173         case NOTE_ON:
174                 DUMP(format("Starting at note on event @ %1%\n") % earliest_t);
175                 _event = boost::shared_ptr< Event<Time> >(
176                                 new Event<Time>((*_note_iter)->on_event(), true));
177                 _active_notes.push(*_note_iter);
178                 break;
179         case SYSEX:
180                 DUMP(format("Starting at sysex event @ %1%\n") % earliest_t);
181                 _event = boost::shared_ptr< Event<Time> >(
182                                 new Event<Time>(*(*_sysex_iter), true));
183                 break;
184         case CONTROL:
185                 DUMP(format("Starting at control event @ %1%\n") % earliest_t);
186                 seq.control_to_midi_event(_event, earliest_control);
187                 break;
188         default:
189                 break;
190         }
191
192         if (_type == NIL || !_event || _event->size() == 0) {
193                 DUMP(format("Starting at end @ %1%\n") % t);
194                 _type   = NIL;
195                 _is_end = true;
196                 _locked = false;
197                 _seq->read_unlock();
198         } else {
199                 DUMP(format("New iterator = %1% : %2% @ %3%\n")
200                                 % (int)_event->event_type()
201                                 % (int)((MIDIEvent<Time>*)_event.get())->type()
202                                 % _event->time());
203                 assert(midi_event_is_valid(_event->buffer(), _event->size()));
204         }
205 }
206
207 template<typename Time>
208 Sequence<Time>::const_iterator::~const_iterator()
209 {
210         if (_locked) {
211                 _seq->read_unlock();
212         }
213 }
214
215 template<typename Time>
216 const typename Sequence<Time>::const_iterator&
217 Sequence<Time>::const_iterator::operator++()
218 {
219         if (_is_end) {
220                 throw std::logic_error("Attempt to iterate past end of Sequence");
221         }
222         
223         DUMP("Sequence::const_iterator++\n");
224         assert(_event && _event->buffer() && _event->size() > 0);
225         
226         const MIDIEvent<Time>& ev = *((MIDIEvent<Time>*)_event.get());
227
228         if (!(     ev.is_note()
229                         || ev.is_cc()
230                         || ev.is_pgm_change()
231                         || ev.is_pitch_bender()
232                         || ev.is_channel_pressure()
233                         || ev.is_sysex()) ) {
234                 cerr << "WARNING: Unknown event (type " << _type << "): " << hex
235                         << int(ev.buffer()[0]) << int(ev.buffer()[1]) << int(ev.buffer()[2]) << endl;
236         }
237         
238         double x   = 0.0;
239         double y   = 0.0;
240         bool   ret = false;
241         
242         // Increment past current event
243         switch (_type) {
244         case NOTE_ON:
245                 ++_note_iter;
246                 break;
247         case NOTE_OFF:
248                 break;
249         case CONTROL:
250                 // Increment current controller iterator
251                 ret = _control_iter->list->rt_safe_earliest_event_unlocked(
252                                 _control_iter->x, DBL_MAX, x, y, false);
253                 assert(!ret || x > _control_iter->x);
254                 if (ret) {
255                         _control_iter->x = x;
256                         _control_iter->y = y;
257                 } else {
258                         _control_iter->list.reset();
259                         _control_iter->x = DBL_MAX;
260                         _control_iter->y = DBL_MAX;
261                 }
262         
263                 // Find the controller with the next earliest event time
264                 _control_iter = _control_iters.begin();
265                 for (ControlIterators::iterator i = _control_iters.begin();
266                                 i != _control_iters.end(); ++i) {
267                         if (i->x < _control_iter->x) {
268                                 _control_iter = i;
269                         }
270                 }
271                 break;
272         case SYSEX:
273                 ++_sysex_iter;
274                 break;
275         default:
276                 assert(false);
277         }
278
279         // Now find the earliest event overall and point to it
280         _type = NIL;
281         Time earliest_t = std::numeric_limits<Time>::max();
282
283         // Next earliest note on
284         if (_note_iter != _seq->notes().end()) {
285                 _type = NOTE_ON;
286                 earliest_t = (*_note_iter)->time();
287         }
288
289         // Use the next note off iff it's earlier or the same time as the note on
290         if (!_seq->percussive() && (!_active_notes.empty())) {
291                 if (_type == NIL || _active_notes.top()->end_time() <= earliest_t) {
292                         _type = NOTE_OFF;
293                         earliest_t = _active_notes.top()->end_time();
294                 }
295         }
296
297         // Use the next earliest controller iff it's earlier than the note event
298         if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX) {
299                 if (_type == NIL || _control_iter->x < earliest_t) {
300                         _type = CONTROL;
301                         earliest_t = _control_iter->x;
302                 }
303         }
304         
305         // Use the next earliest SysEx iff it's earlier than the controller
306         if (_sysex_iter != _seq->sysexes().end()) {
307                 if (_type == NIL || (*_sysex_iter)->time() < earliest_t) {
308                         _type = SYSEX;
309                         earliest_t = (*_sysex_iter)->time();
310                 }
311         }
312
313         // Set event to reflect new position
314         switch (_type) {
315         case NOTE_ON:
316                 DUMP("iterator = note on\n");
317                 *_event = (*_note_iter)->on_event();
318                 _active_notes.push(*_note_iter);
319                 break;
320         case NOTE_OFF:
321                 DUMP("iterator = note off\n");
322                 assert(!_active_notes.empty());
323                 *_event = _active_notes.top()->off_event();
324                 _active_notes.pop();
325                 break;
326         case CONTROL:
327                 DUMP("iterator = control\n");
328                 _seq->control_to_midi_event(_event, *_control_iter);
329                 break;
330         case SYSEX:
331                 DUMP("iterator = sysex\n");
332                 *_event = *(*_sysex_iter);
333                 break;
334         default:
335                 DUMP("iterator = end\n");
336                 _is_end = true;
337         }
338
339         assert(_is_end || (_event->size() > 0 && _event->buffer() && _event->buffer()[0] != '\0'));
340
341         return *this;
342 }
343
344 template<typename Time>
345 bool
346 Sequence<Time>::const_iterator::operator==(const const_iterator& other) const
347 {
348         if (_seq != other._seq) {
349                 return false;
350         } else if (_is_end || other._is_end) {
351                 return (_is_end == other._is_end);
352         } else if (_type != other._type) {
353                 return false;
354         } else {
355                 return (_event == other._event);
356         }
357 }
358
359 template<typename Time>
360 typename Sequence<Time>::const_iterator&
361 Sequence<Time>::const_iterator::operator=(const const_iterator& other)
362 {
363         if (_seq != other._seq) {
364                 if (_locked) {
365                         _seq->read_unlock();
366                 }
367                 if (other._locked) {
368                    other._seq->read_lock();
369                 }
370         } else if (!_locked && other._locked) {
371                 _seq->read_lock();
372         }
373
374         _seq           = other._seq;
375         _event         = other._event;
376         _active_notes  = other._active_notes;
377         _type          = other._type;
378         _is_end        = other._is_end;
379         _locked        = other._locked;
380         _note_iter     = other._note_iter;
381         _sysex_iter    = other._sysex_iter;
382         _control_iters = other._control_iters;
383         size_t index   = other._control_iter - other._control_iters.begin();
384         _control_iter  = _control_iters.begin() + index;
385
386         return *this;
387 }
388
389 // Sequence
390
391 template<typename Time>
392 Sequence<Time>::Sequence(const TypeMap& type_map, size_t size)
393         : _read_iter(*this, DBL_MAX)
394         , _edited(false)
395         , _type_map(type_map)
396         , _notes(size)
397         , _writing(false)
398         , _end_iter(*this, DBL_MAX)
399         , _percussive(false)
400         , _lowest_note(127)
401         , _highest_note(0)
402 {
403         DUMP(format("Sequence (size %1%) constructed: %2%\n") % size % this);
404         assert(_end_iter._is_end);
405         assert( ! _end_iter._locked);
406 }
407
408 /** Write the controller event pointed to by \a iter to \a ev.
409  * The buffer of \a ev will be allocated or resized as necessary.
410  * The event_type of \a ev should be set to the expected output type.
411  * \return true on success
412  */
413 template<typename Time>
414 bool
415 Sequence<Time>::control_to_midi_event(
416                 boost::shared_ptr< Event<Time> >& ev,
417                 const ControlIterator&            iter) const
418 {
419         assert(iter.list.get());
420         const uint32_t event_type = iter.list->parameter().type();
421         
422         // initialize the event pointer with a new event, if necessary
423         if (!ev) {
424                 ev = boost::shared_ptr< Event<Time> >(new Event<Time>(event_type, 0, 3, NULL, true));
425         }
426         
427         uint8_t midi_type = _type_map.parameter_midi_type(iter.list->parameter());
428         ev->set_event_type(_type_map.midi_event_type(midi_type));
429         switch (midi_type) {
430         case MIDI_CMD_CONTROL:
431                 assert(iter.list.get());
432                 assert(iter.list->parameter().channel() < 16);
433                 assert(iter.list->parameter().id() <= INT8_MAX);
434                 assert(iter.y <= INT8_MAX);
435                 
436                 ev->time() = iter.x;
437                 ev->realloc(3);
438                 ev->buffer()[0] = MIDI_CMD_CONTROL + iter.list->parameter().channel();
439                 ev->buffer()[1] = (uint8_t)iter.list->parameter().id();
440                 ev->buffer()[2] = (uint8_t)iter.y;
441                 break;
442
443         case MIDI_CMD_PGM_CHANGE:
444                 assert(iter.list.get());
445                 assert(iter.list->parameter().channel() < 16);
446                 assert(iter.y <= INT8_MAX);
447                 
448                 ev->time() = iter.x;
449                 ev->realloc(2);
450                 ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.list->parameter().channel();
451                 ev->buffer()[1] = (uint8_t)iter.y;
452                 break;
453
454         case MIDI_CMD_BENDER:
455                 assert(iter.list.get());
456                 assert(iter.list->parameter().channel() < 16);
457                 assert(iter.y < (1<<14));
458                 
459                 ev->time() = iter.x;
460                 ev->realloc(3);
461                 ev->buffer()[0] = MIDI_CMD_BENDER + iter.list->parameter().channel();
462                 ev->buffer()[1] = uint16_t(iter.y) & 0x7F; // LSB
463                 ev->buffer()[2] = (uint16_t(iter.y) >> 7) & 0x7F; // MSB
464                 break;
465
466         case MIDI_CMD_CHANNEL_PRESSURE:
467                 assert(iter.list.get());
468                 assert(iter.list->parameter().channel() < 16);
469                 assert(iter.y <= INT8_MAX);
470
471                 ev->time() = iter.x;
472                 ev->realloc(2);
473                 ev->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.list->parameter().channel();
474                 ev->buffer()[1] = (uint8_t)iter.y;
475                 break;
476
477         default:
478                 return false;
479         }
480
481         return true;
482 }
483
484 /** Clear all events from the model.
485  */
486 template<typename Time>
487 void
488 Sequence<Time>::clear()
489 {
490         _lock.writer_lock();
491         _notes.clear();
492         for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li)
493                 li->second->list()->clear();
494         _read_iter = end();
495         _lock.writer_unlock();
496 }
497
498 /** Begin a write of events to the model.
499  *
500  * If \a mode is Sustained, complete notes with length are constructed as note
501  * on/off events are received.  Otherwise (Percussive), only note on events are
502  * stored; note off events are discarded entirely and all contained notes will
503  * have length 0.
504  */
505 template<typename Time>
506 void
507 Sequence<Time>::start_write()
508 {
509         DUMP(format("%1% : start_write (percussive = %2%)\n") % this % _percussive);
510         write_lock();
511         _writing = true;
512         for (int i = 0; i < 16; ++i) {
513                 _write_notes[i].clear();
514         }
515         _dirty_controls.clear();
516         write_unlock();
517 }
518
519 /** Finish a write of events to the model.
520  *
521  * If \a delete_stuck is true and the current mode is Sustained, note on events
522  * that were never resolved with a corresonding note off will be deleted.
523  * Otherwise they will remain as notes with length 0.
524  */
525 template<typename Time>
526 void
527 Sequence<Time>::end_write(bool delete_stuck)
528 {
529         write_lock();
530         assert(_writing);
531
532         DUMP(format("%1% : end_write (%2% notes)\n") % this % _notes.size());
533
534         if (!_percussive && delete_stuck) {
535                 for (typename Notes::iterator n = _notes.begin(); n != _notes.end() ;) {
536                         if ((*n)->length() == 0) {
537                                 cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
538                                 n = _notes.erase(n);
539                                 // we have to break here because erase invalidates the iterator
540                                 break;
541                         } else {
542                                 ++n;
543                         }
544                 }
545         }
546
547         for (int i = 0; i < 16; ++i) {
548                 if (!_write_notes[i].empty()) {
549                         cerr << "WARNING: Sequence<Time>::end_write: Channel " << i << " has "
550                                         << _write_notes[i].size() << " stuck notes" << endl;
551                 }
552                 _write_notes[i].clear();
553         }
554
555         for (ControlLists::const_iterator i = _dirty_controls.begin(); i != _dirty_controls.end(); ++i) {
556                 (*i)->mark_dirty();
557         }
558         
559         _writing = false;
560         write_unlock();
561 }
562
563 /** Append \a ev to model.  NOT realtime safe.
564  *
565  * Timestamps of events in \a buf are expected to be relative to
566  * the start of this model (t=0) and MUST be monotonically increasing
567  * and MUST be >= the latest event currently in the model.
568  */
569 template<typename Time>
570 void
571 Sequence<Time>::append(const Event<Time>& event)
572 {
573         write_lock();
574         _edited = true;
575         
576         const MIDIEvent<Time>& ev = (const MIDIEvent<Time>&)event;
577
578         assert(_notes.empty() || ev.time() >= _notes.back()->time());
579         assert(_writing);
580
581         if (!midi_event_is_valid(ev.buffer(), ev.size())) {
582                 cerr << "WARNING: Sequence ignoring illegal MIDI event" << endl;
583                 write_unlock();
584                 return;
585         }
586
587         if (ev.is_note_on()) {
588                 append_note_on_unlocked(ev.channel(), ev.time(), ev.note(), ev.velocity());
589         } else if (ev.is_note_off()) {
590                 append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
591         } else if (ev.is_sysex()) {
592                 append_sysex_unlocked(ev);
593         } else if (!_type_map.type_is_midi(ev.event_type())) {
594                 printf("WARNING: Sequence: Unknown event type %X: ", ev.event_type());
595                 for (size_t i=0; i < ev.size(); ++i) {
596                         printf("%X ", ev.buffer()[i]);
597                 }
598                 printf("\n");
599         } else if (ev.is_cc()) {
600                 append_control_unlocked(
601                                 Evoral::MIDI::ContinuousController(ev.event_type(), ev.channel(), ev.cc_number()),
602                                 ev.time(), ev.cc_value());
603         } else if (ev.is_pgm_change()) {
604                 append_control_unlocked(
605                                 Evoral::MIDI::ProgramChange(ev.event_type(), ev.channel()),
606                                 ev.time(), ev.pgm_number());
607         } else if (ev.is_pitch_bender()) {
608                 append_control_unlocked(
609                                 Evoral::MIDI::PitchBender(ev.event_type(), ev.channel()),
610                                 ev.time(), double(  (0x7F & ev.pitch_bender_msb()) << 7
611                                         | (0x7F & ev.pitch_bender_lsb()) ));
612         } else if (ev.is_channel_pressure()) {
613                 append_control_unlocked(
614                                 Evoral::MIDI::ChannelPressure(ev.event_type(), ev.channel()),
615                                 ev.time(), ev.channel_pressure());
616         } else {
617                 printf("WARNING: Sequence: Unknown MIDI event type %X\n", ev.type());
618         }
619
620         write_unlock();
621 }
622
623 template<typename Time>
624 void
625 Sequence<Time>::append_note_on_unlocked(uint8_t chan, Time time, uint8_t note_num, uint8_t velocity)
626 {
627         DUMP(format("%1% c=%2% note %3% on @ %4% v=%5%\n")
628                         % this % (int)chan % (int)note_num % time % (int)velocity);
629         assert(note_num <= 127);
630         assert(chan < 16);
631         assert(_writing);
632         _edited = true;
633
634         if (velocity == 0) {
635                 append_note_off_unlocked(chan, time, note_num);
636                 return;
637         }
638
639         if (note_num < _lowest_note)
640                 _lowest_note = note_num;
641         if (note_num > _highest_note)
642                 _highest_note = note_num;
643
644         boost::shared_ptr< Note<Time> > new_note(new Note<Time>(chan, time, 0, note_num, velocity));
645         _notes.push_back(new_note);
646         if (!_percussive) {
647                 DUMP(format("Sustained: Appending active note on %1% channel %2%\n")
648                                 % (unsigned)(uint8_t)note_num % chan);
649                 _write_notes[chan].push_back(_notes.size() - 1);
650         } else {
651                 DUMP("Percussive: NOT appending active note on\n");
652          }
653 }
654
655 template<typename Time>
656 void
657 Sequence<Time>::append_note_off_unlocked(uint8_t chan, Time time, uint8_t note_num)
658 {
659         DUMP(format("%1% c=%2% note %3% off @ %4%\n")
660                         % this % (int)chan % (int)note_num % time);
661         assert(note_num <= 127);
662         assert(chan < 16);
663         assert(_writing);
664         _edited = true;
665
666         if (_percussive) {
667                 DUMP("Sequence Ignoring note off (percussive mode)\n");
668                 return;
669         }
670
671         /* FIXME: make _write_notes fixed size (127 noted) for speed */
672
673         /* FIXME: note off velocity for that one guy out there who actually has
674          * keys that send it */
675
676         bool resolved = false;
677
678         for (WriteNotes::iterator n = _write_notes[chan].begin(); n
679                         != _write_notes[chan].end(); ++n) {
680                 Note<Time>& note = *_notes[*n].get();
681                 if (note.note() == note_num) {
682                         assert(time >= note.time());
683                         note.set_length(time - note.time());
684                         _write_notes[chan].erase(n);
685                         DUMP(format("resolved note, length: %1%\n") % note.length());
686                         resolved = true;
687                         break;
688                 }
689         }
690
691         if (!resolved) {
692                 cerr << this << " spurious note off chan " << (int)chan
693                                 << ", note " << (int)note_num << " @ " << time << endl;
694         }
695 }
696
697 template<typename Time>
698 void
699 Sequence<Time>::append_control_unlocked(const Parameter& param, Time time, double value)
700 {
701         DUMP(format("%1% %2% @ %3%\t=\t%4% # controls: %5%\n")
702                         % this % _type_map.to_symbol(param) % time % value % _controls.size());
703         boost::shared_ptr<Control> c = control(param, true);
704         c->list()->rt_add(time, value);
705 }
706
707 template<typename Time>
708 void
709 Sequence<Time>::append_sysex_unlocked(const MIDIEvent<Time>& ev)
710 {
711         #ifdef DEBUG_SEQUENCE
712         cerr << this << " SysEx @ " << ev.time() << " \t= \t [ " << hex;
713         for (size_t i=0; i < ev.size(); ++i) {
714                 cerr << int(ev.buffer()[i]) << " ";
715         } cerr << "]" << endl;
716         #endif
717
718         boost::shared_ptr<MIDIEvent<Time> > event(new MIDIEvent<Time>(ev, true));
719         _sysexes.push_back(event);
720 }
721
722 template<typename Time>
723 void
724 Sequence<Time>::add_note_unlocked(const boost::shared_ptr< Note<Time> > note)
725 {
726         DUMP(format("%1% add note %2% @ %3%\n") % this % (int)note->note() % note->time());
727         _edited = true;
728         typename Notes::iterator i = upper_bound(_notes.begin(), _notes.end(), note,
729                         note_time_comparator);
730         _notes.insert(i, note);
731 }
732
733 template<typename Time>
734 void
735 Sequence<Time>::remove_note_unlocked(const boost::shared_ptr< const Note<Time> > note)
736 {
737         _edited = true;
738         DUMP(format("%1% remove note %2% @ %3%\n") % this % (int)note->note() % note->time());
739         for (typename Notes::iterator n = _notes.begin(); n != _notes.end(); ++n) {
740                 if (*(*n) == *note) {
741                         _notes.erase(n);
742                         break;
743                 }
744         }
745 }
746
747 template class Sequence<double>;
748
749 } // namespace Evoral
750