arduino-audio-tools
Loading...
Searching...
No Matches
DynamicMultiBuffer.h
1#pragma once
2
3namespace audio_tools {
4
25template <typename T, template<typename> class BufferType>
26class DynamicMultiBuffer : public BaseBuffer<T> {
27 public:
35 DynamicMultiBuffer(size_t component_size, size_t initial_components = 1,
36 size_t max_components = 0) {
37 TRACED();
38 component_size_ = component_size;
39 max_components_ = max_components;
40
41 // Create initial buffer components
42 for (size_t i = 0; i < initial_components; i++) {
43 if (!addBufferComponent()) {
44 LOGE("Failed to allocate initial buffer component %d", (int)i);
45 break;
46 }
47 }
48 }
49
54 TRACED();
55 // Clean up all buffer components
56 for (auto* buffer : buffer_components) {
57 delete buffer;
58 }
59 buffer_components.clear();
60 }
61
70 bool read(T &result) override {
71 if (isEmpty()) {
72 return false;
73 }
74
75 // Find the buffer component containing the read position
76 size_t buffer_idx = read_pos / component_size_;
77 size_t local_pos = read_pos % component_size_;
78
79 // Perform read from the appropriate buffer
80 bool success = buffer_components[buffer_idx]->read(result);
81 if (success) {
82 read_pos++;
83 }
84
85 return success;
86 }
87
96 bool peek(T &result) override {
97 if (isEmpty()) {
98 return false;
99 }
100
101 // Find the buffer component containing the read position
102 size_t buffer_idx = read_pos / component_size_;
103 size_t local_pos = read_pos % component_size_;
104
105 // Perform peek from the appropriate buffer
106 return buffer_components[buffer_idx]->peek(result);
107 }
108
118 bool write(T data) override {
119 // Check if we need to add a new buffer component
120 if (isCurrentBufferFull()) {
121 if (!addBufferComponent()) {
122 return false; // Couldn't expand, so write fails
123 }
124 }
125
126 // Find the buffer component for writing
127 size_t buffer_idx = write_pos / component_size_;
128 size_t local_pos = write_pos % component_size_;
129
130 // Perform write to the appropriate buffer
131 bool success = buffer_components[buffer_idx]->write(data);
132 if (success) {
133 write_pos++;
134 }
135
136 return success;
137 }
138
148 int readArray(T data[], int len) override {
149 if (isEmpty() || data == nullptr) {
150 return 0;
151 }
152
153 int total_read = 0;
154 int remaining = min(len, available());
155
156 while (remaining > 0) {
157 // Find the current buffer component and position
158 size_t buffer_idx = read_pos / component_size_;
159 size_t local_pos = read_pos % component_size_;
160
161 // Calculate how many elements we can read from this component
162 int can_read = min(remaining, (int)(component_size_ - local_pos));
163
164 // Set up the buffer component for reading from the correct position
165 buffer_components[buffer_idx]->reset();
166 for (size_t i = 0; i < local_pos; i++) {
167 T dummy;
168 buffer_components[buffer_idx]->read(dummy);
169 }
170
171 // Read from the buffer component
172 int actually_read = buffer_components[buffer_idx]->readArray(data + total_read, can_read);
173
174 // Update positions
175 total_read += actually_read;
176 read_pos += actually_read;
177 remaining -= actually_read;
178
179 // If we couldn't read as much as expected, stop
180 if (actually_read < can_read) {
181 break;
182 }
183 }
184
185 return total_read;
186 }
187
198 int writeArray(const T data[], int len) override {
199 if (data == nullptr) {
200 return 0;
201 }
202
203 int total_written = 0;
204 int remaining = len;
205
206 while (remaining > 0) {
207 // Check if we need to add a new buffer component
208 if (isCurrentBufferFull()) {
209 if (!addBufferComponent()) {
210 break; // Couldn't expand, so stop writing
211 }
212 }
213
214 // Find the current buffer component and position
215 size_t buffer_idx = write_pos / component_size_;
216 size_t local_pos = write_pos % component_size_;
217
218 // Calculate how many elements we can write to this component
219 int can_write = min(remaining, (int)(component_size_ - local_pos));
220
221 // Set up the buffer component for writing at the correct position
222 buffer_components[buffer_idx]->reset();
223 for (size_t i = 0; i < local_pos; i++) {
224 buffer_components[buffer_idx]->write(T()); // Write dummy values
225 }
226
227 // Write to the buffer component
228 int actually_written = buffer_components[buffer_idx]->writeArray(data + total_written, can_write);
229
230 // Update positions
231 total_written += actually_written;
232 write_pos += actually_written;
233 remaining -= actually_written;
234
235 // If we couldn't write as much as expected, stop
236 if (actually_written < can_write) {
237 break;
238 }
239 }
240
241 return total_written;
242 }
243
249 void reset() override {
250 read_pos = 0;
251 write_pos = 0;
252
253 // Reset all buffer components
254 for (auto* buffer : buffer_components) {
255 buffer->reset();
256 }
257 }
258
264 int available() override {
265 return write_pos - read_pos;
266 }
267
276 int availableForWrite() override {
277 // Calculate space in existing buffers
278 size_t existing_space = totalCapacity() - write_pos;
279
280 // If no maximum component limit, return a large value
281 if (max_components_ == 0 || buffer_components.size() < max_components_) {
282 return existing_space + 1000000; // Effectively unlimited
283 }
284
285 return existing_space;
286 }
287
296 bool isFull() override {
297 if (max_components_ == 0) {
298 return false; // Never full if unlimited components
299 }
300
301 return buffer_components.size() >= max_components_ && isCurrentBufferFull();
302 }
303
309 bool isEmpty() override {
310 return available() == 0;
311 }
312
321 T* address() override {
322 if (isEmpty() || buffer_components.empty()) {
323 return nullptr;
324 }
325
326 size_t buffer_idx = read_pos / component_size_;
327 return buffer_components[buffer_idx]->address();
328 }
329
335 size_t size() override {
336 return totalCapacity();
337 }
338
347 bool resize(int new_size) override {
348 // Calculate needed components
349 size_t needed_components = (new_size + component_size_ - 1) / component_size_;
350
351 // Check if we're allowed to have this many components
352 if (max_components_ != 0 && needed_components > max_components_) {
353 needed_components = max_components_;
354 }
355
356 // Remove excess components
357 while (buffer_components.size() > needed_components) {
358 delete buffer_components.back();
359 buffer_components.pop_back();
360 }
361
362 // Add needed components
363 while (buffer_components.size() < needed_components) {
364 if (!addBufferComponent()) {
365 return false;
366 }
367 }
368
369 // Adjust read/write positions if they're now out of bounds
370 size_t total_capacity = totalCapacity();
371 if (write_pos > total_capacity) {
372 write_pos = total_capacity;
373 }
374 if (read_pos > write_pos) {
375 read_pos = write_pos;
376 }
377
378 return true;
379 }
380
387 return buffer_components.size();
388 }
389
396 return component_size_;
397 }
398
402 bool begin() {
403 read_pos = 0;
404 return true;
405 }
406
410 bool begin(int pos) {
411 if (pos > write_pos) return false;
412 read_pos = pos;
413 return true;
414 }
415
416 protected:
417 Vector<BufferType<T>*> buffer_components; // Collection of buffer components
418 size_t component_size_ = 0; // Size of each component in elements
419 size_t max_components_ = 0; // Maximum number of components (0 = unlimited)
420 size_t read_pos = 0; // Global read position
421 size_t write_pos = 0; // Global write position
422
431 // Check if we're allowed to add more components
432 if (max_components_ != 0 && buffer_components.size() >= max_components_) {
433 LOGW("Maximum number of buffer components reached: %d", (int)max_components_);
434 return false;
435 }
436
437 // Create new buffer component
438 BufferType<T>* new_buffer = new BufferType<T>(component_size_);
439 if (new_buffer == nullptr) {
440 LOGE("Failed to allocate new buffer component");
441 return false;
442 }
443
444 // make sure the component has the correct size
445 new_buffer->resize(component_size_);
446
447 // Add to our collection
448 buffer_components.push_back(new_buffer);
449 LOGI("Added buffer component #%d", (int)buffer_components.size());
450
451 return true;
452 }
453
459 size_t totalCapacity() {
460 return buffer_components.size() * component_size_;
461 }
462
469 if (buffer_components.empty()) {
470 return true;
471 }
472
473 size_t buffer_idx = write_pos / component_size_;
474 size_t local_pos = write_pos % component_size_;
475
476 return local_pos >= component_size_ || buffer_idx >= buffer_components.size();
477 }
478};
479
480}
Shared functionality of all buffers.
Definition Buffers.h:22
Auto-expanding buffer composed of multiple buffer instances.
Definition DynamicMultiBuffer.h:26
bool resize(int new_size) override
Resize the buffer.
Definition DynamicMultiBuffer.h:347
size_t getComponentCount()
Get the number of buffer components.
Definition DynamicMultiBuffer.h:386
size_t size() override
Get total capacity of the buffer.
Definition DynamicMultiBuffer.h:335
bool peek(T &result) override
Peek at the next value without removing it.
Definition DynamicMultiBuffer.h:96
bool read(T &result) override
Read a single value from the buffer.
Definition DynamicMultiBuffer.h:70
bool addBufferComponent()
Add a new buffer component.
Definition DynamicMultiBuffer.h:430
bool begin()
(Re)sets the read pos to the start
Definition DynamicMultiBuffer.h:402
bool write(T data) override
Write a value to the buffer.
Definition DynamicMultiBuffer.h:118
DynamicMultiBuffer(size_t component_size, size_t initial_components=1, size_t max_components=0)
Constructor with buffer configuration.
Definition DynamicMultiBuffer.h:35
int available() override
Get number of elements available to read.
Definition DynamicMultiBuffer.h:264
virtual ~DynamicMultiBuffer()
Destructor - releases all buffer components.
Definition DynamicMultiBuffer.h:53
int availableForWrite() override
Get space available for writing.
Definition DynamicMultiBuffer.h:276
T * address() override
Get pointer to current read position.
Definition DynamicMultiBuffer.h:321
bool isFull() override
Check if the buffer is full.
Definition DynamicMultiBuffer.h:296
int writeArray(const T data[], int len) override
Optimized bulk write operation.
Definition DynamicMultiBuffer.h:198
bool isCurrentBufferFull()
Check if the current write buffer is full.
Definition DynamicMultiBuffer.h:468
size_t totalCapacity()
Calculate total capacity of all buffer components.
Definition DynamicMultiBuffer.h:459
size_t getComponentSize()
Get the size of each component.
Definition DynamicMultiBuffer.h:395
void reset() override
Reset the buffer to empty state.
Definition DynamicMultiBuffer.h:249
bool isEmpty() override
Check if the buffer is empty.
Definition DynamicMultiBuffer.h:309
int readArray(T data[], int len) override
Optimized bulk read operation.
Definition DynamicMultiBuffer.h:148
bool begin(int pos)
(Re)sets the read pos to the indicated position
Definition DynamicMultiBuffer.h:410
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10