merge with master.
[ardour.git] / libs / ardour / lv2_evbuf.c
1 /*
2   Copyright 2008-2012 David Robillard <http://drobilla.net>
3
4   Permission to use, copy, modify, and/or distribute this software for any
5   purpose with or without fee is hereby granted, provided that the above
6   copyright notice and this permission notice appear in all copies.
7
8   THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <assert.h>
18 #include <string.h>
19 #include <stdlib.h>
20
21 #include "lv2/lv2plug.in/ns/ext/atom/atom.h"
22 #include "lv2/lv2plug.in/ns/ext/event/event.h"
23
24 #include "lv2_evbuf.h"
25
26 struct LV2_Evbuf_Impl {
27         LV2_Evbuf_Type type;
28         uint32_t       capacity;
29         uint32_t       atom_Chunk;
30         uint32_t       atom_Sequence;
31         union {
32                 LV2_Event_Buffer  event;
33                 LV2_Atom_Sequence atom;
34         } buf;
35 };
36
37 static inline uint32_t
38 lv2_evbuf_pad_size(uint32_t size)
39 {
40         return (size + 7) & (~7);
41 }
42
43 LV2_Evbuf*
44 lv2_evbuf_new(uint32_t       capacity,
45               LV2_Evbuf_Type type,
46               uint32_t       atom_Chunk,
47               uint32_t       atom_Sequence)
48 {
49         // FIXME: memory must be 64-bit aligned
50         LV2_Evbuf* evbuf = (LV2_Evbuf*)malloc(
51                 sizeof(LV2_Evbuf) + sizeof(LV2_Atom_Sequence) + capacity);
52         evbuf->capacity      = capacity;
53         evbuf->atom_Chunk    = atom_Chunk;
54         evbuf->atom_Sequence = atom_Sequence;
55         lv2_evbuf_set_type(evbuf, type);
56         lv2_evbuf_reset(evbuf, true);
57         return evbuf;
58 }
59
60 void
61 lv2_evbuf_free(LV2_Evbuf* evbuf)
62 {
63         free(evbuf);
64 }
65
66 void
67 lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type)
68 {
69         evbuf->type = type;
70         switch (type) {
71         case LV2_EVBUF_EVENT:
72                 evbuf->buf.event.data     = (uint8_t*)(evbuf + 1);
73                 evbuf->buf.event.capacity = evbuf->capacity;
74                 break;
75         case LV2_EVBUF_ATOM:
76                 break;
77         }
78         lv2_evbuf_reset(evbuf, true);
79 }
80
81 void
82 lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input)
83 {
84         switch (evbuf->type) {
85         case LV2_EVBUF_EVENT:
86                 evbuf->buf.event.header_size = sizeof(LV2_Event_Buffer);
87                 evbuf->buf.event.stamp_type  = LV2_EVENT_AUDIO_STAMP;
88                 evbuf->buf.event.event_count = 0;
89                 evbuf->buf.event.size        = 0;
90                 break;
91         case LV2_EVBUF_ATOM:
92                 if (input) {
93                         evbuf->buf.atom.atom.size = sizeof(LV2_Atom_Sequence_Body);
94                         evbuf->buf.atom.atom.type = evbuf->atom_Sequence;
95                 } else {
96                         evbuf->buf.atom.atom.size = evbuf->capacity;
97                         evbuf->buf.atom.atom.type = evbuf->atom_Chunk;
98                 }
99         }
100 }
101
102 uint32_t
103 lv2_evbuf_get_size(LV2_Evbuf* evbuf)
104 {
105         switch (evbuf->type) {
106         case LV2_EVBUF_EVENT:
107                 return evbuf->buf.event.size;
108         case LV2_EVBUF_ATOM:
109                 assert(evbuf->buf.atom.atom.type != evbuf->atom_Sequence
110                        || evbuf->buf.atom.atom.size >= sizeof(LV2_Atom_Sequence_Body));
111                 return evbuf->buf.atom.atom.type == evbuf->atom_Sequence
112                         ? evbuf->buf.atom.atom.size - sizeof(LV2_Atom_Sequence_Body)
113                         : 0;
114         }
115         return 0;
116 }
117
118 uint32_t
119 lv2_evbuf_get_capacity(LV2_Evbuf* evbuf)
120 {
121         return evbuf->capacity;
122 }
123
124 void*
125 lv2_evbuf_get_buffer(LV2_Evbuf* evbuf)
126 {
127         switch (evbuf->type) {
128         case LV2_EVBUF_EVENT:
129                 return &evbuf->buf.event;
130         case LV2_EVBUF_ATOM:
131                 return &evbuf->buf.atom;
132         }
133         return NULL;
134 }
135
136 LV2_Evbuf_Iterator
137 lv2_evbuf_begin(LV2_Evbuf* evbuf)
138 {
139         LV2_Evbuf_Iterator iter = { evbuf, 0 };
140         return iter;
141 }
142
143 LV2_Evbuf_Iterator
144 lv2_evbuf_end(LV2_Evbuf* evbuf)
145 {
146         const uint32_t           size = lv2_evbuf_get_size(evbuf);
147         const LV2_Evbuf_Iterator iter = { evbuf, lv2_evbuf_pad_size(size) };
148         return iter;
149 }
150
151 bool
152 lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter)
153 {
154         return iter.offset < lv2_evbuf_get_size(iter.evbuf);
155 }
156
157 LV2_Evbuf_Iterator
158 lv2_evbuf_next(LV2_Evbuf_Iterator iter)
159 {
160         if (!lv2_evbuf_is_valid(iter)) {
161                 return iter;
162         }
163
164         LV2_Evbuf* evbuf  = iter.evbuf;
165         uint32_t   offset = iter.offset;
166         uint32_t   size;
167         switch (evbuf->type) {
168         case LV2_EVBUF_EVENT:
169                 size    = ((LV2_Event*)(evbuf->buf.event.data + offset))->size;
170                 offset += lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
171                 break;
172         case LV2_EVBUF_ATOM:
173                 size = ((LV2_Atom_Event*)
174                         ((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, &evbuf->buf.atom)
175                          + offset))->body.size;
176                 offset += lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
177                 break;
178         }
179
180         LV2_Evbuf_Iterator next = { evbuf, offset };
181         return next;
182 }
183
184 bool
185 lv2_evbuf_get(LV2_Evbuf_Iterator iter,
186               uint32_t*          frames,
187               uint32_t*          subframes,
188               uint32_t*          type,
189               uint32_t*          size,
190               uint8_t**          data)
191 {
192         *frames = *subframes = *type = *size = 0;
193         *data = NULL;
194
195         if (!lv2_evbuf_is_valid(iter)) {
196                 return false;
197         }
198
199         LV2_Event_Buffer*  ebuf;
200         LV2_Event*         ev;
201         LV2_Atom_Sequence* aseq;
202         LV2_Atom_Event*    aev;
203         switch (iter.evbuf->type) {
204         case LV2_EVBUF_EVENT:
205                 ebuf = &iter.evbuf->buf.event;
206                 ev = (LV2_Event*)((char*)ebuf->data + iter.offset);
207                 *frames    = ev->frames;
208                 *subframes = ev->subframes;
209                 *type      = ev->type;
210                 *size      = ev->size;
211                 *data      = (uint8_t*)ev + sizeof(LV2_Event);
212                 break;
213         case LV2_EVBUF_ATOM:
214                 aseq = (LV2_Atom_Sequence*)&iter.evbuf->buf.atom;
215                 aev = (LV2_Atom_Event*)(
216                         (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq)
217                         + iter.offset);
218                 *frames    = aev->time.frames;
219                 *subframes = 0;
220                 *type      = aev->body.type;
221                 *size      = aev->body.size;
222                 *data      = (uint8_t*)LV2_ATOM_BODY(&aev->body);
223                 break;
224         }
225
226         return true;
227 }
228
229 bool
230 lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
231                 uint32_t            frames,
232                 uint32_t            subframes,
233                 uint32_t            type,
234                 uint32_t            size,
235                 const uint8_t*      data)
236 {
237         LV2_Event_Buffer*  ebuf;
238         LV2_Event*         ev;
239         LV2_Atom_Sequence* aseq;
240         LV2_Atom_Event*    aev;
241         switch (iter->evbuf->type) {
242         case LV2_EVBUF_EVENT:
243                 ebuf = &iter->evbuf->buf.event;
244                 if (ebuf->capacity - ebuf->size < sizeof(LV2_Event) + size) {
245                         return false;
246                 }
247
248                 ev = (LV2_Event*)(ebuf->data + iter->offset);
249                 ev->frames    = frames;
250                 ev->subframes = subframes;
251                 ev->type      = type;
252                 ev->size      = size;
253                 memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
254
255                 size               = lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
256                 ebuf->size        += size;
257                 ebuf->event_count += 1;
258                 iter->offset      += size;
259                 break;
260         case LV2_EVBUF_ATOM:
261                 aseq = (LV2_Atom_Sequence*)&iter->evbuf->buf.atom;
262                 if (iter->evbuf->capacity - sizeof(LV2_Atom) - aseq->atom.size
263                     < sizeof(LV2_Atom_Event) + size) {
264                         return false;
265                 }
266
267                 aev = (LV2_Atom_Event*)(
268                         (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq)
269                         + iter->offset);
270                 aev->time.frames = frames;
271                 aev->body.type   = type;
272                 aev->body.size   = size;
273                 memcpy(LV2_ATOM_BODY(&aev->body), data, size);
274
275                 size             = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
276                 aseq->atom.size += size;
277                 iter->offset    += size;
278                 break;
279         default:
280                 return false;
281         }
282
283         return true;
284 }