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