arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
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
15// forward declaration
16template <typename T>
17class NBuffer;
18
25template <typename T>
27 public:
28 BaseBuffer() = default;
29 virtual ~BaseBuffer() = default;
30 BaseBuffer(BaseBuffer const &) = delete;
31 // BaseBuffer &operator=(BaseBuffer const &) = delete;
32
34 virtual bool read(T &result) = 0;
35
37 virtual int readArray(T data[], int len) {
38 if (data == nullptr) {
39 LOGE("NPE");
40 return 0;
41 }
42 int lenResult = min(len, available());
43 for (int j = 0; j < lenResult; j++) {
44 read(data[j]);
45 }
46 LOGD("readArray %d -> %d", len, lenResult);
47 return lenResult;
48 }
49
51 virtual int clearArray(int len) {
52 int lenResult = min(len, available());
53 T dummy[lenResult];
54 readArray(dummy, lenResult);
55 return lenResult;
56 }
57
59 virtual int writeArray(const T data[], int len) {
60 // LOGD("%s: %d", LOG_METHOD, len);
61 // CHECK_MEMORY();
62
63 int result = 0;
64 for (int j = 0; j < len; j++) {
65 if (!write(data[j])) {
66 break;
67 }
68 result = j + 1;
69 }
70 // CHECK_MEMORY();
71 LOGD("writeArray %d -> %d", len, result);
72 return result;
73 }
74
76 virtual int writeArrayOverwrite(const T data[], int len) {
77 int to_delete = len - availableForWrite();
78 if (to_delete > 0) {
79 clearArray(to_delete);
80 }
81 return writeArray(data, len);
82 }
83
85 virtual bool peek(T &result) = 0;
86
88 virtual bool isFull() { return availableForWrite() == 0; }
89
90 bool isEmpty() { return available() == 0; }
91
93 virtual bool write(T data) = 0;
94
96 virtual void reset() = 0;
97
99 void clear() { reset(); }
100
102 virtual int available() = 0;
103
105 virtual int availableForWrite() = 0;
106
108 virtual T *address() = 0;
109
110 virtual size_t size() = 0;
111
113 virtual float levelPercent() {
114 // prevent div by 0.
115 if (size() == 0) return 0.0f;
116 return 100.0f * static_cast<float>(available()) /
117 static_cast<float>(size());
118 }
119
120 protected:
121 void setWritePos(int pos) {};
122
123 friend NBuffer<T>;
124};
125
126/***
127 * @brief A FrameBuffer reads multiple values for array of 2 dimensional frames
128 */
129template <typename T>
131 public:
132 FrameBuffer(BaseBuffer<T> &buffer) { p_buffer = &buffer; }
134 int readFrames(T data[][2], int len) {
135 LOGD("%s: %d", LOG_METHOD, len);
136 // CHECK_MEMORY();
137 int result = min(len, p_buffer->available());
138 for (int j = 0; j < result; j++) {
139 T sample = 0;
140 p_buffer->read(sample);
141 data[j][0] = sample;
142 data[j][1] = sample;
143 }
144 // CHECK_MEMORY();
145 return result;
146 }
147
148 template <int rows, int channels>
149 int readFrames(T (&data)[rows][channels]) {
150 int lenResult = min(rows, p_buffer->available());
151 for (int j = 0; j < lenResult; j++) {
152 T sample = 0;
153 p_buffer->read(sample);
154 for (int i = 0; i < channels; i++) {
155 // data[j][i] = htons(sample);
156 data[j][i] = sample;
157 }
158 }
159 return lenResult;
160 }
161
162 protected:
163 BaseBuffer<T> *p_buffer = nullptr;
164};
165
174template <typename T>
175class SingleBuffer : public BaseBuffer<T> {
176 public:
182 SingleBuffer(int size) {
183 buffer.resize(size);
184 reset();
185 }
186
191
193 void onExternalBufferRefilled(void *data, int len) {
194 this->owns_buffer = false;
195 this->buffer = (uint8_t *)data;
196 this->current_read_pos = 0;
197 this->current_write_pos = len;
198 }
199
200 bool write(T sample) override {
201 bool result = false;
202 if (current_write_pos < buffer.size()) {
203 buffer[current_write_pos++] = sample;
204 result = true;
205 }
206 return result;
207 }
208
209 bool read(T &result) override {
210 bool success = false;
211 if (current_read_pos < current_write_pos) {
212 result = buffer[current_read_pos++];
213 success = true;
214 }
215 return success;
216 }
217
218 bool peek(T &result) override {
219 bool success = false;
220 if (current_read_pos < current_write_pos) {
221 result = buffer[current_read_pos];
222 success = true;
223 }
224 return success;
225 }
226
227 int available() override {
228 int result = current_write_pos - current_read_pos;
229 return max(result, 0);
230 }
231
232 int availableForWrite() override { return buffer.size() - current_write_pos; }
233
234 bool isFull() override { return availableForWrite() <= 0; }
235
237 int clearArray(int len) override {
238 int len_available = available();
239 if (len > available()) {
240 reset();
241 return len_available;
242 }
243 current_read_pos += len;
244 len_available -= len;
245 memmove(buffer.data(), buffer.data() + current_read_pos, len_available);
246 current_read_pos = 0;
247 current_write_pos = len_available;
248
249 if (is_clear_with_zero) {
250 memset(buffer.data() + current_write_pos, 0,
251 buffer.size() - current_write_pos);
252 }
253
254 return len;
255 }
256
258 T *address() override { return buffer.data(); }
259
261 T *data() { return buffer.data() + current_read_pos; }
262
263 void reset() override {
264 current_read_pos = 0;
265 current_write_pos = 0;
266 if (is_clear_with_zero) {
267 memset(buffer.data(), 0, buffer.size());
268 }
269 }
270
273 size_t setAvailable(size_t available_size) {
274 size_t result = min(available_size, (size_t)buffer.size());
275 current_read_pos = 0;
276 current_write_pos = result;
277 return result;
278 }
279
280 size_t size() { return buffer.size(); }
281
282 void resize(int size) {
283 if (buffer.size() != size) {
284 TRACED();
285 buffer.resize(size);
286 }
287 }
288
290 void setClearWithZero(bool flag) { is_clear_with_zero = flag; }
291
292 protected:
293 int current_read_pos = 0;
294 int current_write_pos = 0;
295 bool owns_buffer = true;
296 bool is_clear_with_zero = false;
297 Vector<T> buffer{0};
298
299 void setWritePos(int pos) { current_write_pos = pos; }
300};
301
307template <typename T>
308class RingBuffer : public BaseBuffer<T> {
309 public:
310 RingBuffer(int size) {
311 resize(size);
312 reset();
313 }
314
315 bool read(T &result) override {
316 if (isEmpty()) {
317 return false;
318 }
319
320 result = _aucBuffer[_iTail];
321 _iTail = nextIndex(_iTail);
322 _numElems--;
323
324 return true;
325 }
326
327 // peeks the actual entry from the buffer
328 bool peek(T &result) override {
329 if (isEmpty()) {
330 return false;
331 }
332
333 result = _aucBuffer[_iTail];
334 return true;
335 }
336
337 virtual int peekArray(T *data, int n) {
338 if (isEmpty()) return -1;
339 int result = 0;
340 int count = _numElems;
341 int tail = _iTail;
342 for (int j = 0; j < n; j++) {
343 data[j] = _aucBuffer[tail];
344 tail = nextIndex(tail);
345 count--;
346 result++;
347 if (count == 0) break;
348 }
349 return result;
350 }
351
352 // checks if the buffer is full
353 virtual bool isFull() { return available() == max_size; }
354
355 bool isEmpty() { return available() == 0; }
356
357 // write add an entry to the buffer
358 virtual bool write(T data) {
359 bool result = false;
360 if (!isFull()) {
361 _aucBuffer[_iHead] = data;
362 _iHead = nextIndex(_iHead);
363 _numElems++;
364 result = true;
365 }
366 return result;
367 }
368
369 // clears the buffer
370 virtual void reset() {
371 _iHead = 0;
372 _iTail = 0;
373 _numElems = 0;
374 }
375
376 // provides the number of entries that are available to read
377 virtual int available() { return _numElems; }
378
379 // provides the number of entries that are available to write
380 virtual int availableForWrite() { return (max_size - _numElems); }
381
382 // returns the address of the start of the physical read buffer
383 virtual T *address() { return _aucBuffer.data(); }
384
385 virtual void resize(int len) {
386 if (max_size != len) {
387 LOGI("resize: %d", len);
388 _aucBuffer.resize(len);
389 max_size = len;
390 }
391 }
392
394 virtual size_t size() { return max_size; }
395
396 protected:
397 Vector<T> _aucBuffer;
398 int _iHead;
399 int _iTail;
400 int _numElems;
401 int max_size = 0;
402
403 int nextIndex(int index) { return (uint32_t)(index + 1) % max_size; }
404};
405
414template <class File, typename T>
415class RingBufferFile : public BaseBuffer<T> {
416 public:
417 RingBufferFile(int size) { resize(size); }
418 RingBufferFile(int size, File &file) {
419 resize(size);
420 begin(file);
421 }
423 if (p_file) p_file->close();
424 }
425
427 bool begin(File &bufferFile) {
428 if (bufferFile) {
429 p_file = &bufferFile;
430 } else {
431 LOGE("file is not valid");
432 }
433 return bufferFile;
434 }
435
437 bool read(T &result) override { return readArray(&result, 1) == 1; }
438
440 int readArray(T data[], int count) override {
441 if (p_file == nullptr) return 0;
442 int read_count = min(count, available());
443
444 OffsetInfo offset = getOffset(read_pos, read_count);
445 if (!file_seek(offset.pos)) return false;
446 int n = file_read(data, offset.len);
447 if (offset.len1 > 0) {
448 file_seek(0);
449 n += file_read(data + offset.len, offset.len1);
450 read_pos = offset.len1;
451 } else {
452 read_pos += read_count;
453 }
454 assert(n == read_count);
455 element_count -= read_count;
456 return read_count;
457 }
458
460 bool peek(T &result) override {
461 if (p_file == nullptr || isEmpty()) {
462 return false;
463 }
464
465 if (!file_seek(read_pos)) return false;
466 size_t count = file_read(&result, 1);
467 return count == 1;
468 }
469
471 int peekArray(T data[], int count) {
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 }
482 assert(n == read_count);
483 return read_count;
484 }
485
487 bool write(T data) override { return writeArray(&data, 1); }
488
490 int writeArray(const T data[], int len) override {
491 if (p_file == nullptr) return 0;
492
493 int write_count = min(len, availableForWrite());
494 OffsetInfo offset = getOffset(write_pos, write_count);
495
496 if (!file_seek(offset.pos)) return false;
497 int n = file_write(data, offset.len);
498 if (offset.len1 > 0) {
499 file_seek(0);
500 n += file_write(data + offset.len, offset.len1);
501 write_pos = offset.len1;
502 } else {
503 write_pos += write_count;
504 }
505 assert(n == write_count);
506 element_count += write_count;
507 return write_count;
508 }
509
511 bool isFull() override { return available() == max_size; }
512
513 bool isEmpty() { return available() == 0; }
514
516 void reset() override {
517 write_pos = 0;
518 read_pos = 0;
519 element_count = 0;
520 if (p_file != nullptr) file_seek(0);
521 }
522
524 int available() override { return element_count; }
525
527 int availableForWrite() override { return (max_size - element_count); }
528
530 size_t size() override { return max_size; }
531
533 void resize(int size) { max_size = size; }
534
535 // not supported
536 T *address() override { return nullptr; }
537
538 protected:
539 File *p_file = nullptr;
540 int write_pos = 0;
541 int read_pos = 0;
542 int element_count = 0;
543 int max_size = 0;
544
545 struct OffsetInfo {
546 int pos = 0; // start pos
547 int len = 0; // length of first part
548 int len1 = 0; // length of second part on overflow
549 };
550
553 OffsetInfo getOffset(int pos, int len) {
554 OffsetInfo result;
555 result.pos = pos;
556 int overflow = (pos + len) - max_size;
557 if (overflow <= 0) {
558 // we can write the complete data
559 result.len = len;
560 result.len1 = 0;
561 } else {
562 // we need to split the data
563 result.len = len - overflow;
564 result.len1 = overflow;
565 }
566 return result;
567 }
568
570 bool file_seek(int pos) {
571 int file_pos = pos * sizeof(T);
572 if (p_file->position() != file_pos) {
573 LOGD("file_seek: %d", pos);
574 if (!p_file->seek(file_pos)) {
575 LOGE("seek %d", file_pos);
576 return false;
577 }
578 }
579 return true;
580 }
581
583 int file_write(const T *data, int count) {
584 LOGD("file_write: %d", count);
585 if (p_file == nullptr) return 0;
586 int to_write = sizeof(T) * count;
587 int bytes_written = p_file->write((const uint8_t *)data, to_write);
588 p_file->flush();
589 int elements_written = bytes_written / sizeof(T);
590 if (bytes_written != to_write) {
591 LOGE("write: %d -> %d", to_write, bytes_written);
592 }
593 return elements_written;
594 }
595
597 int file_read(T *result, int count) {
598 LOGD("file_read: %d", count);
599 int read_bytes = count * sizeof(T);
600 int result_bytes = p_file->readBytes((char *)result, read_bytes);
601 int result_count = result_bytes / sizeof(T);
602 if (result_count != count) {
603 LOGE("readBytes: %d -> %d", read_bytes, result_bytes);
604 }
605 return result_count;
606 }
607};
608
616template <typename T>
617class NBuffer : public BaseBuffer<T> {
618 public:
619 NBuffer(int size, int count) { resize(size, count); }
620
621 virtual ~NBuffer() { freeMemory(); }
622
623 // reads an entry from the buffer
624 bool read(T &result) override {
625 if (available() == 0) return false;
626 return actual_read_buffer->read(result);
627 }
628
629 // peeks the actual entry from the buffer
630 bool peek(T &result) override {
631 if (available() == 0) return false;
632 return actual_read_buffer->peek(result);
633 }
634
635 // checks if the buffer is full
636 bool isFull() { return availableForWrite() == 0; }
637
638 // write add an entry to the buffer
639 bool write(T data) {
640 bool result = false;
641 if (actual_write_buffer == nullptr) {
642 actual_write_buffer = getNextAvailableBuffer();
643 }
644 if (actual_write_buffer != nullptr) {
645 result = actual_write_buffer->write(data);
646 // if buffer is full move to next available
647 if (actual_write_buffer->isFull()) {
648 addFilledBuffer(actual_write_buffer);
649 actual_write_buffer = getNextAvailableBuffer();
650 }
651 } else {
652 // Logger.debug("actual_write_buffer is full");
653 }
654
655 if (start_time == 0l) {
656 start_time = millis();
657 }
658 if (result) sample_count++;
659
660 return result;
661 }
662
663 // determines the available entries for the current read buffer
664 int available() {
665 if (actual_read_buffer == nullptr) {
666 actual_read_buffer = getNextFilledBuffer();
667 }
668 if (actual_read_buffer == nullptr) {
669 return 0;
670 }
671 int result = actual_read_buffer->available();
672 if (result == 0) {
673 // make current read buffer available again
674 resetCurrent();
675 result =
676 (actual_read_buffer == nullptr) ? 0 : actual_read_buffer->available();
677 }
678 return result;
679 }
680
681 // deterMINes the available entries for the write buffer
683 if (actual_write_buffer == nullptr) {
684 actual_write_buffer = getNextAvailableBuffer();
685 }
686 // if we used up all buffers - there is nothing available any more
687 if (actual_write_buffer == nullptr) {
688 return 0;
689 }
690 // check on actual buffer
691 if (actual_write_buffer->isFull()) {
692 // if buffer is full we move it to filled buffers ang get the next
693 // available
694 addFilledBuffer(actual_write_buffer);
695 actual_write_buffer = getNextAvailableBuffer();
696 }
697 return actual_write_buffer->availableForWrite();
698 }
699
700 // resets all buffers
701 void reset() {
702 TRACED();
703 while (actual_read_buffer != nullptr) {
704 actual_read_buffer->reset();
705 addAvailableBuffer(actual_read_buffer);
706 // get next read buffer
707 actual_read_buffer = getNextFilledBuffer();
708 }
709 }
710
711 // provides the actual sample rate
712 unsigned long sampleRate() {
713 unsigned long run_time = (millis() - start_time);
714 return run_time == 0 ? 0 : sample_count * 1000 / run_time;
715 }
716
717 // returns the address of the start of the phsical read buffer
718 T *address() {
719 return actual_read_buffer == nullptr ? nullptr
720 : actual_read_buffer->address();
721 }
722
723 // Alternative interface using address: the current buffer has been filled
724 BaseBuffer<T> &writeEnd() {
725 if (actual_write_buffer != nullptr) {
726 actual_write_buffer->setWritePos(buffer_size);
727 addFilledBuffer(actual_write_buffer);
728 }
729 actual_write_buffer = getNextAvailableBuffer();
730 return *actual_write_buffer;
731 }
732
733 // Alternative interface using address: marks actual buffer as processed and
734 // provides access to next read buffer
735 BaseBuffer<T> &readEnd() {
736 // make current read buffer available again
737 resetCurrent();
738 return *actual_read_buffer;
739 }
740
741 virtual int bufferCountFilled() { return filled_buffers.size(); }
742
743 virtual int bufferCountEmpty() { return available_buffers.size(); }
744
745 virtual void resize(int size, int count) {
746 if (buffer_size == size && buffer_count == count) return;
747 freeMemory();
748 filled_buffers.resize(count);
749 available_buffers.resize(count);
750 // filled_buffers.clear();
751 // available_buffers.clear();
752
753 buffer_count = count;
754 buffer_size = size;
755 for (int j = 0; j < count; j++) {
756 BaseBuffer<T> *buffer = new SingleBuffer<T>(size);
757 LOGD("new buffer %p", buffer);
758 available_buffers.enqueue(buffer);
759 }
760 }
761
762 size_t size() { return buffer_size * buffer_count; }
763
764 protected:
765 int buffer_size = 0;
766 uint16_t buffer_count = 0;
767 BaseBuffer<T> *actual_read_buffer = nullptr;
768 BaseBuffer<T> *actual_write_buffer = nullptr;
769 QueueFromVector<BaseBuffer<T> *> available_buffers{0, nullptr};
770 QueueFromVector<BaseBuffer<T> *> filled_buffers{0, nullptr};
771 // Queue<BaseBuffer<T> *> available_buffers;
772 // Queue<BaseBuffer<T> *> filled_buffers;
773 unsigned long start_time = 0;
774 unsigned long sample_count = 0;
775
776 // empty constructor only allowed by subclass
777 NBuffer() = default;
778
779 void freeMemory() {
780 if (actual_write_buffer) {
781 LOGD("deleting %p", actual_write_buffer);
782 delete actual_write_buffer;
783 actual_write_buffer = nullptr;
784 }
785 if (actual_read_buffer) {
786 LOGD("deleting %p", actual_read_buffer);
787 delete actual_read_buffer;
788 actual_read_buffer = nullptr;
789 }
790
791 BaseBuffer<T> *ptr = getNextAvailableBuffer();
792 while (ptr != nullptr) {
793 LOGD("deleting %p", ptr);
794 delete ptr;
795 ptr = getNextAvailableBuffer();
796 }
797
798 ptr = getNextFilledBuffer();
799 while (ptr != nullptr) {
800 LOGD("deleting %p", ptr);
801 delete ptr;
802 ptr = getNextFilledBuffer();
803 }
804 }
805
806 void resetCurrent() {
807 if (actual_read_buffer != nullptr) {
808 actual_read_buffer->reset();
809 addAvailableBuffer(actual_read_buffer);
810 }
811 // get next read buffer
812 actual_read_buffer = getNextFilledBuffer();
813 }
814
815 virtual BaseBuffer<T> *getNextAvailableBuffer() {
816 if (available_buffers.empty()) return nullptr;
817 BaseBuffer<T> *result = nullptr;
818 available_buffers.dequeue(result);
819 return result;
820 }
821
822 virtual bool addAvailableBuffer(BaseBuffer<T> *buffer) {
823 return available_buffers.enqueue(buffer);
824 }
825
826 virtual BaseBuffer<T> *getNextFilledBuffer() {
827 if (filled_buffers.empty()) return nullptr;
828 BaseBuffer<T> *result = nullptr;
829 filled_buffers.dequeue(result);
830 return result;
831 }
832
833 virtual bool addFilledBuffer(BaseBuffer<T> *buffer) {
834 return filled_buffers.enqueue(buffer);
835 }
836};
837
838/***
839 * @brief A File backed buffer which uses the provided files for buffering with
840 * the indicated max size. A file is made available for reading as soon as it
841 * reached the size limit. You must provide the files opened in "Write" mode with the
842 * addFile() method!
843 * @ingroup buffers
844 * @tparam File: file class
845 * @tparam T: buffered data type
846 */
847template <class File, typename T>
848class NBufferFile : public BaseBuffer<T> {
849 public:
851 NBufferFile(int fileSize) { number_of_objects_per_file = fileSize; }
854
856 const char *nextFileName() {
857 next_file_name.set("buffer-");
858 char number[40];
859 snprintf(number, 40, "%d", file_count);
860 next_file_name.add(number);
861 next_file_name.add(".tmp");
862 return next_file_name.c_str();
863 }
864
867 bool addFile(File &file) {
868 if (!file) return false;
869 empty_files.enqueue(file);
870 file_count++;
871 return true;
872 }
873
874 bool read(T &result) override { return readArray(&result, 1) == 1; }
875
876 int readArray(T data[], int len) override {
877 // make sure we have a read file
878 if (!read_file) {
879 if (!filled_files.dequeue(read_file)) {
880 // no more data
881 return 0;
882 }
883 read_file.seek(0);
884 }
885 // read the data
886 int result = read_file.readBytes((char *)data, len * sizeof(T)) / sizeof(T);
887
888 // if we have consumed all content
889 if (result < len) {
890 read_file.seek(0);
891 empty_files.enqueue(read_file);
892 read_file = empty;
893 }
894 return result;
895 }
896
897 bool peek(T &data) override {
898 size_t pos = read_file.position();
899 bool result = read(data);
900 read_file.seek(pos);
901 return result;
902 }
903
904 bool write(T sample) override { return writeArray(&sample, 1) == 1; }
905
906 int writeArray(const T data[], int len) override {
907 if (!write_file || write_file.size() + len > number_of_objects_per_file) {
908 // moved to filled files
909 if (write_file) {
910 write_file.seek(0);
911 filled_files.enqueue(write_file);
912 }
913 // get next empty file
914 if (!empty_files.dequeue(write_file)) return false;
915 }
916 int result = write_file.write((uint8_t *)data, len * sizeof(T));
917 return result / sizeof(T);
918 }
919
920 int available() override {
921 return filled_files.size() * number_of_objects_per_file +
922 (read_file.available() / sizeof(T));
923 }
924
925 // provides the number of entries that are available to write
926 int availableForWrite() override {
927 int open_current =
928 number_of_objects_per_file - (write_file.available() / sizeof(T));
929 return empty_files.size() * number_of_objects_per_file +
930 write_file.available() + open_current;
931 }
932
933 size_t size() override { return number_of_objects_per_file * file_count; }
934
936 void end() {
937 cleanupFile(read_file);
938 cleanupFile(write_file);
939 File file;
940 while (empty_files.dequeue(file)) cleanupFile(file);
941 while (filled_files.dequeue(file)) cleanupFile(file);
942 }
943
945 void setFileDeleteCallback(void (*cb)(const char *filename)) {
946 file_delete_callback = cb;
947 }
948
949 void reset() {
950 if (read_file) {
951 read_file.seek(0);
952 empty_files.enqueue(read_file);
953 read_file = empty;
954 }
955 if (write_file) {
956 write_file.seek(0);
957 empty_files.enqueue(write_file);
958 write_file = empty;
959 }
960 File file;
961 while (filled_files.dequeue(file)) {
962 file.seek(0);
963 empty_files.enqueue(file);
964 }
965 }
967 T *address() { return nullptr; }
968
969 protected:
970 Queue<File> empty_files;
971 Queue<File> filled_files;
972 File read_file;
973 File write_file;
974 File empty;
975 int number_of_objects_per_file = 0; // number of objects per file
976 int file_count = 0; // number of files
977 const uint16_t max_file_name = 256;
978 Str next_file_name;
979 void (*file_delete_callback)(const char *filename);
980
981 void cleanupFile(File &file) {
982 if (!file) return;
983 // after close the file name is gone
984 int len = strlen(file.name());
985 char file_name[len + 1];
986 strncpy(file_name, file.name(), len);
987 file.close();
988 file_delete_callback(file_name);
989 }
990};
991
1001template <typename T>
1003 public:
1004 BufferedArray(Stream &input, int len) {
1005 LOGI("BufferedArray(%d)", len);
1006 array.resize(len);
1007 p_stream = &input;
1008 }
1009 // access values, the offset and length are specified in samples of type <T>
1010 int16_t *getValues(size_t offset, size_t length) {
1011 LOGD("getValues(%d,%d) - max %d", offset, length, array.size());
1012 if (offset == 0) {
1013 // we restart at the beginning
1014 last_end = 0;
1015 actual_end = length;
1016 } else {
1017 // if first position is at end we do not want to read the full buffer
1018 last_end = actual_end >= 0 ? actual_end : offset;
1019 // increase actual end if bigger then old
1020 actual_end = offset + length > actual_end ? offset + length : actual_end;
1021 }
1022 int size = actual_end - last_end;
1023 if (size > 0) {
1024 LOGD("readBytes(%d,%d)", last_end, size);
1025 assert(last_end + size <= array.size());
1026 p_stream->readBytes((uint8_t *)(&array[last_end]), size * 2);
1027 }
1028 assert(offset < actual_end);
1029 return &array[offset];
1030 }
1031
1032 protected:
1033 int actual_end = -1;
1034 int last_end = 0;
1035 Vector<T> array;
1036 Stream *p_stream = nullptr;
1037};
1038
1039} // namespace audio_tools
Shared functionality of all buffers.
Definition Buffers.h:26
virtual bool read(T &result)=0
reads a single value
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:37
virtual void reset()=0
clears the buffer
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:59
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:76
virtual int clearArray(int len)
Removes the next len entries.
Definition Buffers.h:51
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:88
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:113
void clear()
same as reset
Definition Buffers.h:99
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
Class which is usfull ot provide incremental data access e.g. for EdgeImpulse which request data with...
Definition Buffers.h:1002
Definition Buffers.h:130
int readFrames(T data[][2], int len)
reads multiple values for array of 2 dimensional frames
Definition Buffers.h:134
Definition Buffers.h:848
const char * nextFileName()
Determines the next unique file name (after calling addFile)
Definition Buffers.h:856
void setFileDeleteCallback(void(*cb)(const char *filename))
Define the file delete operation.
Definition Buffers.h:945
bool peek(T &data) override
peeks the actual entry from the buffer
Definition Buffers.h:897
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:904
~NBufferFile()
RAII close the files.
Definition Buffers.h:853
bool read(T &result) override
reads a single value
Definition Buffers.h:874
int available() override
provides the number of entries that are available to read
Definition Buffers.h:920
bool addFile(File &file)
Definition Buffers.h:867
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:926
NBufferFile(int fileSize)
Provide the file size in objects!
Definition Buffers.h:851
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:906
void end()
clean up files
Definition Buffers.h:936
void reset()
clears the buffer
Definition Buffers.h:949
T * address()
not supported
Definition Buffers.h:967
int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:876
A lock free N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:617
bool isFull()
checks if the buffer is full
Definition Buffers.h:636
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:630
int available()
provides the number of entries that are available to read
Definition Buffers.h:664
bool read(T &result) override
reads a single value
Definition Buffers.h:624
bool write(T data)
write add an entry to the buffer
Definition Buffers.h:639
int availableForWrite()
provides the number of entries that are available to write
Definition Buffers.h:682
void reset()
clears the buffer
Definition Buffers.h:701
T * address()
returns the address of the start of the physical read buffer
Definition Buffers.h:718
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:415
int readArray(T data[], int count) override
reads multiple values
Definition Buffers.h:440
size_t size() override
Provides the capacity.
Definition Buffers.h:530
int peekArray(T data[], int count)
gets multiple values w/o removing them
Definition Buffers.h:471
int file_write(const T *data, int count)
Reed the indicated number of objects.
Definition Buffers.h:583
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:460
bool read(T &result) override
Reads a single value from the buffer.
Definition Buffers.h:437
bool write(T data) override
write add a single entry to the buffer
Definition Buffers.h:487
int available() override
provides the number of entries that are available to read
Definition Buffers.h:524
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:527
T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:536
bool isFull() override
checks if the buffer is full
Definition Buffers.h:511
bool begin(File &bufferFile)
Assigns the p_file to be used.
Definition Buffers.h:427
bool file_seek(int pos)
Seeks to the given object position.
Definition Buffers.h:570
int writeArray(const T data[], int len) override
Fills the data from the buffer.
Definition Buffers.h:490
int file_read(T *result, int count)
Writes the indicated number of objects.
Definition Buffers.h:597
OffsetInfo getOffset(int pos, int len)
Definition Buffers.h:553
void resize(int size)
Defines the capacity.
Definition Buffers.h:533
void reset() override
clears the buffer
Definition Buffers.h:516
Implements a typed Ringbuffer.
Definition Buffers.h:308
virtual T * address()
returns the address of the start of the physical read buffer
Definition Buffers.h:383
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:328
virtual int availableForWrite()
provides the number of entries that are available to write
Definition Buffers.h:380
virtual int available()
provides the number of entries that are available to read
Definition Buffers.h:377
bool read(T &result) override
reads a single value
Definition Buffers.h:315
virtual bool write(T data)
write add an entry to the buffer
Definition Buffers.h:358
virtual void reset()
clears the buffer
Definition Buffers.h:370
virtual size_t size()
Returns the maximum capacity of the buffer.
Definition Buffers.h:394
virtual bool isFull()
checks if the buffer is full
Definition Buffers.h:353
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:175
size_t setAvailable(size_t available_size)
Definition Buffers.h:273
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:200
SingleBuffer(int size)
Construct a new Single Buffer object.
Definition Buffers.h:182
void setClearWithZero(bool flag)
Sets the buffer to 0 on clear.
Definition Buffers.h:290
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:218
bool read(T &result) override
reads a single value
Definition Buffers.h:209
int available() override
provides the number of entries that are available to read
Definition Buffers.h:227
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:232
T * address() override
Provides address to beginning of the buffer.
Definition Buffers.h:258
bool isFull() override
checks if the buffer is full
Definition Buffers.h:234
void onExternalBufferRefilled(void *data, int len)
notifies that the external buffer has been refilled
Definition Buffers.h:193
SingleBuffer()
Construct a new Single Buffer w/o allocating any memory.
Definition Buffers.h:190
T * data()
Provides address of actual data.
Definition Buffers.h:261
void reset() override
clears the buffer
Definition Buffers.h:263
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:237
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