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
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};
116
117/***
118 * @brief A FrameBuffer reads multiple values for array of 2 dimensional frames
119 */
120template <typename T>
122 public:
123 FrameBuffer(BaseBuffer<T> &buffer) { p_buffer = &buffer; }
125 int readFrames(T data[][2], int len) {
126 LOGD("%s: %d", LOG_METHOD, len);
127 // CHECK_MEMORY();
128 int result = min(len, p_buffer->available());
129 for (int j = 0; j < result; j++) {
130 T sample = 0;
131 p_buffer->read(sample);
132 data[j][0] = sample;
133 data[j][1] = sample;
134 }
135 // CHECK_MEMORY();
136 return result;
137 }
138
139 template <int rows, int channels>
140 int readFrames(T (&data)[rows][channels]) {
141 int lenResult = min(rows, p_buffer->available());
142 for (int j = 0; j < lenResult; j++) {
143 T sample = 0;
144 p_buffer->read(sample);
145 for (int i = 0; i < channels; i++) {
146 // data[j][i] = htons(sample);
147 data[j][i] = sample;
148 }
149 }
150 return lenResult;
151 }
152
153 protected:
154 BaseBuffer<T> *p_buffer = nullptr;
155};
156
165template <typename T>
166class SingleBuffer : public BaseBuffer<T> {
167 public:
173 SingleBuffer(int size) {
174 buffer.resize(size);
175 reset();
176 }
177
182
184 void onExternalBufferRefilled(void *data, int len) {
185 this->owns_buffer = false;
186 this->buffer = (uint8_t *)data;
187 this->current_read_pos = 0;
188 this->current_write_pos = len;
189 }
190
191 int writeArray(const T data[], int len) override {
192 if (size() == 0) resize(len);
193 return BaseBuffer<T>::writeArray(data, len);
194 }
195
196 bool write(T sample) override {
197 bool result = false;
198 if (current_write_pos < buffer.size()) {
199 buffer[current_write_pos++] = sample;
200 result = true;
201 }
202 return result;
203 }
204
205 bool read(T &result) override {
206 bool success = false;
207 if (current_read_pos < current_write_pos) {
208 result = buffer[current_read_pos++];
209 success = true;
210 }
211 return success;
212 }
213
214 bool peek(T &result) override {
215 bool success = false;
216 if (current_read_pos < current_write_pos) {
217 result = buffer[current_read_pos];
218 success = true;
219 }
220 return success;
221 }
222
223 int available() override {
224 int result = current_write_pos - current_read_pos;
225 return max(result, 0);
226 }
227
228 int availableForWrite() override { return buffer.size() - current_write_pos; }
229
230 bool isFull() override { return availableForWrite() <= 0; }
231
233 int clearArray(int len) override {
234 int len_available = available();
235 if (len > available()) {
236 reset();
237 return len_available;
238 }
239 current_read_pos += len;
240 len_available -= len;
241 memmove(buffer.data(), buffer.data() + current_read_pos, len_available);
242 current_read_pos = 0;
243 current_write_pos = len_available;
244
245 if (is_clear_with_zero) {
246 memset(buffer.data() + current_write_pos, 0,
247 buffer.size() - current_write_pos);
248 }
249
250 return len;
251 }
252
254 T *address() override { return buffer.data(); }
255
257 T *data() { return buffer.data() + current_read_pos; }
258
259 void reset() override {
260 current_read_pos = 0;
261 current_write_pos = 0;
262 if (is_clear_with_zero) {
263 memset(buffer.data(), 0, buffer.size());
264 }
265 }
266
269 size_t setAvailable(size_t available_size) {
270 size_t result = min(available_size, (size_t)buffer.size());
271 current_read_pos = 0;
272 current_write_pos = result;
273 return result;
274 }
275
276 size_t size() override { return buffer.size(); }
277
278 void resize(int size) {
279 if (buffer.size() != size) {
280 TRACED();
281 buffer.resize(size);
282 }
283 }
284
286 void setClearWithZero(bool flag) { is_clear_with_zero = flag; }
287
289 void setWritePos(int pos) { current_write_pos = pos; }
290
292 int id = 0;
294 bool active = true;
296 uint64_t timestamp = 0;
297
298 protected:
299 int current_read_pos = 0;
300 int current_write_pos = 0;
301 bool owns_buffer = true;
302 bool is_clear_with_zero = false;
303 Vector<T> buffer{0};
304};
305
311template <typename T>
312class RingBuffer : public BaseBuffer<T> {
313 public:
314 RingBuffer(int size) {
315 resize(size);
316 reset();
317 }
318
319 bool read(T &result) override {
320 if (isEmpty()) {
321 return false;
322 }
323
324 result = _aucBuffer[_iTail];
325 _iTail = nextIndex(_iTail);
326 _numElems--;
327
328 return true;
329 }
330
331 // peeks the actual entry from the buffer
332 bool peek(T &result) override {
333 if (isEmpty()) {
334 return false;
335 }
336
337 result = _aucBuffer[_iTail];
338 return true;
339 }
340
341 virtual int peekArray(T *data, int n) {
342 if (isEmpty()) return -1;
343 int result = 0;
344 int count = _numElems;
345 int tail = _iTail;
346 for (int j = 0; j < n; j++) {
347 data[j] = _aucBuffer[tail];
348 tail = nextIndex(tail);
349 count--;
350 result++;
351 if (count == 0) break;
352 }
353 return result;
354 }
355
356 // checks if the buffer is full
357 virtual bool isFull() override { return available() == max_size; }
358
359 bool isEmpty() { return available() == 0; }
360
361 // write add an entry to the buffer
362 virtual bool write(T data) override {
363 bool result = false;
364 if (!isFull()) {
365 _aucBuffer[_iHead] = data;
366 _iHead = nextIndex(_iHead);
367 _numElems++;
368 result = true;
369 }
370 return result;
371 }
372
373 // clears the buffer
374 virtual void reset() override {
375 _iHead = 0;
376 _iTail = 0;
377 _numElems = 0;
378 }
379
380 // provides the number of entries that are available to read
381 virtual int available() override { return _numElems; }
382
383 // provides the number of entries that are available to write
384 virtual int availableForWrite() override { return (max_size - _numElems); }
385
386 // returns the address of the start of the physical read buffer
387 virtual T *address() override { return _aucBuffer.data(); }
388
389 virtual void resize(int len) {
390 if (max_size != len) {
391 LOGI("resize: %d", len);
392 _aucBuffer.resize(len);
393 max_size = len;
394 }
395 }
396
398 virtual size_t size() override { return max_size; }
399
400 protected:
401 Vector<T> _aucBuffer;
402 int _iHead;
403 int _iTail;
404 int _numElems;
405 int max_size = 0;
406
407 int nextIndex(int index) { return (uint32_t)(index + 1) % max_size; }
408};
409
418template <class File, typename T>
419class RingBufferFile : public BaseBuffer<T> {
420 public:
421 RingBufferFile(int size) { resize(size); }
422 RingBufferFile(int size, File &file) {
423 resize(size);
424 begin(file);
425 }
427 if (p_file) p_file->close();
428 }
429
431 bool begin(File &bufferFile) {
432 if (bufferFile) {
433 p_file = &bufferFile;
434 } else {
435 LOGE("file is not valid");
436 }
437 return bufferFile;
438 }
439
441 bool read(T &result) override { return readArray(&result, 1) == 1; }
442
444 int readArray(T data[], int count) override {
445 if (p_file == nullptr) return 0;
446 int read_count = min(count, available());
447
448 OffsetInfo offset = getOffset(read_pos, read_count);
449 if (!file_seek(offset.pos)) return false;
450 int n = file_read(data, offset.len);
451 if (offset.len1 > 0) {
452 file_seek(0);
453 n += file_read(data + offset.len, offset.len1);
454 read_pos = offset.len1;
455 } else {
456 read_pos += read_count;
457 }
458 assert(n == read_count);
459 element_count -= read_count;
460 return read_count;
461 }
462
464 bool peek(T &result) override {
465 if (p_file == nullptr || isEmpty()) {
466 return false;
467 }
468
469 if (!file_seek(read_pos)) return false;
470 size_t count = file_read(&result, 1);
471 return count == 1;
472 }
473
475 int peekArray(T data[], int count) {
476 if (p_file == nullptr) return 0;
477 int read_count = min(count, available());
478
479 OffsetInfo offset = getOffset(read_pos, read_count);
480 if (!file_seek(offset.pos)) return false;
481 int n = file_read(data, offset.len);
482 if (offset.len1 > 0) {
483 file_seek(0);
484 n += file_read(data + offset.len, offset.len1);
485 }
486 assert(n == read_count);
487 return read_count;
488 }
489
491 bool write(T data) override { return writeArray(&data, 1); }
492
494 int writeArray(const T data[], int len) override {
495 if (p_file == nullptr) return 0;
496
497 int write_count = min(len, availableForWrite());
498 OffsetInfo offset = getOffset(write_pos, write_count);
499
500 if (!file_seek(offset.pos)) return false;
501 int n = file_write(data, offset.len);
502 if (offset.len1 > 0) {
503 file_seek(0);
504 n += file_write(data + offset.len, offset.len1);
505 write_pos = offset.len1;
506 } else {
507 write_pos += write_count;
508 }
509 assert(n == write_count);
510 element_count += write_count;
511 return write_count;
512 }
513
515 bool isFull() override { return available() == max_size; }
516
517 bool isEmpty() { return available() == 0; }
518
520 void reset() override {
521 write_pos = 0;
522 read_pos = 0;
523 element_count = 0;
524 if (p_file != nullptr) file_seek(0);
525 }
526
528 int available() override { return element_count; }
529
531 int availableForWrite() override { return (max_size - element_count); }
532
534 size_t size() override { return max_size; }
535
537 void resize(int size) { max_size = size; }
538
539 // not supported
540 T *address() override { return nullptr; }
541
542 protected:
543 File *p_file = nullptr;
544 int write_pos = 0;
545 int read_pos = 0;
546 int element_count = 0;
547 int max_size = 0;
548
549 struct OffsetInfo {
550 int pos = 0; // start pos
551 int len = 0; // length of first part
552 int len1 = 0; // length of second part on overflow
553 };
554
557 OffsetInfo getOffset(int pos, int len) {
558 OffsetInfo result;
559 result.pos = pos;
560 int overflow = (pos + len) - max_size;
561 if (overflow <= 0) {
562 // we can write the complete data
563 result.len = len;
564 result.len1 = 0;
565 } else {
566 // we need to split the data
567 result.len = len - overflow;
568 result.len1 = overflow;
569 }
570 return result;
571 }
572
574 bool file_seek(int pos) {
575 int file_pos = pos * sizeof(T);
576 if (p_file->position() != file_pos) {
577 LOGD("file_seek: %d", pos);
578 if (!p_file->seek(file_pos)) {
579 LOGE("seek %d", file_pos);
580 return false;
581 }
582 }
583 return true;
584 }
585
587 int file_write(const T *data, int count) {
588 LOGD("file_write: %d", count);
589 if (p_file == nullptr) return 0;
590 int to_write = sizeof(T) * count;
591 int bytes_written = p_file->write((const uint8_t *)data, to_write);
592 p_file->flush();
593 int elements_written = bytes_written / sizeof(T);
594 if (bytes_written != to_write) {
595 LOGE("write: %d -> %d", to_write, bytes_written);
596 }
597 return elements_written;
598 }
599
601 int file_read(T *result, int count) {
602 LOGD("file_read: %d", count);
603 int read_bytes = count * sizeof(T);
604 int result_bytes = p_file->readBytes((char *)result, read_bytes);
605 int result_count = result_bytes / sizeof(T);
606 if (result_count != count) {
607 LOGE("readBytes: %d -> %d", read_bytes, result_bytes);
608 }
609 return result_count;
610 }
611};
612
620template <typename T>
621class NBuffer : public BaseBuffer<T> {
622 public:
623 NBuffer(int size, int count) { resize(size, count); }
624
625 virtual ~NBuffer() { freeMemory(); }
626
628 bool read(T &result) override {
629 if (available() == 0) return false;
630 return actual_read_buffer->read(result);
631 }
632
634 bool peek(T &result) override {
635 if (available() == 0) return false;
636 return actual_read_buffer->peek(result);
637 }
638
640 bool isFull() { return availableForWrite() == 0; }
641
643 bool write(T data) {
644 bool result = false;
645 if (actual_write_buffer == nullptr) {
646 actual_write_buffer = getNextAvailableBuffer();
647 }
648 if (actual_write_buffer != nullptr) {
649 result = actual_write_buffer->write(data);
650 // if buffer is full move to next available
651 if (actual_write_buffer->isFull()) {
652 addFilledBuffer(actual_write_buffer);
653 actual_write_buffer = getNextAvailableBuffer();
654 }
655 }
656
657 if (start_time == 0l) {
658 start_time = millis();
659 }
660 if (result) sample_count++;
661
662 return result;
663 }
664
666 int available() {
667 if (actual_read_buffer == nullptr) {
668 actual_read_buffer = getNextFilledBuffer();
669 }
670 if (actual_read_buffer == nullptr) {
671 return 0;
672 }
673 int result = actual_read_buffer->available();
674 if (result == 0) {
675 // make current read buffer available again
676 resetCurrent();
677 result =
678 (actual_read_buffer == nullptr) ? 0 : actual_read_buffer->available();
679 }
680 return result;
681 }
682
685 if (actual_write_buffer == nullptr) {
686 actual_write_buffer = getNextAvailableBuffer();
687 }
688 // if we used up all buffers - there is nothing available any more
689 if (actual_write_buffer == nullptr) {
690 return 0;
691 }
692 // check on actual buffer
693 if (actual_write_buffer->isFull()) {
694 // if buffer is full we move it to filled buffers ang get the next
695 // available
696 addFilledBuffer(actual_write_buffer);
697 actual_write_buffer = getNextAvailableBuffer();
698 }
699 return actual_write_buffer->availableForWrite();
700 }
701
703 void reset() {
704 TRACED();
705 while (actual_read_buffer != nullptr) {
706 actual_read_buffer->reset();
707 addAvailableBuffer(actual_read_buffer);
708 // get next read buffer
709 actual_read_buffer = getNextFilledBuffer();
710 }
711 }
712
714 unsigned long sampleRate() {
715 unsigned long run_time = (millis() - start_time);
716 return run_time == 0 ? 0 : sample_count * 1000 / run_time;
717 }
718
720 T *address() {
721 return actual_read_buffer == nullptr ? nullptr
722 : actual_read_buffer->address();
723 }
724
726 virtual int bufferCountFilled() { return filled_buffers.size(); }
727
729 virtual int bufferCountEmpty() { return available_buffers.size(); }
730
732 virtual void resize(int size, int count) {
733 if (buffer_size == size && buffer_count == count) return;
734 freeMemory();
735 filled_buffers.resize(count);
736 available_buffers.resize(count);
737 // filled_buffers.clear();
738 // available_buffers.clear();
739
740 buffer_count = count;
741 buffer_size = size;
742 for (int j = 0; j < count; j++) {
743 BaseBuffer<T> *buffer = new SingleBuffer<T>(size);
744 LOGD("new buffer %p", buffer);
745 available_buffers.enqueue(buffer);
746 }
747 }
748
750 size_t size() { return buffer_size * buffer_count; }
751
752 protected:
753 int buffer_size = 0;
754 uint16_t buffer_count = 0;
755 BaseBuffer<T> *actual_read_buffer = nullptr;
756 BaseBuffer<T> *actual_write_buffer = nullptr;
757 QueueFromVector<BaseBuffer<T> *> available_buffers{0, nullptr};
758 QueueFromVector<BaseBuffer<T> *> filled_buffers{0, nullptr};
759 unsigned long start_time = 0;
760 unsigned long sample_count = 0;
761
763 NBuffer() = default;
764
765 void freeMemory() {
766 if (actual_write_buffer) {
767 LOGD("deleting %p", actual_write_buffer);
768 delete actual_write_buffer;
769 actual_write_buffer = nullptr;
770 }
771 if (actual_read_buffer) {
772 LOGD("deleting %p", actual_read_buffer);
773 delete actual_read_buffer;
774 actual_read_buffer = nullptr;
775 }
776
777 BaseBuffer<T> *ptr = getNextAvailableBuffer();
778 while (ptr != nullptr) {
779 LOGD("deleting %p", ptr);
780 delete ptr;
781 ptr = getNextAvailableBuffer();
782 }
783
784 ptr = getNextFilledBuffer();
785 while (ptr != nullptr) {
786 LOGD("deleting %p", ptr);
787 delete ptr;
788 ptr = getNextFilledBuffer();
789 }
790 }
791
792 void resetCurrent() {
793 if (actual_read_buffer != nullptr) {
794 actual_read_buffer->reset();
795 addAvailableBuffer(actual_read_buffer);
796 }
797 // get next read buffer
798 actual_read_buffer = getNextFilledBuffer();
799 }
800
801 virtual BaseBuffer<T> *getNextAvailableBuffer() {
802 if (available_buffers.empty()) return nullptr;
803 BaseBuffer<T> *result = nullptr;
804 available_buffers.dequeue(result);
805 return result;
806 }
807
808 virtual bool addAvailableBuffer(BaseBuffer<T> *buffer) {
809 return available_buffers.enqueue(buffer);
810 }
811
812 virtual BaseBuffer<T> *getNextFilledBuffer() {
813 if (filled_buffers.empty()) return nullptr;
814 BaseBuffer<T> *result = nullptr;
815 filled_buffers.dequeue(result);
816 return result;
817 }
818
819 virtual bool addFilledBuffer(BaseBuffer<T> *buffer) {
820 return filled_buffers.enqueue(buffer);
821 }
822};
823
830template <typename T>
831class NBufferExt : public NBuffer<T> {
832 public:
833 NBufferExt(int size, int count) { resize(size, count); }
834
838 actual_write_buffer = getNextAvailableBuffer();
839 if (actual_write_buffer != nullptr) {
840 addFilledBuffer(actual_write_buffer);
841 }
842 return (SingleBuffer<T> *)actual_write_buffer;
843 }
844
847 // make current read buffer available again
848 resetCurrent();
849 return (SingleBuffer<T> *)actual_read_buffer;
850 }
851
854 for (auto &buffer : this->filled_buffers.toVector()) {
855 SingleBuffer<T>* sbuffer = (SingleBuffer<T> *)&buffer;
856 if (sbuffer->id == id) {
857 return sbuffer;
858 }
859 }
860 return nullptr;
861 }
862
863 using NBuffer<T>::resize;
864
865 protected:
866 using NBuffer<T>::resetCurrent;
867 using NBuffer<T>::addFilledBuffer;
868 using NBuffer<T>::getNextAvailableBuffer;
869 using NBuffer<T>::actual_write_buffer;
870 using NBuffer<T>::actual_read_buffer;
871 using NBuffer<T>::buffer_size;
872};
873
874/***
875 * @brief A File backed buffer which uses the provided files for buffering with
876 * the indicated max size. A file is made available for reading as soon as it
877 * reached the size limit. You must provide the files opened in "Write" mode
878 * with the addFile() method!
879 * @ingroup buffers
880 * @tparam File: file class
881 * @tparam T: buffered data type
882 */
883template <class File, typename T>
884class NBufferFile : public BaseBuffer<T> {
885 public:
887 NBufferFile(int fileSize) { number_of_objects_per_file = fileSize; }
890
892 const char *nextFileName() {
893 next_file_name.set("buffer-");
894 char number[40];
895 snprintf(number, 40, "%d", file_count);
896 next_file_name.add(number);
897 next_file_name.add(".tmp");
898 return next_file_name.c_str();
899 }
900
903 bool addFile(File &file) {
904 if (!file) return false;
905 empty_files.enqueue(file);
906 file_count++;
907 return true;
908 }
909
910 bool read(T &result) override { return readArray(&result, 1) == 1; }
911
912 int readArray(T data[], int len) override {
913 // make sure we have a read file
914 if (!read_file) {
915 if (!filled_files.dequeue(read_file)) {
916 // no more data
917 return 0;
918 }
919 read_file.seek(0);
920 }
921 // read the data
922 int result = read_file.readBytes((char *)data, len * sizeof(T)) / sizeof(T);
923
924 // if we have consumed all content
925 if (result < len) {
926 read_file.seek(0);
927 empty_files.enqueue(read_file);
928 read_file = empty;
929 }
930 return result;
931 }
932
933 bool peek(T &data) override {
934 size_t pos = read_file.position();
935 bool result = read(data);
936 read_file.seek(pos);
937 return result;
938 }
939
940 bool write(T sample) override { return writeArray(&sample, 1) == 1; }
941
942 int writeArray(const T data[], int len) override {
943 if (!write_file || write_file.size() + len > number_of_objects_per_file) {
944 // moved to filled files
945 if (write_file) {
946 write_file.seek(0);
947 filled_files.enqueue(write_file);
948 }
949 // get next empty file
950 if (!empty_files.dequeue(write_file)) return false;
951 }
952 int result = write_file.write((uint8_t *)data, len * sizeof(T));
953 return result / sizeof(T);
954 }
955
956 int available() override {
957 return filled_files.size() * number_of_objects_per_file +
958 (read_file.available() / sizeof(T));
959 }
960
961 // provides the number of entries that are available to write
962 int availableForWrite() override {
963 int open_current =
964 number_of_objects_per_file - (write_file.available() / sizeof(T));
965 return empty_files.size() * number_of_objects_per_file +
966 write_file.available() + open_current;
967 }
968
969 size_t size() override { return number_of_objects_per_file * file_count; }
970
972 void end() {
973 cleanupFile(read_file);
974 cleanupFile(write_file);
975 File file;
976 while (empty_files.dequeue(file)) cleanupFile(file);
977 while (filled_files.dequeue(file)) cleanupFile(file);
978 }
979
981 void setFileDeleteCallback(void (*cb)(const char *filename)) {
982 file_delete_callback = cb;
983 }
984
985 void reset() {
986 if (read_file) {
987 read_file.seek(0);
988 empty_files.enqueue(read_file);
989 read_file = empty;
990 }
991 if (write_file) {
992 write_file.seek(0);
993 empty_files.enqueue(write_file);
994 write_file = empty;
995 }
996 File file;
997 while (filled_files.dequeue(file)) {
998 file.seek(0);
999 empty_files.enqueue(file);
1000 }
1001 }
1003 T *address() { return nullptr; }
1004
1005 protected:
1006 Queue<File> empty_files;
1007 Queue<File> filled_files;
1008 File read_file;
1009 File write_file;
1010 File empty;
1011 int number_of_objects_per_file = 0; // number of objects per file
1012 int file_count = 0; // number of files
1013 const uint16_t max_file_name = 256;
1014 Str next_file_name;
1015 void (*file_delete_callback)(const char *filename);
1016
1017 void cleanupFile(File &file) {
1018 if (!file) return;
1019 // after close the file name is gone
1020 int len = strlen(file.name());
1021 char file_name[len + 1];
1022 strncpy(file_name, file.name(), len);
1023 file.close();
1024 file_delete_callback(file_name);
1025 }
1026};
1027
1037template <typename T>
1039 public:
1040 BufferedArray(Stream &input, int len) {
1041 LOGI("BufferedArray(%d)", len);
1042 array.resize(len);
1043 p_stream = &input;
1044 }
1045 // access values, the offset and length are specified in samples of type <T>
1046 int16_t *getValues(size_t offset, size_t length) {
1047 LOGD("getValues(%d,%d) - max %d", offset, length, array.size());
1048 if (offset == 0) {
1049 // we restart at the beginning
1050 last_end = 0;
1051 actual_end = length;
1052 } else {
1053 // if first position is at end we do not want to read the full buffer
1054 last_end = actual_end >= 0 ? actual_end : offset;
1055 // increase actual end if bigger then old
1056 actual_end = offset + length > actual_end ? offset + length : actual_end;
1057 }
1058 int size = actual_end - last_end;
1059 if (size > 0) {
1060 LOGD("readBytes(%d,%d)", last_end, size);
1061 assert(last_end + size <= array.size());
1062 p_stream->readBytes((uint8_t *)(&array[last_end]), size * 2);
1063 }
1064 assert(offset < actual_end);
1065 return &array[offset];
1066 }
1067
1068 protected:
1069 int actual_end = -1;
1070 int last_end = 0;
1071 Vector<T> array;
1072 Stream *p_stream = nullptr;
1073};
1074
1075} // 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
Class which is usfull ot provide incremental data access e.g. for EdgeImpulse which request data with...
Definition Buffers.h:1038
Definition Buffers.h:121
int readFrames(T data[][2], int len)
reads multiple values for array of 2 dimensional frames
Definition Buffers.h:125
A NBufferExt is a subclass of NBuffer which allows to use a direct access API to the BaseBuffer.
Definition Buffers.h:831
SingleBuffer< T > * getBuffer(int id)
Provides the buffer with the indicated id.
Definition Buffers.h:853
SingleBuffer< T > * readEnd()
Alternative interface using address: provides access to the next read buffer.
Definition Buffers.h:846
SingleBuffer< T > * writeEnd()
Definition Buffers.h:837
Definition Buffers.h:884
const char * nextFileName()
Determines the next unique file name (after calling addFile)
Definition Buffers.h:892
void setFileDeleteCallback(void(*cb)(const char *filename))
Define the file delete operation.
Definition Buffers.h:981
bool peek(T &data) override
peeks the actual entry from the buffer
Definition Buffers.h:933
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:940
~NBufferFile()
RAII close the files.
Definition Buffers.h:889
bool read(T &result) override
reads a single value
Definition Buffers.h:910
int available() override
provides the number of entries that are available to read
Definition Buffers.h:956
bool addFile(File &file)
Definition Buffers.h:903
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:962
NBufferFile(int fileSize)
Provide the file size in objects!
Definition Buffers.h:887
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:942
void end()
clean up files
Definition Buffers.h:972
void reset()
clears the buffer
Definition Buffers.h:985
T * address()
not supported
Definition Buffers.h:1003
int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:912
A lock free N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:621
virtual void resize(int size, int count)
Resize the buffers by defining a new buffer size and buffer count.
Definition Buffers.h:732
size_t size()
Provides the total capacity (=buffer size * buffer count)
Definition Buffers.h:750
virtual int bufferCountEmpty()
Provides the number of entries that are available to write.
Definition Buffers.h:729
NBuffer()=default
empty constructor only allowed by subclass
bool isFull()
checks if the buffer is full
Definition Buffers.h:640
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:634
int available()
determines the available entries for the current read buffer
Definition Buffers.h:666
bool read(T &result) override
reads an entry from the buffer
Definition Buffers.h:628
bool write(T data)
write add an entry to the buffer
Definition Buffers.h:643
int availableForWrite()
determines the available entries for the write buffer
Definition Buffers.h:684
virtual int bufferCountFilled()
Provides the number of entries that are available to read.
Definition Buffers.h:726
void reset()
resets all buffers
Definition Buffers.h:703
unsigned long sampleRate()
provides the actual sample rate
Definition Buffers.h:714
T * address()
returns the address of the start of the phsical read buffer
Definition Buffers.h:720
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:419
int readArray(T data[], int count) override
reads multiple values
Definition Buffers.h:444
size_t size() override
Provides the capacity.
Definition Buffers.h:534
int peekArray(T data[], int count)
gets multiple values w/o removing them
Definition Buffers.h:475
int file_write(const T *data, int count)
Reed the indicated number of objects.
Definition Buffers.h:587
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:464
bool read(T &result) override
Reads a single value from the buffer.
Definition Buffers.h:441
bool write(T data) override
write add a single entry to the buffer
Definition Buffers.h:491
int available() override
provides the number of entries that are available to read
Definition Buffers.h:528
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:531
T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:540
bool isFull() override
checks if the buffer is full
Definition Buffers.h:515
bool begin(File &bufferFile)
Assigns the p_file to be used.
Definition Buffers.h:431
bool file_seek(int pos)
Seeks to the given object position.
Definition Buffers.h:574
int writeArray(const T data[], int len) override
Fills the data from the buffer.
Definition Buffers.h:494
int file_read(T *result, int count)
Writes the indicated number of objects.
Definition Buffers.h:601
OffsetInfo getOffset(int pos, int len)
Definition Buffers.h:557
void resize(int size)
Defines the capacity.
Definition Buffers.h:537
void reset() override
clears the buffer
Definition Buffers.h:520
Implements a typed Ringbuffer.
Definition Buffers.h:312
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:332
bool read(T &result) override
reads a single value
Definition Buffers.h:319
virtual T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:387
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:384
virtual bool write(T data) override
write add an entry to the buffer
Definition Buffers.h:362
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:398
virtual void reset() override
clears the buffer
Definition Buffers.h:374
virtual bool isFull() override
checks if the buffer is full
Definition Buffers.h:357
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:381
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:166
bool active
Optional active/inactive status.
Definition Buffers.h:294
size_t setAvailable(size_t available_size)
Definition Buffers.h:269
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:196
SingleBuffer(int size)
Construct a new Single Buffer object.
Definition Buffers.h:173
void setClearWithZero(bool flag)
Sets the buffer to 0 on clear.
Definition Buffers.h:286
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:214
uint64_t timestamp
Optional timestamp.
Definition Buffers.h:296
void setWritePos(int pos)
Updates the actual available data size.
Definition Buffers.h:289
bool read(T &result) override
reads a single value
Definition Buffers.h:205
int available() override
provides the number of entries that are available to read
Definition Buffers.h:223
int id
Optional ID.
Definition Buffers.h:292
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:228
T * address() override
Provides address to beginning of the buffer.
Definition Buffers.h:254
bool isFull() override
checks if the buffer is full
Definition Buffers.h:230
void onExternalBufferRefilled(void *data, int len)
notifies that the external buffer has been refilled
Definition Buffers.h:184
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:191
SingleBuffer()
Construct a new Single Buffer w/o allocating any memory.
Definition Buffers.h:181
T * data()
Provides address of actual data.
Definition Buffers.h:257
void reset() override
clears the buffer
Definition Buffers.h:259
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:233
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