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