aboutsummaryrefslogtreecommitdiffstats
path: root/lv2/ns/ext/atom/atom-buffer.h
blob: f4b90dd750de975a790fdd07b2a2613d1ef4a07b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
  Copyright 2008-2011 David Robillard <http://drobilla.net>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
   @file atom-event-buffer.h Helper functions for atom:EventBuffer.

   Note that these functions are all static inline which basically means:
   do not take the address of these functions.
*/

#ifndef LV2_ATOM_EVENT_BUFFER_H
#define LV2_ATOM_EVENT_BUFFER_H

#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

#include "lv2/lv2plug.in/ns/ext/atom/atom.h"

/**
   Initialize an existing atom buffer.
   All fields of @c buf are reset, except capacity which is unmodified.
*/
static inline void
lv2_atom_buffer_reset(LV2_Atom_Buffer* buf)
{
	buf->event_count = 0;
	buf->size        = 0;
}

/**
   Allocate a new, empty atom buffer.
*/
static inline LV2_Atom_Buffer*
lv2_atom_buffer_new(uint32_t capacity)
{
	const uint32_t   size = sizeof(LV2_Atom_Buffer) + capacity;
	LV2_Atom_Buffer* buf  = (LV2_Atom_Buffer*)malloc(size);
	if (buf) {
		buf->data     = (uint8_t*)(buf + 1);
		buf->capacity = capacity;
		lv2_atom_buffer_reset(buf);
	}
	return buf;
}

/**
   Free an atom buffer allocated with lv2_atom_buffer_new().
*/
static inline void
lv2_atom_buffer_free(LV2_Atom_Buffer* buf)
{
	free(buf);
}

/**
   An iterator over an LV2_Atom_Buffer.
*/
typedef struct {
	LV2_Atom_Buffer* buf;
	uint32_t         offset;
} LV2_Atom_Buffer_Iterator;

/**
   Return an iterator to the beginning of @c buf.
*/
static inline LV2_Atom_Buffer_Iterator
lv2_atom_buffer_begin(LV2_Atom_Buffer* buf)
{
	const LV2_Atom_Buffer_Iterator i = { buf, 0 };
	return i;
}

/**
   Return true iff @c i points to a valid atom.
*/
static inline bool
lv2_atom_buffer_is_valid(LV2_Atom_Buffer_Iterator i)
{
	return i.offset < i.buf->size;
}

/**
   Return the iterator to the next element after @c i.
   @param i A valid iterator to an atom in a buffer.
*/
static inline LV2_Atom_Buffer_Iterator
lv2_atom_buffer_next(LV2_Atom_Buffer_Iterator i)
{
	if (!lv2_atom_buffer_is_valid(i)) {
		return i;
	}
	const LV2_Atom_Event* const ev = (LV2_Atom_Event*)(i.buf->data + i.offset);
	i.offset += lv2_atom_pad_size(sizeof(LV2_Atom_Event) + ev->body.size);
	return i;
}

/**
   Return a pointer to the atom currently pointed to by @c i.
*/
static inline LV2_Atom_Event*
lv2_atom_buffer_get(LV2_Atom_Buffer_Iterator i)
{
	if (!lv2_atom_buffer_is_valid(i)) {
		return NULL;
	}
	return (LV2_Atom_Event*)(i.buf->data + i.offset);
}

/**
   Write an atom to a buffer.

   The atom will be written at the location pointed to by @c i, which will be
   incremented to point to the location where the next atom should be written
   (which is likely now garbage).  Thus, this function can be called repeatedly
   with a single @c i to write a sequence of atoms to the buffer.

   @return True if atom was written, otherwise false (buffer is full).
*/
static inline bool
lv2_atom_buffer_write(LV2_Atom_Buffer_Iterator* i,
                      uint32_t                  frames,
                      uint32_t                  subframes,
                      uint32_t                  type,
                      uint32_t                  size,
                      const uint8_t*            data)
{
	const uint32_t free_space = i->buf->capacity - i->buf->size;
	if (free_space < sizeof(LV2_Atom_Event) + size) {
		return false;
	}

	LV2_Atom_Event* const ev = (LV2_Atom_Event*)(i->buf->data + i->offset);

	ev->frames    = frames;
	ev->subframes = subframes;
	ev->body.type = type;
	ev->body.size = size;
	memcpy((uint8_t*)ev + sizeof(LV2_Atom_Event), data, size);
	++i->buf->event_count;

	size          = lv2_atom_pad_size(sizeof(LV2_Atom_Event) + size);
	i->buf->size += size;
	i->offset    += size;

	return true;
}

#endif /* LV2_ATOM_EVENT_BUFFER_H */