Support LV2 atom sequence ports alongside old event 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 <stdint.h>
18 #include <stdbool.h>
19 #include <string.h>
20 #include <stdlib.h>
21
22 #include "lv2/lv2plug.in/ns/ext/atom/atom.h"
23 #include "lv2/lv2plug.in/ns/ext/event/event.h"
24
25 #include "lv2_evbuf.h"
26
27 struct LV2_Evbuf_Impl {
28         LV2_Evbuf_Type type;
29         uint32_t       capacity;
30         union {
31                 LV2_Event_Buffer     event;
32                 LV2_Atom_Port_Buffer atom;
33         } buf;
34 };
35
36 static inline uint32_t
37 lv2_evbuf_pad_size(uint32_t size)
38 {
39         return (size + 7) & (~7);
40 }
41
42 LV2_Evbuf*
43 lv2_evbuf_new(uint32_t capacity, LV2_Evbuf_Type type, uint32_t atom_type)
44 {
45         // FIXME: memory must be 64-bit aligned
46         LV2_Evbuf* evbuf = (LV2_Evbuf*)malloc(
47                 sizeof(LV2_Evbuf) + sizeof(LV2_Atom_Sequence) + capacity);
48         evbuf->capacity = capacity;
49         lv2_evbuf_set_type(evbuf, type, atom_type);
50         lv2_evbuf_reset(evbuf);
51         return evbuf;
52 }
53
54 void
55 lv2_evbuf_free(LV2_Evbuf* evbuf)
56 {
57         free(evbuf);
58 }
59
60 void
61 lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type, uint32_t atom_type)
62 {
63         evbuf->type = type;
64         switch (type) {
65         case LV2_EVBUF_EVENT:
66                 evbuf->buf.event.data     = (uint8_t*)(evbuf + 1);
67                 evbuf->buf.event.capacity = evbuf->capacity;
68                 break;
69         case LV2_EVBUF_ATOM:
70                 evbuf->buf.atom.data       = (LV2_Atom*)(evbuf + 1);
71                 evbuf->buf.atom.size       = sizeof(LV2_Atom_Port_Buffer);
72                 evbuf->buf.atom.capacity   = evbuf->capacity;
73                 evbuf->buf.atom.data->type = atom_type;
74                 evbuf->buf.atom.data->size = 0;
75                 break;
76         }
77         lv2_evbuf_reset(evbuf);
78 }
79
80 void
81 lv2_evbuf_reset(LV2_Evbuf* evbuf)
82 {
83         switch (evbuf->type) {
84         case LV2_EVBUF_EVENT:
85                 evbuf->buf.event.header_size = sizeof(LV2_Event_Buffer);
86                 evbuf->buf.event.stamp_type  = LV2_EVENT_AUDIO_STAMP;
87                 evbuf->buf.event.event_count = 0;
88                 evbuf->buf.event.size        = 0;
89                 break;
90         case LV2_EVBUF_ATOM:
91                 evbuf->buf.atom.data->size = 0;
92         }
93 }
94
95 uint32_t
96 lv2_evbuf_get_size(LV2_Evbuf* evbuf)
97 {
98         switch (evbuf->type) {
99         case LV2_EVBUF_EVENT:
100                 return evbuf->buf.event.size;
101         case LV2_EVBUF_ATOM:
102                 return evbuf->buf.atom.data->size;
103         }
104         return 0;
105 }
106
107 void*
108 lv2_evbuf_get_buffer(LV2_Evbuf* evbuf)
109 {
110         switch (evbuf->type) {
111         case LV2_EVBUF_EVENT:
112                 return &evbuf->buf.event;
113         case LV2_EVBUF_ATOM:
114                 return &evbuf->buf.atom;
115         }
116         return NULL;
117 }
118
119 LV2_Evbuf_Iterator
120 lv2_evbuf_begin(LV2_Evbuf* evbuf)
121 {
122         LV2_Evbuf_Iterator iter = { evbuf, 0 };
123         return iter;
124 }
125
126 LV2_Evbuf_Iterator
127 lv2_evbuf_end(LV2_Evbuf* evbuf)
128 {
129         const size_t             size = lv2_evbuf_get_size(evbuf);
130         const LV2_Evbuf_Iterator iter = { evbuf, lv2_evbuf_pad_size(size) };
131         return iter;
132 }
133
134 bool
135 lv2_evbuf_is_valid(LV2_Evbuf_Iterator iter)
136 {
137         return iter.offset < lv2_evbuf_get_size(iter.evbuf);
138 }
139
140 LV2_Evbuf_Iterator
141 lv2_evbuf_next(LV2_Evbuf_Iterator iter)
142 {
143         if (!lv2_evbuf_is_valid(iter)) {
144                 return iter;
145         }
146
147         LV2_Evbuf* evbuf  = iter.evbuf;
148         uint32_t   offset = iter.offset;
149         uint32_t   size;
150         switch (evbuf->type) {
151         case LV2_EVBUF_EVENT:
152                 size    = ((LV2_Event*)(evbuf->buf.event.data + offset))->size;
153                 offset += lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
154                 break;
155         case LV2_EVBUF_ATOM:
156                 size = ((LV2_Atom_Event*)
157                         ((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, evbuf->buf.atom.data)
158                          + offset))->body.size;
159                 offset += lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
160                 break;
161         }
162
163         LV2_Evbuf_Iterator next = { evbuf, offset };
164         return next;
165 }
166
167 bool
168 lv2_evbuf_get(LV2_Evbuf_Iterator iter,
169               uint32_t*          frames,
170               uint32_t*          subframes,
171               uint32_t*          type,
172               uint32_t*          size,
173               uint8_t**          data)
174 {
175         *frames = *subframes = *type = *size = 0;
176         *data = NULL;
177
178         if (!lv2_evbuf_is_valid(iter)) {
179                 return false;
180         }
181
182         LV2_Event_Buffer*     ebuf;
183         LV2_Event*            ev;
184         LV2_Atom_Port_Buffer* abuf;
185         LV2_Atom_Event*       aev;
186         switch (iter.evbuf->type) {
187         case LV2_EVBUF_EVENT:
188                 ebuf = &iter.evbuf->buf.event;
189                 ev = (LV2_Event*)ebuf->data + iter.offset;
190                 *frames    = ev->frames;
191                 *subframes = ev->subframes;
192                 *type      = ev->type;
193                 *size      = ev->size;
194                 *data      = (uint8_t*)ev + sizeof(LV2_Event);
195                 break;
196         case LV2_EVBUF_ATOM:
197                 abuf = &iter.evbuf->buf.atom;
198                 aev = (LV2_Atom_Event*)(
199                         (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, abuf->data)
200                         + iter.offset);
201                 *frames    = aev->time.frames;
202                 *subframes = 0;
203                 *type      = aev->body.type;
204                 *size      = aev->body.size;
205                 *data      = LV2_ATOM_BODY(&aev->body);
206                 break;
207         }
208
209         return true;
210 }
211
212 bool
213 lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
214                 uint32_t            frames,
215                 uint32_t            subframes,
216                 uint32_t            type,
217                 uint32_t            size,
218                 const uint8_t*      data)
219 {
220         LV2_Event_Buffer*     ebuf;
221         LV2_Event*            ev;
222         LV2_Atom_Port_Buffer* abuf;
223         LV2_Atom_Event*       aev;
224         switch (iter->evbuf->type) {
225         case LV2_EVBUF_EVENT:
226                 ebuf = &iter->evbuf->buf.event;
227                 if (ebuf->capacity - ebuf->size < sizeof(LV2_Event) + size) {
228                         return false;
229                 }
230
231                 ev = (LV2_Event*)(ebuf->data + iter->offset);
232                 ev->frames    = frames;
233                 ev->subframes = subframes;
234                 ev->type      = type;
235                 ev->size      = size;
236                 memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
237
238                 size               = lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
239                 ebuf->size        += size;
240                 ebuf->event_count += 1;
241                 iter->offset      += size;
242                 break;
243         case LV2_EVBUF_ATOM:
244                 abuf = &iter->evbuf->buf.atom;
245                 if (abuf->capacity - abuf->data->size < sizeof(LV2_Atom_Event) + size) {
246                         return false;
247                 }
248
249                 aev = (LV2_Atom_Event*)(
250                         (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, abuf->data)
251                         + iter->offset);
252                 aev->time.frames = frames;
253                 aev->body.type   = type;
254                 aev->body.size   = size;
255                 memcpy(LV2_ATOM_BODY(&aev->body), data, size);
256
257                 size              = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
258                 abuf->data->size += size;
259                 iter->offset     += size;
260                 break;
261         }
262
263         return true;
264 }