OpenWareLaboratory
CircularBuffer.h
Go to the documentation of this file.
1 #ifndef _CircularBuffer_hpp_
2 #define _CircularBuffer_hpp_
3 
4 #include <stdint.h>
5 #include <string.h> // for memcpy
6 
7 #ifndef FLOW_ASSERT
8 #define FLOW_ASSERT(x, y)
9 #endif
10 
11 template<typename DataType, typename IndexType = size_t>
13 protected:
14  DataType* data;
15  IndexType size;
16  IndexType writepos = 0;
17  IndexType readpos = 0;
18  bool empty = true;
19 public:
20  CircularBuffer(): data(NULL), size(0){}
21  CircularBuffer(DataType* data, IndexType size): data(data), size(size){}
22 
23  void setData(DataType* data, IndexType len) {
24  this->data = data;
25  size = len;
26  }
27 
28  IndexType getSize() const {
29  return size;
30  }
31 
32  DataType* getData() {
33  return data;
34  }
35 
36  bool isEmpty() const {
37  return empty;
38  }
39 
40  bool isFull() const {
41  return (writepos == readpos) && !empty;
42  }
43 
44  void write(DataType c){
45  FLOW_ASSERT(getWriteCapacity() > 0, "overflow");
46  data[writepos++] = c;
47  if(writepos >= size)
48  writepos = 0;
49  empty = false;
50  }
51 
52  void write(DataType* source, IndexType len){
53  FLOW_ASSERT(getWriteCapacity() >= len, "overflow");
54  DataType* dest = getWriteHead();
55  IndexType rem = size-writepos;
56  if(len >= rem){
57  memcpy(dest, source, rem*sizeof(DataType));
58  writepos = len-rem;
59  memcpy(data, source+rem, writepos*sizeof(DataType));
60  }else{
61  memcpy(dest, source, len*sizeof(DataType));
62  writepos += len;
63  }
64  empty = false;
65  }
66 
67  void writeAt(IndexType index, DataType value){
68  data[index % size] = value;
69  }
70 
71  void overdub(DataType c){
72  data[writepos++] += c;
73  if(writepos >= size)
74  writepos = 0;
75  empty = false;
76  }
77 
78  void overdubAt(IndexType index, DataType value){
79  data[index % size] += value;
80  }
81 
82  DataType read(){
83  FLOW_ASSERT(getReadCapacity() > 0, "underflow");
84  DataType c = data[readpos++];
85  if(readpos >= size)
86  readpos = 0;
87  empty = readpos == writepos;
88  return c;
89  }
90 
91  void read(DataType* dst, IndexType len){
92  FLOW_ASSERT(getReadCapacity() >= len, "underflow");
93  DataType* src = getReadHead();
94  IndexType rem = size-readpos;
95  if(len > rem){
96  memcpy(dst, src, rem*sizeof(DataType));
97  readpos = len-rem;
98  memcpy(dst+rem, data, readpos*sizeof(DataType));
99  }else{
100  memcpy(dst, src, len*sizeof(DataType));
101  readpos += len;
102  }
103  empty = readpos == writepos;
104  }
105 
106  DataType readAt(IndexType index){
107  return data[index % size];
108  }
109 
110  void skipUntilLast(char c){
111  DataType* src = getReadHead();
112  IndexType rem = size-readpos;
113  for(int i=0; i<rem; ++i){
114  if(src[i] != c){
115  readpos += i;
116  return;
117  }
118  }
119  rem = writepos;
120  for(int i=0; i<rem; ++i){
121  if(data[i] != c){
122  readpos = i;
123  return;
124  }
125  }
126  empty = readpos == writepos;
127  }
128 
129  IndexType getWriteIndex(){
130  return writepos;
131  }
132 
133  void setWriteIndex(IndexType pos){
134  writepos = pos % size;
135  }
136 
137  DataType* getWriteHead(){
138  return data+writepos;
139  }
140 
141  void moveWriteHead(int32_t samples){
142  FLOW_ASSERT(getWriteCapacity() >= samples, "overflow");
143  writepos = (writepos + samples) % size;
144  empty = false;
145  }
146 
147  IndexType getReadIndex(){
148  return readpos;
149  }
150 
151  void setReadIndex(IndexType pos){
152  readpos = pos % size;
153  }
154 
155  DataType* getReadHead(){
156  return data+readpos;
157  }
158 
159  void moveReadHead(int32_t samples){
160  FLOW_ASSERT(getReadCapacity() < samples, "underflow");
161  readpos = (readpos + samples) % size;
162  empty = readpos == writepos;
163  }
164 
168  void setDelay(int samples){
169  readpos = (writepos-samples+size) % size;
170  }
171 
175  IndexType getDelay() const {
176  return (writepos-readpos+size) % size;
177  }
178 
182  void delay(DataType* in, DataType* out, IndexType len, int delay_samples){
183  setDelay(delay_samples); // set delay relative to where we start writing
184  write(in, len);
185  read(out, len);
186  }
187 
188  IndexType getReadCapacity() const {
189  return size - getWriteCapacity();
190  }
191 
192  IndexType getWriteCapacity() const {
193  return size*empty + (readpos + size - writepos) % size;
194  }
195 
196  IndexType getContiguousWriteCapacity() const {
197  if(writepos < readpos)
198  return readpos - writepos;
199  else
200  return size - writepos;
201  }
202 
203  IndexType getContiguousReadCapacity() const {
204  if(writepos > readpos)
205  return writepos - readpos;
206  else
207  return size - readpos;
208  }
209 
210  void setAll(const DataType value){
211  for(IndexType i=0; i<size; ++i)
212  data[i] = value;
213  }
214 
215  void reset(){
216  readpos = writepos = 0;
217  empty = true;
218  }
219 
220  void clear(){
221  setAll(0);
222  }
223 
224  static CircularBuffer<DataType>* create(IndexType len){
225  CircularBuffer<DataType>* obj = new CircularBuffer<DataType>(new DataType[len], len);
226  obj->clear();
227  return obj;
228  }
229 
231  delete[] obj->data;
232  delete obj;
233  }
234 };
235 
239 
240 #endif /* _CircularBuffer_hpp_ */
#define FLOW_ASSERT(x, y)
Definition: CircularBuffer.h:8
CircularBuffer< float > CircularFloatBuffer
CircularBuffer< int32_t > CircularIntBuffer
CircularBuffer< int16_t > CircularShortBuffer
void setAll(const DataType value)
bool isFull() const
bool isEmpty() const
DataType readAt(IndexType index)
static void destroy(CircularBuffer< DataType > *obj)
void overdub(DataType c)
IndexType size
IndexType readpos
IndexType getReadIndex()
void write(DataType *source, IndexType len)
CircularBuffer(DataType *data, IndexType size)
DataType * getWriteHead()
IndexType writepos
IndexType getDelay() const
Get the read index expressed as delay behind the write index.
void overdubAt(IndexType index, DataType value)
void setData(DataType *data, IndexType len)
static CircularBuffer< DataType > * create(IndexType len)
void setWriteIndex(IndexType pos)
DataType * data
IndexType getContiguousWriteCapacity() const
void read(DataType *dst, IndexType len)
void setReadIndex(IndexType pos)
IndexType getSize() const
void skipUntilLast(char c)
DataType * getData()
void delay(DataType *in, DataType *out, IndexType len, int delay_samples)
Write to buffer and read with a delay.
void write(DataType c)
DataType * getReadHead()
IndexType getWriteIndex()
void moveWriteHead(int32_t samples)
IndexType getContiguousReadCapacity() const
void moveReadHead(int32_t samples)
IndexType getReadCapacity() const
IndexType getWriteCapacity() const
DataType read()
void setDelay(int samples)
Set the read index.
void writeAt(IndexType index, DataType value)