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