OpenWareLaboratory
FractionalCircularBuffer.h
Go to the documentation of this file.
1 #ifndef _FractionalCircularBuffer_hpp_
2 #define _FractionalCircularBuffer_hpp_
3 
4 #include <stdint.h>
5 
10 template<typename T = float>
12 private:
13  T* data;
14  T* delta;
15  const size_t size;
16  size_t writepos = 0;
17  float readpos = 0;
18 
19 protected:
23  inline T update(T previous, T current, size_t i){
24  delta[i] = previous - current;
25  data[i] = current;
26  return current;
27  }
28 public:
29  FractionalCircularBuffer(): data(NULL), delta(NULL), size(0){}
30  FractionalCircularBuffer(T* data, T* delta, size_t size) : data(data), delta(delta), size(size){}
31 
32  size_t getSize() const {
33  return size;
34  }
35 
36  T* getData() {
37  return data;
38  }
39 
40  T* getDelta() {
41  return delta;
42  }
43 
44  bool isEmpty() const {
45  return abs(writepos-readpos) < 1;
46  }
47 
48  void write(T value){
49  size_t pos = (writepos-1+size) % size;
50  update(data[pos], value, writepos);
51  if(++writepos >= size)
52  writepos = 0;
53  }
54 
55  void write(T* src, size_t len){
56  T previous = data[(writepos-1+size) % size];
57  size_t rem = size-writepos;
58  if(len > rem){
59  for(size_t i=writepos; i<size; ++i)
60  previous = update(previous, *src++, i);
61  writepos = len-rem;
62  for(size_t i=0; i<writepos; ++i)
63  previous = update(previous, *src++, i);
64  }else{
65  size_t i = writepos;
66  writepos += len;
67  for(; i<writepos; ++i)
68  previous = update(previous, *src++, i);
69  }
70  }
71 
72  void writeAt(size_t index, T value){
73  size_t pos = (index-1+size) % size;
74  update(data[pos], value, index);
75  }
76 
77  T read(){
78  size_t idx = (size_t)readpos;
79  T current = data[idx];
80  T diff = delta[idx];
81  float fraction = readpos-idx;
82  readpos += 1;
83  if(readpos >= size)
84  readpos -= size;
85  return current + fraction*diff;
86  }
87 
88  void read(T* dst, size_t len){
89  size_t idx = (size_t)readpos;
90  float fraction = 1 - (readpos-idx);
91  idx = (idx+1) % size;
92 
93  size_t rem = size-idx;
94  T* pdata = data+idx;
95  T* pdelta = delta+idx;
96  if(len > rem){
97  readpos += len - size;
98  for(size_t i=idx; i<size; ++i)
99  *dst++ = *pdata++ + fraction*(*pdelta++);
100  idx = (size_t)readpos;
101  for(size_t i=0; i<idx; ++i)
102  *dst++ = *pdata++ + fraction*(*pdelta++);
103  }else{
104  readpos += len;
105  while(len--)
106  *dst++ = *pdata++ + fraction*(*pdelta++);
107  }
108  }
109 
110  T readAt(float index){
111  size_t idx = (size_t)index;
112  float fraction = 1 - (index-idx);
113  idx = (idx+1) % size;
114  return data[idx] + fraction*delta[idx];
115  }
116 
117  size_t getWriteIndex(){
118  return writepos;
119  }
120 
121  void setWriteIndex(size_t pos){
122  writepos = pos % size;
123  }
124 
126  return data+writepos;
127  }
128 
129  void moveWriteHead(int samples){
130  writepos += samples;
131  if(writepos >= size)
132  writepos -= size;
133  }
134 
135  float getReadIndex(){
136  return readpos;
137  }
138 
139  void setReadIndex(float pos){
140  readpos = fmodf(pos+size, size);
141  }
142 
144  return data+(size_t)readpos;
145  }
146 
147  void moveReadHead(float samples){
148  setReadIndex(readpos+samples);
149  }
150 
154  void setDelay(float samples){
155  setReadIndex(writepos-samples);
156  }
157 
161  float getDelay(){
162  return fmodf(writepos-readpos+size, size);
163  }
164 
168  void delay(T* in, T* out, size_t len, float delay){
169  setDelay(delay);
170  write(in, len);
171  read(out, len);
172  }
173 
178  void delay(T* in, T* out, size_t len, float beginDelay, float endDelay){
179  setDelay(beginDelay);
180  float pos = readpos;
181  float incr = (len+endDelay-beginDelay)/len;
182  T previous = data[(writepos-1+size) % size];
183  size_t rem = size-writepos;
184  if(len > rem){
185  for(size_t i=writepos; i<size; ++i){
186  previous = update(previous, *in++, i);
187  *out++ = readAt(pos);
188  pos += incr;
189  }
190  writepos = len-rem;
191  for(size_t i=0; i<writepos; ++i){
192  previous = update(previous, *in++, i);
193  *out++ = readAt(pos);
194  pos += incr;
195  }
196  }else{
197  size_t i = writepos;
198  writepos += len;
199  for(; i<writepos; ++i){
200  previous = update(previous, *in++, i);
201  *out++ = readAt(pos);
202  pos += incr;
203  }
204  }
205  setDelay(endDelay);
206  }
207 
208  size_t getReadCapacity(){
209  return (writepos + size - (size_t)readpos) % size;
210  }
211 
213  return size - getReadCapacity();
214  }
215 
217  if(writepos < (size_t)readpos)
218  return (size_t)readpos - writepos;
219  else
220  return size - writepos;
221  }
222 
224  if(writepos < (size_t)readpos)
225  return size - (size_t)readpos;
226  else
227  return writepos - (size_t)readpos;
228  }
229 
230  void setAll(const T value){
231  for(size_t i=0; i<size; ++i){
232  data[i] = value;
233  delta[i] = value;
234  }
235  }
236 
237  void reset(){
238  readpos = writepos = 0;
239  }
240 
241  void clear(){
242  setAll(0);
243  }
244 
245  static FractionalCircularBuffer<T>* create(size_t len){
246  FractionalCircularBuffer<T>* obj = new FractionalCircularBuffer<T>(new T[len], new T[len], len);
247  obj->clear();
248  return obj;
249  }
250 
252  delete[] obj->data;
253  delete[] obj->delta;
254  delete obj;
255  }
256 };
257 
261 
262 #endif /* _FractionalCircularBuffer_hpp_ */
FractionalCircularBuffer< int16_t > FractionalCircularShortBuffer
FractionalCircularBuffer< int32_t > FractionalCircularIntBuffer
FractionalCircularBuffer< float > FractionalCircularFloatBuffer
#define abs(x)
Definition: basicmaths.h:44
Circular buffer that keeps a delta table of differences for faster fractional delay lines.
void write(T *src, size_t len)
FractionalCircularBuffer(T *data, T *delta, size_t size)
static FractionalCircularBuffer< T > * create(size_t len)
void read(T *dst, size_t len)
static void destroy(FractionalCircularBuffer< T > *obj)
T update(T previous, T current, size_t i)
Update an entry in the internal data and delta tables.
void setDelay(float samples)
Set the read index.
void writeAt(size_t index, T value)
void delay(T *in, T *out, size_t len, float delay)
Write to buffer and read with a delay.
float getDelay()
Get the read index expressed as delay behind the write index.
void delay(T *in, T *out, size_t len, float beginDelay, float endDelay)
Write to buffer and read with a delay that ramps up or down from beginDelay to endDelay.