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 int bufferCountFilled() { return -1; }
134
136 virtual int bufferCountEmpty() { return -1; }
137
138};
139
143template <typename T = uint8_t>
145 public:
146 FrameBuffer(BaseBuffer<T> &buffer) { p_buffer = &buffer; }
148 int readFrames(T data[][2], int len) {
149 LOGD("%s: %d", LOG_METHOD, len);
150 // CHECK_MEMORY();
151 int result = min(len, p_buffer->available());
152 for (int j = 0; j < result; j++) {
153 T sample = 0;
154 p_buffer->read(sample);
155 data[j][0] = sample;
156 data[j][1] = sample;
157 }
158 // CHECK_MEMORY();
159 return result;
160 }
161
162 template <int rows, int channels>
163 int readFrames(T (&data)[rows][channels]) {
164 int lenResult = min(rows, p_buffer->available());
165 for (int j = 0; j < lenResult; j++) {
166 T sample = 0;
167 p_buffer->read(sample);
168 for (int i = 0; i < channels; i++) {
169 // data[j][i] = htons(sample);
170 data[j][i] = sample;
171 }
172 }
173 return lenResult;
174 }
175
176 protected:
178};
179
188template <typename T = uint8_t>
189class SingleBuffer : public BaseBuffer<T> {
190 public:
197 : _allocator(allocator) {
198 buffer.resize(size);
199 reset();
200 }
201
202 SingleBuffer(const SingleBuffer&) = default;
204
209
211 void onExternalBufferRefilled(void *data, int len) {
212 this->owns_buffer = false;
213 this->buffer = (uint8_t *)data;
214 this->current_read_pos = 0;
215 this->current_write_pos = len;
216 }
217
218 int writeArray(const T data[], int len) override {
219 if (size() == 0) resize(len);
220 return BaseBuffer<T>::writeArray(data, len);
221 }
222
223 bool write(T sample) override {
224 bool result = false;
225 if (current_write_pos < buffer.size()) {
226 buffer[current_write_pos++] = sample;
227 result = true;
228 }
229 return result;
230 }
231
232 bool read(T &result) override {
233 bool success = false;
235 result = buffer[current_read_pos++];
236 success = true;
237 }
238 return success;
239 }
240
241 bool peek(T &result) override {
242 bool success = false;
244 result = buffer[current_read_pos];
245 success = true;
246 }
247 return success;
248 }
249
250 int available() override {
251 int result = current_write_pos - current_read_pos;
252 return max(result, 0);
253 }
254
255 int availableForWrite() override { return buffer.size() - current_write_pos; }
256
257 bool isFull() override { return availableForWrite() <= 0; }
258
259 int peekArray(uint8_t *data, int len) {
260 int len_available = available();
261 if (len > len_available) {
262 len = len_available;
263 }
264 memcpy(data, buffer.data() + current_read_pos, len);
265 return len;
266 }
267
269 int clearArray(int len) override {
270 int len_available = available();
271 if (len > available()) {
272 reset();
273 return len_available;
274 }
275 current_read_pos += len;
276 len_available -= len;
277 memmove(buffer.data(), buffer.data() + current_read_pos, len_available * sizeof(T));
279 current_write_pos = len_available;
280
281 if (is_clear_with_zero) {
282 memset(buffer.data() + current_write_pos, 0,
283 buffer.size() - current_write_pos);
284 }
285
286 return len;
287 }
288
290 void trim() {
291 int av = available();
292 memmove(buffer.data(), buffer.data() + current_read_pos, av * sizeof(T));
295 }
296
298 T *address() override { return buffer.data(); }
299
301 T *data() { return buffer.data() + current_read_pos; }
302
303 void reset() override {
306 if (is_clear_with_zero) {
307 memset(buffer.data(), 0, buffer.size());
308 }
309 }
310
313 size_t setAvailable(size_t available_size) {
314 size_t result = min(available_size, (size_t)buffer.size());
316 current_write_pos = result;
317 return result;
318 }
319
320 size_t size() override { return buffer.size(); }
321
322 bool resize(size_t size) {
323 if (buffer.size() < size) {
324 TRACED();
325 return buffer.resize(size);
326 }
327 return true;
328 }
329
331 void setClearWithZero(bool flag) { is_clear_with_zero = flag; }
332
334 void setWritePos(int pos) { current_write_pos = pos; }
335
337 int id = 0;
339 bool active = true;
341 uint64_t timestamp = 0;
342
343 protected:
347 bool owns_buffer = true;
348 bool is_clear_with_zero = false;
350};
351
357template <typename T = uint8_t>
358class RingBuffer : public BaseBuffer<T> {
359 public:
360 RingBuffer(int size, Allocator &allocator = DefaultAllocator) : _allocator(allocator) {
361 resize(size);
362 reset();
363 }
364
365 bool read(T &result) override {
366 if (isEmpty()) {
367 return false;
368 }
369
370 result = _aucBuffer[_iTail];
372 _numElems--;
373
374 return true;
375 }
376
377 // peeks the actual entry from the buffer
378 bool peek(T &result) override {
379 if (isEmpty()) {
380 return false;
381 }
382
383 result = _aucBuffer[_iTail];
384 return true;
385 }
386
387 virtual int peekArray(T *data, int n) {
388 if (isEmpty()) return -1;
389 int result = 0;
390 int count = _numElems;
391 int tail = _iTail;
392 for (int j = 0; j < n; j++) {
393 data[j] = _aucBuffer[tail];
394 tail = nextIndex(tail);
395 count--;
396 result++;
397 if (count == 0) break;
398 }
399 return result;
400 }
401
402 // Bulk read: the inherited BaseBuffer<T>::readArray() calls read() once
403 // per element - a virtual call plus a modulo (nextIndex()) for every
404 // single byte, which is expensive on MCUs without hardware integer
405 // divide (e.g. RP2040's Cortex-M0+). Copy in at most two contiguous
406 // runs (handling ring wraparound) instead.
407 virtual int readArray(T data[], int len) override {
408 if (data == nullptr) {
409 LOGE("NPE");
410 return 0;
411 }
412 int to_read = min(len, available());
413 if (to_read <= 0) return 0;
414 int first = min(to_read, max_size - _iTail);
415 memcpy(data, _aucBuffer.data() + _iTail, first * sizeof(T));
416 int second = to_read - first;
417 if (second > 0) {
418 memcpy(data + first, _aucBuffer.data(), second * sizeof(T));
419 }
420 _iTail = (_iTail + to_read) % max_size;
421 _numElems -= to_read;
422 return to_read;
423 }
424
425 // Bulk write: see readArray() above for why this avoids the inherited
426 // per-element BaseBuffer<T>::writeArray() loop.
427 virtual int writeArray(const T data[], int len) override {
428 if (data == nullptr) {
429 LOGE("NPE");
430 return 0;
431 }
432 int to_write = min(len, availableForWrite());
433 if (to_write <= 0) return 0;
434 int first = min(to_write, max_size - _iHead);
435 memcpy(_aucBuffer.data() + _iHead, data, first * sizeof(T));
436 int second = to_write - first;
437 if (second > 0) {
438 memcpy(_aucBuffer.data(), data + first, second * sizeof(T));
439 }
440 _iHead = (_iHead + to_write) % max_size;
441 _numElems += to_write;
442 return to_write;
443 }
444
445 // checks if the buffer is full
446 virtual bool isFull() override { return available() == max_size; }
447
448 bool isEmpty() { return available() == 0; }
449
450 // write add an entry to the buffer
451 virtual bool write(T data) override {
452 bool result = false;
453 if (!isFull()) {
454 _aucBuffer[_iHead] = data;
456 _numElems++;
457 result = true;
458 }
459 return result;
460 }
461
462 // clears the buffer
463 virtual void reset() override {
464 _iHead = 0;
465 _iTail = 0;
466 _numElems = 0;
467 }
468
469 // provides the number of entries that are available to read
470 virtual int available() override { return _numElems; }
471
472 // provides the number of entries that are available to write
473 virtual int availableForWrite() override { return (max_size - _numElems); }
474
475 // returns the address of the start of the physical read buffer
476 virtual T *address() override { return _aucBuffer.data(); }
477
478 virtual bool resize(size_t len) {
479 if (max_size != len && len > 0) {
480 LOGI("resize: %d", len);
481 _aucBuffer.resize(len);
482 max_size = len;
483 }
484 return true;
485 }
486
488 virtual size_t size() override { return max_size; }
489
490 protected:
496 int max_size = 0;
497
498 int nextIndex(int index) {
499 if (max_size == 0) return 0;
500 return (uint32_t)(index + 1) % max_size; }
501};
502
511template <class File, typename T>
512class RingBufferFile : public BaseBuffer<T> {
513 public:
516 resize(size);
517 begin(file);
518 }
520 if (p_file) p_file->close();
521 }
522
524 bool begin(File &bufferFile) {
525 if (bufferFile) {
526 p_file = &bufferFile;
527 } else {
528 LOGE("file is not valid");
529 }
530 return bufferFile;
531 }
532
534 bool read(T &result) override { return readArray(&result, 1) == 1; }
535
537 int readArray(T data[], int count) override {
538 if (p_file == nullptr) return 0;
539 int read_count = min(count, available());
540
541 OffsetInfo offset = getOffset(read_pos, read_count);
542 if (!file_seek(offset.pos)) return false;
543 int n = file_read(data, offset.len);
544 if (offset.len1 > 0) {
545 file_seek(0);
546 n += file_read(data + offset.len, offset.len1);
547 read_pos = offset.len1;
548 } else {
549 read_pos += read_count;
550 }
551
552 for (int i = 0; i < count; i++) {
553 LOGI("read #%d value %d", offset.pos, (int)data[i]);
554 }
555
556 element_count -= read_count;
557 return read_count;
558 }
559
561 bool peek(T &result) override {
562 if (p_file == nullptr || isEmpty()) {
563 return false;
564 }
565
566 if (!file_seek(read_pos)) return false;
567 size_t count = file_read(&result, 1);
568 return count == 1;
569 }
570
572 int peekArray(T data[], int count) {
573 if (p_file == nullptr) return 0;
574 int read_count = min(count, available());
575
576 OffsetInfo offset = getOffset(read_pos, read_count);
577 if (!file_seek(offset.pos)) return false;
578 int n = file_read(data, offset.len);
579 if (offset.len1 > 0) {
580 file_seek(0);
581 n += file_read(data + offset.len, offset.len1);
582 }
583 assert(n == read_count);
584 return read_count;
585 }
586
588 bool write(T data) override { return writeArray(&data, 1); }
589
591 int writeArray(const T data[], int len) override {
592 if (p_file == nullptr) return 0;
593 for (int i = 0; i < len; i++) {
594 LOGI("write #%d value %d", write_pos, (int)data[i]);
595 }
596
597 int write_count = min(len, availableForWrite());
598 OffsetInfo offset = getOffset(write_pos, write_count);
599
600 if (!file_seek(offset.pos)) return false;
601 int n = file_write(data, offset.len);
602 if (offset.len1 > 0) {
603 file_seek(0);
604 n += file_write(data + offset.len, offset.len1);
605 write_pos = offset.len1;
606 } else {
607 write_pos += write_count;
608 }
609 element_count += write_count;
610 return write_count;
611 }
612
614 bool isFull() override { return available() == max_size; }
615
616 bool isEmpty() { return available() == 0; }
617
619 void reset() override {
620 write_pos = 0;
621 read_pos = 0;
622 element_count = 0;
623 if (p_file != nullptr) file_seek(0);
624 }
625
627 int available() override { return element_count; }
628
630 int availableForWrite() override { return (max_size - element_count); }
631
633 size_t size() override { return max_size; }
634
636 bool resize(size_t size) {
637 max_size = size;
638 return true;
639 }
640
641 // not supported
642 T *address() override { return nullptr; }
643
644 protected:
645 File *p_file = nullptr;
646 int write_pos = 0;
647 int read_pos = 0;
649 int max_size = 0;
650
651 struct OffsetInfo {
652 int pos = 0; // start pos
653 int len = 0; // length of first part
654 int len1 = 0; // length of second part on overflow
655 };
656
659 OffsetInfo getOffset(int pos, int len) {
660 OffsetInfo result;
661 result.pos = pos;
662 int overflow = (pos + len) - max_size;
663 if (overflow <= 0) {
664 // we can write the complete data
665 result.len = len;
666 result.len1 = 0;
667 } else {
668 // we need to split the data
669 result.len = len - overflow;
670 result.len1 = overflow;
671 }
672 return result;
673 }
674
676 bool file_seek(int pos) {
677 int file_pos = pos * sizeof(T);
678 if (p_file->position() != file_pos) {
679 LOGD("file_seek: %d", pos);
680 if (!p_file->seek(file_pos)) {
681 LOGE("seek %d", file_pos);
682 return false;
683 }
684 }
685 return true;
686 }
687
689 int file_write(const T *data, int count) {
690 LOGD("file_write: %d", count);
691 if (p_file == nullptr) return 0;
692 int to_write_bytes = sizeof(T) * count;
693 int bytes_written = p_file->write((const uint8_t *)data, to_write_bytes);
694 p_file->flush();
695 int elements_written = bytes_written / sizeof(T);
696 if (bytes_written != to_write_bytes) {
697 LOGE("write: %d -> %d bytes", to_write_bytes, bytes_written);
698 }
699 return elements_written;
700 }
701
703 int file_read(T *result, int count) {
704 LOGD("file_read: %d", count);
705 int read_bytes = count * sizeof(T);
706 int result_bytes = p_file->readBytes((char *)result, read_bytes);
707 int result_count = result_bytes / sizeof(T);
708 if (result_count != count) {
709 LOGE("readBytes: %d -> %d", read_bytes, result_bytes);
710 }
711 return result_count;
712 }
713};
714
722template <typename T = uint8_t>
723class NBuffer : public BaseBuffer<T> {
724 public:
725 NBuffer(int size, int count) { resize(size, count); }
726
727 virtual ~NBuffer() { freeMemory(); }
728
730 bool read(T &result) override {
731 if (available() == 0) return false;
732 return actual_read_buffer->read(result);
733 }
734
738 int readArray(T data[], int len) override {
739 int count = 0;
740 while (count < len) {
741 if (available() == 0) break;
742 actual_read_buffer->read(data[count]);
743 count++;
744 }
745 return count;
746 }
747
749 bool peek(T &result) override {
750 if (available() == 0) return false;
751 return actual_read_buffer->peek(result);
752 }
753
755 bool isFull() { return availableForWrite() == 0; }
756
758 bool write(T data) {
759 bool result = false;
760 if (actual_write_buffer == nullptr) {
762 }
763 if (actual_write_buffer != nullptr) {
764 result = actual_write_buffer->write(data);
765 // if buffer is full move to next available
769 }
770 }
771
772 if (start_time == 0l) {
773 start_time = millis();
774 }
775 if (result) sample_count++;
776
777 return result;
778 }
779
781 int available() {
782 if (actual_read_buffer == nullptr) {
784 }
785 if (actual_read_buffer == nullptr) {
786 return 0;
787 }
788 int result = actual_read_buffer->available();
789 if (result == 0) {
790 // make current read buffer available again
791 resetCurrent();
792 result =
793 (actual_read_buffer == nullptr) ? 0 : actual_read_buffer->available();
794 }
795 return result;
796 }
797
800 if (actual_write_buffer == nullptr) {
802 }
803 // if we used up all buffers - there is nothing available any more
804 if (actual_write_buffer == nullptr) {
805 return 0;
806 }
807 // check on actual buffer
809 // if buffer is full we move it to filled buffers ang get the next
810 // available
813 }
815 }
816
820 void flush() {
821 if (actual_write_buffer != nullptr && actual_write_buffer->available() > 0) {
823 actual_write_buffer = nullptr;
824 }
825 }
826
828 void reset() {
829 TRACED();
830 while (actual_read_buffer != nullptr) {
833 // get next read buffer
835 }
836 }
837
839 unsigned long sampleRate() {
840 unsigned long run_time = (millis() - start_time);
841 return run_time == 0 ? 0 : sample_count * 1000 / run_time;
842 }
843
845 T *address() {
846 return actual_read_buffer == nullptr ? nullptr
848 }
849
851 virtual int bufferCountFilled() { return filled_buffers.size(); }
852
854 virtual int bufferCountEmpty() { return available_buffers.size(); }
855
856 virtual bool resize(size_t bytes) {
857 int count = bytes / buffer_size;
858 return resize(buffer_size, count);
859 }
860
862 virtual bool resize(size_t size, int count) {
863 if (buffer_size == size && buffer_count == count) return true;
864 freeMemory();
865 filled_buffers.resize(count);
866 available_buffers.resize(count);
867 // filled_buffers.clear();
868 // available_buffers.clear();
869
870 buffer_count = count;
872 for (int j = 0; j < count; j++) {
873 BaseBuffer<T> *buffer = new SingleBuffer<T>(size);
874 LOGD("new buffer %p", buffer);
875 available_buffers.enqueue(buffer);
876 }
877 return true;
878 }
879
881 size_t size() { return buffer_size * buffer_count; }
882
883 protected:
884 int buffer_size = 1024;
885 uint16_t buffer_count = 0;
890 unsigned long start_time = 0;
891 unsigned long sample_count = 0;
892
894 NBuffer() = default;
895
896 void freeMemory() {
898 LOGD("deleting %p", actual_write_buffer);
899 delete actual_write_buffer;
900 actual_write_buffer = nullptr;
901 }
902 if (actual_read_buffer) {
903 LOGD("deleting %p", actual_read_buffer);
904 delete actual_read_buffer;
905 actual_read_buffer = nullptr;
906 }
907
909 while (ptr != nullptr) {
910 LOGD("deleting %p", ptr);
911 delete ptr;
913 }
914
915 ptr = getNextFilledBuffer();
916 while (ptr != nullptr) {
917 LOGD("deleting %p", ptr);
918 delete ptr;
919 ptr = getNextFilledBuffer();
920 }
921 }
922
924 if (actual_read_buffer != nullptr) {
927 }
928 // get next read buffer
930 }
931
933 if (available_buffers.empty()) return nullptr;
934 BaseBuffer<T> *result = nullptr;
935 available_buffers.dequeue(result);
936 return result;
937 }
938
939 virtual bool addAvailableBuffer(BaseBuffer<T> *buffer) {
940 return available_buffers.enqueue(buffer);
941 }
942
944 if (filled_buffers.empty()) return nullptr;
945 BaseBuffer<T> *result = nullptr;
946 filled_buffers.dequeue(result);
947 return result;
948 }
949
950 virtual bool addFilledBuffer(BaseBuffer<T> *buffer) {
951 return filled_buffers.enqueue(buffer);
952 }
953};
954
961template <typename T = uint8_t>
962class NBufferExt : public NBuffer<T> {
963 public:
964 NBufferExt(int size, int count) { resize(size, count); }
965
975
979 // make current read buffer available again
980 resetCurrent();
982 }
983
986 for (auto &buffer : this->filled_buffers.toVector()) {
987 SingleBuffer<T> *sbuffer = (SingleBuffer<T> *)&buffer;
988 if (sbuffer->id == id) {
989 return sbuffer;
990 }
991 }
992 return nullptr;
993 }
994
995 using NBuffer<T>::resize;
996
997 protected:
998 using NBuffer<T>::resetCurrent;
1003 using NBuffer<T>::buffer_size;
1004};
1005
1015template <class File, typename T>
1016class NBufferFile : public BaseBuffer<T> {
1017 public:
1019 NBufferFile(int fileSize) { number_of_objects_per_file = fileSize; }
1022
1024 const char *nextFileName() {
1025 next_file_name.set("buffer-");
1026 char number[40];
1027 snprintf(number, 40, "%d", file_count);
1028 next_file_name.add(number);
1029 next_file_name.add(".tmp");
1030 return next_file_name.c_str();
1031 }
1032
1035 bool addFile(File &file) {
1036 if (!file) return false;
1037 empty_files.enqueue(file);
1038 file_count++;
1039 return true;
1040 }
1041
1042 bool read(T &result) override { return readArray(&result, 1) == 1; }
1043
1044 int readArray(T data[], int len) override {
1045 // make sure we have a read file
1046 if (!read_file) {
1047 if (!filled_files.dequeue(read_file)) {
1048 // no more data
1049 return 0;
1050 }
1051 read_file.seek(0);
1052 }
1053 // read the data
1054 int result = read_file.readBytes((char *)data, len * sizeof(T)) / sizeof(T);
1055
1056 // if we have consumed all content
1057 if (result < len) {
1058 read_file.seek(0);
1059 empty_files.enqueue(read_file);
1060 read_file = empty;
1061 }
1062 return result;
1063 }
1064
1065 bool peek(T &data) override {
1066 size_t pos = read_file.position();
1067 bool result = read(data);
1068 read_file.seek(pos);
1069 return result;
1070 }
1071
1072 bool write(T sample) override { return writeArray(&sample, 1) == 1; }
1073
1074 int writeArray(const T data[], int len) override {
1076 // moved to filled files
1077 if (write_file) {
1078 write_file.seek(0);
1079 filled_files.enqueue(write_file);
1080 }
1081 // get next empty file
1082 if (!empty_files.dequeue(write_file)) return false;
1083 }
1084 int result = write_file.write((uint8_t *)data, len * sizeof(T));
1085 return result / sizeof(T);
1086 }
1087
1088 int available() override {
1090 (read_file.available() / sizeof(T));
1091 }
1092
1093 // provides the number of entries that are available to write
1094 int availableForWrite() override {
1095 int open_current =
1097 return empty_files.size() * number_of_objects_per_file +
1098 write_file.available() + open_current;
1099 }
1100
1101 size_t size() override { return number_of_objects_per_file * file_count; }
1102
1104 void end() {
1107 File file;
1108 while (empty_files.dequeue(file)) cleanupFile(file);
1109 while (filled_files.dequeue(file)) cleanupFile(file);
1110 }
1111
1113 void setFileDeleteCallback(void (*cb)(const char *filename)) {
1115 }
1116
1117 void reset() {
1118 if (read_file) {
1119 read_file.seek(0);
1120 empty_files.enqueue(read_file);
1121 read_file = empty;
1122 }
1123 if (write_file) {
1124 write_file.seek(0);
1125 empty_files.enqueue(write_file);
1126 write_file = empty;
1127 }
1128 File file;
1129 while (filled_files.dequeue(file)) {
1130 file.seek(0);
1131 empty_files.enqueue(file);
1132 }
1133 }
1135 T *address() { return nullptr; }
1136
1137 protected:
1143 int number_of_objects_per_file = 0; // number of objects per file
1144 int file_count = 0; // number of files
1145 const uint16_t max_file_name = 256;
1147 void (*file_delete_callback)(const char *filename);
1148
1149 void cleanupFile(File &file) {
1150 if (!file) return;
1151 // after close the file name is gone
1152 int len = strlen(file.name());
1153 char file_name[len + 1];
1154 strncpy(file_name, file.name(), len);
1155 file.close();
1156 file_delete_callback(file_name);
1157 }
1158};
1159
1169template <typename T = uint8_t>
1171 public:
1172 BufferedArray(Stream &input, int len) {
1173 LOGI("BufferedArray(%d)", len);
1174 array.resize(len);
1175 p_stream = &input;
1176 }
1177 // access values, the offset and length are specified in samples of type <T>
1178 int16_t *getValues(size_t offset, size_t length) {
1179 LOGD("getValues(%d,%d) - max %d", offset, length, array.size());
1180 if (offset == 0) {
1181 // we restart at the beginning
1182 last_end = 0;
1183 actual_end = length;
1184 } else {
1185 // if first position is at end we do not want to read the full buffer
1186 last_end = actual_end >= 0 ? actual_end : offset;
1187 // increase actual end if bigger then old
1188 actual_end = offset + length > actual_end ? offset + length : actual_end;
1189 }
1190 int size = actual_end - last_end;
1191 if (size > 0) {
1192 LOGD("readBytes(%d,%d)", last_end, size);
1193 assert(last_end + size <= array.size());
1194 p_stream->readBytes((uint8_t *)(&array[last_end]), size * 2);
1195 }
1196 assert(offset < actual_end);
1197 return &array[offset];
1198 }
1199
1200 protected:
1201 int actual_end = -1;
1202 int last_end = 0;
1204 Stream *p_stream = nullptr;
1205};
1206
1207} // namespace audio_tools
#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:24
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:136
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 int bufferCountFilled()
Provides the number of entries that are available to read: -1 does not apply.
Definition Buffers.h:133
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:1170
int16_t * getValues(size_t offset, size_t length)
Definition Buffers.h:1178
BufferedArray(Stream &input, int len)
Definition Buffers.h:1172
Stream * p_stream
Definition Buffers.h:1204
int last_end
Definition Buffers.h:1202
Vector< T > array
Definition Buffers.h:1203
int actual_end
Definition Buffers.h:1201
A FrameBuffer reads multiple values for array of 2 dimensional frames.
Definition Buffers.h:144
BaseBuffer< T > * p_buffer
Definition Buffers.h:177
FrameBuffer(BaseBuffer< T > &buffer)
Definition Buffers.h:146
int readFrames(T(&data)[rows][channels])
Definition Buffers.h:163
int readFrames(T data[][2], int len)
reads multiple values for array of 2 dimensional frames
Definition Buffers.h:148
A NBufferExt is a subclass of NBuffer which allows to use a direct access API to the BaseBuffer.
Definition Buffers.h:962
SingleBuffer< T > * getBuffer(int id)
Provides the buffer with the indicated id.
Definition Buffers.h:985
NBufferExt(int size, int count)
Definition Buffers.h:964
SingleBuffer< T > * readEnd()
Definition Buffers.h:978
SingleBuffer< T > * writeEnd()
Definition Buffers.h:968
A File backed buffer which uses the provided files for buffering with the indicated max size....
Definition Buffers.h:1016
Str next_file_name
Definition Buffers.h:1146
const char * nextFileName()
Determines the next unique file name (after calling addFile)
Definition Buffers.h:1024
size_t size() override
Definition Buffers.h:1101
void setFileDeleteCallback(void(*cb)(const char *filename))
Define the file delete operation.
Definition Buffers.h:1113
bool peek(T &data) override
peeks the actual entry from the buffer
Definition Buffers.h:1065
void(* file_delete_callback)(const char *filename)
Definition Buffers.h:1147
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:1072
~NBufferFile()
RAII close the files.
Definition Buffers.h:1021
void cleanupFile(File &file)
Definition Buffers.h:1149
bool read(T &result) override
reads a single value
Definition Buffers.h:1042
int available() override
provides the number of entries that are available to read
Definition Buffers.h:1088
Queue< File > empty_files
Definition Buffers.h:1138
File read_file
Definition Buffers.h:1140
bool addFile(File &file)
Definition Buffers.h:1035
File write_file
Definition Buffers.h:1141
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:1094
const uint16_t max_file_name
Definition Buffers.h:1145
NBufferFile(int fileSize)
Provide the file size in objects!
Definition Buffers.h:1019
int number_of_objects_per_file
Definition Buffers.h:1143
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:1074
void end()
clean up files
Definition Buffers.h:1104
Queue< File > filled_files
Definition Buffers.h:1139
int file_count
Definition Buffers.h:1144
File empty
Definition Buffers.h:1142
void reset()
clears the buffer
Definition Buffers.h:1117
T * address()
not supported
Definition Buffers.h:1135
int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:1044
A lock free N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:723
unsigned long start_time
Definition Buffers.h:890
size_t size()
Provides the total capacity (=buffer size * buffer count)
Definition Buffers.h:881
QueueFromVector< BaseBuffer< T > * > available_buffers
Definition Buffers.h:888
void resetCurrent()
Definition Buffers.h:923
virtual ~NBuffer()
Definition Buffers.h:727
virtual int bufferCountEmpty()
Provides the number of entries that are available to write.
Definition Buffers.h:854
NBuffer()=default
empty constructor only allowed by subclass
virtual bool resize(size_t bytes)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:856
bool isFull()
checks if the buffer is full
Definition Buffers.h:755
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:749
int available()
determines the available entries for the current read buffer
Definition Buffers.h:781
bool read(T &result) override
reads an entry from the buffer
Definition Buffers.h:730
bool write(T data)
write add an entry to the buffer
Definition Buffers.h:758
void freeMemory()
Definition Buffers.h:896
int availableForWrite()
determines the available entries for the write buffer
Definition Buffers.h:799
virtual bool addAvailableBuffer(BaseBuffer< T > *buffer)
Definition Buffers.h:939
NBuffer(int size, int count)
Definition Buffers.h:725
virtual bool resize(size_t size, int count)
Resize the buffers by defining a new buffer size and buffer count.
Definition Buffers.h:862
virtual int bufferCountFilled()
Provides the number of entries that are available to read.
Definition Buffers.h:851
uint16_t buffer_count
Definition Buffers.h:885
virtual bool addFilledBuffer(BaseBuffer< T > *buffer)
Definition Buffers.h:950
void reset()
resets all buffers
Definition Buffers.h:828
unsigned long sampleRate()
provides the actual sample rate
Definition Buffers.h:839
BaseBuffer< T > * actual_read_buffer
Definition Buffers.h:886
void flush()
Definition Buffers.h:820
T * address()
returns the address of the start of the phsical read buffer
Definition Buffers.h:845
BaseBuffer< T > * actual_write_buffer
Definition Buffers.h:887
QueueFromVector< BaseBuffer< T > * > filled_buffers
Definition Buffers.h:889
virtual BaseBuffer< T > * getNextAvailableBuffer()
Definition Buffers.h:932
unsigned long sample_count
Definition Buffers.h:891
int readArray(T data[], int len) override
Definition Buffers.h:738
int buffer_size
Definition Buffers.h:884
virtual BaseBuffer< T > * getNextFilledBuffer()
Definition Buffers.h:943
FIFO Queue which is based on a Vector.
Definition QueueFromVector.h:14
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:512
int readArray(T data[], int count) override
reads multiple values
Definition Buffers.h:537
size_t size() override
Provides the capacity.
Definition Buffers.h:633
int peekArray(T data[], int count)
gets multiple values w/o removing them
Definition Buffers.h:572
int file_write(const T *data, int count)
Reed the indicated number of objects.
Definition Buffers.h:689
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:561
RingBufferFile(int size, File &file)
Definition Buffers.h:515
bool read(T &result) override
Reads a single value from the buffer.
Definition Buffers.h:534
bool write(T data) override
write add a single entry to the buffer
Definition Buffers.h:588
int available() override
provides the number of entries that are available to read
Definition Buffers.h:627
~RingBufferFile()
Definition Buffers.h:519
File * p_file
Definition Buffers.h:645
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:630
int write_pos
Definition Buffers.h:646
T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:642
bool isFull() override
checks if the buffer is full
Definition Buffers.h:614
int read_pos
Definition Buffers.h:647
bool begin(File &bufferFile)
Assigns the p_file to be used.
Definition Buffers.h:524
int max_size
Definition Buffers.h:649
bool file_seek(int pos)
Seeks to the given object position.
Definition Buffers.h:676
int writeArray(const T data[], int len) override
Fills the data from the buffer.
Definition Buffers.h:591
RingBufferFile(int size)
Definition Buffers.h:514
int file_read(T *result, int count)
Writes the indicated number of objects.
Definition Buffers.h:703
OffsetInfo getOffset(int pos, int len)
Definition Buffers.h:659
bool resize(size_t size)
Defines the capacity.
Definition Buffers.h:636
void reset() override
clears the buffer
Definition Buffers.h:619
int element_count
Definition Buffers.h:648
bool isEmpty()
Definition Buffers.h:616
Implements a typed Ringbuffer.
Definition Buffers.h:358
virtual int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:407
virtual int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:427
RingBuffer(int size, Allocator &allocator=DefaultAllocator)
Definition Buffers.h:360
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:378
virtual int peekArray(T *data, int n)
Definition Buffers.h:387
bool read(T &result) override
reads a single value
Definition Buffers.h:365
virtual T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:476
int nextIndex(int index)
Definition Buffers.h:498
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:473
virtual bool write(T data) override
write add an entry to the buffer
Definition Buffers.h:451
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:488
int max_size
Definition Buffers.h:496
virtual void reset() override
clears the buffer
Definition Buffers.h:463
Allocator & _allocator
Definition Buffers.h:491
int _iHead
Definition Buffers.h:493
virtual bool isFull() override
checks if the buffer is full
Definition Buffers.h:446
int _numElems
Definition Buffers.h:495
Vector< T > _aucBuffer
Definition Buffers.h:492
virtual bool resize(size_t len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:478
bool isEmpty()
Definition Buffers.h:448
int _iTail
Definition Buffers.h:494
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:470
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:189
bool active
Optional active/inactive status.
Definition Buffers.h:339
size_t size() override
Definition Buffers.h:320
SingleBuffer & operator=(const SingleBuffer &)=default
size_t setAvailable(size_t available_size)
Definition Buffers.h:313
void trim()
Moves the unprocessed data to the beginning of the buffer.
Definition Buffers.h:290
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:223
Allocator _allocator
Definition Buffers.h:344
void setClearWithZero(bool flag)
Sets the buffer to 0 on clear.
Definition Buffers.h:331
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:241
bool owns_buffer
Definition Buffers.h:347
uint64_t timestamp
Optional timestamp.
Definition Buffers.h:341
void setWritePos(int pos)
Updates the actual available data size.
Definition Buffers.h:334
bool read(T &result) override
reads a single value
Definition Buffers.h:232
int available() override
provides the number of entries that are available to read
Definition Buffers.h:250
int id
Optional ID.
Definition Buffers.h:337
bool is_clear_with_zero
Definition Buffers.h:348
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:255
T * address() override
Provides address to beginning of the buffer.
Definition Buffers.h:298
bool isFull() override
checks if the buffer is full
Definition Buffers.h:257
int current_read_pos
Definition Buffers.h:345
void onExternalBufferRefilled(void *data, int len)
notifies that the external buffer has been refilled
Definition Buffers.h:211
int current_write_pos
Definition Buffers.h:346
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:218
int peekArray(uint8_t *data, int len)
Definition Buffers.h:259
Vector< T > buffer
Definition Buffers.h:349
SingleBuffer(const SingleBuffer &)=default
SingleBuffer(int size, Allocator &allocator=DefaultAllocator)
Construct a new Single Buffer object.
Definition Buffers.h:196
SingleBuffer()
Construct a new Single Buffer w/o allocating any memory.
Definition Buffers.h:208
T * data()
Provides address of actual data.
Definition Buffers.h:301
bool resize(size_t size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:322
void reset() override
clears the buffer
Definition Buffers.h:303
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:269
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:47
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:380
virtual void add(int value)
adds a int value
Definition StrView.h:126
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
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:207
uint32_t millis()
Returns the milliseconds since the start.
Definition Arduino.h:260
int pos
Definition Buffers.h:652
int len1
Definition Buffers.h:654
int len
Definition Buffers.h:653