remove complex iterators from Evoral::Sequence and add "global" _events member to store shared_ptr to all events in a time-ordered map

This commit is contained in:
Paul Davis 2016-11-03 14:38:35 +00:00
parent cb567dd881
commit a565955d30
14 changed files with 102 additions and 215 deletions

View file

@ -39,9 +39,9 @@ class LIBARDOUR_API MidiPatternSource : public MidiSource, public PatternSource
MidiSource one, so these are no-ops.
*/
void append_event_beats(const Lock& lock,
const Evoral::Event<Evoral::Beats>& ev) {}
boost::shared_ptr<Evoral::Event<Evoral::Beats> > const & ev) {}
void append_event_frames(const Lock& lock,
const Evoral::Event<framepos_t>& ev,
boost::shared_ptr<Evoral::Event<framepos_t> > const & ev,
framepos_t source_start) {}
void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode) {}
void mark_streaming_write_started (const Lock& lock) {}

View file

@ -45,8 +45,8 @@ public:
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
void append_event_beats(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<Evoral::Beats>& ev);
void append_event_frames(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<framepos_t>& ev, framepos_t source_start);
void append_event_beats(const Glib::Threads::Mutex::Lock& lock, boost::shared_ptr<Evoral::Event<Evoral::Beats> > const & ev);
void append_event_frames(const Glib::Threads::Mutex::Lock& lock, boost::shared_ptr<Evoral::Event<framepos_t> > const & ev, framepos_t source_start);
void load_model(const Glib::Threads::Mutex::Lock& lock, bool force_reload=false);
void destroy_model(const Glib::Threads::Mutex::Lock& lock);

View file

@ -114,16 +114,13 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
*
* Caller must ensure that the event is later than the last written event.
*/
virtual void append_event_beats(const Lock& lock,
const Evoral::Event<Evoral::Beats>& ev) = 0;
virtual void append_event_beats(Lock const & lock, boost::shared_ptr<Evoral::Event<Evoral::Beats> > const & ev) = 0;
/** Append a single event with a timestamp in frames.
*
* Caller must ensure that the event is later than the last written event.
*/
virtual void append_event_frames(const Lock& lock,
const Evoral::Event<framepos_t>& ev,
framepos_t source_start) = 0;
virtual void append_event_frames(Lock const & lock, const boost::shared_ptr <Evoral::Event<framepos_t> > & ev, framepos_t source_start) = 0;
virtual bool empty () const;
virtual framecnt_t length (framepos_t pos) const;

View file

@ -51,8 +51,8 @@ public:
return safe_midi_file_extension(path);
}
void append_event_beats (const Lock& lock, const Evoral::Event<Evoral::Beats>& ev);
void append_event_frames (const Lock& lock, const Evoral::Event<framepos_t>& ev, framepos_t source_start);
void append_event_beats (const Lock& lock, boost::shared_ptr<Evoral::Event<Evoral::Beats> > const & ev);
void append_event_frames (const Lock& lock, boost::shared_ptr<Evoral::Event<framepos_t> > const & ev, framepos_t source_start);
void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode);
void mark_streaming_write_completed (const Lock& lock);

View file

@ -415,13 +415,13 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
first = false;
}
smfs->append_event_beats(
source_lock,
Evoral::Event<Evoral::Beats>(
0,
Evoral::Beats::ticks_at_rate(t, source->ppqn()),
size,
buf));
smfs->append_event_beats (source_lock,
boost::shared_ptr<Evoral::Event<Evoral::Beats> > (
new Evoral::Event<Evoral::Beats> (
0,
Evoral::Beats::ticks_at_rate(t, source->ppqn()),
size,
buf)));
if (status.progress < 0.99) {
status.progress += 0.01;
@ -629,4 +629,3 @@ Session::import_files (ImportStatus& status)
status.done = true;
}

View file

@ -1429,11 +1429,11 @@ MidiModel::write_to (boost::shared_ptr<MidiSource> source,
source->mark_streaming_midi_write_started (source_lock, note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin (); i != end(); ++i) {
source->append_event_beats(source_lock, *i);
source->append_event_beats (source_lock, *i);
}
set_percussive(old_percussive);
source->mark_streaming_write_completed(source_lock);
source->mark_streaming_write_completed (source_lock);
set_edited(false);
@ -1502,17 +1502,17 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source,
source->mark_streaming_midi_write_started (source_lock, note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin (); i != end(); ++i) {
if (i->time() >= begin_time && i->time() < end_time) {
if ((*i)->time() >= begin_time && (*i)->time() < end_time) {
Evoral::MIDIEvent<TimeType> mev (*i, true); /* copy the event */
boost::shared_ptr<Evoral::MIDIEvent<TimeType> > mev (new Evoral::MIDIEvent<TimeType> (**i, true)); /* copy the event */
if (offset_events) {
mev.set_time(mev.time() - begin_time);
mev->set_time(mev->time() - begin_time);
}
if (mev.is_note_off()) {
if (mev->is_note_off()) {
if (!mst.active (mev.note(), mev.channel())) {
if (!mst.active (mev->note(), mev->channel())) {
/* the matching note-on was outside the
time range we were given, so just
ignore this note-off.
@ -1521,10 +1521,10 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source,
}
source->append_event_beats (source_lock, mev);
mst.remove (mev.note(), mev.channel());
mst.remove (mev->note(), mev->channel());
} else if (mev.is_note_on()) {
mst.add (mev.note(), mev.channel());
} else if (mev->is_note_on()) {
mst.add (mev->note(), mev->channel());
source->append_event_beats(source_lock, mev);
} else {
source->append_event_beats(source_lock, mev);

View file

@ -152,14 +152,14 @@ MidiPlaylistSource::write_unlocked (const Lock&,
}
void
MidiPlaylistSource::append_event_beats(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<Evoral::Beats>& /*ev*/)
MidiPlaylistSource::append_event_beats(const Glib::Threads::Mutex::Lock& /*lock*/, boost::shared_ptr<Evoral::Event<Evoral::Beats> > const & /*ev*/)
{
fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_beats() called - should be impossible") << endmsg;
abort(); /*NOTREACHED*/
}
void
MidiPlaylistSource::append_event_frames(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<framepos_t>& /* ev */, framepos_t /*source_start*/)
MidiPlaylistSource::append_event_frames(const Glib::Threads::Mutex::Lock& /*lock*/, boost::shared_ptr<Evoral::Event<framepos_t> > const & /* ev */, framepos_t /*source_start*/)
{
fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_frames() called - should be impossible") << endmsg;
abort(); /*NOTREACHED*/

View file

@ -229,13 +229,13 @@ MidiSource::midi_read (const Lock& lm,
string_compose ("MidiSource::midi_read() %5 sstart %1 start %2 (qn = %5) cnt %3 tracker %4\n",
source_start, start, cnt, tracker, name(), start_qn));
for (MidiModel::const_iterator i = _model->lower_bound (first_possible_event_time); i != _model->end() && i->time() < last_possible_event_time; ++i) {
for (MidiModel::const_iterator i = _model->lower_bound (first_possible_event_time); i != _model->end() && (*i)->time() < last_possible_event_time; ++i) {
#if 0
if (filter && filter->filter(i->buffer(), i->size())) {
if (filter && filter->filter((*i)->buffer(), (*i)->size())) {
DEBUG_TRACE (DEBUG::MidiSourceIO,
string_compose ("%1: filter event @ %2 type %3 size %4\n",
_name, i->time(), i->event_type(), i->size()));
_name, (*i)->time(), (*i)->event_type(), (*i)->size()));
continue;
}
@ -243,18 +243,18 @@ MidiSource::midi_read (const Lock& lm,
// time_frames = loop_range->squish (time_frames);
}
// dst.write (time_frames, i->event_type(), i->size(), i->buffer());
// dst.write (time_frames, (*i)->event_type(), (*i)->size(), (*i)->buffer());
#ifndef NDEBUG
if (DEBUG_ENABLED(DEBUG::MidiSourceIO)) {
DEBUG_STR_DECL(a);
DEBUG_STR_APPEND(a, string_compose ("%1 added event @ %2 sz %3 within %4 .. %5 ",
_name, time_frames, i->size(),
_name, time_frames, (*i)->size(),
start + source_start, start + cnt + source_start));
for (size_t n=0; n < i->size(); ++n) {
DEBUG_STR_APPEND(a,hex);
DEBUG_STR_APPEND(a,"0x");
DEBUG_STR_APPEND(a,(int)i->buffer()[n]);
DEBUG_STR_APPEND(a,(int)(*i)->buffer()[n]);
DEBUG_STR_APPEND(a,' ');
}
DEBUG_STR_APPEND(a,'\n');
@ -264,7 +264,7 @@ MidiSource::midi_read (const Lock& lm,
#endif
if (tracker) {
tracker->track (*i);
tracker->track (**i);
}
}

View file

@ -181,12 +181,13 @@ MidiStateTracker::resolve_notes (MidiSource& src, const MidiSource::Lock& lock,
for (int channel = 0; channel < 16; ++channel) {
for (int note = 0; note < 128; ++note) {
while (_active_notes[note + 128 * channel]) {
Evoral::MIDIEvent<Evoral::Beats> ev ((MIDI_CMD_NOTE_OFF|channel), time, 3, 0, true);
ev.set_type (MIDI_CMD_NOTE_OFF);
ev.set_channel (channel);
ev.set_note (note);
ev.set_velocity (0);
src.append_event_beats (lock, ev);
Evoral::MIDIEvent<Evoral::Beats> * ev = new Evoral::MIDIEvent<Evoral::Beats> ((MIDI_CMD_NOTE_OFF|channel), time, 3, 0, true);
ev->set_type (MIDI_CMD_NOTE_OFF);
ev->set_channel (channel);
ev->set_note (note);
ev->set_velocity (0);
boost::shared_ptr<Evoral::Event<Evoral::Beats> > e (ev);
src.append_event_beats (lock, e);
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: MS-resolved note %2/%3 at %4\n",
this, (int) note, (int) channel, time));
_active_notes[note + 128 * channel]--;

View file

@ -95,17 +95,12 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
boost::shared_ptr<MidiModel> new_model = new_src->model();
new_model->start_write();
/* Note: pass true into force_discrete for the begin() iterator so that the model doesn't
* do interpolation of controller data when we stretch.
*/
for (Evoral::Sequence<MidiModel::TimeType>::const_iterator i = old_model->begin ();
i != old_model->end(); ++i) {
const MidiModel::TimeType new_time = i->time() * (double)_request.time_fraction;
for (Evoral::Sequence<MidiModel::TimeType>::const_iterator i = old_model->begin (); i != old_model->end(); ++i) {
const MidiModel::TimeType new_time = (*i)->time() * (double)_request.time_fraction;
// FIXME: double copy
Evoral::Event<MidiModel::TimeType> ev(*i, true);
ev.set_time(new_time);
new_model->append(ev, Evoral::next_event_id());
boost::shared_ptr<Evoral::Event<MidiModel::TimeType> > ev (new Evoral::Event<MidiModel::TimeType> (**i, true));
ev->set_time (new_time);
new_model->append (ev, Evoral::next_event_id());
}
new_model->end_write (Evoral::Sequence<Evoral::Beats>::DeleteStuckNotes);

View file

@ -5974,8 +5974,8 @@ Session::write_one_track (Track& track, framepos_t start, framepos_t end,
const MidiBuffer& buf = buffers.get_midi(0);
for (MidiBuffer::const_iterator i = buf.begin(); i != buf.end(); ++i) {
Evoral::Event<framepos_t> ev = *i;
ev.set_time(ev.time() - position);
boost::shared_ptr<Evoral::Event<framepos_t> > ev (new Evoral::Event<framepos_t> (*i));
ev->set_time (ev->time() - position);
ms->append_event_frames(lock, ev, ms->timeline_position());
}
}

View file

@ -334,7 +334,7 @@ SMFSource::write_unlocked (const Lock& lock,
_model->start_write();
}
Evoral::MIDIEvent<framepos_t> ev;
boost::shared_ptr<Evoral::MIDIEvent<framepos_t> > ev;
while (true) {
/* Get the event time, in frames since session start but ignoring looping. */
bool ret;
@ -376,15 +376,14 @@ SMFSource::write_unlocked (const Lock& lock,
}
time -= position;
ev.set(buf, size, time);
ev.set_event_type(midi_parameter_type(ev.buffer()[0]));
ev.set_id(Evoral::next_event_id());
ev.reset (new Evoral::MIDIEvent<framepos_t> (midi_parameter_type (buf[0]), time, size, buf));
ev->set_id (Evoral::next_event_id());
if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
if (!(ev->is_channel_event() || ev->is_smf_meta_event() || ev->is_sysex())) {
continue;
}
append_event_frames(lock, ev, position);
append_event_frames (lock, ev, position);
}
Evoral::SMF::flush ();
@ -396,19 +395,19 @@ SMFSource::write_unlocked (const Lock& lock,
/** Append an event with a timestamp in beats */
void
SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
const Evoral::Event<Evoral::Beats>& ev)
boost::shared_ptr<Evoral::Event<Evoral::Beats> > const & ev)
{
if (!_writing || ev.size() == 0) {
if (!_writing || ev->size() == 0) {
return;
}
#if 0
printf("SMFSource: %s - append_event_beats ID = %d time = %lf, size = %u, data = ",
name().c_str(), ev.id(), ev.time(), ev.size());
for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
name().c_str(), ev->id(), ev->time(), ev->size());
for (size_t i = 0; i < ev->size(); ++i) printf("%X ", ev->buffer()[i]); printf("\n");
#endif
Evoral::Beats time = ev.time();
Evoral::Beats time = ev->time();
if (time < _last_ev_time_beats) {
const Evoral::Beats difference = _last_ev_time_beats - time;
if (difference.to_double() / (double)ppqn() < 1.0) {
@ -420,7 +419,7 @@ SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
} else {
/* Out of order by more than a tick. */
warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
ev.time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn())
ev->time(), _last_ev_time_beats, difference, difference.to_double() / (double)ppqn())
<< endmsg;
return;
}
@ -428,10 +427,10 @@ SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
Evoral::event_id_t event_id;
if (ev.id() < 0) {
if (ev->id() < 0) {
event_id = Evoral::next_event_id();
} else {
event_id = ev.id();
event_id = ev->id();
}
if (_model) {
@ -443,7 +442,7 @@ SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
const Evoral::Beats delta_time_beats = time - _last_ev_time_beats;
const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
Evoral::SMF::append_event_delta(delta_time_ticks, ev->size(), ev->buffer(), event_id);
_last_ev_time_beats = time;
_flags = Source::Flag (_flags & ~Empty);
}
@ -451,39 +450,37 @@ SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock,
/** Append an event with a timestamp in frames (framepos_t) */
void
SMFSource::append_event_frames (const Glib::Threads::Mutex::Lock& lock,
const Evoral::Event<framepos_t>& ev,
framepos_t position)
boost::shared_ptr <Evoral::Event<framepos_t> > const & ev,
framepos_t position)
{
if (!_writing || ev.size() == 0) {
if (!_writing || ev->size() == 0) {
return;
}
// printf("SMFSource: %s - append_event_frames ID = %d time = %u, size = %u, data = ",
// name().c_str(), ev.id(), ev.time(), ev.size());
// for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
// name().c_str(), ev->id(), ev->time(), ev->size());
// for (size_t i=0; i < ev->size(); ++i) printf("%X ", ev->buffer()[i]); printf("\n");
if (ev.time() < _last_ev_time_frames) {
if (ev->time() < _last_ev_time_frames) {
warning << string_compose(_("Skipping event with unordered frame time %1 < %2"),
ev.time(), _last_ev_time_frames)
ev->time(), _last_ev_time_frames)
<< endmsg;
return;
}
BeatsFramesConverter converter(_session.tempo_map(), position);
const Evoral::Beats ev_time_beats = converter.from(ev.time());
const Evoral::Beats ev_time_beats = converter.from(ev->time());
Evoral::event_id_t event_id;
if (ev.id() < 0) {
if (ev->id() < 0) {
event_id = Evoral::next_event_id();
} else {
event_id = ev.id();
event_id = ev->id();
}
if (_model) {
const Evoral::Event<Evoral::Beats> beat_ev (ev.event_type(),
ev_time_beats,
ev.size(),
const_cast<uint8_t*>(ev.buffer()));
boost::shared_ptr<Evoral::Event<Evoral::Beats> > beat_ev
(new Evoral::Event<Evoral::Beats> (ev->event_type(), ev_time_beats, ev->size(), const_cast<uint8_t*>(ev->buffer())));
_model->append (beat_ev, event_id);
}
@ -493,8 +490,8 @@ SMFSource::append_event_frames (const Glib::Threads::Mutex::Lock& lock,
const Evoral::Beats delta_time_beats = ev_time_beats - last_time_beats;
const uint32_t delta_time_ticks = delta_time_beats.to_ticks(ppqn());
Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
_last_ev_time_frames = ev.time();
Evoral::SMF::append_event_delta (delta_time_ticks, ev->size(), ev->buffer(), event_id);
_last_ev_time_frames = ev->time();
_flags = Source::Flag (_flags & ~Empty);
}
@ -603,12 +600,6 @@ SMFSource::safe_midi_file_extension (const string& file)
return true;
}
static bool compare_eventlist (
const std::pair< Evoral::Event<Evoral::Beats>*, gint >& a,
const std::pair< Evoral::Event<Evoral::Beats>*, gint >& b) {
return ( a.first->time() < b.first->time() );
}
void
SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
{
@ -651,7 +642,10 @@ SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload
std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > > eventlist;
for (unsigned i = 1; i <= num_tracks(); ++i) {
if (seek_to_track(i)) continue;
if (seek_to_track(i)) {
continue;
}
time = 0;
have_event_id = false;
@ -689,14 +683,12 @@ SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload
delta_t, time, size, ss , event_type, event_id, name()));
#endif
eventlist.push_back(make_pair (
new Evoral::Event<Evoral::Beats> (
event_type, event_time,
size, buf, true)
, event_id));
boost::shared_ptr<Evoral::Event<Evoral::Beats> > ev (
new Evoral::Event<Evoral::Beats> (event_type, event_time, size, buf, true));
_model->append (ev, event_id);
// Set size to max capacity to minimize allocs in read_event
scratch_size = std::max(size, scratch_size);
scratch_size = std::max (size, scratch_size);
size = scratch_size;
_length_beats = max(_length_beats, event_time);
@ -707,23 +699,15 @@ SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload
}
}
eventlist.sort(compare_eventlist);
std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > >::iterator it;
for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
_model->append (*it->first, it->second);
delete it->first;
}
// cerr << "----SMF-SRC-----\n";
// _playback_buf->dump (cerr);
// cerr << "----------------\n";
_model->end_write (Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, _length_beats);
_model->set_edited (false);
invalidate(lock);
invalidate (lock);
free(buf);
free (buf);
}
void

View file

@ -41,22 +41,6 @@ template<typename Time> class EventSink;
template<typename Time> class Note;
template<typename Time> class Event;
/** An iterator over (the x axis of) a 2-d double coordinate space.
*/
class /*LIBEVORAL_API*/ ControlIterator {
public:
ControlIterator(boost::shared_ptr<const ControlList> al, double ax, double ay)
: list(al)
, x(ax)
, y(ay)
{}
boost::shared_ptr<const ControlList> list;
double x;
double y;
};
/** This is a higher level view of events, with separate representations for
* notes (instead of just unassociated note on/off events) and controller data.
* Controller data is represented as a list of time-stamped float values. */
@ -80,13 +64,17 @@ class LIBEVORAL_API Sequence : virtual public ControlSet {
};
public:
typedef typename boost::shared_ptr<Evoral::Event<Time> > EventPtr;
typedef typename boost::weak_ptr<Evoral::Event<Time> > WeakEventPtr;
typedef typename boost::shared_ptr<const Evoral::Event<Time> > constEventPtr;
struct EventTimeComparator {
bool operator() (Event<Time> const & a, Event<Time> const & b) const {
return a.time() < b.time();
inline bool operator() (const EventPtr a, const EventPtr b) const {
return a->time() < b->time();
}
};
typedef typename std::multiset<Evoral::Event<Time>,EventTimeComparator> Events;
typedef typename std::multiset<EventPtr,EventTimeComparator> Events;
typedef typename Events::const_iterator const_iterator;
private:
@ -122,7 +110,7 @@ class LIBEVORAL_API Sequence : virtual public ControlSet {
void end_write (StuckNoteOption, Time when = Time());
void append(const Event<Time>& ev, Evoral::event_id_t evid);
void append (EventPtr const & ev, Evoral::event_id_t evid);
const TypeMap& type_map() const { return _type_map; }
@ -222,9 +210,11 @@ private:
typedef std::priority_queue<NotePtr, std::deque<NotePtr>, LaterNoteEndComparator> ActiveNotes;
public:
const_iterator begin () const { return _events.begin(); }
const const_iterator end() const { return _events.end(); }
const_iterator lower_bound (Time t) const { Event<Time> ev (0, t, 0, 0, false); return _events.lower_bound (ev); }
/* XXX heap allocation for lower-bound ... fix this */
const_iterator lower_bound (Time t) const { EventPtr e (new Event<Time> (0, t, 0, 0, false)); return _events.lower_bound (e); }
// CONST iterator implementations (x3)
typename Notes::const_iterator note_lower_bound (Time t) const;
@ -236,9 +226,6 @@ public:
typename PatchChanges::iterator patch_change_lower_bound (Time t);
typename SysExes::iterator sysex_lower_bound (Time t);
bool control_to_midi_event(boost::shared_ptr< Event<Time> >& ev,
const ControlIterator& iter) const;
bool edited() const { return _edited; }
void set_edited(bool yn) { _edited = yn; }

View file

@ -111,82 +111,6 @@ Sequence<Time>::Sequence(const Sequence<Time>& other)
DEBUG_TRACE (DEBUG::Sequence, string_compose ("Sequence copied: %1\n", this));
}
/** 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
*/
template<typename Time>
bool
Sequence<Time>::control_to_midi_event(
boost::shared_ptr< Event<Time> >& ev,
const ControlIterator& iter) const
{
assert(iter.list.get());
const uint32_t event_type = iter.list->parameter().type();
// initialize the event pointer with a new event, if necessary
if (!ev) {
ev = boost::shared_ptr< Event<Time> >(new Event<Time>(event_type, Time(), 3, NULL, true));
}
uint8_t midi_type = _type_map.parameter_midi_type(iter.list->parameter());
ev->set_event_type(_type_map.midi_event_type(midi_type));
ev->set_id(-1);
switch (midi_type) {
case MIDI_CMD_CONTROL:
assert(iter.list.get());
assert(iter.list->parameter().channel() < 16);
assert(iter.list->parameter().id() <= INT8_MAX);
assert(iter.y <= INT8_MAX);
ev->set_time(Time(iter.x));
ev->realloc(3);
ev->buffer()[0] = MIDI_CMD_CONTROL + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.list->parameter().id();
ev->buffer()[2] = (uint8_t)iter.y;
break;
case MIDI_CMD_PGM_CHANGE:
assert(iter.list.get());
assert(iter.list->parameter().channel() < 16);
assert(iter.y <= INT8_MAX);
ev->set_time(Time(iter.x));
ev->realloc(2);
ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.y;
break;
case MIDI_CMD_BENDER:
assert(iter.list.get());
assert(iter.list->parameter().channel() < 16);
assert(iter.y < (1<<14));
ev->set_time(Time(iter.x));
ev->realloc(3);
ev->buffer()[0] = MIDI_CMD_BENDER + iter.list->parameter().channel();
ev->buffer()[1] = uint16_t(iter.y) & 0x7F; // LSB
ev->buffer()[2] = (uint16_t(iter.y) >> 7) & 0x7F; // MSB
break;
case MIDI_CMD_CHANNEL_PRESSURE:
assert(iter.list.get());
assert(iter.list->parameter().channel() < 16);
assert(iter.y <= INT8_MAX);
ev->set_time(Time(iter.x));
ev->realloc(2);
ev->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.y;
break;
default:
return false;
}
return true;
}
/** Clear all events from the model.
*/
@ -480,25 +404,25 @@ Sequence<Time>::remove_sysex_unlocked (const SysExPtr sysex)
/** Append \a ev to model. NOT realtime safe.
*
* The timestamp of event is expected to be relative to
* the start of this model (t=0) and MUST be monotonically increasing
* and MUST be >= the latest event currently in the model.
* the start of this model (t=0).
*/
template<typename Time>
void
Sequence<Time>::append(const Event<Time>& event, event_id_t evid)
Sequence<Time>::append(EventPtr const & event, event_id_t evid)
{
WriteLock lock(write_lock());
const MIDIEvent<Time>& ev = (const MIDIEvent<Time>&)event;
assert(_notes.empty() || ev.time() >= (*_notes.rbegin())->time());
assert(_writing);
assert (_writing);
if (!midi_event_is_valid(ev.buffer(), ev.size())) {
cerr << "WARNING: Sequence ignoring illegal MIDI event" << endl;
return;
}
_events.insert (event);
if (ev.is_note_on() && ev.velocity() > 0) {
append_note_on_unlocked (ev, evid);
} else if (ev.is_note_off() || (ev.is_note_on() && ev.velocity() == 0)) {