1 /* 2 * Copyright (C) 2008-2016 David Robillard <d@drobilla.net> 3 * Copyright (C) 2009-2013 Paul Davis <paul@linuxaudiosystems.com> 4 * Copyright (C) 2009 Hans Baier <hansfbaier@googlemail.com> 5 * Copyright (C) 2010 Carl Hetherington <carl@carlh.net> 6 * Copyright (C) 2015-2016 Robin Gareus <robin@gareus.org> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, write to the Free Software Foundation, Inc., 20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 */ 22 23 #ifndef EVORAL_EVENT_HPP 24 #define EVORAL_EVENT_HPP 25 26 #include <cstdlib> 27 #include <cstring> 28 #include <sstream> 29 #include <stdint.h> 30 31 #include "evoral/midi_events.h" 32 #include "evoral/types.h" 33 #include "evoral/visibility.h" 34 35 /** If this is not defined, all methods of MidiEvent are RT safe 36 * but MidiEvent will never deep copy and (depending on the scenario) 37 * may not be usable in STL containers, signals, etc. 38 */ 39 #define EVORAL_EVENT_ALLOC 1 40 41 namespace Evoral { 42 43 LIBEVORAL_API event_id_t event_id_counter(); 44 LIBEVORAL_API event_id_t next_event_id(); 45 LIBEVORAL_API void init_event_id_counter(event_id_t n); 46 47 /** An event (much like a type generic jack_midi_event_t) 48 * 49 * Template parameter Time is the type of the time stamp used for this event. 50 */ 51 template<typename Time> 52 class LIBEVORAL_API Event { 53 public: 54 #ifdef EVORAL_EVENT_ALLOC 55 Event(EventType type=NO_EVENT, Time time=Time(), uint32_t size=0, uint8_t* buf=NULL, bool alloc=false); 56 57 Event(EventType type, Time time, uint32_t size, const uint8_t* buf); 58 59 /** Copy \a copy. 60 * 61 * If \a alloc is true, the buffer will be copied and this method 62 * is NOT REALTIME SAFE. Otherwise both events share a buffer and 63 * memory management semantics are the caller's problem. 64 */ 65 Event(const Event& copy, bool alloc); 66 67 ~Event(); 68 69 void assign(const Event& other); 70 71 void set(const uint8_t* buf, uint32_t size, Time t); 72 73 inline bool operator==(const Event& other) const { 74 if (_type != other._type || _time != other._time || _size != other._size) { 75 return false; 76 } 77 return !memcmp(_buf, other._buf, _size); 78 } 79 80 inline bool operator!=(const Event& other) const { return ! operator==(other); } 81 owns_buffer()82 inline bool owns_buffer() const { return _owns_buf; } 83 84 /** set event data (e.g. midi data) 85 * @param size number of bytes 86 * @param buf raw 8bit data 87 * @param own set to true if the buffer owns the data (copy, allocate/free) or false to reference previously allocated data. 88 */ set_buffer(uint32_t size,uint8_t * buf,bool own)89 inline void set_buffer(uint32_t size, uint8_t* buf, bool own) { 90 if (_owns_buf) { 91 free(_buf); 92 _buf = NULL; 93 } 94 _size = size; 95 _buf = buf; 96 _owns_buf = own; 97 } 98 realloc(uint32_t size)99 inline void realloc(uint32_t size) { 100 if (_owns_buf) { 101 if (size > _size) 102 _buf = (uint8_t*) ::realloc(_buf, size); 103 } else { 104 _buf = (uint8_t*) ::malloc(size); 105 _owns_buf = true; 106 } 107 108 _size = size; 109 } 110 clear()111 inline void clear() { 112 _type = NO_EVENT; 113 _time = Time(); 114 _size = 0; 115 _buf = NULL; 116 } 117 118 #endif // EVORAL_EVENT_ALLOC 119 event_type()120 inline EventType event_type() const { return _type; } time()121 inline Time time() const { return _time; } size()122 inline uint32_t size() const { return _size; } buffer()123 inline const uint8_t* buffer() const { return _buf; } buffer()124 inline uint8_t* buffer() { return _buf; } 125 is_midi()126 inline bool is_midi () const { return _type == LIVE_MIDI_EVENT || _type == MIDI_EVENT; } is_live_midi()127 inline bool is_live_midi () const { return _type == LIVE_MIDI_EVENT; } 128 set_event_type(EventType t)129 inline void set_event_type(EventType t) { _type = t; } 130 set_time(Time t)131 inline void set_time(Time t) { _time = t; } 132 id()133 inline event_id_t id() const { return _id; } set_id(event_id_t n)134 inline void set_id(event_id_t n) { _id = n; } 135 136 /* The following methods are type specific and only make sense for the 137 correct event type. It is the caller's responsibility to only call 138 methods which make sense for the given event type. Currently this means 139 they all only make sense for MIDI, but built-in support may be added for 140 other protocols in the future, or the internal representation may change 141 to be protocol agnostic. */ 142 type()143 uint8_t type() const { return _buf[0] & 0xF0; } channel()144 uint8_t channel() const { return _buf[0] & 0x0F; } is_note_on()145 bool is_note_on() const { return type() == MIDI_CMD_NOTE_ON; } is_note_off()146 bool is_note_off() const { return type() == MIDI_CMD_NOTE_OFF; } is_note()147 bool is_note() const { return is_note_on() || is_note_off(); } is_poly_pressure()148 bool is_poly_pressure() const { return type() == MIDI_CMD_NOTE_PRESSURE; } is_channel_pressure()149 bool is_channel_pressure() const { return type() == MIDI_CMD_CHANNEL_PRESSURE; } is_cc()150 bool is_cc() const { return type() == MIDI_CMD_CONTROL; } is_pgm_change()151 bool is_pgm_change() const { return type() == MIDI_CMD_PGM_CHANGE; } is_pitch_bender()152 bool is_pitch_bender() const { return type() == MIDI_CMD_BENDER; } is_channel_event()153 bool is_channel_event() const { return (0x80 <= type()) && (type() <= 0xE0); } is_smf_meta_event()154 bool is_smf_meta_event() const { return _buf[0] == 0xFF; } is_sysex()155 bool is_sysex() const { return _buf[0] == 0xF0 || _buf[0] == 0xF7; } is_spp()156 bool is_spp() const { return _buf[0] == 0xF2 && size() == 1; } is_mtc_quarter()157 bool is_mtc_quarter() const { return _buf[0] == 0xF1 && size() == 1; } is_mtc_full()158 bool is_mtc_full() const { return (size() == 10 && 159 _buf[0] == 0xF0 && _buf[1] == 0x7F && 160 _buf[3] == 0x01 && _buf[4] == 0x01); } 161 note()162 uint8_t note() const { return _buf[1]; } velocity()163 uint8_t velocity() const { return _buf[2]; } poly_note()164 uint8_t poly_note() const { return _buf[1]; } poly_pressure()165 uint8_t poly_pressure() const { return _buf[2]; } channel_pressure()166 uint8_t channel_pressure() const { return _buf[1]; } cc_number()167 uint8_t cc_number() const { return _buf[1]; } cc_value()168 uint8_t cc_value() const { return _buf[2]; } pgm_number()169 uint8_t pgm_number() const { return _buf[1]; } pitch_bender_lsb()170 uint8_t pitch_bender_lsb() const { return _buf[1]; } pitch_bender_msb()171 uint8_t pitch_bender_msb() const { return _buf[2]; } pitch_bender_value()172 uint16_t pitch_bender_value() const { return ((0x7F & _buf[2]) << 7 | (0x7F & _buf[1])); } 173 set_channel(uint8_t channel)174 void set_channel(uint8_t channel) { _buf[0] = (0xF0 & _buf[0]) | (0x0F & channel); } set_type(uint8_t type)175 void set_type(uint8_t type) { _buf[0] = (0x0F & _buf[0]) | (0xF0 & type); } set_note(uint8_t num)176 void set_note(uint8_t num) { _buf[1] = num; } set_velocity(uint8_t val)177 void set_velocity(uint8_t val) { _buf[2] = val; } set_cc_number(uint8_t num)178 void set_cc_number(uint8_t num) { _buf[1] = num; } set_cc_value(uint8_t val)179 void set_cc_value(uint8_t val) { _buf[2] = val; } set_pgm_number(uint8_t num)180 void set_pgm_number(uint8_t num) { _buf[1] = num; } 181 value()182 uint16_t value() const { 183 switch (type()) { 184 case MIDI_CMD_CONTROL: 185 return cc_value(); 186 case MIDI_CMD_BENDER: 187 return pitch_bender_value(); 188 case MIDI_CMD_NOTE_PRESSURE: 189 return poly_pressure(); 190 case MIDI_CMD_CHANNEL_PRESSURE: 191 return channel_pressure(); 192 case MIDI_CMD_PGM_CHANGE: 193 return pgm_number(); 194 default: 195 return 0; 196 } 197 } 198 199 protected: 200 EventType _type; ///< Type of event (application relative, NOT MIDI 'type') 201 Time _time; ///< Time stamp of event 202 uint32_t _size; ///< Size of buffer in bytes 203 uint8_t* _buf; ///< Event contents (e.g. raw MIDI data) 204 event_id_t _id; ///< Unique event ID 205 #ifdef EVORAL_EVENT_ALLOC 206 bool _owns_buf; ///< Whether buffer is locally allocated 207 #endif 208 }; 209 210 template<typename Time> 211 /*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream& o, const Evoral::Event<Time>& ev) { 212 o << "Event #" << ev.id() << " type = " << ev.event_type() << " @ " << ev.time(); 213 o << std::hex; 214 for (uint32_t n = 0; n < ev.size(); ++n) { 215 o << ' ' << (int) ev.buffer()[n]; 216 } 217 o << std::dec; 218 return o; 219 } 220 221 } // namespace Evoral 222 223 #endif // EVORAL_EVENT_HPP 224 225