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
|
#include "lfringbuffer.h"
#include "foundation/error.h"
#include <stdlib.h>
typedef struct LFRingBufferHeader
{
volatile size_t used; /* number of bytes written, in elements */
size_t size; /* in elements */
size_t write_position;
size_t read_position;
} LFRingBufferHeader;
typedef struct LFRingBuffer
{
LFRingBufferHeader header;
float data[1];
} LFRingBuffer;
/* create a ring buffer with the desired number of elements */
int lfringbuffer_create(lfringbuffer_t *out_ring_buffer, size_t number_of_elements)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)malloc(sizeof(LFRingBufferHeader) + sizeof(float) * number_of_elements);
if (!ring_buffer)
return NErr_OutOfMemory;
ring_buffer->header.used = 0;
ring_buffer->header.size = number_of_elements;
ring_buffer->header.write_position = 0;
ring_buffer->header.read_position = 0;
*out_ring_buffer = (lfringbuffer_t)ring_buffer;
return NErr_Success;
}
int lfringbuffer_destroy(lfringbuffer_t ring_buffer)
{
free(ring_buffer);
return NErr_Success;
}
/* ----- Read functions ----- */
/* get how many elements can currently be read */
size_t lfringbuffer_read_available(lfringbuffer_t rb)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
return ring_buffer->header.used;
}
/* retrieve a pointer that can be read from.
you might have to call this twice, because of ring buffer wraparound
call lfringbuffer_read_update() when you are done */
int lfringbuffer_read_get(lfringbuffer_t rb, size_t elements_requested, const float **out_buffer, size_t *elements_available)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
size_t end, to_copy;
int ret = NErr_Success;
/* can only read how many bytes we have available */
to_copy=ring_buffer->header.used;
if (to_copy > elements_requested)
{
to_copy = elements_requested;
ret = NErr_Underrun; /* signal that there was a buffer underrun when reading */
}
/* can only read until the end of the buffer */
end = ring_buffer->header.size-ring_buffer->header.read_position;
if (to_copy > end)
{
to_copy = end;
ret = NErr_TryAgain; /* signal that they need to call again to get the next part of the buffer */
}
*out_buffer = ring_buffer->data + ring_buffer->header.read_position;
*elements_available = to_copy;
ring_buffer->header.read_position += to_copy;
if (ring_buffer->header.read_position == ring_buffer->header.size)
ring_buffer->header.read_position=0;
return ret;
}
/* call to acknowledge that you have read the bytes */
void lfringbuffer_read_update(lfringbuffer_t rb, size_t elements_read)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
#if defined(__ARM_ARCH_7A__)
__asm__ __volatile__ ("dmb" : : : "memory");
#endif
nx_atomic_sub(elements_read, &ring_buffer->header.used);
}
static void lfringbuffer_read_set_position(lfringbuffer_t rb, size_t position)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
intptr_t bytes_to_flush = (intptr_t)(position - (size_t)ring_buffer->header.read_position);
if (bytes_to_flush < 0)
bytes_to_flush += ring_buffer->header.size;
lfringbuffer_read_update(rb, bytes_to_flush);
}
/* ----- Write functions ----- */
/* get how many elements can currently be written */
size_t lfringbuffer_write_available(lfringbuffer_t rb)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
return ring_buffer->header.size - ring_buffer->header.used;
}
/* retrieve a pointer that can be written to.
you might have to call this twice, because of ring buffer wraparound
call lfringbuffer_write_update() when you are done */
int lfringbuffer_write_get(lfringbuffer_t rb, size_t elements_requested, float **out_buffer, size_t *elements_available)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
size_t end, to_copy;
int ret = NErr_Success;
/* can only write how many bytes we have available */
to_copy=ring_buffer->header.size - ring_buffer->header.used;
if (to_copy > elements_requested)
{
to_copy = elements_requested;
ret = NErr_Underrun; /* signal that there was a buffer underrun when reading */
}
/* can only read until the end of the buffer */
end = ring_buffer->header.size-ring_buffer->header.write_position;
if (to_copy > end)
{
to_copy = end;
ret = NErr_TryAgain; /* signal that they need to call again to get the next part of the buffer */
}
*out_buffer = ring_buffer->data + ring_buffer->header.write_position;
*elements_available = to_copy;
ring_buffer->header.write_position += to_copy;
if (ring_buffer->header.write_position == ring_buffer->header.size)
ring_buffer->header.write_position=0;
return ret;
}
/* call to acknowledge that you have written the bytes */
void lfringbuffer_write_update(lfringbuffer_t rb, size_t elements_read)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
#if defined(__ARM_ARCH_7A__)
__asm__ __volatile__ ("dmb" : : : "memory");
#endif
nx_atomic_add(elements_read, &ring_buffer->header.used);
}
size_t lfringbuffer_write_get_position(lfringbuffer_t rb)
{
LFRingBuffer *ring_buffer = (LFRingBuffer *)rb;
return ring_buffer->header.write_position;
}
|