Fix atom sequence ports.
[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 void*
119 lv2_evbuf_get_buffer(LV2_Evbuf* evbuf)
120 {
121         switch (evbuf->type) {
122         case LV2_EVBUF_EVENT:
123                 return &evbuf->buf.event;
124         case LV2_EVBUF_ATOM:
125                 return &evbuf->buf.atom;
126         }
127         return NULL;
128 }
129
130 LV2_Evbuf_Iterator
131 lv2_evbuf_begin(LV2_Evbuf* evbuf)
132 {
133         LV2_Evbuf_Iterator iter = { evbuf, 0 };
134         return iter;
135 }
136
137 LV2_Evbuf_Iterator
138 lv2_evbuf_end(LV2_Evbuf* evbuf)
139 {
140         const uint32_t           size = lv2_evbuf_get_size(evbuf);
141         const LV2_Evbuf_Iterator iter = { evbuf, lv2_evbuf_pad_size(size) };
142         return iter;
143 }
144
145 bool
146 lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter)
147 {
148         return iter.offset < lv2_evbuf_get_size(iter.evbuf);
149 }
150
151 LV2_Evbuf_Iterator
152 lv2_evbuf_next(LV2_Evbuf_Iterator iter)
153 {
154         if (!lv2_evbuf_is_valid(iter)) {
155                 return iter;
156         }
157
158         LV2_Evbuf* evbuf  = iter.evbuf;
159         uint32_t   offset = iter.offset;
160         uint32_t   size;
161         switch (evbuf->type) {
162         case LV2_EVBUF_EVENT:
163                 size    = ((LV2_Event*)(evbuf->buf.event.data + offset))->size;
164                 offset += lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
165                 break;
166         case LV2_EVBUF_ATOM:
167                 size = ((LV2_Atom_Event*)
168                         ((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, &evbuf->buf.atom)
169                          + offset))->body.size;
170                 offset += lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
171                 break;
172         }
173
174         LV2_Evbuf_Iterator next = { evbuf, offset };
175         return next;
176 }
177
178 bool
179 lv2_evbuf_get(LV2_Evbuf_Iterator iter,
180               uint32_t*          frames,
181               uint32_t*          subframes,
182               uint32_t*          type,
183               uint32_t*          size,
184               uint8_t**          data)
185 {
186         *frames = *subframes = *type = *size = 0;
187         *data = NULL;
188
189         if (!lv2_evbuf_is_valid(iter)) {
190                 return false;
191         }
192
193         LV2_Event_Buffer*  ebuf;
194         LV2_Event*         ev;
195         LV2_Atom_Sequence* aseq;
196         LV2_Atom_Event*    aev;
197         switch (iter.evbuf->type) {
198         case LV2_EVBUF_EVENT:
199                 ebuf = &iter.evbuf->buf.event;
200                 ev = (LV2_Event*)ebuf->data + iter.offset;
201                 *frames    = ev->frames;
202                 *subframes = ev->subframes;
203                 *type      = ev->type;
204                 *size      = ev->size;
205                 *data      = (uint8_t*)ev + sizeof(LV2_Event);
206                 break;
207         case LV2_EVBUF_ATOM:
208                 aseq = (LV2_Atom_Sequence*)&iter.evbuf->buf.atom;
209                 aev = (LV2_Atom_Event*)(
210                         (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq)
211                         + iter.offset);
212                 *frames    = aev->time.frames;
213                 *subframes = 0;
214                 *type      = aev->body.type;
215                 *size      = aev->body.size;
216                 *data      = LV2_ATOM_BODY(&aev->body);
217                 break;
218         }
219
220         return true;
221 }
222
223 bool
224 lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
225                 uint32_t            frames,
226                 uint32_t            subframes,
227                 uint32_t            type,
228                 uint32_t            size,
229                 const uint8_t*      data)
230 {
231         LV2_Event_Buffer*  ebuf;
232         LV2_Event*         ev;
233         LV2_Atom_Sequence* aseq;
234         LV2_Atom_Event*    aev;
235         switch (iter->evbuf->type) {
236         case LV2_EVBUF_EVENT:
237                 ebuf = &iter->evbuf->buf.event;
238                 if (ebuf->capacity - ebuf->size < sizeof(LV2_Event) + size) {
239                         return false;
240                 }
241
242                 ev = (LV2_Event*)(ebuf->data + iter->offset);
243                 ev->frames    = frames;
244                 ev->subframes = subframes;
245                 ev->type      = type;
246                 ev->size      = size;
247                 memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
248
249                 size               = lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
250                 ebuf->size        += size;
251                 ebuf->event_count += 1;
252                 iter->offset      += size;
253                 break;
254         case LV2_EVBUF_ATOM:
255                 aseq = (LV2_Atom_Sequence*)&iter->evbuf->buf.atom;
256                 if (iter->evbuf->capacity - sizeof(LV2_Atom) - aseq->atom.size
257                     < sizeof(LV2_Atom_Event) + size) {
258                         return false;
259                 }
260
261                 aev = (LV2_Atom_Event*)(
262                         (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq)
263                         + iter->offset);
264                 aev->time.frames = frames;
265                 aev->body.type   = type;
266                 aev->body.size   = size;
267                 memcpy(LV2_ATOM_BODY(&aev->body), data, size);
268
269                 size             = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
270                 aseq->atom.size += size;
271                 iter->offset    += size;
272                 break;
273         }
274
275         return true;
276 }