1 /*
2 circularbuffer.c:
3
4 Copyright (C) 2012 Victor Lazzarini
5
6 This file is part of Csound.
7
8 The Csound Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 Csound is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with Csound; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 #include <csoundCore.h>
25
26 typedef struct _circular_buffer {
27 char *buffer;
28 int wp;
29 int rp;
30 int numelem;
31 int elemsize; /* in number of bytes */
32 } circular_buffer;
33
csoundCreateCircularBuffer(CSOUND * csound,int numelem,int elemsize)34 void *csoundCreateCircularBuffer(CSOUND *csound, int numelem, int elemsize){
35 circular_buffer *p;
36 if ((p = (circular_buffer *)
37 csound->Malloc(csound, sizeof(circular_buffer))) == NULL) {
38 return NULL;
39 }
40 p->numelem = numelem;
41 p->wp = p->rp = 0;
42 p->elemsize = elemsize;
43
44 if ((p->buffer = (char *) csound->Malloc(csound, numelem*elemsize)) == NULL) {
45 return NULL;
46 }
47 memset(p->buffer, 0, numelem*elemsize);
48 return (void *)p;
49 }
50
checkspace(circular_buffer * p,int writeCheck)51 static int checkspace(circular_buffer *p, int writeCheck){
52 int wp = p->wp, rp = p->rp, numelem = p->numelem;
53 if(writeCheck){
54 if (wp > rp) return rp - wp + numelem - 1;
55 else if (wp < rp) return rp - wp - 1;
56 else return numelem - 1;
57 }
58 else {
59 if (wp > rp) return wp - rp;
60 else if (wp < rp) return wp - rp + numelem;
61 else return 0;
62 }
63 }
64
csoundReadCircularBuffer(CSOUND * csound,void * p,void * out,int items)65 int csoundReadCircularBuffer(CSOUND *csound, void *p, void *out, int items)
66 {
67 IGN(csound);
68 if (p == NULL) return 0;
69 {
70 int remaining;
71 int itemsread, numelem = ((circular_buffer *)p)->numelem;
72 int elemsize = ((circular_buffer *)p)->elemsize;
73 int i=0, rp = ((circular_buffer *)p)->rp;
74 char *buffer = ((circular_buffer *)p)->buffer;
75 if ((remaining = checkspace(p, 0)) == 0) {
76 return 0;
77 }
78 itemsread = items > remaining ? remaining : items;
79 for (i=0; i < itemsread; i++){
80 memcpy((char *) out + (i * elemsize),
81 &(buffer[elemsize * rp++]), elemsize);
82 if (rp == numelem) {
83 rp = 0;
84 }
85 }
86 #if defined(MSVC)
87 InterlockedExchange(&((circular_buffer *)p)->rp, rp);
88 #elif defined(HAVE_ATOMIC_BUILTIN)
89 __atomic_exchange_n(&((circular_buffer *)p)->rp,rp, __ATOMIC_SEQ_CST);
90 #else
91 ((circular_buffer *)p)->rp = rp;
92 #endif
93 return itemsread;
94 }
95 }
96
csoundPeekCircularBuffer(CSOUND * csound,void * p,void * out,int items)97 int csoundPeekCircularBuffer(CSOUND *csound, void *p, void *out, int items)
98 {
99 IGN(csound);
100 if (p == NULL) return 0;
101 int remaining;
102 int itemsread, numelem = ((circular_buffer *)p)->numelem;
103 int elemsize = ((circular_buffer *)p)->elemsize;
104 int i=0, rp = ((circular_buffer *)p)->rp;
105 char *buffer = ((circular_buffer *)p)->buffer;
106 if ((remaining = checkspace(p, 0)) == 0) {
107 return 0;
108 }
109 itemsread = items > remaining ? remaining : items;
110 for(i=0; i < itemsread; i++){
111 memcpy((char *) out + (i * elemsize),
112 &(buffer[elemsize * rp++]), elemsize);
113 if (rp == numelem) {
114 rp = 0;
115 }
116 }
117 return itemsread;
118 }
119
csoundFlushCircularBuffer(CSOUND * csound,void * p)120 void csoundFlushCircularBuffer(CSOUND *csound, void *p)
121 {
122 IGN(csound);
123 if (p == NULL) return;
124 int remaining;
125 int itemsread, numelem = ((circular_buffer *)p)->numelem;
126 int i=0, rp = ((circular_buffer *)p)->rp;
127 //MYFLT *buffer = ((circular_buffer *)p)->buffer;
128 if ((remaining = checkspace(p, 0)) == 0) {
129 return;
130 }
131 itemsread = numelem > remaining ? remaining: numelem;
132 for (i=0; i < itemsread; i++){
133 rp++;
134 if(rp == numelem) rp = 0;
135 }
136 #if defined(MSVC)
137 InterlockedExchange(&((circular_buffer *)p)->rp, rp);
138 #elif defined(HAVE_ATOMIC_BUILTIN)
139 __atomic_store_n(&((circular_buffer *)p)->rp,rp, __ATOMIC_SEQ_CST);
140 #else
141 ((circular_buffer *)p)->rp = rp;
142 #endif
143 }
144
145
csoundWriteCircularBuffer(CSOUND * csound,void * p,const void * in,int items)146 int csoundWriteCircularBuffer(CSOUND *csound, void *p, const void *in, int items)
147 {
148 IGN(csound);
149 if (p == NULL) return 0;
150 int remaining;
151 int itemswrite, numelem = ((circular_buffer *)p)->numelem;
152 int elemsize = ((circular_buffer *)p)->elemsize;
153 int i=0, wp = ((circular_buffer *)p)->wp;
154 char *buffer = ((circular_buffer *)p)->buffer;
155 if ((remaining = checkspace(p, 1)) == 0) {
156 return 0;
157 }
158 itemswrite = items > remaining ? remaining : items;
159 for(i=0; i < itemswrite; i++){
160 memcpy(&(buffer[elemsize * wp++]),
161 ((char *) in) + (i * elemsize), elemsize);
162 if(wp == numelem) wp = 0;
163 }
164 #if defined(MSVC)
165 InterlockedExchange(&((circular_buffer *)p)->wp, wp);
166 #elif defined(HAVE_ATOMIC_BUILTIN)
167 __atomic_store_n(&((circular_buffer *)p)->wp,wp, __ATOMIC_SEQ_CST);
168 #else
169 ((circular_buffer *)p)->wp = wp;
170 #endif
171 return itemswrite;
172 }
173
csoundDestroyCircularBuffer(CSOUND * csound,void * p)174 void csoundDestroyCircularBuffer(CSOUND *csound, void *p){
175 if(p == NULL) return;
176 csound->Free(csound, ((circular_buffer *)p)->buffer);
177 csound->Free(csound, p);
178 }
179