DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

event-helpers.h (7644B)


      1 /*
      2   Copyright 2008-2015 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 /**
     18    @file event-helpers.h Helper functions for the LV2 Event extension
     19    <http://lv2plug.in/ns/ext/event>.
     20 */
     21 
     22 #ifndef LV2_EVENT_HELPERS_H
     23 #define LV2_EVENT_HELPERS_H
     24 
     25 #include <stdint.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 
     29 #include "event.h"
     30 
     31 #ifdef __cplusplus
     32 extern "C" {
     33 #else
     34 #    include <stdbool.h>
     35 #endif
     36 
     37 /** @file
     38  * Helper functions for the LV2 Event extension
     39  * <http://lv2plug.in/ns/ext/event>.
     40  *
     41  * These functions are provided for convenience only, use of them is not
     42  * required for supporting lv2ev (i.e. the events extension is defined by the
     43  * raw buffer format described in lv2_event.h and NOT by this API).
     44  *
     45  * Note that these functions are all static inline which basically means:
     46  * do not take the address of these functions. */
     47 
     48 
     49 /** Pad a size to 64 bits (for event sizes) */
     50 static inline uint16_t
     51 lv2_event_pad_size(uint16_t size)
     52 {
     53 	return (uint16_t)(size + 7U) & (uint16_t)(~7U);
     54 }
     55 
     56 
     57 /** Initialize (empty, reset..) an existing event buffer.
     58  * The contents of buf are ignored entirely and overwritten, except capacity
     59  * which is unmodified. */
     60 static inline void
     61 lv2_event_buffer_reset(LV2_Event_Buffer*  buf,
     62                        uint16_t           stamp_type,
     63                        uint8_t*           data)
     64 {
     65 	buf->data = data;
     66 	buf->header_size = sizeof(LV2_Event_Buffer);
     67 	buf->stamp_type = stamp_type;
     68 	buf->event_count = 0;
     69 	buf->size = 0;
     70 }
     71 
     72 
     73 /** Allocate a new, empty event buffer. */
     74 static inline LV2_Event_Buffer*
     75 lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type)
     76 {
     77 	const size_t      size = sizeof(LV2_Event_Buffer) + capacity;
     78 	LV2_Event_Buffer* buf  = (LV2_Event_Buffer*)malloc(size);
     79 	if (buf != NULL) {
     80 		buf->capacity = capacity;
     81 		lv2_event_buffer_reset(buf, stamp_type, (uint8_t *)(buf + 1));
     82 		return buf;
     83 	} else {
     84 		return NULL;
     85 	}
     86 }
     87 
     88 
     89 /** An iterator over an LV2_Event_Buffer.
     90  *
     91  * Multiple simultaneous read iterators over a single buffer is fine,
     92  * but changing the buffer invalidates all iterators (e.g. RW Lock). */
     93 typedef struct {
     94 	LV2_Event_Buffer* buf;
     95 	uint32_t          offset;
     96 } LV2_Event_Iterator;
     97 
     98 
     99 /** Reset an iterator to point to the start of `buf`.
    100  * @return True if `iter` is valid, otherwise false (buffer is empty) */
    101 static inline bool
    102 lv2_event_begin(LV2_Event_Iterator* iter,
    103                 LV2_Event_Buffer*   buf)
    104 {
    105 	iter->buf = buf;
    106 	iter->offset = 0;
    107 	return (buf->size > 0);
    108 }
    109 
    110 
    111 /** Check if `iter` is valid.
    112  * @return True if `iter` is valid, otherwise false (past end of buffer) */
    113 static inline bool
    114 lv2_event_is_valid(LV2_Event_Iterator* iter)
    115 {
    116 	return (iter->buf && (iter->offset < iter->buf->size));
    117 }
    118 
    119 
    120 /** Advance `iter` forward one event.
    121  * `iter` must be valid.
    122  * @return True if `iter` is valid, otherwise false (reached end of buffer) */
    123 static inline bool
    124 lv2_event_increment(LV2_Event_Iterator* iter)
    125 {
    126 	if (!lv2_event_is_valid(iter)) {
    127 		return false;
    128 	}
    129 
    130 	LV2_Event* const ev = (LV2_Event*)(
    131 			(uint8_t*)iter->buf->data + iter->offset);
    132 
    133 	iter->offset += lv2_event_pad_size(
    134 		(uint16_t)((uint16_t)sizeof(LV2_Event) + ev->size));
    135 
    136 	return true;
    137 }
    138 
    139 
    140 /** Dereference an event iterator (get the event currently pointed at).
    141  * `iter` must be valid.
    142  * `data` if non-NULL, will be set to point to the contents of the event
    143  *         returned.
    144  * @return A Pointer to the event `iter` is currently pointing at, or NULL
    145  *         if the end of the buffer is reached (in which case `data` is
    146  *         also set to NULL). */
    147 static inline LV2_Event*
    148 lv2_event_get(LV2_Event_Iterator* iter,
    149               uint8_t**           data)
    150 {
    151 	if (!lv2_event_is_valid(iter)) {
    152 		return NULL;
    153 	}
    154 
    155 	LV2_Event* const ev = (LV2_Event*)(
    156 			(uint8_t*)iter->buf->data + iter->offset);
    157 
    158 	if (data)
    159 		*data = (uint8_t*)ev + sizeof(LV2_Event);
    160 
    161 	return ev;
    162 }
    163 
    164 
    165 /** Write an event at `iter`.
    166  * The event (if any) pointed to by `iter` will be overwritten, and `iter`
    167  * incremented to point to the following event (i.e. several calls to this
    168  * function can be done in sequence without twiddling iter in-between).
    169  * @return True if event was written, otherwise false (buffer is full). */
    170 static inline bool
    171 lv2_event_write(LV2_Event_Iterator* iter,
    172                 uint32_t            frames,
    173                 uint32_t            subframes,
    174                 uint16_t            type,
    175                 uint16_t            size,
    176                 const uint8_t*      data)
    177 {
    178 	if (!iter->buf)
    179 		return false;
    180 
    181 	if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size)
    182 		return false;
    183 
    184 	LV2_Event* const ev = (LV2_Event*)(
    185 			(uint8_t*)iter->buf->data + iter->offset);
    186 
    187 	ev->frames = frames;
    188 	ev->subframes = subframes;
    189 	ev->type = type;
    190 	ev->size = size;
    191 	memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
    192 	++iter->buf->event_count;
    193 
    194 	size = lv2_event_pad_size((uint16_t)(sizeof(LV2_Event) + size));
    195 	iter->buf->size += size;
    196 	iter->offset    += size;
    197 
    198 	return true;
    199 }
    200 
    201 
    202 /** Reserve space for an event in the buffer and return a pointer to
    203     the memory where the caller can write the event data, or NULL if there
    204     is not enough room in the buffer. */
    205 static inline uint8_t*
    206 lv2_event_reserve(LV2_Event_Iterator* iter,
    207                   uint32_t frames,
    208                   uint32_t subframes,
    209                   uint16_t type,
    210                   uint16_t size)
    211 {
    212 	const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + size);
    213 	if (iter->buf->capacity - iter->buf->size < total_size)
    214 		return NULL;
    215 
    216 	LV2_Event* const ev = (LV2_Event*)(
    217 		(uint8_t*)iter->buf->data + iter->offset);
    218 
    219 	ev->frames = frames;
    220 	ev->subframes = subframes;
    221 	ev->type = type;
    222 	ev->size = size;
    223 	++iter->buf->event_count;
    224 
    225 	const uint16_t padded_size = lv2_event_pad_size(total_size);
    226 	iter->buf->size += padded_size;
    227 	iter->offset    += padded_size;
    228 
    229 	return (uint8_t*)ev + sizeof(LV2_Event);
    230 }
    231 
    232 
    233 /** Write an event at `iter`.
    234  * The event (if any) pointed to by `iter` will be overwritten, and `iter`
    235  * incremented to point to the following event (i.e. several calls to this
    236  * function can be done in sequence without twiddling iter in-between).
    237  * @return True if event was written, otherwise false (buffer is full). */
    238 static inline bool
    239 lv2_event_write_event(LV2_Event_Iterator* iter,
    240                       const LV2_Event*    ev,
    241                       const uint8_t*      data)
    242 {
    243 	const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + ev->size);
    244 	if (iter->buf->capacity - iter->buf->size < total_size)
    245 		return false;
    246 
    247 	LV2_Event* const write_ev = (LV2_Event*)(
    248 		(uint8_t*)iter->buf->data + iter->offset);
    249 
    250 	*write_ev = *ev;
    251 	memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size);
    252 	++iter->buf->event_count;
    253 
    254 	const uint16_t padded_size = lv2_event_pad_size(total_size);
    255 	iter->buf->size += padded_size;
    256 	iter->offset    += padded_size;
    257 
    258 	return true;
    259 }
    260 
    261 #ifdef __cplusplus
    262 }  /* extern "C" */
    263 #endif
    264 
    265 #endif /* LV2_EVENT_HELPERS_H */