arduino-audio-tools
Loading...
Searching...
No Matches
Buffers.h
1#pragma once
2
3#include "AudioTools/CoreAudio/AudioBasic/Collections.h"
4#include "AudioTools/CoreAudio/AudioBasic/Str.h"
5#include "AudioTools/CoreAudio/AudioLogger.h"
6
13namespace audio_tools {
14
21template <typename T>
23 public:
24 BaseBuffer() = default;
25 virtual ~BaseBuffer() = default;
26 BaseBuffer(BaseBuffer const &) = delete;
27 // BaseBuffer &operator=(BaseBuffer const &) = delete;
28
30 virtual bool read(T &result) = 0;
31
33 virtual int readArray(T data[], int len) {
34 if (data == nullptr) {
35 LOGE("NPE");
36 return 0;
37 }
38 int lenResult = min(len, available());
39 for (int j = 0; j < lenResult; j++) {
40 read(data[j]);
41 }
42 LOGD("readArray %d -> %d", len, lenResult);
43 return lenResult;
44 }
45
47 virtual int clearArray(int len) {
48 int lenResult = min(len, available());
49 T dummy[lenResult];
50 readArray(dummy, lenResult);
51 return lenResult;
52 }
53
55 virtual int writeArray(const T data[], int len) {
56 // LOGD("%s: %d", LOG_METHOD, len);
57 // CHECK_MEMORY();
58
59 int result = 0;
60 for (int j = 0; j < len; j++) {
61 if (!write(data[j])) {
62 break;
63 }
64 result = j + 1;
65 }
66 // CHECK_MEMORY();
67 LOGD("writeArray %d -> %d", len, result);
68 return result;
69 }
70
72 virtual int writeArrayOverwrite(const T data[], int len) {
73 int to_delete = len - availableForWrite();
74 if (to_delete > 0) {
75 clearArray(to_delete);
76 }
77 return writeArray(data, len);
78 }
79
81 virtual bool peek(T &result) = 0;
82
84 virtual bool isFull() { return availableForWrite() == 0; }
85
86 bool isEmpty() { return available() == 0; }
87
89 virtual bool write(T data) = 0;
90
92 virtual void reset() = 0;
93
95 void clear() { reset(); }
96
98 virtual int available() = 0;
99
101 virtual int availableForWrite() = 0;
102
104 virtual T *address() = 0;
105
106 virtual size_t size() = 0;
107
109 virtual float levelPercent() {
110 // prevent div by 0.
111 if (size() == 0) return 0.0f;
112 return 100.0f * static_cast<float>(available()) /
113 static_cast<float>(size());
114 }
115
117 virtual bool resize(int bytes) {
118 LOGE("resize not implemented for this buffer");
119 return false;
120 }
121};
122
123/***
124 * @brief A FrameBuffer reads multiple values for array of 2 dimensional frames
125 */
126template <typename T>
128 public:
129 FrameBuffer(BaseBuffer<T> &buffer) { p_buffer = &buffer; }
131 int readFrames(T data[][2], int len) {
132 LOGD("%s: %d", LOG_METHOD, len);
133 // CHECK_MEMORY();
134 int result = min(len, p_buffer->available());
135 for (int j = 0; j < result; j++) {
136 T sample = 0;
137 p_buffer->read(sample);
138 data[j][0] = sample;
139 data[j][1] = sample;
140 }
141 // CHECK_MEMORY();
142 return result;
143 }
144
145 template <int rows, int channels>
146 int readFrames(T (&data)[rows][channels]) {
147 int lenResult = min(rows, p_buffer->available());
148 for (int j = 0; j < lenResult; j++) {
149 T sample = 0;
150 p_buffer->read(sample);
151 for (int i = 0; i < channels; i++) {
152 // data[j][i] = htons(sample);
153 data[j][i] = sample;
154 }
155 }
156 return lenResult;
157 }
158
159 protected:
160 BaseBuffer<T> *p_buffer = nullptr;
161};
162
171template <typename T>
172class SingleBuffer : public BaseBuffer<T> {
173 public:
179 SingleBuffer(int size) {
180 buffer.resize(size);
181 reset();
182 }
183
188
190 void onExternalBufferRefilled(void *data, int len) {
191 this->owns_buffer = false;
192 this->buffer = (uint8_t *)data;
193 this->current_read_pos = 0;
194 this->current_write_pos = len;
195 }
196
197 int writeArray(const T data[], int len) override {
198 if (size() == 0) resize(len);
199 return BaseBuffer<T>::writeArray(data, len);
200 }
201
202 bool write(T sample) override {
203 bool result = false;
204 if (current_write_pos < buffer.size()) {
205 buffer[current_write_pos++] = sample;
206 result = true;
207 }
208 return result;
209 }
210
211 bool read(T &result) override {
212 bool success = false;
213 if (current_read_pos < current_write_pos) {
214 result = buffer[current_read_pos++];
215 success = true;
216 }
217 return success;
218 }
219
220 bool peek(T &result) override {
221 bool success = false;
222 if (current_read_pos < current_write_pos) {
223 result = buffer[current_read_pos];
224 success = true;
225 }
226 return success;
227 }
228
229 int available() override {
230 int result = current_write_pos - current_read_pos;
231 return max(result, 0);
232 }
233
234 int availableForWrite() override { return buffer.size() - current_write_pos; }
235
236 bool isFull() override { return availableForWrite() <= 0; }
237
238 int peekArray(uint8_t *data, int len) {
239 int len_available = available();
240 if (len > len_available) {
241 len = len_available;
242 }
243 memcpy(data, buffer.data() + current_read_pos, len);
244 return len;
245 }
246
248 int clearArray(int len) override {
249 int len_available = available();
250 if (len > available()) {
251 reset();
252 return len_available;
253 }
254 current_read_pos += len;
255 len_available -= len;
256 memmove(buffer.data(), buffer.data() + current_read_pos, len_available * sizeof(T));
257 current_read_pos = 0;
258 current_write_pos = len_available;
259
260 if (is_clear_with_zero) {
261 memset(buffer.data() + current_write_pos, 0,
262 buffer.size() - current_write_pos);
263 }
264
265 return len;
266 }
267
269 void trim() {
270 int av = available();
271 memmove(buffer.data(), buffer.data() + current_read_pos, av * sizeof(T));
272 current_write_pos = av;
273 current_read_pos = 0;
274 }
275
277 T *address() override { return buffer.data(); }
278
280 T *data() { return buffer.data() + current_read_pos; }
281
282 void reset() override {
283 current_read_pos = 0;
284 current_write_pos = 0;
285 if (is_clear_with_zero) {
286 memset(buffer.data(), 0, buffer.size());
287 }
288 }
289
292 size_t setAvailable(size_t available_size) {
293 size_t result = min(available_size, (size_t)buffer.size());
294 current_read_pos = 0;
295 current_write_pos = result;
296 return result;
297 }
298
299 size_t size() override { return buffer.size(); }
300
301 bool resize(int size) {
302 if (buffer.size() < size) {
303 TRACED();
304 buffer.resize(size);
305 }
306 return true;
307 }
308
310 void setClearWithZero(bool flag) { is_clear_with_zero = flag; }
311
313 void setWritePos(int pos) { current_write_pos = pos; }
314
316 int id = 0;
318 bool active = true;
320 uint64_t timestamp = 0;
321
322 protected:
323 int current_read_pos = 0;
324 int current_write_pos = 0;
325 bool owns_buffer = true;
326 bool is_clear_with_zero = false;
327 Vector<T> buffer{0};
328};
329
335template <typename T>
336class RingBuffer : public BaseBuffer<T> {
337 public:
338 RingBuffer(int size) {
339 resize(size);
340 reset();
341 }
342
343 bool read(T &result) override {
344 if (isEmpty()) {
345 return false;
346 }
347
348 result = _aucBuffer[_iTail];
349 _iTail = nextIndex(_iTail);
350 _numElems--;
351
352 return true;
353 }
354
355 // peeks the actual entry from the buffer
356 bool peek(T &result) override {
357 if (isEmpty()) {
358 return false;
359 }
360
361 result = _aucBuffer[_iTail];
362 return true;
363 }
364
365 virtual int peekArray(T *data, int n) {
366 if (isEmpty()) return -1;
367 int result = 0;
368 int count = _numElems;
369 int tail = _iTail;
370 for (int j = 0; j < n; j++) {
371 data[j] = _aucBuffer[tail];
372 tail = nextIndex(tail);
373 count--;
374 result++;
375 if (count == 0) break;
376 }
377 return result;
378 }
379
380 // checks if the buffer is full
381 virtual bool isFull() override { return available() == max_size; }
382
383 bool isEmpty() { return available() == 0; }
384
385 // write add an entry to the buffer
386 virtual bool write(T data) override {
387 bool result = false;
388 if (!isFull()) {
389 _aucBuffer[_iHead] = data;
390 _iHead = nextIndex(_iHead);
391 _numElems++;
392 result = true;
393 }
394 return result;
395 }
396
397 // clears the buffer
398 virtual void reset() override {
399 _iHead = 0;
400 _iTail = 0;
401 _numElems = 0;
402 }
403
404 // provides the number of entries that are available to read
405 virtual int available() override { return _numElems; }
406
407 // provides the number of entries that are available to write
408 virtual int availableForWrite() override { return (max_size - _numElems); }
409
410 // returns the address of the start of the physical read buffer
411 virtual T *address() override { return _aucBuffer.data(); }
412
413 virtual bool resize(int len) {
414 if (max_size != len) {
415 LOGI("resize: %d", len);
416 _aucBuffer.resize(len);
417 max_size = len;
418 }
419 return true;
420 }
421
423 virtual size_t size() override { return max_size; }
424
425 protected:
426 Vector<T> _aucBuffer;
427 int _iHead;
428 int _iTail;
429 int _numElems;
430 int max_size = 0;
431
432 int nextIndex(int index) {
433 if (max_size == 0) return 0;
434 return (uint32_t)(index + 1) % max_size; }
435};
436
445template <class File, typename T>
446class RingBufferFile : public BaseBuffer<T> {
447 public:
448 RingBufferFile(int size) { resize(size); }
449 RingBufferFile(int size, File &file) {
450 resize(size);
451 begin(file);
452 }
454 if (p_file) p_file->close();
455 }
456
458 bool begin(File &bufferFile) {
459 if (bufferFile) {
460 p_file = &bufferFile;
461 } else {
462 LOGE("file is not valid");
463 }
464 return bufferFile;
465 }
466
468 bool read(T &result) override { return readArray(&result, 1) == 1; }
469
471 int readArray(T data[], int count) override {
472 if (p_file == nullptr) return 0;
473 int read_count = min(count, available());
474
475 OffsetInfo offset = getOffset(read_pos, read_count);
476 if (!file_seek(offset.pos)) return false;
477 int n = file_read(data, offset.len);
478 if (offset.len1 > 0) {
479 file_seek(0);
480 n += file_read(data + offset.len, offset.len1);
481 read_pos = offset.len1;
482 } else {
483 read_pos += read_count;
484 }
485
486 for (int i = 0; i < count; i++) {
487 LOGI("read #%d value %d", offset.pos, (int)data[i]);
488 }
489
490 element_count -= read_count;
491 return read_count;
492 }
493
495 bool peek(T &result) override {
496 if (p_file == nullptr || isEmpty()) {
497 return false;
498 }
499
500 if (!file_seek(read_pos)) return false;
501 size_t count = file_read(&result, 1);
502 return count == 1;
503 }
504
506 int peekArray(T data[], int count) {
507 if (p_file == nullptr) return 0;
508 int read_count = min(count, available());
509
510 OffsetInfo offset = getOffset(read_pos, read_count);
511 if (!file_seek(offset.pos)) return false;
512 int n = file_read(data, offset.len);
513 if (offset.len1 > 0) {
514 file_seek(0);
515 n += file_read(data + offset.len, offset.len1);
516 }
517 assert(n == read_count);
518 return read_count;
519 }
520
522 bool write(T data) override { return writeArray(&data, 1); }
523
525 int writeArray(const T data[], int len) override {
526 if (p_file == nullptr) return 0;
527 for (int i = 0; i < len; i++) {
528 LOGI("write #%d value %d", write_pos, (int)data[i]);
529 }
530
531 int write_count = min(len, availableForWrite());
532 OffsetInfo offset = getOffset(write_pos, write_count);
533
534 if (!file_seek(offset.pos)) return false;
535 int n = file_write(data, offset.len);
536 if (offset.len1 > 0) {
537 file_seek(0);
538 n += file_write(data + offset.len, offset.len1);
539 write_pos = offset.len1;
540 } else {
541 write_pos += write_count;
542 }
543 element_count += write_count;
544 return write_count;
545 }
546
548 bool isFull() override { return available() == max_size; }
549
550 bool isEmpty() { return available() == 0; }
551
553 void reset() override {
554 write_pos = 0;
555 read_pos = 0;
556 element_count = 0;
557 if (p_file != nullptr) file_seek(0);
558 }
559
561 int available() override { return element_count; }
562
564 int availableForWrite() override { return (max_size - element_count); }
565
567 size_t size() override { return max_size; }
568
570 bool resize(int size) {
571 max_size = size;
572 return true;
573 }
574
575 // not supported
576 T *address() override { return nullptr; }
577
578 protected:
579 File *p_file = nullptr;
580 int write_pos = 0;
581 int read_pos = 0;
582 int element_count = 0;
583 int max_size = 0;
584
585 struct OffsetInfo {
586 int pos = 0; // start pos
587 int len = 0; // length of first part
588 int len1 = 0; // length of second part on overflow
589 };
590
593 OffsetInfo getOffset(int pos, int len) {
594 OffsetInfo result;
595 result.pos = pos;
596 int overflow = (pos + len) - max_size;
597 if (overflow <= 0) {
598 // we can write the complete data
599 result.len = len;
600 result.len1 = 0;
601 } else {
602 // we need to split the data
603 result.len = len - overflow;
604 result.len1 = overflow;
605 }
606 return result;
607 }
608
610 bool file_seek(int pos) {
611 int file_pos = pos * sizeof(T);
612 if (p_file->position() != file_pos) {
613 LOGD("file_seek: %d", pos);
614 if (!p_file->seek(file_pos)) {
615 LOGE("seek %d", file_pos);
616 return false;
617 }
618 }
619 return true;
620 }
621
623 int file_write(const T *data, int count) {
624 LOGD("file_write: %d", count);
625 if (p_file == nullptr) return 0;
626 int to_write_bytes = sizeof(T) * count;
627 int bytes_written = p_file->write((const uint8_t *)data, to_write_bytes);
628 p_file->flush();
629 int elements_written = bytes_written / sizeof(T);
630 if (bytes_written != to_write_bytes) {
631 LOGE("write: %d -> %d bytes", to_write_bytes, bytes_written);
632 }
633 return elements_written;
634 }
635
637 int file_read(T *result, int count) {
638 LOGD("file_read: %d", count);
639 int read_bytes = count * sizeof(T);
640 int result_bytes = p_file->readBytes((char *)result, read_bytes);
641 int result_count = result_bytes / sizeof(T);
642 if (result_count != count) {
643 LOGE("readBytes: %d -> %d", read_bytes, result_bytes);
644 }
645 return result_count;
646 }
647};
648
656template <typename T>
657class NBuffer : public BaseBuffer<T> {
658 public:
659 NBuffer(int size, int count) { resize(size, count); }
660
661 virtual ~NBuffer() { freeMemory(); }
662
664 bool read(T &result) override {
665 if (available() == 0) return false;
666 return actual_read_buffer->read(result);
667 }
668
670 bool peek(T &result) override {
671 if (available() == 0) return false;
672 return actual_read_buffer->peek(result);
673 }
674
676 bool isFull() { return availableForWrite() == 0; }
677
679 bool write(T data) {
680 bool result = false;
681 if (actual_write_buffer == nullptr) {
682 actual_write_buffer = getNextAvailableBuffer();
683 }
684 if (actual_write_buffer != nullptr) {
685 result = actual_write_buffer->write(data);
686 // if buffer is full move to next available
687 if (actual_write_buffer->isFull()) {
688 addFilledBuffer(actual_write_buffer);
689 actual_write_buffer = getNextAvailableBuffer();
690 }
691 }
692
693 if (start_time == 0l) {
694 start_time = millis();
695 }
696 if (result) sample_count++;
697
698 return result;
699 }
700
702 int available() {
703 if (actual_read_buffer == nullptr) {
704 actual_read_buffer = getNextFilledBuffer();
705 }
706 if (actual_read_buffer == nullptr) {
707 return 0;
708 }
709 int result = actual_read_buffer->available();
710 if (result == 0) {
711 // make current read buffer available again
712 resetCurrent();
713 result =
714 (actual_read_buffer == nullptr) ? 0 : actual_read_buffer->available();
715 }
716 return result;
717 }
718
721 if (actual_write_buffer == nullptr) {
722 actual_write_buffer = getNextAvailableBuffer();
723 }
724 // if we used up all buffers - there is nothing available any more
725 if (actual_write_buffer == nullptr) {
726 return 0;
727 }
728 // check on actual buffer
729 if (actual_write_buffer->isFull()) {
730 // if buffer is full we move it to filled buffers ang get the next
731 // available
732 addFilledBuffer(actual_write_buffer);
733 actual_write_buffer = getNextAvailableBuffer();
734 }
735 return actual_write_buffer->availableForWrite();
736 }
737
739 void reset() {
740 TRACED();
741 while (actual_read_buffer != nullptr) {
742 actual_read_buffer->reset();
743 addAvailableBuffer(actual_read_buffer);
744 // get next read buffer
745 actual_read_buffer = getNextFilledBuffer();
746 }
747 }
748
750 unsigned long sampleRate() {
751 unsigned long run_time = (millis() - start_time);
752 return run_time == 0 ? 0 : sample_count * 1000 / run_time;
753 }
754
756 T *address() {
757 return actual_read_buffer == nullptr ? nullptr
758 : actual_read_buffer->address();
759 }
760
762 virtual int bufferCountFilled() { return filled_buffers.size(); }
763
765 virtual int bufferCountEmpty() { return available_buffers.size(); }
766
767 virtual bool resize(int bytes) {
768 int count = bytes / buffer_size;
769 return resize(buffer_size, count);
770 }
771
773 virtual bool resize(int size, int count) {
774 if (buffer_size == size && buffer_count == count) return true;
775 freeMemory();
776 filled_buffers.resize(count);
777 available_buffers.resize(count);
778 // filled_buffers.clear();
779 // available_buffers.clear();
780
781 buffer_count = count;
782 buffer_size = size;
783 for (int j = 0; j < count; j++) {
784 BaseBuffer<T> *buffer = new SingleBuffer<T>(size);
785 LOGD("new buffer %p", buffer);
786 available_buffers.enqueue(buffer);
787 }
788 return true;
789 }
790
792 size_t size() { return buffer_size * buffer_count; }
793
794 protected:
795 int buffer_size = 1024;
796 uint16_t buffer_count = 0;
797 BaseBuffer<T> *actual_read_buffer = nullptr;
798 BaseBuffer<T> *actual_write_buffer = nullptr;
799 QueueFromVector<BaseBuffer<T> *> available_buffers{0, nullptr};
800 QueueFromVector<BaseBuffer<T> *> filled_buffers{0, nullptr};
801 unsigned long start_time = 0;
802 unsigned long sample_count = 0;
803
805 NBuffer() = default;
806
807 void freeMemory() {
808 if (actual_write_buffer) {
809 LOGD("deleting %p", actual_write_buffer);
810 delete actual_write_buffer;
811 actual_write_buffer = nullptr;
812 }
813 if (actual_read_buffer) {
814 LOGD("deleting %p", actual_read_buffer);
815 delete actual_read_buffer;
816 actual_read_buffer = nullptr;
817 }
818
819 BaseBuffer<T> *ptr = getNextAvailableBuffer();
820 while (ptr != nullptr) {
821 LOGD("deleting %p", ptr);
822 delete ptr;
823 ptr = getNextAvailableBuffer();
824 }
825
826 ptr = getNextFilledBuffer();
827 while (ptr != nullptr) {
828 LOGD("deleting %p", ptr);
829 delete ptr;
830 ptr = getNextFilledBuffer();
831 }
832 }
833
834 void resetCurrent() {
835 if (actual_read_buffer != nullptr) {
836 actual_read_buffer->reset();
837 addAvailableBuffer(actual_read_buffer);
838 }
839 // get next read buffer
840 actual_read_buffer = getNextFilledBuffer();
841 }
842
843 virtual BaseBuffer<T> *getNextAvailableBuffer() {
844 if (available_buffers.empty()) return nullptr;
845 BaseBuffer<T> *result = nullptr;
846 available_buffers.dequeue(result);
847 return result;
848 }
849
850 virtual bool addAvailableBuffer(BaseBuffer<T> *buffer) {
851 return available_buffers.enqueue(buffer);
852 }
853
854 virtual BaseBuffer<T> *getNextFilledBuffer() {
855 if (filled_buffers.empty()) return nullptr;
856 BaseBuffer<T> *result = nullptr;
857 filled_buffers.dequeue(result);
858 return result;
859 }
860
861 virtual bool addFilledBuffer(BaseBuffer<T> *buffer) {
862 return filled_buffers.enqueue(buffer);
863 }
864};
865
872template <typename T>
873class NBufferExt : public NBuffer<T> {
874 public:
875 NBufferExt(int size, int count) { resize(size, count); }
876
880 actual_write_buffer = getNextAvailableBuffer();
881 if (actual_write_buffer != nullptr) {
882 addFilledBuffer(actual_write_buffer);
883 }
884 return (SingleBuffer<T> *)actual_write_buffer;
885 }
886
890 // make current read buffer available again
891 resetCurrent();
892 return (SingleBuffer<T> *)actual_read_buffer;
893 }
894
897 for (auto &buffer : this->filled_buffers.toVector()) {
898 SingleBuffer<T> *sbuffer = (SingleBuffer<T> *)&buffer;
899 if (sbuffer->id == id) {
900 return sbuffer;
901 }
902 }
903 return nullptr;
904 }
905
906 using NBuffer<T>::resize;
907
908 protected:
909 using NBuffer<T>::resetCurrent;
910 using NBuffer<T>::addFilledBuffer;
911 using NBuffer<T>::getNextAvailableBuffer;
912 using NBuffer<T>::actual_write_buffer;
913 using NBuffer<T>::actual_read_buffer;
914 using NBuffer<T>::buffer_size;
915};
916
917/***
918 * @brief A File backed buffer which uses the provided files for buffering with
919 * the indicated max size. A file is made available for reading as soon as it
920 * reached the size limit. You must provide the files opened in "Write" mode
921 * with the addFile() method!
922 * @ingroup buffers
923 * @tparam File: file class
924 * @tparam T: buffered data type
925 */
926template <class File, typename T>
927class NBufferFile : public BaseBuffer<T> {
928 public:
930 NBufferFile(int fileSize) { number_of_objects_per_file = fileSize; }
933
935 const char *nextFileName() {
936 next_file_name.set("buffer-");
937 char number[40];
938 snprintf(number, 40, "%d", file_count);
939 next_file_name.add(number);
940 next_file_name.add(".tmp");
941 return next_file_name.c_str();
942 }
943
946 bool addFile(File &file) {
947 if (!file) return false;
948 empty_files.enqueue(file);
949 file_count++;
950 return true;
951 }
952
953 bool read(T &result) override { return readArray(&result, 1) == 1; }
954
955 int readArray(T data[], int len) override {
956 // make sure we have a read file
957 if (!read_file) {
958 if (!filled_files.dequeue(read_file)) {
959 // no more data
960 return 0;
961 }
962 read_file.seek(0);
963 }
964 // read the data
965 int result = read_file.readBytes((char *)data, len * sizeof(T)) / sizeof(T);
966
967 // if we have consumed all content
968 if (result < len) {
969 read_file.seek(0);
970 empty_files.enqueue(read_file);
971 read_file = empty;
972 }
973 return result;
974 }
975
976 bool peek(T &data) override {
977 size_t pos = read_file.position();
978 bool result = read(data);
979 read_file.seek(pos);
980 return result;
981 }
982
983 bool write(T sample) override { return writeArray(&sample, 1) == 1; }
984
985 int writeArray(const T data[], int len) override {
986 if (!write_file || write_file.size() + len > number_of_objects_per_file) {
987 // moved to filled files
988 if (write_file) {
989 write_file.seek(0);
990 filled_files.enqueue(write_file);
991 }
992 // get next empty file
993 if (!empty_files.dequeue(write_file)) return false;
994 }
995 int result = write_file.write((uint8_t *)data, len * sizeof(T));
996 return result / sizeof(T);
997 }
998
999 int available() override {
1000 return filled_files.size() * number_of_objects_per_file +
1001 (read_file.available() / sizeof(T));
1002 }
1003
1004 // provides the number of entries that are available to write
1005 int availableForWrite() override {
1006 int open_current =
1007 number_of_objects_per_file - (write_file.available() / sizeof(T));
1008 return empty_files.size() * number_of_objects_per_file +
1009 write_file.available() + open_current;
1010 }
1011
1012 size_t size() override { return number_of_objects_per_file * file_count; }
1013
1015 void end() {
1016 cleanupFile(read_file);
1017 cleanupFile(write_file);
1018 File file;
1019 while (empty_files.dequeue(file)) cleanupFile(file);
1020 while (filled_files.dequeue(file)) cleanupFile(file);
1021 }
1022
1024 void setFileDeleteCallback(void (*cb)(const char *filename)) {
1025 file_delete_callback = cb;
1026 }
1027
1028 void reset() {
1029 if (read_file) {
1030 read_file.seek(0);
1031 empty_files.enqueue(read_file);
1032 read_file = empty;
1033 }
1034 if (write_file) {
1035 write_file.seek(0);
1036 empty_files.enqueue(write_file);
1037 write_file = empty;
1038 }
1039 File file;
1040 while (filled_files.dequeue(file)) {
1041 file.seek(0);
1042 empty_files.enqueue(file);
1043 }
1044 }
1046 T *address() { return nullptr; }
1047
1048 protected:
1049 Queue<File> empty_files;
1050 Queue<File> filled_files;
1051 File read_file;
1052 File write_file;
1053 File empty;
1054 int number_of_objects_per_file = 0; // number of objects per file
1055 int file_count = 0; // number of files
1056 const uint16_t max_file_name = 256;
1057 Str next_file_name;
1058 void (*file_delete_callback)(const char *filename);
1059
1060 void cleanupFile(File &file) {
1061 if (!file) return;
1062 // after close the file name is gone
1063 int len = strlen(file.name());
1064 char file_name[len + 1];
1065 strncpy(file_name, file.name(), len);
1066 file.close();
1067 file_delete_callback(file_name);
1068 }
1069};
1070
1080template <typename T>
1082 public:
1083 BufferedArray(Stream &input, int len) {
1084 LOGI("BufferedArray(%d)", len);
1085 array.resize(len);
1086 p_stream = &input;
1087 }
1088 // access values, the offset and length are specified in samples of type <T>
1089 int16_t *getValues(size_t offset, size_t length) {
1090 LOGD("getValues(%d,%d) - max %d", offset, length, array.size());
1091 if (offset == 0) {
1092 // we restart at the beginning
1093 last_end = 0;
1094 actual_end = length;
1095 } else {
1096 // if first position is at end we do not want to read the full buffer
1097 last_end = actual_end >= 0 ? actual_end : offset;
1098 // increase actual end if bigger then old
1099 actual_end = offset + length > actual_end ? offset + length : actual_end;
1100 }
1101 int size = actual_end - last_end;
1102 if (size > 0) {
1103 LOGD("readBytes(%d,%d)", last_end, size);
1104 assert(last_end + size <= array.size());
1105 p_stream->readBytes((uint8_t *)(&array[last_end]), size * 2);
1106 }
1107 assert(offset < actual_end);
1108 return &array[offset];
1109 }
1110
1111 protected:
1112 int actual_end = -1;
1113 int last_end = 0;
1114 Vector<T> array;
1115 Stream *p_stream = nullptr;
1116};
1117
1118} // namespace audio_tools
Shared functionality of all buffers.
Definition Buffers.h:22
virtual bool read(T &result)=0
reads a single value
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:33
virtual void reset()=0
clears the buffer
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:55
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:72
virtual int clearArray(int len)
Removes the next len entries.
Definition Buffers.h:47
virtual int availableForWrite()=0
provides the number of entries that are available to write
virtual bool isFull()
checks if the buffer is full
Definition Buffers.h:84
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:109
void clear()
same as reset
Definition Buffers.h:95
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
virtual bool resize(int bytes)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:117
Class which is usfull ot provide incremental data access e.g. for EdgeImpulse which request data with...
Definition Buffers.h:1081
Definition Buffers.h:127
int readFrames(T data[][2], int len)
reads multiple values for array of 2 dimensional frames
Definition Buffers.h:131
A NBufferExt is a subclass of NBuffer which allows to use a direct access API to the BaseBuffer.
Definition Buffers.h:873
SingleBuffer< T > * getBuffer(int id)
Provides the buffer with the indicated id.
Definition Buffers.h:896
SingleBuffer< T > * readEnd()
Definition Buffers.h:889
SingleBuffer< T > * writeEnd()
Definition Buffers.h:879
Definition Buffers.h:927
const char * nextFileName()
Determines the next unique file name (after calling addFile)
Definition Buffers.h:935
void setFileDeleteCallback(void(*cb)(const char *filename))
Define the file delete operation.
Definition Buffers.h:1024
bool peek(T &data) override
peeks the actual entry from the buffer
Definition Buffers.h:976
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:983
~NBufferFile()
RAII close the files.
Definition Buffers.h:932
bool read(T &result) override
reads a single value
Definition Buffers.h:953
int available() override
provides the number of entries that are available to read
Definition Buffers.h:999
bool addFile(File &file)
Definition Buffers.h:946
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:1005
NBufferFile(int fileSize)
Provide the file size in objects!
Definition Buffers.h:930
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:985
void end()
clean up files
Definition Buffers.h:1015
void reset()
clears the buffer
Definition Buffers.h:1028
T * address()
not supported
Definition Buffers.h:1046
int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:955
A lock free N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:657
size_t size()
Provides the total capacity (=buffer size * buffer count)
Definition Buffers.h:792
virtual int bufferCountEmpty()
Provides the number of entries that are available to write.
Definition Buffers.h:765
NBuffer()=default
empty constructor only allowed by subclass
bool isFull()
checks if the buffer is full
Definition Buffers.h:676
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:670
int available()
determines the available entries for the current read buffer
Definition Buffers.h:702
bool read(T &result) override
reads an entry from the buffer
Definition Buffers.h:664
bool write(T data)
write add an entry to the buffer
Definition Buffers.h:679
virtual bool resize(int size, int count)
Resize the buffers by defining a new buffer size and buffer count.
Definition Buffers.h:773
int availableForWrite()
determines the available entries for the write buffer
Definition Buffers.h:720
virtual int bufferCountFilled()
Provides the number of entries that are available to read.
Definition Buffers.h:762
void reset()
resets all buffers
Definition Buffers.h:739
unsigned long sampleRate()
provides the actual sample rate
Definition Buffers.h:750
T * address()
returns the address of the start of the phsical read buffer
Definition Buffers.h:756
virtual bool resize(int bytes)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:767
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:446
int readArray(T data[], int count) override
reads multiple values
Definition Buffers.h:471
size_t size() override
Provides the capacity.
Definition Buffers.h:567
int peekArray(T data[], int count)
gets multiple values w/o removing them
Definition Buffers.h:506
int file_write(const T *data, int count)
Reed the indicated number of objects.
Definition Buffers.h:623
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:495
bool read(T &result) override
Reads a single value from the buffer.
Definition Buffers.h:468
bool write(T data) override
write add a single entry to the buffer
Definition Buffers.h:522
int available() override
provides the number of entries that are available to read
Definition Buffers.h:561
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:564
T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:576
bool isFull() override
checks if the buffer is full
Definition Buffers.h:548
bool begin(File &bufferFile)
Assigns the p_file to be used.
Definition Buffers.h:458
bool resize(int size)
Defines the capacity.
Definition Buffers.h:570
bool file_seek(int pos)
Seeks to the given object position.
Definition Buffers.h:610
int writeArray(const T data[], int len) override
Fills the data from the buffer.
Definition Buffers.h:525
int file_read(T *result, int count)
Writes the indicated number of objects.
Definition Buffers.h:637
OffsetInfo getOffset(int pos, int len)
Definition Buffers.h:593
void reset() override
clears the buffer
Definition Buffers.h:553
Implements a typed Ringbuffer.
Definition Buffers.h:336
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:356
bool read(T &result) override
reads a single value
Definition Buffers.h:343
virtual T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:411
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:408
virtual bool write(T data) override
write add an entry to the buffer
Definition Buffers.h:386
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:423
virtual void reset() override
clears the buffer
Definition Buffers.h:398
virtual bool isFull() override
checks if the buffer is full
Definition Buffers.h:381
virtual bool resize(int len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:413
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:405
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
bool active
Optional active/inactive status.
Definition Buffers.h:318
size_t setAvailable(size_t available_size)
Definition Buffers.h:292
void trim()
Moves the unprocessed data to the beginning of the buffer.
Definition Buffers.h:269
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:202
SingleBuffer(int size)
Construct a new Single Buffer object.
Definition Buffers.h:179
void setClearWithZero(bool flag)
Sets the buffer to 0 on clear.
Definition Buffers.h:310
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:220
uint64_t timestamp
Optional timestamp.
Definition Buffers.h:320
void setWritePos(int pos)
Updates the actual available data size.
Definition Buffers.h:313
bool read(T &result) override
reads a single value
Definition Buffers.h:211
int available() override
provides the number of entries that are available to read
Definition Buffers.h:229
int id
Optional ID.
Definition Buffers.h:316
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:234
T * address() override
Provides address to beginning of the buffer.
Definition Buffers.h:277
bool isFull() override
checks if the buffer is full
Definition Buffers.h:236
void onExternalBufferRefilled(void *data, int len)
notifies that the external buffer has been refilled
Definition Buffers.h:190
bool resize(int size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:301
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:197
SingleBuffer()
Construct a new Single Buffer w/o allocating any memory.
Definition Buffers.h:187
T * data()
Provides address of actual data.
Definition Buffers.h:280
void reset() override
clears the buffer
Definition Buffers.h:282
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:248
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:379
virtual void add(int value)
adds a int value
Definition StrView.h:126
Definition NoArduino.h:142
Arduino File support using std::fstream.
Definition VFSFile.h:33
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
uint32_t millis()
Returns the milliseconds since the start.
Definition Time.h:12