use drobilla's suggestion to improve Event structure

This commit is contained in:
Paul Davis 2016-12-05 23:29:52 +00:00
parent 4069c84eca
commit d322b74941
8 changed files with 364 additions and 312 deletions

View file

@ -148,6 +148,7 @@ void
MidiModel::NoteDiffCommand::add (NotePtr const & note)
{
_removed_notes.remove(note);
/* copies NotePtr, puts it into an STL (non-invasive) list */
_added_notes.push_back(note);
}
@ -155,6 +156,7 @@ void
MidiModel::NoteDiffCommand::remove (NotePtr const & note)
{
_added_notes.remove(note);
/* copies NotePtr, puts it into an STL (non-invasive) list */
_removed_notes.push_back(note);
}
@ -242,8 +244,15 @@ MidiModel::NoteDiffCommand::operator() ()
{
MidiModel::WriteLock lock(_model->edit_lock());
for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) {
if (!_model->add_note_unlocked(*i)) {
for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); *i) {
/* locally scoped pointer to note */
NotePtr np (*i);
cerr << "local NP linked? " << np.is_linked() << " iterator version " << (*i).is_linked() << endl;
if (!_model->add_note_unlocked (np)) {
/* failed to add it, so don't leave it in the removed list, to
avoid apparent errors on undo.
*/
@ -252,7 +261,8 @@ MidiModel::NoteDiffCommand::operator() ()
}
for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) {
_model->remove_note_unlocked(*i);
NotePtr np (*i);
_model->remove_note_unlocked (np);
}
/* notes we modify in a way that requires remove-then-add to maintain ordering */

View file

@ -48,227 +48,6 @@ LIBEVORAL_API void init_event_id_counter(event_id_t n);
template<typename T> class Sequence;
#define COMMON_EVENT_DATA \
EventType _type; /*< Type of event (application relative, NOT MIDI 'type') */ \
Time _time; /*< Time stamp of event */ \
uint32_t _size; /*< Size of buffer in bytes */ \
event_id_t _id; /*< Unique event ID */ \
uint8_t _buf[0]; /*< Event data. Must be at end, to use C-style variable-sized structure hack */
#define COMMON_EVENT_METHODS \
inline EventType event_type() const { return _type; } \
inline Time time() const { return _time; } \
inline uint32_t size() const { return _size; } \
inline void set_size (uint32_t s) { _size = s; /* CAREFUL !!! */ } \
inline uint32_t object_size() const { return size() + sizeof (*this); } \
inline const uint8_t* buffer() const { return _buf; } \
inline uint8_t* buffer() { return _buf; } \
\
inline void set_event_type(EventType t) { _type = t; } \
\
inline void set_time(Time t) { _time = t; } \
\
inline event_id_t id() const { return _id; } \
inline void set_id(event_id_t n) { _id = n; } \
\
/* The following methods are type specific and only make sense for the \
correct event type. It is the caller's responsibility to only call \
methods which make sense for the given event type. Currently this
means \
they all only make sense for MIDI, but built-in support may be added
for \
other protocols in the future, or the internal representation may
change \
to be protocol agnostic. */ \
\
uint8_t type() const { return midi_type (_buf); } \
uint8_t channel() const { return midi_channel (_buf); } \
bool is_channel_msg() const { return midi_is_channel_msg (_buf); } \
bool is_note_on() const { return midi_is_note_on (_buf); } \
bool is_note_off() const { return midi_is_note_off (_buf); } \
bool is_note() const { return midi_is_note (_buf); } \
bool is_poly_pressure() const { return midi_is_poly_pressure (_buf); } \
bool is_channel_pressure() const { return midi_is_channel_pressure (_buf); } \
bool is_cc() const { return midi_is_cc (_buf); } \
bool is_pgm_change() const { return midi_is_pgm_change (_buf); } \
bool is_pitch_bender() const { return midi_is_pitch_bender (_buf); } \
bool is_channel_event() const { return midi_is_channel_event (_buf); } \
bool is_smf_meta_event() const { return midi_is_smf_meta_event (_buf); } \
bool is_sysex() const { return midi_is_sysex (_buf); } \
bool is_spp() const { return midi_is_spp (_buf, _size); } \
bool is_mtc_quarter() const { return midi_is_mtc_quarter (_buf, _size); } \
bool is_mtc_full() const { return midi_is_mtc_full (_buf, _size); } \
\
uint8_t note() const { return midi_note (_buf); } \
uint8_t velocity() const { return midi_velocity (_buf); } \
uint8_t poly_note() const { return midi_poly_note (_buf); } \
uint8_t poly_pressure() const { return midi_poly_pressure (_buf); } \
uint8_t channel_pressure() const { return midi_channel_pressure (_buf); } \
uint8_t cc_number() const { return midi_cc_number (_buf); } \
uint8_t cc_value() const { return midi_cc_value (_buf); } \
uint8_t pgm_number() const { return midi_pgm_number (_buf); } \
uint8_t pitch_bender_lsb() const { return midi_pitch_bender_lsb (_buf); } \
uint8_t pitch_bender_msb() const { return midi_pitch_bender_msb (_buf); } \
uint16_t pitch_bender_value() const { return midi_pitch_bender_value (_buf); } \
\
void set_channel(uint8_t channel) { _buf[0] = (0xF0 & _buf[0]) | (0x0F & channel); } \
void set_type(uint8_t type) { _buf[0] = (0x0F & _buf[0]) | (0xF0 & type); } \
void set_note(uint8_t num) { _buf[1] = num; } \
void set_velocity(uint8_t val) { _buf[2] = val; } \
void set_cc_number(uint8_t num) { _buf[1] = num; } \
void set_cc_value(uint8_t val) { _buf[2] = val; } \
void set_pgm_number(uint8_t num) { _buf[1] = num; } \
\
uint16_t value() const { \
switch (type()) { \
case MIDI_CMD_CONTROL: \
return cc_value(); \
case MIDI_CMD_BENDER: \
return pitch_bender_value(); \
case MIDI_CMD_NOTE_PRESSURE: \
return poly_pressure(); \
case MIDI_CMD_CHANNEL_PRESSURE: \
return channel_pressure(); \
default: \
return 0; \
} \
}
template<typename E>
bool event_time_order (const E & a, const E & other)
{
if (a.time() < other.time()) {
return true;
} else if (a.time() > other.time()) {
return false;
}
if (a.type() != MIDI_EVENT) {
/* times are equal, sort order is arbitrary */
return false;
}
/* times are equal. Use MIDI semantics */
bool other_first = false;
/* two events at identical times. we need to determine
the order in which they should occur.
the rule is:
Controller messages
Program Change
Note Off
Note On
Note Pressure
Channel Pressure
Pitch Bend
*/
if (!a.is_channel_msg() || !other.is_channel_msg() || (a.channel() != other.channel())) {
/* if either message is not a channel message, or if
* the channels are
* different, we don't care about the type.
*/
other_first = true;
} else {
switch (other.type()) {
case MIDI_CMD_CONTROL:
other_first = true;
break;
case MIDI_CMD_PGM_CHANGE:
switch (a.type()) {
case MIDI_CMD_CONTROL:
break;
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
}
break;
case MIDI_CMD_NOTE_OFF:
switch (a.type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
break;
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
} \
break;
case MIDI_CMD_NOTE_ON:
switch (a.type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
break;
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
}
break;
case MIDI_CMD_NOTE_PRESSURE:
switch (a.type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
break;
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
}
break;
case MIDI_CMD_CHANNEL_PRESSURE:
switch (a.type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
break;
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
}
break;
case MIDI_CMD_BENDER:
switch (a.type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
break;
case MIDI_CMD_BENDER:
other_first = true;
}
break;
}
}
return other_first;
}
/** An event.
*
* Template parameter Time is the type of the time stamp used for this event.
@ -302,7 +81,10 @@ public:
, _size (other.size())
, _id (next_event_id())
{
memcpy (_buf, other.buffer(), _size);
if (other.size()) {
assert (other.buffer());
memcpy (_buf, other.buffer(), other.size());
}
}
~Event() {}
@ -310,29 +92,248 @@ public:
Event& operator= (Event const & other) {
/* Does NOT copy event ID */
if (this != &other) {
_type = other._type;
_time = other._time;
_size = other._size;
memcpy (_buf, other._buf, _size);
_type = other.event_type();
_time = other.time();
_size = other.size();
if (other.size()) {
assert (other.buffer());
memcpy (_buf, other.buffer(), other.size());
}
}
return *this;
}
bool operator== (Event const & other) const {
/* Does NOT compare event IDs */
return _type == other._type &&
_time == other._time &&
_size == other._size &&
!memcmp (_buf, other._buf, _size);
return _type == other.event_type() &&
_time == other.time() &&
_size == other.size() &&
!memcmp (_buf, other.buffer(), other.size());
}
bool time_order_before (Event const & other) const {
return event_time_order (*this, other);
if (time() < other.time()) {
return true;
} else if (time() > other.time()) {
return false;
}
if (event_type() != MIDI_EVENT) {
/* times are equal, sort order is arbitrary */
return false;
}
/* times are equal. Use MIDI semantics */
bool other_first = false;
/* two events at identical times. we need to determine
the order in which they should occur.
the rule is:
Controller messages
Program Change
Note Off
Note On
Note Pressure
Channel Pressure
Pitch Bend
*/
if (!is_channel_msg() || !other.is_channel_msg() || (channel() != other.channel())) {
/* if either message is not a channel message, or if
* the channels are
* different, we don't care about the type.
*/
other_first = true;
} else {
switch (other.type()) {
case MIDI_CMD_CONTROL:
other_first = true;
break;
case MIDI_CMD_PGM_CHANGE:
switch (type()) {
case MIDI_CMD_CONTROL:
break;
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
}
break;
case MIDI_CMD_NOTE_OFF:
switch (type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
break;
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
} \
break;
case MIDI_CMD_NOTE_ON:
switch (type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
break;
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
}
break;
case MIDI_CMD_NOTE_PRESSURE:
switch (type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
break;
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
}
break;
case MIDI_CMD_CHANNEL_PRESSURE:
switch (type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
break;
case MIDI_CMD_CHANNEL_PRESSURE:
case MIDI_CMD_BENDER:
other_first = true;
}
break;
case MIDI_CMD_BENDER:
switch (type()) {
case MIDI_CMD_CONTROL:
case MIDI_CMD_PGM_CHANGE:
case MIDI_CMD_NOTE_OFF:
case MIDI_CMD_NOTE_ON:
case MIDI_CMD_NOTE_PRESSURE:
case MIDI_CMD_CHANNEL_PRESSURE:
break;
case MIDI_CMD_BENDER:
other_first = true;
}
break;
}
}
return other_first;
}
COMMON_EVENT_METHODS;
inline EventType event_type() const { return _type; }
inline Time time() const { return _time; }
inline uint32_t size() const { return _size; }
inline void set_size (uint32_t s) { _size = s; /* CAREFUL !!! */ }
inline uint32_t object_size() const { return size() + sizeof (*this); }
inline const uint8_t* buffer() const { return _buf; }
inline uint8_t* buffer() { return _buf; }
inline void set_event_type(EventType t) { _type = t; }
inline void set_time(Time t) { _time = t; }
inline event_id_t id() const { return _id; }
inline void set_id(event_id_t n) { _id = n; }
/* The following methods are type specific and only make sense for the
* correct event type. It is the caller's responsibility to only call
* methods which make sense for the given event type. Currently this
* means they all only make sense for MIDI, but built-in support may be
* added for other protocols in the future, or the internal
* representation may change to be protocol agnostic.
*/
uint8_t type() const { return midi_type (_buf); }
uint8_t channel() const { return midi_channel (_buf); }
bool is_channel_msg() const { return midi_is_channel_msg (_buf); }
bool is_note_on() const { return midi_is_note_on (_buf); }
bool is_note_off() const { return midi_is_note_off (_buf); }
bool is_note() const { return midi_is_note (_buf); }
bool is_poly_pressure() const { return midi_is_poly_pressure (_buf); }
bool is_channel_pressure() const { return midi_is_channel_pressure (_buf); }
bool is_cc() const { return midi_is_cc (_buf); }
bool is_pgm_change() const { return midi_is_pgm_change (_buf); }
bool is_pitch_bender() const { return midi_is_pitch_bender (_buf); }
bool is_channel_event() const { return midi_is_channel_event (_buf); }
bool is_smf_meta_event() const { return midi_is_smf_meta_event (_buf); }
bool is_sysex() const { return midi_is_sysex (_buf); }
bool is_spp() const { return midi_is_spp (_buf, _size); }
bool is_mtc_quarter() const { return midi_is_mtc_quarter (_buf, _size); }
bool is_mtc_full() const { return midi_is_mtc_full (_buf, _size); }
uint8_t note() const { return midi_note (_buf); }
uint8_t velocity() const { return midi_velocity (_buf); }
uint8_t poly_note() const { return midi_poly_note (_buf); }
uint8_t poly_pressure() const { return midi_poly_pressure (_buf); }
uint8_t channel_pressure() const { return midi_channel_pressure (_buf); }
uint8_t cc_number() const { return midi_cc_number (_buf); }
uint8_t cc_value() const { return midi_cc_value (_buf); }
uint8_t pgm_number() const { return midi_pgm_number (_buf); }
uint8_t pitch_bender_lsb() const { return midi_pitch_bender_lsb (_buf); }
uint8_t pitch_bender_msb() const { return midi_pitch_bender_msb (_buf); }
uint16_t pitch_bender_value() const { return midi_pitch_bender_value (_buf); }
void set_channel(uint8_t channel) { _buf[0] = (0xF0 & _buf[0]) | (0x0F & channel); }
void set_type(uint8_t type) { _buf[0] = (0x0F & _buf[0]) | (0xF0 & type); }
void set_note(uint8_t num) { _buf[1] = num; }
void set_velocity(uint8_t val) { _buf[2] = val; }
void set_cc_number(uint8_t num) { _buf[1] = num; }
void set_cc_value(uint8_t val) { _buf[2] = val; }
void set_pgm_number(uint8_t num) { _buf[1] = num; }
uint16_t value() const {
switch (type()) {
case MIDI_CMD_CONTROL:
return cc_value();
case MIDI_CMD_BENDER:
return pitch_bender_value();
case MIDI_CMD_NOTE_PRESSURE:
return poly_pressure();
case MIDI_CMD_CHANNEL_PRESSURE:
return channel_pressure();
default:
return 0;
}
}
public:
COMMON_EVENT_DATA
EventType _type; /*< Type of event (application relative, NOT MIDI 'type') */ \
Time _time; /*< Time stamp of event */ \
uint32_t _size; /*< Size of buffer in bytes */ \
event_id_t _id; /*< Unique event ID */ \
uint8_t _buf[0]; /*< Event data. Must be at end, to use C-style variable-sized structure hack */
/* C++ standard: "Nonstatic data members of a (non-union) class with
* the same access control (Clause 11) are allocated so that later
* members have higher addresses within a class object." (9.2.13)
*
* NO MORE DATA MEMBERS AFTER THIS POINT
*/
private:
/* hide these methods since they are illegal. Event<T> can only be
@ -409,29 +410,66 @@ class LIBEVORAL_API ManagedEvent /* INHERITANCE ILLEGAL HERE */
}
ManagedEvent& operator= (ManagedEvent<Time> const & other) {
/* Does NOT copy event ID */
if (this != &other) {
_type = other._type;
_time = other._time;
_size = other._size;
memcpy (_buf, other._buf, _size);
_event = other._event;
}
return *this;
}
bool operator== (ManagedEvent const & other) const {
/* Does NOT compare event IDs */
return _type == other._type &&
_time == other._time &&
_size == other._size &&
!memcmp (_buf, other._buf, _size);
return _event == other._event;
}
bool time_order_before (ManagedEvent const & other) const {
return event_time_order (*this, other);
return _event.time_order_before (other._event);
}
COMMON_EVENT_METHODS;
inline EventType event_type() const { return _event.event_type (); }
inline Time time() const { return _event.time (); }
inline uint32_t size() const { return _event.size (); }
inline void set_size (uint32_t s) { return _event.set_size (s); }
inline const uint8_t* buffer() const { return _event.buffer (); }
inline uint8_t* buffer() { return _event.buffer (); }
inline void set_event_type(EventType t) { return _event.set_event_type (t); }
inline void set_time(Time t) { return _event.set_time (t); }
inline event_id_t id() const { return _event.id (); }
inline void set_id(event_id_t n) { return _event.set_id (n); }
inline uint8_t type() const { return _event.type (); }
inline uint8_t channel() const { return _event.channel (); }
inline bool is_channel_msg() const { return _event.is_channel_msg (); }
inline bool is_note_on() const { return _event.is_note_on (); }
inline bool is_note_off() const { return _event.is_note_off (); }
inline bool is_note() const { return _event.is_note (); }
inline bool is_poly_pressure() const { return _event.is_poly_pressure (); }
inline bool is_channel_pressure() const { return _event.is_channel_pressure (); }
inline bool is_cc() const { return _event.is_cc (); }
inline bool is_pgm_change() const { return _event.is_pgm_change (); }
inline bool is_pitch_bender() const { return _event.is_pitch_bender (); }
inline bool is_channel_event() const { return _event.is_channel_event (); }
inline bool is_smf_meta_event() const { return _event.is_smf_meta_event (); }
inline bool is_sysex() const { return _event.is_sysex (); }
inline bool is_spp() const { return _event.is_spp (); }
inline bool is_mtc_quarter() const { return _event.is_mtc_quarter (); }
inline bool is_mtc_full() const { return _event.is_mtc_full (); }
inline uint8_t note() const { return _event.note (); }
inline uint8_t velocity() const { return _event.velocity (); }
inline uint8_t poly_note() const { return _event.poly_note (); }
inline uint8_t poly_pressure() const { return _event.poly_pressure (); }
inline uint8_t channel_pressure() const { return _event.channel_pressure (); }
inline uint8_t cc_number() const { return _event.cc_number (); }
inline uint8_t cc_value() const { return _event.cc_value (); }
inline uint8_t pgm_number() const { return _event.pgm_number (); }
inline uint8_t pitch_bender_lsb() const { return _event.pitch_bender_lsb (); }
inline uint8_t pitch_bender_msb() const { return _event.pitch_bender_msb (); }
inline uint16_t pitch_bender_value() const { return _event.pitch_bender_value (); }
inline void set_channel(uint8_t channel) { return _event.set_channel (channel); }
inline void set_type(uint8_t type) { return _event.set_type (type); }
inline void set_note(uint8_t num) { return _event.set_note (num); }
inline void set_velocity(uint8_t val) { return _event.set_velocity (val); }
inline void set_cc_number(uint8_t num) { return _event.set_cc_number (num); }
inline void set_cc_value(uint8_t val) { return _event.set_cc_value (val); }
inline void set_pgm_number(uint8_t num) { return _event.set_pgm_number (num); }
inline uint16_t value() const { return _event.value(); }
private:
mutable boost::atomic<int> _refcnt;
@ -451,59 +489,37 @@ class LIBEVORAL_API ManagedEvent /* INHERITANCE ILLEGAL HERE */
}
}
private:
EventPool* _pool;
COMMON_EVENT_DATA;
EventPool* _pool;
Event<Time> _event;
/* C++ standard: "Nonstatic data members of a (non-union) class with
* the same access control (Clause 11) are allocated so that later
* members have higher addresses within a class object." (9.2.13)
*
* NO MORE DATA MEMBERS AFTER THIS POINT
*/
ManagedEvent (EventPool& p, EventType ty, Time tm, size_t sz, uint8_t* data, event_id_t id = -1)
: _pool (&p)
, _type (ty)
, _time (tm)
, _size (sz)
, _id (id)
, _event (ty, tm, sz, data, id)
{
if (data) {
/* specs for memcpy(2) state that passing size == zero is completely legal */
memcpy (_buf, data, sz);
} else {
/* hopefully data will be written in shortly */
memset (_buf, 0, sz);
}
}
ManagedEvent (EventPool& p, Event<Time> const & other)
: _pool (&p)
, _type (other.event_type())
, _time (other.time())
, _size (other.size())
, _id (next_event_id())
, _event (other)
{
memcpy (_buf, other.buffer(), _size);
}
ManagedEvent (EventType ty, Time tm, size_t sz, uint8_t* data, event_id_t id = -1)
: _pool (0)
, _type (ty)
, _time (tm)
, _size (sz)
, _id (id)
, _event (ty, tm, sz, data, id)
{
if (data) {
/* specs for memcpy(2) state that passing size == zero is completely legal */
memcpy (_buf, data, sz);
} else {
/* hopefully data will be written in shortly */
memset (_buf, 0, sz);
}
}
ManagedEvent (Event<Time> const & other)
: _pool (0)
, _type (other.event_type())
, _time (other.time())
, _size (other.size())
, _id (next_event_id())
, _event (other)
{
memcpy (_buf, other.buffer(), _size);
}
};
@ -579,7 +595,7 @@ template<typename Time, size_t _num_events>
struct MultiEvent : public boost::intrusive_ref_counter<MultiEvent<Time,_num_events>,boost::thread_safe_counter>
{
public:
MultiEvent () {}
MultiEvent () { std::cerr << "new MEV[" << _num_events << "] @ " << this << std::endl; }
virtual ~MultiEvent() {}
size_t num_events() const { return _num_events; }
@ -641,8 +657,16 @@ struct MultiEventPointer : public boost::intrusive_ptr<MultiEventObject>,
{
MultiEventPointer () {}
MultiEventPointer (MultiEventObject* meo) : boost::intrusive_ptr<MultiEventObject> (meo) { }
MultiEventPointer (MultiEventPointer const & mep);
~MultiEventPointer () { }
MultiEventPointer& operator= (MultiEventPointer const & mep) {
if (this != &mep) {
this->reset (mep.get());
}
return *this;
}
};
/* A comparison functor that orders Events by time, and for Events with

View file

@ -139,9 +139,11 @@ class NotePointer : public MultiEventPointer<Note<Time> >
public:
NotePointer () {}
NotePointer (Note<Time>* n) : MultiEventPointer<Note<Time> > (n) {}
NotePointer (NotePointer const & other);
NotePointer (uint8_t chan, Time time, Time length, uint8_t note, uint8_t velocity)
: MultiEventPointer<Note<Time> > (new Note<Time> (chan, time, length, note, velocity))
{}
{
}
~NotePointer () { }

View file

@ -107,9 +107,9 @@ public:
return (this->time() == o.time() && program() == o.program() && bank() == o.bank());
}
EventPointer<Time> const & bank_msb_message () const { return _events[0]; }
EventPointer<Time> const & bank_lsb_message () const { return _events[1]; }
EventPointer<Time> const & program_message () const { return _events[2]; }
EventPointer<Time> & bank_msb_message () { return _events[0]; }
EventPointer<Time> & bank_lsb_message () { return _events[1]; }
EventPointer<Time> & program_message () { return _events[2]; }
};
template<typename Time>

View file

@ -297,11 +297,7 @@ private:
bool overlaps_unlocked (const NotePtr& ev, const NotePtr& ignore_this_note) const;
bool contains_unlocked (const NotePtr& ev) const;
void append_note_on_unlocked (EventPtr & event);
void append_note_off_unlocked (EventPtr & event);
void append_control_unlocked (Parameter const & param, Time time, double value);
void append_sysex_unlocked (EventPtr & ev);
void append_patch_change_unlocked (PatchChangePtr &);
void get_notes_by_pitch (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
void get_notes_by_velocity (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;

View file

@ -65,6 +65,16 @@ next_event_id ()
return g_atomic_int_add (&_event_id_counter, 1);
}
template<typename MultiEventObject>
MultiEventPointer<MultiEventObject>::MultiEventPointer (MultiEventPointer const & mep)
: boost::intrusive_ptr<MultiEventObject> (mep.get())
{
std::cerr << "copy-constructed MEV pointer[" << mep->num_events() << "] @ " << this << " points to " << this->get()
<< " UC now " << this->get()->use_count()
<< " linked ? " << this->is_linked ()
<< std::endl;
}
/* each type of EventPointer<Time> needs it own pool
*/
@ -85,4 +95,7 @@ template class ManagedEvent<int64_t>; /* framepos_t in Ardour */
template class EventPointer<Evoral::Beats>;
template class EventPointer<int64_t>; /* framepos_t in Ardour */
template class MultiEventPointer<Note<Evoral::Beats> >;
template class MultiEventPointer<PatchChange<Evoral::Beats> >;
} // namespace Evoral

View file

@ -24,12 +24,14 @@
#include "evoral/Note.hpp"
#endif
#include "pbd/stacktrace.h"
#include "evoral/Beats.hpp"
namespace Evoral {
template<typename Time>
Note<Time>::Note (EventPointer<Time> const & on, EventPointer<Time> const & off)
Note<Time>::Note (EventPointer<Time> const & on, EventPointer<Time> const & off)
{
set_event (0, on);
set_event (1, off);
@ -49,6 +51,8 @@ Note<Time>::Note (uint8_t chan, Time time, Time length, uint8_t note, uint8_t ve
data[1] = note;
data[2] = velocity;
std::cerr << "NEW NOTE\n";
set_event (0, EventPointer<Time>::create (Evoral::MIDI_EVENT, time, 3, data));
data[0] = (MIDI_CMD_NOTE_OFF|chan);
@ -56,6 +60,7 @@ Note<Time>::Note (uint8_t chan, Time time, Time length, uint8_t note, uint8_t ve
data[2] = velocity;
set_event (1, EventPointer<Time>::create (Evoral::MIDI_EVENT, time + length, 3, data));
std::cerr << "NEW NOTE DONE\n";
}
template<typename Time>
@ -64,8 +69,11 @@ Note<Time>::Note (Note<Time> const & other)
EventPointer<Time> on (other.on_event());
EventPointer<Time> off (other.off_event());
std::cerr << "NOTE COPY\n";
set_event (0, EventPointer<Time>::create (Evoral::MIDI_EVENT, on->time(), on->size(), on->buffer()));
set_event (1, EventPointer<Time>::create (Evoral::MIDI_EVENT, off->time(), off->size(), off->buffer()));
std::cerr << "NOTE COPY DONE\n";
}
template<typename Time>
@ -91,7 +99,18 @@ Note<Time>::operator=(const Note<Time>& other)
return *this;
}
template<typename Time>
NotePointer<Time>::NotePointer (NotePointer<Time> const & other)
: MultiEventPointer<Note<Time> > (other.get())
{
std::cerr << "copy-constructed note pointer @ " << this << " points to " << this->get()
<< " UC now " << this->get()->use_count()
<< " linked ? " << this->is_linked ()
<< std::endl;
PBD::stacktrace (std::cerr, 20);
}
template class Note<Evoral::Beats>;
template class NotePointer<Evoral::Beats>;
} // namespace Evoral

View file

@ -397,8 +397,6 @@ Sequence<Time>::add_event (EventPtr & ev)
ev->set_id (next_event_id());
}
ordered_insert (_events, ev, TimeComparator<EventPtr,Time>());
if (!midi_event_is_valid(ev->buffer(), ev->size())) {
cerr << "WARNING: Sequence ignoring illegal MIDI event" << endl;
return;
@ -414,7 +412,7 @@ Sequence<Time>::add_event (EventPtr & ev)
} else if (ev->is_sysex()) {
append_sysex_unlocked (ev);
add_sysex_unlocked (ev);
} else if (ev->is_cc() && (ev->cc_number() == MIDI_CTL_MSB_BANK || ev->cc_number() == MIDI_CTL_LSB_BANK)) {
@ -445,7 +443,7 @@ Sequence<Time>::add_event (EventPtr & ev)
new PatchChange<Time> (*_event_pool,
ev->time(), ev->channel(),
ev->pgm_number(), _bank[ev->channel()]));
append_patch_change_unlocked (*pcp);
add_patch_change_unlocked (*pcp);
} else if (ev->is_pitch_bender()) {
@ -619,7 +617,7 @@ Sequence<Time>::append_control_unlocked(const Parameter& param, Time time, doubl
template<typename Time>
void
Sequence<Time>::append_sysex_unlocked(EventPtr & ev)
Sequence<Time>::add_sysex_unlocked(EventPtr & ev)
{
#ifdef DEBUG_SEQUENCE
cerr << this << " SysEx @ " << ev.time() << " \t= \t [ " << hex;
@ -628,30 +626,20 @@ Sequence<Time>::append_sysex_unlocked(EventPtr & ev)
} cerr << "]" << endl;
#endif
ordered_insert (_events, ev, TimeComparator<EventPtr,Time>());
ordered_insert (_sysexes, ev, TimeComparator<EventPtr,Time>());
}
template<typename Time>
void
Sequence<Time>::append_patch_change_unlocked (PatchChangePtr & pcp)
{
add_patch_change_unlocked (pcp);
}
template<typename Time>
void
Sequence<Time>::add_patch_change_unlocked (PatchChangePtr & p)
{
ordered_insert (_events, p->bank_msb_message(), TimeComparator<EventPtr,Time>());
ordered_insert (_events, p->bank_lsb_message(), TimeComparator<EventPtr,Time>());
ordered_insert (_events, p->program_message(), TimeComparator<EventPtr,Time>());
ordered_insert (_patch_changes, p, TimeComparator<PatchChangePtr,Time>());
}
template<typename Time>
void
Sequence<Time>::add_sysex_unlocked (EventPtr & ep)
{
ordered_insert (_sysexes, ep, TimeComparator<EventPtr,Time>());
}
template<typename Time>
bool
Sequence<Time>::contains (const NotePtr& note) const