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