mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-30 10:27:44 +01:00
use drobilla's suggestion to improve Event structure
This commit is contained in:
parent
4069c84eca
commit
d322b74941
8 changed files with 364 additions and 312 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 () { }
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue