* enlage MidiBuffer size to 128 bytes to allow for sysex events
[ardour.git] / libs / evoral / src / Sequence.cpp
index 9e073699d944fdb784562f1785f124a023f2b2e5..7781ea890707259dae0422d965ff083f6677babf 100644 (file)
 #include <algorithm>
 #include <stdexcept>
 #include <stdint.h>
-#include <evoral/Sequence.hpp>
-#include <evoral/ControlList.hpp>
-#include <evoral/Control.hpp>
-#include <evoral/ControlSet.hpp>
-#include <evoral/EventSink.hpp>
-#include <evoral/MIDIParameters.hpp>
+#include "evoral/Sequence.hpp"
+#include "evoral/ControlList.hpp"
+#include "evoral/Control.hpp"
+#include "evoral/ControlSet.hpp"
+#include "evoral/EventSink.hpp"
+#include "evoral/MIDIParameters.hpp"
+#include "evoral/TypeMap.hpp"
 
 using namespace std;
 
@@ -58,13 +59,12 @@ struct null_ostream : public std::ostream {
 static null_ostream nullout;
 
 //static ostream& debugout = cout;
-//static ostream& errorout = cerr;
 static ostream& debugout = nullout;
-static ostream& errorout = nullout;
+static ostream& errorout = cerr;
 
 // Read iterator (const_iterator)
 
-Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
+Sequence::const_iterator::const_iterator(const Sequence& seq, EventTime t)
        : _seq(&seq)
        , _is_end( (t == DBL_MAX) || seq.empty() )
        , _locked( !_is_end )
@@ -77,8 +77,8 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
 
        seq.read_lock();
 
-       _note_iter = seq.notes().end();
        // find first note which begins after t
+       _note_iter = seq.notes().end();
        for (Sequence::Notes::const_iterator i = seq.notes().begin(); i != seq.notes().end(); ++i) {
                if ((*i)->time() >= t) {
                        _note_iter = i;
@@ -92,7 +92,7 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
        
        // find the earliest control event available
        for (Controls::const_iterator i = seq._controls.begin(); i != seq._controls.end(); ++i) {
-               debugout << "Iterator: control: " << i->first.symbol() << endl;
+               debugout << "Iterator: control: " << seq._type_map.to_symbol(i->first) << endl;
                double x, y;
                bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
                if (!ret) {
@@ -125,26 +125,18 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
                }
        }
 
-       if (_note_iter != seq.notes().end()) {
+       if (_note_iter != seq.notes().end()
+                       && (*_note_iter)->on_event().time() >= t
+                       && (!earliest_control.list
+                               || (*_note_iter)->on_event().time() < earliest_control.x)) {
+               debugout << "Reading note on event @ " << (*_note_iter)->on_event().time() << endl;
                _event = boost::shared_ptr<Event>(new Event((*_note_iter)->on_event(), true));
-       }
-
-       double time = DBL_MAX;
-       // in case we have no notes in the region, we still want to get controller messages
-       if (_event.get()) {
-               time = _event->time();
-               // if the note is going to make it this turn, advance _note_iter
-               if (earliest_control.x > time) {
-                       _active_notes.push(*_note_iter);
-                       ++_note_iter;
-               }
-       }
-       
-       // <=, because we probably would want to send control events first 
-       if (earliest_control.list.get() && earliest_control.x <= time) {
-               seq.control_to_midi_event(_event, earliest_control);
-       } else {
+               _active_notes.push(*_note_iter);
+               ++_note_iter;
                _control_iter = _control_iters.end();
+       } else if (earliest_control.list) {
+               debugout << "Reading control event @ " << earliest_control.x << endl;
+               seq.control_to_midi_event(_event, earliest_control);
        }
 
        if ( (! _event.get()) || _event->size() == 0) {
@@ -159,11 +151,12 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
                        _locked = false;
                }
        } else {
-               debugout << "New Iterator = " << hex << _event->type();
+               debugout << "New Iterator = " << _event->event_type();
+               debugout << " : " << hex << (int)((MIDIEvent*)_event.get())->type();
                debugout << " @ " <<  _event->time() << endl;
        }
 
-       assert(_is_end || (_event->buffer() && _event->buffer()[0] != '\0'));
+       //assert(_is_end || (_event->buffer() && _event->buffer()[0] != '\0'));
 }
 
 Sequence::const_iterator::~const_iterator()
@@ -180,38 +173,42 @@ Sequence::const_iterator& Sequence::const_iterator::operator++()
                throw std::logic_error("Attempt to iterate past end of Sequence");
        }
        
-       assert(_event->buffer() && _event->buffer()[0] != '\0');
+       debugout << "Iterator ++" << endl;
+       assert(_event->buffer() && _event->size() > 0);
+       
+       const MIDIEvent& ev = *((MIDIEvent*)_event.get());
 
        //debugout << "const_iterator::operator++: " << _event->to_string() << endl;
 
-       if (! (_event->is_note() || _event->is_cc() || _event->is_pgm_change()
-                               || _event->is_pitch_bender() || _event->is_channel_aftertouch()) ) {
-               errorout << "Unknown event type: " << hex << int(_event->buffer()[0])
-                       << int(_event->buffer()[1]) << int(_event->buffer()[2]) << endl;
+       if (! (ev.is_note() || ev.is_cc() || ev.is_pgm_change()
+                               || ev.is_pitch_bender() || ev.is_channel_pressure()) ) {
+               errorout << "Unknown event type: " << hex << int(ev.buffer()[0])
+                       << int(ev.buffer()[1]) << int(ev.buffer()[2]) << endl;
        }
-       assert((_event->is_note() || _event->is_cc() || _event->is_pgm_change() || _event->is_pitch_bender() || _event->is_channel_aftertouch()));
+       assert((ev.is_note() || ev.is_cc() || ev.is_pgm_change() || ev.is_pitch_bender() || ev.is_channel_pressure()));
 
        // Increment past current control event
-       if (!_event->is_note() && _control_iter != _control_iters.end() && _control_iter->list.get()) {
+       if (!ev.is_note() && _control_iter != _control_iters.end() && _control_iter->list.get()) {
                double x = 0.0, y = 0.0;
                const bool ret = _control_iter->list->rt_safe_earliest_event_unlocked(
                                _control_iter->x, DBL_MAX, x, y, false);
 
+               assert(!ret || x > _control_iter->x);
+
                if (ret) {
                        _control_iter->x = x;
                        _control_iter->y = y;
                } else {
                        _control_iter->list.reset();
                        _control_iter->x = DBL_MAX;
+                       _control_iter->y = DBL_MAX;
                }
        }
 
-       const std::vector<ControlIterator>::iterator old_control_iter = _control_iter;
        _control_iter = _control_iters.begin();
 
        // find the _control_iter with the earliest event time
-       for (std::vector<ControlIterator>::iterator i = _control_iters.begin();
-                       i != _control_iters.end(); ++i) {
+       for (ControlIterators::iterator i = _control_iters.begin(); i != _control_iters.end(); ++i) {
                if (i->x < _control_iter->x) {
                        _control_iter = i;
                }
@@ -220,7 +217,7 @@ Sequence::const_iterator& Sequence::const_iterator::operator++()
        enum Type {NIL, NOTE_ON, NOTE_OFF, CONTROL};
 
        Type type = NIL;
-       double t = 0;
+       EventTime t = 0;
 
        // Next earliest note on
        if (_note_iter != _seq->notes().end()) {
@@ -230,15 +227,14 @@ Sequence::const_iterator& Sequence::const_iterator::operator++()
 
        // Use the next earliest note off iff it's earlier than the note on
        if (!_seq->percussive() && (! _active_notes.empty())) {
-               if (type == NIL || _active_notes.top()->end_time() <= (*_note_iter)->time()) {
+               if (type == NIL || _active_notes.top()->end_time() <= t) {
                        type = NOTE_OFF;
                        t = _active_notes.top()->end_time();
                }
        }
 
        // Use the next earliest controller iff it's earlier than the note event
-       if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX
-                       && _control_iter != old_control_iter) {
+       if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX) {
                if (type == NIL || _control_iter->x < t) {
                        type = CONTROL;
                }
@@ -261,7 +257,7 @@ Sequence::const_iterator& Sequence::const_iterator::operator++()
                _is_end = true;
        }
 
-       assert(_is_end || _event->size() > 0);
+       assert(_is_end || (_event->size() > 0 && _event->buffer() && _event->buffer()[0] != '\0'));
 
        return *this;
 }
@@ -292,8 +288,16 @@ Sequence::const_iterator::operator=(const const_iterator& other)
        size_t index   = other._control_iter - other._control_iters.begin();
        _control_iter  = _control_iters.begin() + index;
        
-       if (!_is_end) {
-               _event =  boost::shared_ptr<Event>(new Event(*other._event, true));
+       if (!_is_end && other._event) {
+               if (_event) {
+                       *_event = *other._event.get();
+               } else {
+                       _event = boost::shared_ptr<Event>(new Event(*other._event, true));
+               }
+       } else {
+               if (_event) {
+                       _event->clear();
+               }
        }
 
        return *this;
@@ -301,14 +305,17 @@ Sequence::const_iterator::operator=(const const_iterator& other)
 
 // Sequence
 
-Sequence::Sequence(size_t size)
+Sequence::Sequence(const TypeMap& type_map, size_t size)
        : _read_iter(*this, DBL_MAX)
        , _edited(false)
+       , _type_map(type_map)
        , _notes(size)
        , _writing(false)
        , _end_iter(*this, DBL_MAX)
        , _next_read(UINT32_MAX)
        , _percussive(false)
+       , _lowest_note(127)
+       , _highest_note(0)
 {
        debugout << "Sequence (size " << size << ") constructed: " << this << endl;
        assert(_end_iter._is_end);
@@ -322,34 +329,34 @@ Sequence::Sequence(size_t size)
 size_t
 Sequence::read(EventSink& dst, timestamp_t start, timedur_t nframes, timestamp_t offset) const
 {
-       debugout << this << " read ev @ " << start << " * " << nframes << " + " << offset << endl;
+       debugout << this << " read @ " << start << " * " << nframes << " + " << offset << endl;
        debugout << this << " # notes: " << n_notes() << endl;
-       debugout << this << " controls: " << &_controls << endl;
        debugout << this << " # controls: " << _controls.size() << endl;
 
        size_t read_events = 0;
 
        if (start != _next_read) {
-               _read_iter = const_iterator(*this, (double)start);
                debugout << "Repositioning iterator from " << _next_read << " to " << start << endl;
+               _read_iter = const_iterator(*this, (double)start);
        } else {
                debugout << "Using cached iterator at " << _next_read << endl;
        }
 
-       _next_read = (nframes_t) floor (start + nframes);
+       _next_read = (FrameTime) floor (start + nframes);
 
        while (_read_iter != end() && _read_iter->time() < start + nframes) {
                assert(_read_iter->size() > 0);
                assert(_read_iter->buffer());
                dst.write(_read_iter->time() + offset,
+                         _read_iter->event_type(),
                          _read_iter->size(), 
                          _read_iter->buffer());
                
-                debugout << this << " read event @ " << _read_iter->time()  
-                                << " type: " << hex << int(_read_iter->type()) << dec 
-                                << " note: " << int(_read_iter->note()) 
-                                << " velocity: " << int(_read_iter->velocity()) 
-                                << endl;
+                debugout << this << " read event type " << _read_iter->event_type()
+                        << " @ " << _read_iter->time() << " : ";
+                for (size_t i = 0; i < _read_iter->size(); ++i)
+                        debugout << hex << (int)_read_iter->buffer()[i];
+                debugout << endl;
                
                ++_read_iter;
                ++read_events;
@@ -360,18 +367,22 @@ Sequence::read(EventSink& dst, timestamp_t start, timedur_t nframes, timestamp_t
 
 /** Write the controller event pointed to by \a iter to \a ev.
  * The buffer of \a ev will be allocated or resized as necessary.
+ * The event_type of \a ev should be set to the expected output type.
  * \return true on success
  */
 bool
 Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlIterator& iter) const
 {
        assert(iter.list.get());
+       const uint32_t event_type = iter.list->parameter().type();
        if (!ev) {
-               ev = boost::shared_ptr<Event>(new Event(0, 3, NULL, true));
+               ev = boost::shared_ptr<Event>(new Event(event_type, 0, 3, NULL, true));
        }
        
-       switch (iter.list->parameter().type()) {
-       case midi_cc_type:
+       uint8_t midi_type = _type_map.parameter_midi_type(iter.list->parameter());
+       ev->set_event_type(_type_map.midi_event_type(midi_type));
+       switch (midi_type) {
+       case MIDI_CMD_CONTROL:
                assert(iter.list.get());
                assert(iter.list->parameter().channel() < 16);
                assert(iter.list->parameter().id() <= INT8_MAX);
@@ -384,10 +395,9 @@ Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlItera
                ev->buffer()[2] = (uint8_t)iter.y;
                break;
 
-       case midi_pc_type:
+       case MIDI_CMD_PGM_CHANGE:
                assert(iter.list.get());
                assert(iter.list->parameter().channel() < 16);
-               assert(iter.list->parameter().id() == 0);
                assert(iter.y <= INT8_MAX);
                
                ev->time() = iter.x;
@@ -396,10 +406,9 @@ Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlItera
                ev->buffer()[1] = (uint8_t)iter.y;
                break;
 
-       case midi_pb_type:
+       case MIDI_CMD_BENDER:
                assert(iter.list.get());
                assert(iter.list->parameter().channel() < 16);
-               assert(iter.list->parameter().id() == 0);
                assert(iter.y < (1<<14));
                
                ev->time() = iter.x;
@@ -409,10 +418,9 @@ Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlItera
                ev->buffer()[2] = (uint16_t(iter.y) >> 7) & 0x7F; // MSB
                break;
 
-       case midi_ca_type:
+       case MIDI_CMD_CHANNEL_PRESSURE:
                assert(iter.list.get());
                assert(iter.list->parameter().channel() < 16);
-               assert(iter.list->parameter().id() == 0);
                assert(iter.y <= INT8_MAX);
 
                ev->time() = iter.x;
@@ -444,10 +452,10 @@ Sequence::clear()
 
 /** Begin a write of events to the model.
  *
- * If \a mode is Sustained, complete notes with duration are constructed as note
+ * If \a mode is Sustained, complete notes with length are constructed as note
  * on/off events are received.  Otherwise (Percussive), only note on events are
  * stored; note off events are discarded entirely and all contained notes will
- * have duration 0.
+ * have length 0.
  */
 void
 Sequence::start_write()
@@ -466,7 +474,7 @@ Sequence::start_write()
  *
  * If \a delete_stuck is true and the current mode is Sustained, note on events
  * that were never resolved with a corresonding note off will be deleted.
- * Otherwise they will remain as notes with duration 0.
+ * Otherwise they will remain as notes with length 0.
  */
 void
 Sequence::end_write(bool delete_stuck)
@@ -478,7 +486,7 @@ Sequence::end_write(bool delete_stuck)
 
        if (!_percussive && delete_stuck) {
                for (Notes::iterator n = _notes.begin(); n != _notes.end() ;) {
-                       if ((*n)->duration() == 0) {
+                       if ((*n)->length() == 0) {
                                errorout << "WARNING: Stuck note lost: " << (*n)->note() << endl;
                                n = _notes.erase(n);
                                // we have to break here because erase invalidates the iterator
@@ -512,10 +520,12 @@ Sequence::end_write(bool delete_stuck)
  * and MUST be >= the latest event currently in the model.
  */
 void
-Sequence::append(const Event& ev)
+Sequence::append(const Event& event)
 {
        write_lock();
        _edited = true;
+       
+       const MIDIEvent& ev = (const MIDIEvent&)event;
 
        assert(_notes.empty() || ev.time() >= _notes.back()->time());
        assert(_writing);
@@ -525,32 +535,38 @@ Sequence::append(const Event& ev)
                                ev.velocity());
        } else if (ev.is_note_off()) {
                append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
+       } else if (!_type_map.type_is_midi(ev.event_type())) {
+               printf("WARNING: Sequence: Unknown event type %X: ", ev.event_type());
+               for (size_t i=0; i < ev.size(); ++i) {
+                       printf("%X ", ev.buffer()[i]);
+               }
+               printf("\n");
        } else if (ev.is_cc()) {
                append_control_unlocked(
-                               Evoral::MIDI::ContinuousController(midi_cc_type, ev.channel(), ev.cc_number()),
+                               Evoral::MIDI::ContinuousController(ev.event_type(), ev.channel(), ev.cc_number()),
                                ev.time(), ev.cc_value());
        } else if (ev.is_pgm_change()) {
                append_control_unlocked(
-                               Evoral::MIDI::ProgramChange(midi_pc_type, ev.channel()),
+                               Evoral::MIDI::ProgramChange(ev.event_type(), ev.channel()),
                                ev.time(), ev.pgm_number());
        } else if (ev.is_pitch_bender()) {
                append_control_unlocked(
-                               Evoral::MIDI::PitchBender(midi_pb_type, ev.channel()),
+                               Evoral::MIDI::PitchBender(ev.event_type(), ev.channel()),
                                ev.time(), double(  (0x7F & ev.pitch_bender_msb()) << 7
-                                                 | (0x7F & ev.pitch_bender_lsb()) ));
-       } else if (ev.is_channel_aftertouch()) {
+                                       | (0x7F & ev.pitch_bender_lsb()) ));
+       } else if (ev.is_channel_pressure()) {
                append_control_unlocked(
-                               Evoral::MIDI::ChannelAftertouch(midi_ca_type, ev.channel()),
-                               ev.time(), ev.channel_aftertouch());
+                               Evoral::MIDI::ChannelPressure(ev.event_type(), ev.channel()),
+                               ev.time(), ev.channel_pressure());
        } else {
-               printf("WARNING: Sequence: Unknown event type %X\n", ev.type());
+               printf("WARNING: Sequence: Unknown MIDI event type %X\n", ev.type());
        }
 
        write_unlock();
 }
 
 void
-Sequence::append_note_on_unlocked(uint8_t chan, double time, uint8_t note_num, uint8_t velocity)
+Sequence::append_note_on_unlocked(uint8_t chan, EventTime time, uint8_t note_num, uint8_t velocity)
 {
        debugout << this << " c" << (int)chan << " note " << (int)note_num << " off @ " << time << endl;
        assert(note_num <= 127);
@@ -558,6 +574,11 @@ Sequence::append_note_on_unlocked(uint8_t chan, double time, uint8_t note_num, u
        assert(_writing);
        _edited = true;
 
+       if (note_num < _lowest_note)
+               _lowest_note = note_num;
+       if (note_num > _highest_note)
+               _highest_note = note_num;
+
        boost::shared_ptr<Note> new_note(new Note(chan, time, 0, note_num, velocity));
        _notes.push_back(new_note);
        if (!_percussive) {
@@ -569,7 +590,7 @@ Sequence::append_note_on_unlocked(uint8_t chan, double time, uint8_t note_num, u
 }
 
 void
-Sequence::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
+Sequence::append_note_off_unlocked(uint8_t chan, EventTime time, uint8_t note_num)
 {
        debugout << this << " c" << (int)chan << " note " << (int)note_num << " off @ " << time << endl;
        assert(note_num <= 127);
@@ -594,9 +615,9 @@ Sequence::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
                Note& note = *_notes[*n].get();
                if (note.note() == note_num) {
                        assert(time >= note.time());
-                       note.set_duration(time - note.time());
+                       note.set_length(time - note.time());
                        _write_notes[chan].erase(n);
-                       debugout << "resolved note, duration: " << note.duration() << endl;
+                       debugout << "resolved note, length: " << note.length() << endl;
                        resolved = true;
                        break;
                }
@@ -609,12 +630,12 @@ Sequence::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
 }
 
 void
-Sequence::append_control_unlocked(const Parameter& param, double time, double value)
+Sequence::append_control_unlocked(const Parameter& param, EventTime time, double value)
 {
-       debugout << this << " " << param.symbol() << " @ " << time << " = " << value
-                       << " controls: " << &_controls
+       debugout << this << " " << _type_map.to_symbol(param) << " @ " << time << " \t= \t" << value
                        << " # controls: " << _controls.size() << endl;
-       control(param, true)->list()->rt_add(time, value);
+       boost::shared_ptr<Control> c = control(param, true);
+       c->list()->rt_add(time, value);
 }
 
 
@@ -640,8 +661,8 @@ Sequence::remove_note_unlocked(const boost::shared_ptr<const Note> note)
                // persisted undo does not work, because of rounding errors in the
                // event times after saving/restoring to/from MIDI files
                /*cerr << "======================================= " << endl;
-               cerr << int(_n.note()) << "@" << int(_n.time()) << "[" << int(_n.channel()) << "] --" << int(_n.duration()) << "-- #" << int(_n.velocity()) << endl;
-               cerr << int(_note.note()) << "@" << int(_note.time()) << "[" << int(_note.channel()) << "] --" << int(_note.duration()) << "-- #" << int(_note.velocity()) << endl;
+               cerr << int(_n.note()) << "@" << int(_n.time()) << "[" << int(_n.channel()) << "] --" << int(_n.length()) << "-- #" << int(_n.velocity()) << endl;
+               cerr << int(_note.note()) << "@" << int(_note.time()) << "[" << int(_note.channel()) << "] --" << int(_note.length()) << "-- #" << int(_note.velocity()) << endl;
                cerr << "Equal: " << bool(_n == _note) << endl;
                cerr << endl << endl;*/
                if (_n == _note) {