arduino-audio-tools
Loading...
Searching...
No Matches
Buffers.h
Go to the documentation of this file.
1#pragma once
2
3#include "AudioToolsConfig.h"
7
14namespace audio_tools {
15
22template <typename T = uint8_t>
24 public:
25 BaseBuffer() = default;
26 virtual ~BaseBuffer() = default;
27 BaseBuffer(const BaseBuffer&) = default;
28 BaseBuffer &operator=(const BaseBuffer &) = default;
29
31 virtual bool read(T &result) = 0;
32
34 virtual int readArray(T data[], int len) {
35 if (data == nullptr) {
36 LOGE("NPE");
37 return 0;
38 }
39 int lenResult = min(len, available());
40 for (int j = 0; j < lenResult; j++) {
41 read(data[j]);
42 }
43 LOGD("readArray %d -> %d", len, lenResult);
44 return lenResult;
45 }
46
48 virtual int clearArray(int len) {
49 int lenResult = min(len, available());
50 T dummy[lenResult];
51 readArray(dummy, lenResult);
52 return lenResult;
53 }
54
56 virtual int writeArray(const T data[], int len) {
57 // LOGD("%s: %d", LOG_METHOD, len);
58 // CHECK_MEMORY();
59
60 int result = 0;
61 for (int j = 0; j < len; j++) {
62 if (!write(data[j])) {
63 break;
64 }
65 result = j + 1;
66 }
67 // CHECK_MEMORY();
68 LOGD("writeArray %d -> %d", len, result);
69 return result;
70 }
71
73 virtual int writeArrayOverwrite(const T data[], int len) {
74 int to_delete = len - availableForWrite();
75 if (to_delete > 0) {
76 clearArray(to_delete);
77 }
78 return writeArray(data, len);
79 }
80
82 virtual bool peek(T &result) = 0;
83
85 virtual bool isFull() { return availableForWrite() == 0; }
86
87 bool isEmpty() { return available() == 0; }
88
90 virtual bool write(T data) = 0;
91
93 virtual void reset() = 0;
94
96 void clear() { reset(); }
97
100 virtual void flush() {}
101
103 virtual int available() = 0;
104
106 virtual int availableForWrite() = 0;
107
109 virtual T *address() = 0;
110
111 virtual size_t size() = 0;
112
114 virtual float levelPercent() {
115 // prevent div by 0.
116 if (size() == 0) return 0.0f;
117 return 100.0f * static_cast<float>(available()) /
118 static_cast<float>(size());
119 }
120
122 virtual float freePercent() {
123 return 100.0 - levelPercent();
124 }
125
127 virtual bool resize(size_t bytes) {
128 LOGE("resize not implemented for this buffer");
129 return false;
130 }
131
133 virtual bool resize(size_t size, int count) {
134 return resize(size * count);
135 }
136
138 virtual int bufferCountFilled() { return -1; }
139
141 virtual int bufferCountEmpty() { return -1; }
142
143};
144
148template <typename T = uint8_t>
150 public:
151 FrameBuffer(BaseBuffer<T> &buffer) { p_buffer = &buffer; }
153 int readFrames(T data[][2], int len) {
154 LOGD("%s: %d", LOG_METHOD, len);
155 // CHECK_MEMORY();
156 int result = min(len, p_buffer->available());
157 for (int j = 0; j < result; j++) {
158 T sample = 0;
159 p_buffer->read(sample);
160 data[j][0] = sample;
161 data[j][1] = sample;
162 }
163 // CHECK_MEMORY();
164 return result;
165 }
166
167 template <int rows, int channels>
168 int readFrames(T (&data)[rows][channels]) {
169 int lenResult = min(rows, p_buffer->available());
170 for (int j = 0; j < lenResult; j++) {
171 T sample = 0;
172 p_buffer->read(sample);
173 for (int i = 0; i < channels; i++) {
174 // data[j][i] = htons(sample);
175 data[j][i] = sample;
176 }
177 }
178 return lenResult;
179 }
180
181 protected:
183};
184
193template <typename T = uint8_t>
194class SingleBuffer : public BaseBuffer<T> {
195 public:
202 : _allocator(allocator) {
203 buffer.resize(size);
204 reset();
205 }
206
207 SingleBuffer(const SingleBuffer&) = default;
209
214
216 void onExternalBufferRefilled(void *data, int len) {
217 this->owns_buffer = false;
218 this->buffer = (uint8_t *)data;
219 this->current_read_pos = 0;
220 this->current_write_pos = len;
221 }
222
223 int writeArray(const T data[], int len) override {
224 if (size() == 0) resize(len);
225 return BaseBuffer<T>::writeArray(data, len);
226 }
227
228 bool write(T sample) override {
229 bool result = false;
230 if (current_write_pos < buffer.size()) {
231 buffer[current_write_pos++] = sample;
232 result = true;
233 }
234 return result;
235 }
236
237 bool read(T &result) override {
238 bool success = false;
240 result = buffer[current_read_pos++];
241 success = true;
242 }
243 return success;
244 }
245
246 bool peek(T &result) override {
247 bool success = false;
249 result = buffer[current_read_pos];
250 success = true;
251 }
252 return success;
253 }
254
255 int available() override {
256 int result = current_write_pos - current_read_pos;
257 return max(result, 0);
258 }
259
260 int availableForWrite() override { return buffer.size() - current_write_pos; }
261
262 bool isFull() override { return availableForWrite() <= 0; }
263
264 int peekArray(uint8_t *data, int len) {
265 int len_available = available();
266 if (len > len_available) {
267 len = len_available;
268 }
269 memcpy(data, buffer.data() + current_read_pos, len);
270 return len;
271 }
272
274 int clearArray(int len) override {
275 int len_available = available();
276 if (len > available()) {
277 reset();
278 return len_available;
279 }
280 current_read_pos += len;
281 len_available -= len;
282 memmove(buffer.data(), buffer.data() + current_read_pos, len_available * sizeof(T));
284 current_write_pos = len_available;
285
286 if (is_clear_with_zero) {
287 memset(buffer.data() + current_write_pos, 0,
288 buffer.size() - current_write_pos);
289 }
290
291 return len;
292 }
293
295 void trim() {
296 int av = available();
297 memmove(buffer.data(), buffer.data() + current_read_pos, av * sizeof(T));
300 }
301
303 T *address() override { return buffer.data(); }
304
306 T *data() { return buffer.data() + current_read_pos; }
307
308 void reset() override {
311 if (is_clear_with_zero) {
312 memset(buffer.data(), 0, buffer.size());
313 }
314 }
315
318 size_t setAvailable(size_t available_size) {
319 size_t result = min(available_size, (size_t)buffer.size());
321 current_write_pos = result;
322 return result;
323 }
324
325 size_t size() override { return buffer.size(); }
326
327 bool resize(size_t size) {
328 if (buffer.size() < size) {
329 TRACED();
330 return buffer.resize(size);
331 }
332 return true;
333 }
334
336 void setClearWithZero(bool flag) { is_clear_with_zero = flag; }
337
339 void setWritePos(int pos) { current_write_pos = pos; }
340
342 int id = 0;
344 bool active = true;
346 uint64_t timestamp = 0;
347
348 protected:
352 bool owns_buffer = true;
353 bool is_clear_with_zero = false;
355};
356
362template <typename T = uint8_t>
363class RingBuffer : public BaseBuffer<T> {
364 public:
365 RingBuffer(int size, Allocator &allocator = DefaultAllocator) : _allocator(allocator) {
366 resize(size);
367 reset();
368 }
369
370 bool read(T &result) override {
371 if (isEmpty()) {
372 return false;
373 }
374
375 result = _aucBuffer[_iTail];
377 _numElems--;
378
379 return true;
380 }
381
382 // peeks the actual entry from the buffer
383 bool peek(T &result) override {
384 if (isEmpty()) {
385 return false;
386 }
387
388 result = _aucBuffer[_iTail];
389 return true;
390 }
391
392 virtual int peekArray(T *data, int n) {
393 if (isEmpty()) return -1;
394 int result = 0;
395 int count = _numElems;
396 int tail = _iTail;
397 for (int j = 0; j < n; j++) {
398 data[j] = _aucBuffer[tail];
399 tail = nextIndex(tail);
400 count--;
401 result++;
402 if (count == 0) break;
403 }
404 return result;
405 }
406
407 // Bulk read: the inherited BaseBuffer<T>::readArray() calls read() once
408 // per element - a virtual call plus a modulo (nextIndex()) for every
409 // single byte, which is expensive on MCUs without hardware integer
410 // divide (e.g. RP2040's Cortex-M0+). Copy in at most two contiguous
411 // runs (handling ring wraparound) instead.
412 virtual int readArray(T data[], int len) override {
413 if (data == nullptr) {
414 LOGE("NPE");
415 return 0;
416 }
417 int to_read = min(len, available());
418 if (to_read <= 0) return 0;
419 int first = min(to_read, max_size - _iTail);
420 memcpy(data, _aucBuffer.data() + _iTail, first * sizeof(T));
421 int second = to_read - first;
422 if (second > 0) {
423 memcpy(data + first, _aucBuffer.data(), second * sizeof(T));
424 }
425 _iTail = (_iTail + to_read) % max_size;
426 _numElems -= to_read;
427 return to_read;
428 }
429
430 // Bulk write: see readArray() above for why this avoids the inherited
431 // per-element BaseBuffer<T>::writeArray() loop.
432 virtual int writeArray(const T data[], int len) override {
433 if (data == nullptr) {
434 LOGE("NPE");
435 return 0;
436 }
437 int to_write = min(len, availableForWrite());
438 if (to_write <= 0) return 0;
439 int first = min(to_write, max_size - _iHead);
440 memcpy(_aucBuffer.data() + _iHead, data, first * sizeof(T));
441 int second = to_write - first;
442 if (second > 0) {
443 memcpy(_aucBuffer.data(), data + first, second * sizeof(T));
444 }
445 _iHead = (_iHead + to_write) % max_size;
446 _numElems += to_write;
447 return to_write;
448 }
449
450 // checks if the buffer is full
451 virtual bool isFull() override { return available() == max_size; }
452
453 bool isEmpty() { return available() == 0; }
454
455 // write add an entry to the buffer
456 virtual bool write(T data) override {
457 bool result = false;
458 if (!isFull()) {
459 _aucBuffer[_iHead] = data;
461 _numElems++;
462 result = true;
463 }
464 return result;
465 }
466
467 // clears the buffer
468 virtual void reset() override {
469 _iHead = 0;
470 _iTail = 0;
471 _numElems = 0;
472 }
473
474 // provides the number of entries that are available to read
475 virtual int available() override { return _numElems; }
476
477 // provides the number of entries that are available to write
478 virtual int availableForWrite() override { return (max_size - _numElems); }
479
480 // returns the address of the start of the physical read buffer
481 virtual T *address() override { return _aucBuffer.data(); }
482
483 virtual bool resize(size_t len) {
484 if (max_size != len && len > 0) {
485 LOGI("resize: %d", len);
486 _aucBuffer.resize(len);
487 max_size = len;
488 }
489 return true;
490 }
491
493 virtual size_t size() override { return max_size; }
494
495 protected:
501 int max_size = 0;
502
503 int nextIndex(int index) {
504 if (max_size == 0) return 0;
505 return (uint32_t)(index + 1) % max_size; }
506};
507
516template <class File, typename T>
517class RingBufferFile : public BaseBuffer<T> {
518 public:
521 resize(size);
522 begin(file);
523 }
525 if (p_file) p_file->close();
526 }
527
529 bool begin(File &bufferFile) {
530 if (bufferFile) {
531 p_file = &bufferFile;
532 } else {
533 LOGE("file is not valid");
534 }
535 return bufferFile;
536 }
537
539 bool read(T &result) override { return readArray(&result, 1) == 1; }
540
542 int readArray(T data[], int count) override {
543 if (p_file == nullptr) return 0;
544 int read_count = min(count, available());
545
546 OffsetInfo offset = getOffset(read_pos, read_count);
547 if (!file_seek(offset.pos)) return false;
548 int n = file_read(data, offset.len);
549 if (offset.len1 > 0) {
550 file_seek(0);
551 n += file_read(data + offset.len, offset.len1);
552 read_pos = offset.len1;
553 } else {
554 read_pos += read_count;
555 }
556
557 for (int i = 0; i < count; i++) {
558 LOGI("read #%d value %d", offset.pos, (int)data[i]);
559 }
560
561 element_count -= read_count;
562 return read_count;
563 }
564
566 bool peek(T &result) override {
567 if (p_file == nullptr || isEmpty()) {
568 return false;
569 }
570
571 if (!file_seek(read_pos)) return false;
572 size_t count = file_read(&result, 1);
573 return count == 1;
574 }
575
577 int peekArray(T data[], int count) {
578 if (p_file == nullptr) return 0;
579 int read_count = min(count, available());
580
581 OffsetInfo offset = getOffset(read_pos, read_count);
582 if (!file_seek(offset.pos)) return false;
583 int n = file_read(data, offset.len);
584 if (offset.len1 > 0) {
585 file_seek(0);
586 n += file_read(data + offset.len, offset.len1);
587 }
588 assert(n == read_count);
589 return read_count;
590 }
591
593 bool write(T data) override { return writeArray(&data, 1); }
594
596 int writeArray(const T data[], int len) override {
597 if (p_file == nullptr) return 0;
598 for (int i = 0; i < len; i++) {
599 LOGI("write #%d value %d", write_pos, (int)data[i]);
600 }
601
602 int write_count = min(len, availableForWrite());
603 OffsetInfo offset = getOffset(write_pos, write_count);
604
605 if (!file_seek(offset.pos)) return false;
606 int n = file_write(data, offset.len);
607 if (offset.len1 > 0) {
608 file_seek(0);
609 n += file_write(data + offset.len, offset.len1);
610 write_pos = offset.len1;
611 } else {
612 write_pos += write_count;
613 }
614 element_count += write_count;
615 return write_count;
616 }
617
619 bool isFull() override { return available() == max_size; }
620
621 bool isEmpty() { return available() == 0; }
622
624 void reset() override {
625 write_pos = 0;
626 read_pos = 0;
627 element_count = 0;
628 if (p_file != nullptr) file_seek(0);
629 }
630
632 int available() override { return element_count; }
633
635 int availableForWrite() override { return (max_size - element_count); }
636
638 size_t size() override { return max_size; }
639
641 bool resize(size_t size) {
642 max_size = size;
643 return true;
644 }
645
646 // not supported
647 T *address() override { return nullptr; }
648
649 protected:
650 File *p_file = nullptr;
651 int write_pos = 0;
652 int read_pos = 0;
654 int max_size = 0;
655
656 struct OffsetInfo {
657 int pos = 0; // start pos
658 int len = 0; // length of first part
659 int len1 = 0; // length of second part on overflow
660 };
661
664 OffsetInfo getOffset(int pos, int len) {
665 OffsetInfo result;
666 result.pos = pos;
667 int overflow = (pos + len) - max_size;
668 if (overflow <= 0) {
669 // we can write the complete data
670 result.len = len;
671 result.len1 = 0;
672 } else {
673 // we need to split the data
674 result.len = len - overflow;
675 result.len1 = overflow;
676 }
677 return result;
678 }
679
681 bool file_seek(int pos) {
682 int file_pos = pos * sizeof(T);
683 if (p_file->position() != file_pos) {
684 LOGD("file_seek: %d", pos);
685 if (!p_file->seek(file_pos)) {
686 LOGE("seek %d", file_pos);
687 return false;
688 }
689 }
690 return true;
691 }
692
694 int file_write(const T *data, int count) {
695 LOGD("file_write: %d", count);
696 if (p_file == nullptr) return 0;
697 int to_write_bytes = sizeof(T) * count;
698 int bytes_written = p_file->write((const uint8_t *)data, to_write_bytes);
699 p_file->flush();
700 int elements_written = bytes_written / sizeof(T);
701 if (bytes_written != to_write_bytes) {
702 LOGE("write: %d -> %d bytes", to_write_bytes, bytes_written);
703 }
704 return elements_written;
705 }
706
708 int file_read(T *result, int count) {
709 LOGD("file_read: %d", count);
710 int read_bytes = count * sizeof(T);
711 int result_bytes = p_file->readBytes((char *)result, read_bytes);
712 int result_count = result_bytes / sizeof(T);
713 if (result_count != count) {
714 LOGE("readBytes: %d -> %d", read_bytes, result_bytes);
715 }
716 return result_count;
717 }
718};
719
732template <typename T = uint8_t>
733class NBuffer : public BaseBuffer<T> {
734 public:
735 NBuffer(int size, int count) { resize(size, count); }
736
737 virtual ~NBuffer() { freeMemory(); }
738
740 bool read(T &result) override {
741 if (available() == 0) return false;
742 return actual_read_buffer->read(result);
743 }
744
748 int readArray(T data[], int len) override {
749 int count = 0;
750 while (count < len) {
751 if (available() == 0) break;
752 actual_read_buffer->read(data[count]);
753 count++;
754 }
755 return count;
756 }
757
759 bool peek(T &result) override {
760 if (available() == 0) return false;
761 return actual_read_buffer->peek(result);
762 }
763
765 bool isFull() { return availableForWrite() == 0; }
766
768 bool write(T data) {
769 bool result = false;
770 if (actual_write_buffer == nullptr) {
772 }
773 if (actual_write_buffer != nullptr) {
774 result = actual_write_buffer->write(data);
775 // if buffer is full move to next available
779 }
780 }
781
782 if (start_time == 0l) {
783 start_time = millis();
784 }
785 if (result) sample_count++;
786
787 return result;
788 }
789
791 int available() {
792 if (actual_read_buffer == nullptr) {
794 }
795 if (actual_read_buffer == nullptr) {
796 return 0;
797 }
798 int result = actual_read_buffer->available();
799 if (result == 0) {
800 // make current read buffer available again
801 resetCurrent();
802 result =
803 (actual_read_buffer == nullptr) ? 0 : actual_read_buffer->available();
804 }
805 return result;
806 }
807
810 if (actual_write_buffer == nullptr) {
812 }
813 // if we used up all buffers - there is nothing available any more
814 if (actual_write_buffer == nullptr) {
815 return 0;
816 }
817 // check on actual buffer
819 // if buffer is full we move it to filled buffers ang get the next
820 // available
823 }
825 }
826
830 void flush() {
831 if (actual_write_buffer != nullptr && actual_write_buffer->available() > 0) {
833 actual_write_buffer = nullptr;
834 }
835 }
836
838 void reset() {
839 TRACED();
840 while (actual_read_buffer != nullptr) {
843 // get next read buffer
845 }
846 // discard any partially-filled write buffer as well
847 if (actual_write_buffer != nullptr) {
850 actual_write_buffer = nullptr;
851 }
852 }
853
855 unsigned long sampleRate() {
856 unsigned long run_time = (millis() - start_time);
857 return run_time == 0 ? 0 : sample_count * 1000 / run_time;
858 }
859
861 T *address() {
862 return actual_read_buffer == nullptr ? nullptr
864 }
865
867 virtual int bufferCountFilled() { return filled_buffers.size(); }
868
870 virtual int bufferCountEmpty() { return available_buffers.size(); }
871
873 virtual bool resize(size_t bytes) {
874 if (buffer_size == 0) {
875 LOGE("resize: buffer_size is 0");
876 return false;
877 }
878 int count = bytes / buffer_size;
879 if (bytes % buffer_size > 0) count++;
880 return resize(buffer_size, count);
881 }
882
888 virtual bool resize(size_t size, int count) {
889 if (buffer_size == size && buffer_count == count) return true;
890
891 if (buffer_count == 1) {
892 LOGE("buffer count=1: not supported, use SingleBuffer or RingBuffer instead");
893 return false;
894 }
895
896 if (buffer_size != size) {
897 if (buffer_count > 0) {
898 LOGW("resize() changes buffer_size: discarding buffered data");
899 }
900 freeMemory();
901 filled_buffers.resize(count);
902 available_buffers.resize(count);
903 buffer_count = count;
905 for (int j = 0; j < count; j++) {
906 BaseBuffer<T> *buffer = new SingleBuffer<T>(size);
907 LOGD("new buffer %p", buffer);
908 available_buffers.enqueue(buffer);
909 }
910 return true;
911 }
912
913 // same buffer_size: keep existing blocks/data, just grow or shrink
914 // the pool. QueueFromVector::resize() clears its contents, so we
915 // dequeue everything first and re-enqueue it after resizing.
916 Vector<BaseBuffer<T> *> avail;
917 Vector<BaseBuffer<T> *> filled;
918 for (BaseBuffer<T> *b = getNextAvailableBuffer(); b != nullptr;
920 avail.push_back(b);
921 for (BaseBuffer<T> *b = getNextFilledBuffer(); b != nullptr;
923 filled.push_back(b);
924
925 if ((size_t)count > buffer_count) {
926 // grow: add new empty buffers to the available pool
927 for (size_t j = 0; j < (size_t)count - buffer_count; j++) {
928 avail.push_back(new SingleBuffer<T>(size));
929 }
930 } else {
931 // shrink: delete surplus buffers from the available (empty) pool
932 // first; if that's not enough, keep the buffers that still hold data
933 size_t to_remove = buffer_count - (size_t)count;
934 size_t removed = 0;
935 while (removed < to_remove && !avail.empty()) {
936 delete avail[avail.size() - 1];
937 avail.erase(avail.size() - 1);
938 removed++;
939 }
940 if (removed < to_remove) {
941 LOGW("resize() could not shrink to %d buffers: %d still hold data",
942 count, (int)(to_remove - removed));
943 count = (int)(buffer_count - removed);
944 }
945 }
946
947 filled_buffers.resize(count);
948 available_buffers.resize(count);
949 for (int j = 0; j < avail.size(); j++) available_buffers.enqueue(avail[j]);
950 for (int j = 0; j < filled.size(); j++) filled_buffers.enqueue(filled[j]);
951 buffer_count = count;
952 return true;
953 }
954
956 size_t size() { return buffer_size * buffer_count; }
957
958 protected:
959 int buffer_size = 1024;
960 size_t buffer_count = 0;
965 unsigned long start_time = 0;
966 unsigned long sample_count = 0;
967
969 NBuffer() = default;
970
971 void freeMemory() {
973 LOGD("deleting %p", actual_write_buffer);
974 delete actual_write_buffer;
975 actual_write_buffer = nullptr;
976 }
977 if (actual_read_buffer) {
978 LOGD("deleting %p", actual_read_buffer);
979 delete actual_read_buffer;
980 actual_read_buffer = nullptr;
981 }
982
984 while (ptr != nullptr) {
985 LOGD("deleting %p", ptr);
986 delete ptr;
988 }
989
990 ptr = getNextFilledBuffer();
991 while (ptr != nullptr) {
992 LOGD("deleting %p", ptr);
993 delete ptr;
994 ptr = getNextFilledBuffer();
995 }
996 }
997
999 if (actual_read_buffer != nullptr) {
1002 }
1003 // get next read buffer
1005 }
1006
1008 if (available_buffers.empty()) return nullptr;
1009 BaseBuffer<T> *result = nullptr;
1010 available_buffers.dequeue(result);
1011 return result;
1012 }
1013
1014 virtual bool addAvailableBuffer(BaseBuffer<T> *buffer) {
1015 return available_buffers.enqueue(buffer);
1016 }
1017
1019 if (filled_buffers.empty()) return nullptr;
1020 BaseBuffer<T> *result = nullptr;
1021 filled_buffers.dequeue(result);
1022 return result;
1023 }
1024
1025 virtual bool addFilledBuffer(BaseBuffer<T> *buffer) {
1026 return filled_buffers.enqueue(buffer);
1027 }
1028};
1029
1036template <typename T = uint8_t>
1037class NBufferExt : public NBuffer<T> {
1038 public:
1039 NBufferExt(int size, int count) { resize(size, count); }
1040
1050
1054 // make current read buffer available again
1055 resetCurrent();
1057 }
1058
1061 for (auto &buffer : this->filled_buffers.toVector()) {
1062 SingleBuffer<T> *sbuffer = (SingleBuffer<T> *)&buffer;
1063 if (sbuffer->id == id) {
1064 return sbuffer;
1065 }
1066 }
1067 return nullptr;
1068 }
1069
1070 using NBuffer<T>::resize;
1071
1072 protected:
1073 using NBuffer<T>::resetCurrent;
1074 using NBuffer<T>::addFilledBuffer;
1078 using NBuffer<T>::buffer_size;
1079};
1080
1090template <class File, typename T>
1091class NBufferFile : public BaseBuffer<T> {
1092 public:
1094 NBufferFile(int fileSize) { number_of_objects_per_file = fileSize; }
1097
1099 const char *nextFileName() {
1100 next_file_name.set("buffer-");
1101 char number[40];
1102 snprintf(number, 40, "%d", file_count);
1103 next_file_name.add(number);
1104 next_file_name.add(".tmp");
1105 return next_file_name.c_str();
1106 }
1107
1110 bool addFile(File &file) {
1111 if (!file) return false;
1112 empty_files.enqueue(file);
1113 file_count++;
1114 return true;
1115 }
1116
1117 bool read(T &result) override { return readArray(&result, 1) == 1; }
1118
1119 int readArray(T data[], int len) override {
1120 // make sure we have a read file
1121 if (!read_file) {
1122 if (!filled_files.dequeue(read_file)) {
1123 // no more data
1124 return 0;
1125 }
1126 read_file.seek(0);
1127 }
1128 // read the data
1129 int result = read_file.readBytes((char *)data, len * sizeof(T)) / sizeof(T);
1130
1131 // if we have consumed all content
1132 if (result < len) {
1133 read_file.seek(0);
1134 empty_files.enqueue(read_file);
1135 read_file = empty;
1136 }
1137 return result;
1138 }
1139
1140 bool peek(T &data) override {
1141 size_t pos = read_file.position();
1142 bool result = read(data);
1143 read_file.seek(pos);
1144 return result;
1145 }
1146
1147 bool write(T sample) override { return writeArray(&sample, 1) == 1; }
1148
1149 int writeArray(const T data[], int len) override {
1151 // moved to filled files
1152 if (write_file) {
1153 write_file.seek(0);
1154 filled_files.enqueue(write_file);
1155 }
1156 // get next empty file
1157 if (!empty_files.dequeue(write_file)) return false;
1158 }
1159 int result = write_file.write((uint8_t *)data, len * sizeof(T));
1160 return result / sizeof(T);
1161 }
1162
1163 int available() override {
1165 (read_file.available() / sizeof(T));
1166 }
1167
1168 // provides the number of entries that are available to write
1169 int availableForWrite() override {
1170 int open_current =
1172 return empty_files.size() * number_of_objects_per_file +
1173 write_file.available() + open_current;
1174 }
1175
1176 size_t size() override { return number_of_objects_per_file * file_count; }
1177
1179 void end() {
1182 File file;
1183 while (empty_files.dequeue(file)) cleanupFile(file);
1184 while (filled_files.dequeue(file)) cleanupFile(file);
1185 }
1186
1188 void setFileDeleteCallback(void (*cb)(const char *filename)) {
1190 }
1191
1192 void reset() {
1193 if (read_file) {
1194 read_file.seek(0);
1195 empty_files.enqueue(read_file);
1196 read_file = empty;
1197 }
1198 if (write_file) {
1199 write_file.seek(0);
1200 empty_files.enqueue(write_file);
1201 write_file = empty;
1202 }
1203 File file;
1204 while (filled_files.dequeue(file)) {
1205 file.seek(0);
1206 empty_files.enqueue(file);
1207 }
1208 }
1210 T *address() { return nullptr; }
1211
1212 protected:
1218 int number_of_objects_per_file = 0; // number of objects per file
1219 int file_count = 0; // number of files
1220 const uint16_t max_file_name = 256;
1222 void (*file_delete_callback)(const char *filename);
1223
1224 void cleanupFile(File &file) {
1225 if (!file) return;
1226 // after close the file name is gone
1227 int len = strlen(file.name());
1228 char file_name[len + 1];
1229 strncpy(file_name, file.name(), len);
1230 file.close();
1231 file_delete_callback(file_name);
1232 }
1233};
1234
1244template <typename T = uint8_t>
1246 public:
1247 BufferedArray(Stream &input, int len) {
1248 LOGI("BufferedArray(%d)", len);
1249 array.resize(len);
1250 p_stream = &input;
1251 }
1252 // access values, the offset and length are specified in samples of type <T>
1253 int16_t *getValues(size_t offset, size_t length) {
1254 LOGD("getValues(%d,%d) - max %d", offset, length, array.size());
1255 if (offset == 0) {
1256 // we restart at the beginning
1257 last_end = 0;
1258 actual_end = length;
1259 } else {
1260 // if first position is at end we do not want to read the full buffer
1261 last_end = actual_end >= 0 ? actual_end : offset;
1262 // increase actual end if bigger then old
1263 actual_end = offset + length > actual_end ? offset + length : actual_end;
1264 }
1265 int size = actual_end - last_end;
1266 if (size > 0) {
1267 LOGD("readBytes(%d,%d)", last_end, size);
1268 assert(last_end + size <= array.size());
1269 p_stream->readBytes((uint8_t *)(&array[last_end]), size * 2);
1270 }
1271 assert(offset < actual_end);
1272 return &array[offset];
1273 }
1274
1275 protected:
1276 int actual_end = -1;
1277 int last_end = 0;
1279 Stream *p_stream = nullptr;
1280};
1281
1282} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define LOG_METHOD
Definition AudioToolsConfig.h:69
#define assert(T)
Definition avr.h:10
Definition Arduino.h:136
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
Memory allocateator which uses malloc.
Definition Allocator.h:25
Shared functionality of all buffers.
Definition Buffers.h:23
BaseBuffer(const BaseBuffer &)=default
virtual float freePercent()
Returns the free space of the buffer in %.
Definition Buffers.h:122
virtual bool read(T &result)=0
reads a single value
virtual ~BaseBuffer()=default
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:34
virtual void reset()=0
clears the buffer
virtual int bufferCountEmpty()
Provides the number of entries that are available to write: -1 does not apply.
Definition Buffers.h:141
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:56
virtual bool resize(size_t bytes)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:127
virtual T * address()=0
returns the address of the start of the physical read buffer
virtual int writeArrayOverwrite(const T data[], int len)
Fills the buffer data and overwrites the oldest data if the buffer is full.
Definition Buffers.h:73
virtual size_t size()=0
virtual int clearArray(int len)
Removes the next len entries.
Definition Buffers.h:48
BaseBuffer & operator=(const BaseBuffer &)=default
virtual int availableForWrite()=0
provides the number of entries that are available to write
virtual bool resize(size_t size, int count)
Resize the buffer by indicating the size and count (allocated bytes = size * count)
Definition Buffers.h:133
virtual int bufferCountFilled()
Provides the number of entries that are available to read: -1 does not apply.
Definition Buffers.h:138
virtual bool isFull()
checks if the buffer is full
Definition Buffers.h:85
virtual bool peek(T &result)=0
peeks the actual entry from the buffer
virtual float levelPercent()
Returns the level of the buffer in %.
Definition Buffers.h:114
void clear()
same as reset
Definition Buffers.h:96
virtual void flush()
Definition Buffers.h:100
virtual bool write(T data)=0
write add an entry to the buffer
virtual int available()=0
provides the number of entries that are available to read
bool isEmpty()
Definition Buffers.h:87
Class which is usfull ot provide incremental data access e.g. for EdgeImpulse which request data with...
Definition Buffers.h:1245
int16_t * getValues(size_t offset, size_t length)
Definition Buffers.h:1253
BufferedArray(Stream &input, int len)
Definition Buffers.h:1247
Stream * p_stream
Definition Buffers.h:1279
int last_end
Definition Buffers.h:1277
Vector< T > array
Definition Buffers.h:1278
int actual_end
Definition Buffers.h:1276
A FrameBuffer reads multiple values for array of 2 dimensional frames.
Definition Buffers.h:149
BaseBuffer< T > * p_buffer
Definition Buffers.h:182
FrameBuffer(BaseBuffer< T > &buffer)
Definition Buffers.h:151
int readFrames(T(&data)[rows][channels])
Definition Buffers.h:168
int readFrames(T data[][2], int len)
reads multiple values for array of 2 dimensional frames
Definition Buffers.h:153
A NBufferExt is a subclass of NBuffer which allows to use a direct access API to the BaseBuffer.
Definition Buffers.h:1037
SingleBuffer< T > * getBuffer(int id)
Provides the buffer with the indicated id.
Definition Buffers.h:1060
NBufferExt(int size, int count)
Definition Buffers.h:1039
SingleBuffer< T > * readEnd()
Definition Buffers.h:1053
SingleBuffer< T > * writeEnd()
Definition Buffers.h:1043
A File backed buffer which uses the provided files for buffering with the indicated max size....
Definition Buffers.h:1091
Str next_file_name
Definition Buffers.h:1221
const char * nextFileName()
Determines the next unique file name (after calling addFile)
Definition Buffers.h:1099
size_t size() override
Definition Buffers.h:1176
void setFileDeleteCallback(void(*cb)(const char *filename))
Define the file delete operation.
Definition Buffers.h:1188
bool peek(T &data) override
peeks the actual entry from the buffer
Definition Buffers.h:1140
void(* file_delete_callback)(const char *filename)
Definition Buffers.h:1222
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:1147
~NBufferFile()
RAII close the files.
Definition Buffers.h:1096
void cleanupFile(File &file)
Definition Buffers.h:1224
bool read(T &result) override
reads a single value
Definition Buffers.h:1117
int available() override
provides the number of entries that are available to read
Definition Buffers.h:1163
Queue< File > empty_files
Definition Buffers.h:1213
File read_file
Definition Buffers.h:1215
bool addFile(File &file)
Definition Buffers.h:1110
File write_file
Definition Buffers.h:1216
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:1169
const uint16_t max_file_name
Definition Buffers.h:1220
NBufferFile(int fileSize)
Provide the file size in objects!
Definition Buffers.h:1094
int number_of_objects_per_file
Definition Buffers.h:1218
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:1149
void end()
clean up files
Definition Buffers.h:1179
Queue< File > filled_files
Definition Buffers.h:1214
int file_count
Definition Buffers.h:1219
File empty
Definition Buffers.h:1217
void reset()
clears the buffer
Definition Buffers.h:1192
T * address()
not supported
Definition Buffers.h:1210
int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:1119
A N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:733
unsigned long start_time
Definition Buffers.h:965
size_t size()
Provides the total capacity (=buffer size * buffer count)
Definition Buffers.h:956
QueueFromVector< BaseBuffer< T > * > available_buffers
Definition Buffers.h:963
void resetCurrent()
Definition Buffers.h:998
virtual ~NBuffer()
Definition Buffers.h:737
virtual int bufferCountEmpty()
Provides the number of entries that are available to write.
Definition Buffers.h:870
NBuffer()=default
empty constructor only allowed by subclass
virtual bool resize(size_t bytes)
Resize the buffer to the next multiple of buffer size.
Definition Buffers.h:873
bool isFull()
checks if the buffer is full
Definition Buffers.h:765
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:759
size_t buffer_count
Definition Buffers.h:960
int available()
determines the available entries for the current read buffer
Definition Buffers.h:791
bool read(T &result) override
reads an entry from the buffer
Definition Buffers.h:740
bool write(T data)
write add an entry to the buffer
Definition Buffers.h:768
void freeMemory()
Definition Buffers.h:971
int availableForWrite()
determines the available entries for the write buffer
Definition Buffers.h:809
virtual bool addAvailableBuffer(BaseBuffer< T > *buffer)
Definition Buffers.h:1014
NBuffer(int size, int count)
Definition Buffers.h:735
virtual bool resize(size_t size, int count)
Definition Buffers.h:888
virtual int bufferCountFilled()
Provides the number of entries that are available to read.
Definition Buffers.h:867
virtual bool addFilledBuffer(BaseBuffer< T > *buffer)
Definition Buffers.h:1025
void reset()
resets all buffers
Definition Buffers.h:838
unsigned long sampleRate()
provides the actual sample rate
Definition Buffers.h:855
BaseBuffer< T > * actual_read_buffer
Definition Buffers.h:961
void flush()
Definition Buffers.h:830
T * address()
returns the address of the start of the actual physical read buffer
Definition Buffers.h:861
BaseBuffer< T > * actual_write_buffer
Definition Buffers.h:962
QueueFromVector< BaseBuffer< T > * > filled_buffers
Definition Buffers.h:964
virtual BaseBuffer< T > * getNextAvailableBuffer()
Definition Buffers.h:1007
unsigned long sample_count
Definition Buffers.h:966
int readArray(T data[], int len) override
Definition Buffers.h:748
int buffer_size
Definition Buffers.h:959
virtual BaseBuffer< T > * getNextFilledBuffer()
Definition Buffers.h:1018
FIFO Queue which is based on a Vector.
Definition QueueFromVector.h:15
FIFO Queue which is based on a List.
Definition Queue.h:14
An File backed Ring Buffer that we can use to receive streaming audio. We expect an open file as para...
Definition Buffers.h:517
int readArray(T data[], int count) override
reads multiple values
Definition Buffers.h:542
size_t size() override
Provides the capacity.
Definition Buffers.h:638
int peekArray(T data[], int count)
gets multiple values w/o removing them
Definition Buffers.h:577
int file_write(const T *data, int count)
Reed the indicated number of objects.
Definition Buffers.h:694
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:566
RingBufferFile(int size, File &file)
Definition Buffers.h:520
bool read(T &result) override
Reads a single value from the buffer.
Definition Buffers.h:539
bool write(T data) override
write add a single entry to the buffer
Definition Buffers.h:593
int available() override
provides the number of entries that are available to read
Definition Buffers.h:632
~RingBufferFile()
Definition Buffers.h:524
File * p_file
Definition Buffers.h:650
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:635
int write_pos
Definition Buffers.h:651
T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:647
bool isFull() override
checks if the buffer is full
Definition Buffers.h:619
int read_pos
Definition Buffers.h:652
bool begin(File &bufferFile)
Assigns the p_file to be used.
Definition Buffers.h:529
int max_size
Definition Buffers.h:654
bool file_seek(int pos)
Seeks to the given object position.
Definition Buffers.h:681
int writeArray(const T data[], int len) override
Fills the data from the buffer.
Definition Buffers.h:596
RingBufferFile(int size)
Definition Buffers.h:519
int file_read(T *result, int count)
Writes the indicated number of objects.
Definition Buffers.h:708
OffsetInfo getOffset(int pos, int len)
Definition Buffers.h:664
bool resize(size_t size)
Defines the capacity.
Definition Buffers.h:641
void reset() override
clears the buffer
Definition Buffers.h:624
int element_count
Definition Buffers.h:653
bool isEmpty()
Definition Buffers.h:621
Implements a typed Ringbuffer.
Definition Buffers.h:363
virtual int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:412
virtual int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:432
RingBuffer(int size, Allocator &allocator=DefaultAllocator)
Definition Buffers.h:365
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:383
virtual int peekArray(T *data, int n)
Definition Buffers.h:392
bool read(T &result) override
reads a single value
Definition Buffers.h:370
virtual T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:481
int nextIndex(int index)
Definition Buffers.h:503
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:478
virtual bool write(T data) override
write add an entry to the buffer
Definition Buffers.h:456
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:493
int max_size
Definition Buffers.h:501
virtual void reset() override
clears the buffer
Definition Buffers.h:468
Allocator & _allocator
Definition Buffers.h:496
int _iHead
Definition Buffers.h:498
virtual bool isFull() override
checks if the buffer is full
Definition Buffers.h:451
int _numElems
Definition Buffers.h:500
Vector< T > _aucBuffer
Definition Buffers.h:497
virtual bool resize(size_t len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:483
bool isEmpty()
Definition Buffers.h:453
int _iTail
Definition Buffers.h:499
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:475
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:194
bool active
Optional active/inactive status.
Definition Buffers.h:344
size_t size() override
Definition Buffers.h:325
SingleBuffer & operator=(const SingleBuffer &)=default
size_t setAvailable(size_t available_size)
Definition Buffers.h:318
void trim()
Moves the unprocessed data to the beginning of the buffer.
Definition Buffers.h:295
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:228
Allocator _allocator
Definition Buffers.h:349
void setClearWithZero(bool flag)
Sets the buffer to 0 on clear.
Definition Buffers.h:336
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:246
bool owns_buffer
Definition Buffers.h:352
uint64_t timestamp
Optional timestamp.
Definition Buffers.h:346
void setWritePos(int pos)
Updates the actual available data size.
Definition Buffers.h:339
bool read(T &result) override
reads a single value
Definition Buffers.h:237
int available() override
provides the number of entries that are available to read
Definition Buffers.h:255
int id
Optional ID.
Definition Buffers.h:342
bool is_clear_with_zero
Definition Buffers.h:353
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:260
T * address() override
Provides address to beginning of the buffer.
Definition Buffers.h:303
bool isFull() override
checks if the buffer is full
Definition Buffers.h:262
int current_read_pos
Definition Buffers.h:350
void onExternalBufferRefilled(void *data, int len)
notifies that the external buffer has been refilled
Definition Buffers.h:216
int current_write_pos
Definition Buffers.h:351
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:223
int peekArray(uint8_t *data, int len)
Definition Buffers.h:264
Vector< T > buffer
Definition Buffers.h:354
SingleBuffer(const SingleBuffer &)=default
SingleBuffer(int size, Allocator &allocator=DefaultAllocator)
Construct a new Single Buffer object.
Definition Buffers.h:201
SingleBuffer()
Construct a new Single Buffer w/o allocating any memory.
Definition Buffers.h:213
T * data()
Provides address of actual data.
Definition Buffers.h:306
bool resize(size_t size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:327
void reset() override
clears the buffer
Definition Buffers.h:308
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:274
Str which keeps the data on the heap. We grow the allocated memory only if the copy source is not fit...
Definition Str.h:24
virtual void set(const char *alt)
assigs a value
Definition StrView.h:48
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:456
virtual void add(int value)
adds a int value
Definition StrView.h:133
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
void erase(iterator it)
Definition Vector.h:294
bool empty()
Definition Vector.h:180
void push_back(T &&value)
Definition Vector.h:182
int size()
Definition Vector.h:178
Arduino File API for Zephyr.
Definition ZephyrFile.h:23
void flush() override
Definition ZephyrFile.h:152
size_t size() const
Definition ZephyrFile.h:198
size_t write(uint8_t value) override
Definition ZephyrFile.h:129
void close()
Definition ZephyrFile.h:67
int available() override
Definition ZephyrFile.h:89
size_t position() const
Definition ZephyrFile.h:188
size_t readBytes(char *buffer, size_t len)
Definition ZephyrFile.h:119
const char * name() const
Definition ZephyrFile.h:200
bool seek(size_t pos)
Definition ZephyrFile.h:180
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
static TAllocatorExt DefaultAllocator
Definition Allocator.h:208
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:260
int pos
Definition Buffers.h:657
int len1
Definition Buffers.h:659
int len
Definition Buffers.h:658