Mozzi  version v2.0
sound synthesis library for Arduino
CircularBuffer.h
1 /*
2  * CircularBuffer.h
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2014-2024 Tim Barrass and the Mozzi Team
7  *
8  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9  *
10  */
11 
12 /*
13 Modified from https://en.wikipedia.org/wiki/Circular_buffer
14 Mirroring version
15 On 18 April 2014, the simplified version on the Wikipedia page for power of 2 sized buffers
16 doesn't work - cbIsEmpty() returns true whether the buffer is full or empty.
17 
18 April 2025: modified for different buffer sizes under the suggestion
19 of Meebleeps (https://github.com/sensorium/Mozzi/issues/281)
20 */
21 
22 
23 
28 template <class ITEM_TYPE, int16_t BUFFER_SIZE>
30 {
31 
32 public:
35  CircularBuffer(): start(0),end(0),s_msb(0),e_msb(0)
36  {
37  }
38 
39  inline
40  bool isFull() {
41  return end == start && e_msb != s_msb;
42  }
43 
44  inline
45  bool isEmpty() {
46  return end == start && e_msb == s_msb;
47  }
48 
49  inline
50  void write(ITEM_TYPE in) {
51  items[end] = in;
52  //if (isFull()) cbIncrStart(); /* full, overwrite moves start pointer */
53  cbIncrEnd();
54  }
55 
56  inline
57  ITEM_TYPE read() {
58  ITEM_TYPE out = items[start];
59  cbIncrStart();
60  return out;
61  }
62 
63  inline
64  unsigned long count() {
65  return (num_buffers_read << COUNT_LSHIFT) + start;
66  }
67  inline
68  ITEM_TYPE * address() {
69  return items;
70  }
71 
72 private:
73  ITEM_TYPE items[BUFFER_SIZE];
74  uint8_t start; /* index of oldest itement */
75  uint8_t end; /* index at which to write new itement */
76  uint8_t s_msb;
77  uint8_t e_msb;
78  unsigned long num_buffers_read;
79  static constexpr unsigned long COUNT_LSHIFT =
80  (BUFFER_SIZE == 256) ? 8 :
81  (BUFFER_SIZE == 128) ? 7 :
82  (BUFFER_SIZE == 64) ? 6 :
83  (BUFFER_SIZE == 32) ? 5 :
84  (BUFFER_SIZE == 16) ? 4 :
85  (BUFFER_SIZE == 8) ? 3 :
86  (BUFFER_SIZE == 4) ? 2 :
87  (BUFFER_SIZE == 2) ? 1 : 0;
88 
89  inline
90  void cbIncrStart() {
91  start++;
92  if (start == BUFFER_SIZE)
93  {
94  start = 0;
95  s_msb ^= 1;
96  num_buffers_read++;
97  }
98  }
99 
100  inline
101  void cbIncrEnd()
102  {
103  end++;
104  if (end == BUFFER_SIZE)
105  {
106  end = 0;
107  e_msb ^= 1;
108  }
109  }
110 
111 
112 };
113 
114 
115 
121 template <class ITEM_TYPE>
122 class CircularBuffer<ITEM_TYPE, 256>
123 {
124 public:
127  CircularBuffer(): start(0),end(0),s_msb(0),e_msb(0)
128  {
129  }
130 
131  inline
132  bool isFull() {
133  return end == start && e_msb != s_msb;
134  }
135 
136  inline
137  bool isEmpty() {
138  return end == start && e_msb == s_msb;
139  }
140 
141  inline
142  void write(ITEM_TYPE in) {
143  items[end] = in;
144  //if (isFull()) cbIncrStart(); /* full, overwrite moves start pointer */
145  cbIncrEnd();
146  }
147 
148  inline
149  ITEM_TYPE read() {
150  ITEM_TYPE out = items[start];
151  cbIncrStart();
152  return out;
153  }
154 
155  inline
156  unsigned long count() {
157  return (num_buffers_read << 8) + start;
158  }
159  inline
160  ITEM_TYPE * address() {
161  return items;
162  }
163 
164 private:
165  ITEM_TYPE items[256];
166  uint8_t start; /* index of oldest itement */
167  uint8_t end; /* index at which to write new itement */
168  uint8_t s_msb;
169  uint8_t e_msb;
170  unsigned long num_buffers_read;
171 
172 
173  inline
174  void cbIncrStart() {
175  start++;
176  if (start == 0) {
177  s_msb ^= 1;
178  num_buffers_read++;
179  }
180  }
181 
182  inline
183  void cbIncrEnd() {
184  end++;
185  if (end == 0) e_msb ^= 1;
186  }
187 };
188 
Circular buffer object.
CircularBuffer()
Constructor.