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
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
239 int clearArray(int len) override {
240 int len_available = available();
241 if (len > available()) {
242 reset();
243 return len_available;
244 }
245 current_read_pos += len;
246 len_available -= len;
247 memmove(buffer.data(), buffer.data() + current_read_pos, len_available * sizeof(T));
248 current_read_pos = 0;
249 current_write_pos = len_available;
250
251 if (is_clear_with_zero) {
252 memset(buffer.data() + current_write_pos, 0,
253 buffer.size() - current_write_pos);
254 }
255
256 return len;
257 }
258
260 void trim() {
261 int av = available();
262 memmove(buffer.data(), buffer.data() + current_read_pos, av * sizeof(T));
263 current_write_pos = av;
264 current_read_pos = 0;
265 }
266
268 T *address() override { return buffer.data(); }
269
271 T *data() { return buffer.data() + current_read_pos; }
272
273 void reset() override {
274 current_read_pos = 0;
275 current_write_pos = 0;
276 if (is_clear_with_zero) {
277 memset(buffer.data(), 0, buffer.size());
278 }
279 }
280
283 size_t setAvailable(size_t available_size) {
284 size_t result = min(available_size, (size_t)buffer.size());
285 current_read_pos = 0;
286 current_write_pos = result;
287 return result;
288 }
289
290 size_t size() override { return buffer.size(); }
291
292 bool resize(int size) {
293 if (buffer.size() < size) {
294 TRACED();
295 buffer.resize(size);
296 }
297 return true;
298 }
299
301 void setClearWithZero(bool flag) { is_clear_with_zero = flag; }
302
304 void setWritePos(int pos) { current_write_pos = pos; }
305
307 int id = 0;
309 bool active = true;
311 uint64_t timestamp = 0;
312
313 protected:
314 int current_read_pos = 0;
315 int current_write_pos = 0;
316 bool owns_buffer = true;
317 bool is_clear_with_zero = false;
318 Vector<T> buffer{0};
319};
320
326template <typename T>
327class RingBuffer : public BaseBuffer<T> {
328 public:
329 RingBuffer(int size) {
330 resize(size);
331 reset();
332 }
333
334 bool read(T &result) override {
335 if (isEmpty()) {
336 return false;
337 }
338
339 result = _aucBuffer[_iTail];
340 _iTail = nextIndex(_iTail);
341 _numElems--;
342
343 return true;
344 }
345
346 // peeks the actual entry from the buffer
347 bool peek(T &result) override {
348 if (isEmpty()) {
349 return false;
350 }
351
352 result = _aucBuffer[_iTail];
353 return true;
354 }
355
356 virtual int peekArray(T *data, int n) {
357 if (isEmpty()) return -1;
358 int result = 0;
359 int count = _numElems;
360 int tail = _iTail;
361 for (int j = 0; j < n; j++) {
362 data[j] = _aucBuffer[tail];
363 tail = nextIndex(tail);
364 count--;
365 result++;
366 if (count == 0) break;
367 }
368 return result;
369 }
370
371 // checks if the buffer is full
372 virtual bool isFull() override { return available() == max_size; }
373
374 bool isEmpty() { return available() == 0; }
375
376 // write add an entry to the buffer
377 virtual bool write(T data) override {
378 bool result = false;
379 if (!isFull()) {
380 _aucBuffer[_iHead] = data;
381 _iHead = nextIndex(_iHead);
382 _numElems++;
383 result = true;
384 }
385 return result;
386 }
387
388 // clears the buffer
389 virtual void reset() override {
390 _iHead = 0;
391 _iTail = 0;
392 _numElems = 0;
393 }
394
395 // provides the number of entries that are available to read
396 virtual int available() override { return _numElems; }
397
398 // provides the number of entries that are available to write
399 virtual int availableForWrite() override { return (max_size - _numElems); }
400
401 // returns the address of the start of the physical read buffer
402 virtual T *address() override { return _aucBuffer.data(); }
403
404 virtual bool resize(int len) {
405 if (max_size != len) {
406 LOGI("resize: %d", len);
407 _aucBuffer.resize(len);
408 max_size = len;
409 }
410 return true;
411 }
412
414 virtual size_t size() override { return max_size; }
415
416 protected:
417 Vector<T> _aucBuffer;
418 int _iHead;
419 int _iTail;
420 int _numElems;
421 int max_size = 0;
422
423 int nextIndex(int index) { return (uint32_t)(index + 1) % max_size; }
424};
425
434template <class File, typename T>
435class RingBufferFile : public BaseBuffer<T> {
436 public:
437 RingBufferFile(int size) { resize(size); }
438 RingBufferFile(int size, File &file) {
439 resize(size);
440 begin(file);
441 }
443 if (p_file) p_file->close();
444 }
445
447 bool begin(File &bufferFile) {
448 if (bufferFile) {
449 p_file = &bufferFile;
450 } else {
451 LOGE("file is not valid");
452 }
453 return bufferFile;
454 }
455
457 bool read(T &result) override { return readArray(&result, 1) == 1; }
458
460 int readArray(T data[], int count) override {
461 if (p_file == nullptr) return 0;
462 int read_count = min(count, available());
463
464 OffsetInfo offset = getOffset(read_pos, read_count);
465 if (!file_seek(offset.pos)) return false;
466 int n = file_read(data, offset.len);
467 if (offset.len1 > 0) {
468 file_seek(0);
469 n += file_read(data + offset.len, offset.len1);
470 read_pos = offset.len1;
471 } else {
472 read_pos += read_count;
473 }
474
475 for (int i = 0; i < count; i++) {
476 LOGI("read #%d value %d", offset.pos, (int)data[i]);
477 }
478
479 element_count -= read_count;
480 return read_count;
481 }
482
484 bool peek(T &result) override {
485 if (p_file == nullptr || isEmpty()) {
486 return false;
487 }
488
489 if (!file_seek(read_pos)) return false;
490 size_t count = file_read(&result, 1);
491 return count == 1;
492 }
493
495 int peekArray(T data[], int count) {
496 if (p_file == nullptr) return 0;
497 int read_count = min(count, available());
498
499 OffsetInfo offset = getOffset(read_pos, read_count);
500 if (!file_seek(offset.pos)) return false;
501 int n = file_read(data, offset.len);
502 if (offset.len1 > 0) {
503 file_seek(0);
504 n += file_read(data + offset.len, offset.len1);
505 }
506 assert(n == read_count);
507 return read_count;
508 }
509
511 bool write(T data) override { return writeArray(&data, 1); }
512
514 int writeArray(const T data[], int len) override {
515 if (p_file == nullptr) return 0;
516 for (int i = 0; i < len; i++) {
517 LOGI("write #%d value %d", write_pos, (int)data[i]);
518 }
519
520 int write_count = min(len, availableForWrite());
521 OffsetInfo offset = getOffset(write_pos, write_count);
522
523 if (!file_seek(offset.pos)) return false;
524 int n = file_write(data, offset.len);
525 if (offset.len1 > 0) {
526 file_seek(0);
527 n += file_write(data + offset.len, offset.len1);
528 write_pos = offset.len1;
529 } else {
530 write_pos += write_count;
531 }
532 element_count += write_count;
533 return write_count;
534 }
535
537 bool isFull() override { return available() == max_size; }
538
539 bool isEmpty() { return available() == 0; }
540
542 void reset() override {
543 write_pos = 0;
544 read_pos = 0;
545 element_count = 0;
546 if (p_file != nullptr) file_seek(0);
547 }
548
550 int available() override { return element_count; }
551
553 int availableForWrite() override { return (max_size - element_count); }
554
556 size_t size() override { return max_size; }
557
559 bool resize(int size) {
560 max_size = size;
561 return true;
562 }
563
564 // not supported
565 T *address() override { return nullptr; }
566
567 protected:
568 File *p_file = nullptr;
569 int write_pos = 0;
570 int read_pos = 0;
571 int element_count = 0;
572 int max_size = 0;
573
574 struct OffsetInfo {
575 int pos = 0; // start pos
576 int len = 0; // length of first part
577 int len1 = 0; // length of second part on overflow
578 };
579
582 OffsetInfo getOffset(int pos, int len) {
583 OffsetInfo result;
584 result.pos = pos;
585 int overflow = (pos + len) - max_size;
586 if (overflow <= 0) {
587 // we can write the complete data
588 result.len = len;
589 result.len1 = 0;
590 } else {
591 // we need to split the data
592 result.len = len - overflow;
593 result.len1 = overflow;
594 }
595 return result;
596 }
597
599 bool file_seek(int pos) {
600 int file_pos = pos * sizeof(T);
601 if (p_file->position() != file_pos) {
602 LOGD("file_seek: %d", pos);
603 if (!p_file->seek(file_pos)) {
604 LOGE("seek %d", file_pos);
605 return false;
606 }
607 }
608 return true;
609 }
610
612 int file_write(const T *data, int count) {
613 LOGD("file_write: %d", count);
614 if (p_file == nullptr) return 0;
615 int to_write_bytes = sizeof(T) * count;
616 int bytes_written = p_file->write((const uint8_t *)data, to_write_bytes);
617 p_file->flush();
618 int elements_written = bytes_written / sizeof(T);
619 if (bytes_written != to_write_bytes) {
620 LOGE("write: %d -> %d bytes", to_write_bytes, bytes_written);
621 }
622 return elements_written;
623 }
624
626 int file_read(T *result, int count) {
627 LOGD("file_read: %d", count);
628 int read_bytes = count * sizeof(T);
629 int result_bytes = p_file->readBytes((char *)result, read_bytes);
630 int result_count = result_bytes / sizeof(T);
631 if (result_count != count) {
632 LOGE("readBytes: %d -> %d", read_bytes, result_bytes);
633 }
634 return result_count;
635 }
636};
637
645template <typename T>
646class NBuffer : public BaseBuffer<T> {
647 public:
648 NBuffer(int size, int count) { resize(size, count); }
649
650 virtual ~NBuffer() { freeMemory(); }
651
653 bool read(T &result) override {
654 if (available() == 0) return false;
655 return actual_read_buffer->read(result);
656 }
657
659 bool peek(T &result) override {
660 if (available() == 0) return false;
661 return actual_read_buffer->peek(result);
662 }
663
665 bool isFull() { return availableForWrite() == 0; }
666
668 bool write(T data) {
669 bool result = false;
670 if (actual_write_buffer == nullptr) {
671 actual_write_buffer = getNextAvailableBuffer();
672 }
673 if (actual_write_buffer != nullptr) {
674 result = actual_write_buffer->write(data);
675 // if buffer is full move to next available
676 if (actual_write_buffer->isFull()) {
677 addFilledBuffer(actual_write_buffer);
678 actual_write_buffer = getNextAvailableBuffer();
679 }
680 }
681
682 if (start_time == 0l) {
683 start_time = millis();
684 }
685 if (result) sample_count++;
686
687 return result;
688 }
689
691 int available() {
692 if (actual_read_buffer == nullptr) {
693 actual_read_buffer = getNextFilledBuffer();
694 }
695 if (actual_read_buffer == nullptr) {
696 return 0;
697 }
698 int result = actual_read_buffer->available();
699 if (result == 0) {
700 // make current read buffer available again
701 resetCurrent();
702 result =
703 (actual_read_buffer == nullptr) ? 0 : actual_read_buffer->available();
704 }
705 return result;
706 }
707
710 if (actual_write_buffer == nullptr) {
711 actual_write_buffer = getNextAvailableBuffer();
712 }
713 // if we used up all buffers - there is nothing available any more
714 if (actual_write_buffer == nullptr) {
715 return 0;
716 }
717 // check on actual buffer
718 if (actual_write_buffer->isFull()) {
719 // if buffer is full we move it to filled buffers ang get the next
720 // available
721 addFilledBuffer(actual_write_buffer);
722 actual_write_buffer = getNextAvailableBuffer();
723 }
724 return actual_write_buffer->availableForWrite();
725 }
726
728 void reset() {
729 TRACED();
730 while (actual_read_buffer != nullptr) {
731 actual_read_buffer->reset();
732 addAvailableBuffer(actual_read_buffer);
733 // get next read buffer
734 actual_read_buffer = getNextFilledBuffer();
735 }
736 }
737
739 unsigned long sampleRate() {
740 unsigned long run_time = (millis() - start_time);
741 return run_time == 0 ? 0 : sample_count * 1000 / run_time;
742 }
743
745 T *address() {
746 return actual_read_buffer == nullptr ? nullptr
747 : actual_read_buffer->address();
748 }
749
751 virtual int bufferCountFilled() { return filled_buffers.size(); }
752
754 virtual int bufferCountEmpty() { return available_buffers.size(); }
755
756 virtual bool resize(int bytes) {
757 int count = bytes / buffer_size;
758 return resize(buffer_size, count);
759 }
760
762 virtual bool resize(int size, int count) {
763 if (buffer_size == size && buffer_count == count) return true;
764 freeMemory();
765 filled_buffers.resize(count);
766 available_buffers.resize(count);
767 // filled_buffers.clear();
768 // available_buffers.clear();
769
770 buffer_count = count;
771 buffer_size = size;
772 for (int j = 0; j < count; j++) {
773 BaseBuffer<T> *buffer = new SingleBuffer<T>(size);
774 LOGD("new buffer %p", buffer);
775 available_buffers.enqueue(buffer);
776 }
777 return true;
778 }
779
781 size_t size() { return buffer_size * buffer_count; }
782
783 protected:
784 int buffer_size = 1024;
785 uint16_t buffer_count = 0;
786 BaseBuffer<T> *actual_read_buffer = nullptr;
787 BaseBuffer<T> *actual_write_buffer = nullptr;
788 QueueFromVector<BaseBuffer<T> *> available_buffers{0, nullptr};
789 QueueFromVector<BaseBuffer<T> *> filled_buffers{0, nullptr};
790 unsigned long start_time = 0;
791 unsigned long sample_count = 0;
792
794 NBuffer() = default;
795
796 void freeMemory() {
797 if (actual_write_buffer) {
798 LOGD("deleting %p", actual_write_buffer);
799 delete actual_write_buffer;
800 actual_write_buffer = nullptr;
801 }
802 if (actual_read_buffer) {
803 LOGD("deleting %p", actual_read_buffer);
804 delete actual_read_buffer;
805 actual_read_buffer = nullptr;
806 }
807
808 BaseBuffer<T> *ptr = getNextAvailableBuffer();
809 while (ptr != nullptr) {
810 LOGD("deleting %p", ptr);
811 delete ptr;
812 ptr = getNextAvailableBuffer();
813 }
814
815 ptr = getNextFilledBuffer();
816 while (ptr != nullptr) {
817 LOGD("deleting %p", ptr);
818 delete ptr;
819 ptr = getNextFilledBuffer();
820 }
821 }
822
823 void resetCurrent() {
824 if (actual_read_buffer != nullptr) {
825 actual_read_buffer->reset();
826 addAvailableBuffer(actual_read_buffer);
827 }
828 // get next read buffer
829 actual_read_buffer = getNextFilledBuffer();
830 }
831
832 virtual BaseBuffer<T> *getNextAvailableBuffer() {
833 if (available_buffers.empty()) return nullptr;
834 BaseBuffer<T> *result = nullptr;
835 available_buffers.dequeue(result);
836 return result;
837 }
838
839 virtual bool addAvailableBuffer(BaseBuffer<T> *buffer) {
840 return available_buffers.enqueue(buffer);
841 }
842
843 virtual BaseBuffer<T> *getNextFilledBuffer() {
844 if (filled_buffers.empty()) return nullptr;
845 BaseBuffer<T> *result = nullptr;
846 filled_buffers.dequeue(result);
847 return result;
848 }
849
850 virtual bool addFilledBuffer(BaseBuffer<T> *buffer) {
851 return filled_buffers.enqueue(buffer);
852 }
853};
854
861template <typename T>
862class NBufferExt : public NBuffer<T> {
863 public:
864 NBufferExt(int size, int count) { resize(size, count); }
865
869 actual_write_buffer = getNextAvailableBuffer();
870 if (actual_write_buffer != nullptr) {
871 addFilledBuffer(actual_write_buffer);
872 }
873 return (SingleBuffer<T> *)actual_write_buffer;
874 }
875
879 // make current read buffer available again
880 resetCurrent();
881 return (SingleBuffer<T> *)actual_read_buffer;
882 }
883
886 for (auto &buffer : this->filled_buffers.toVector()) {
887 SingleBuffer<T> *sbuffer = (SingleBuffer<T> *)&buffer;
888 if (sbuffer->id == id) {
889 return sbuffer;
890 }
891 }
892 return nullptr;
893 }
894
895 using NBuffer<T>::resize;
896
897 protected:
898 using NBuffer<T>::resetCurrent;
899 using NBuffer<T>::addFilledBuffer;
900 using NBuffer<T>::getNextAvailableBuffer;
901 using NBuffer<T>::actual_write_buffer;
902 using NBuffer<T>::actual_read_buffer;
903 using NBuffer<T>::buffer_size;
904};
905
906/***
907 * @brief A File backed buffer which uses the provided files for buffering with
908 * the indicated max size. A file is made available for reading as soon as it
909 * reached the size limit. You must provide the files opened in "Write" mode
910 * with the addFile() method!
911 * @ingroup buffers
912 * @tparam File: file class
913 * @tparam T: buffered data type
914 */
915template <class File, typename T>
916class NBufferFile : public BaseBuffer<T> {
917 public:
919 NBufferFile(int fileSize) { number_of_objects_per_file = fileSize; }
922
924 const char *nextFileName() {
925 next_file_name.set("buffer-");
926 char number[40];
927 snprintf(number, 40, "%d", file_count);
928 next_file_name.add(number);
929 next_file_name.add(".tmp");
930 return next_file_name.c_str();
931 }
932
935 bool addFile(File &file) {
936 if (!file) return false;
937 empty_files.enqueue(file);
938 file_count++;
939 return true;
940 }
941
942 bool read(T &result) override { return readArray(&result, 1) == 1; }
943
944 int readArray(T data[], int len) override {
945 // make sure we have a read file
946 if (!read_file) {
947 if (!filled_files.dequeue(read_file)) {
948 // no more data
949 return 0;
950 }
951 read_file.seek(0);
952 }
953 // read the data
954 int result = read_file.readBytes((char *)data, len * sizeof(T)) / sizeof(T);
955
956 // if we have consumed all content
957 if (result < len) {
958 read_file.seek(0);
959 empty_files.enqueue(read_file);
960 read_file = empty;
961 }
962 return result;
963 }
964
965 bool peek(T &data) override {
966 size_t pos = read_file.position();
967 bool result = read(data);
968 read_file.seek(pos);
969 return result;
970 }
971
972 bool write(T sample) override { return writeArray(&sample, 1) == 1; }
973
974 int writeArray(const T data[], int len) override {
975 if (!write_file || write_file.size() + len > number_of_objects_per_file) {
976 // moved to filled files
977 if (write_file) {
978 write_file.seek(0);
979 filled_files.enqueue(write_file);
980 }
981 // get next empty file
982 if (!empty_files.dequeue(write_file)) return false;
983 }
984 int result = write_file.write((uint8_t *)data, len * sizeof(T));
985 return result / sizeof(T);
986 }
987
988 int available() override {
989 return filled_files.size() * number_of_objects_per_file +
990 (read_file.available() / sizeof(T));
991 }
992
993 // provides the number of entries that are available to write
994 int availableForWrite() override {
995 int open_current =
996 number_of_objects_per_file - (write_file.available() / sizeof(T));
997 return empty_files.size() * number_of_objects_per_file +
998 write_file.available() + open_current;
999 }
1000
1001 size_t size() override { return number_of_objects_per_file * file_count; }
1002
1004 void end() {
1005 cleanupFile(read_file);
1006 cleanupFile(write_file);
1007 File file;
1008 while (empty_files.dequeue(file)) cleanupFile(file);
1009 while (filled_files.dequeue(file)) cleanupFile(file);
1010 }
1011
1013 void setFileDeleteCallback(void (*cb)(const char *filename)) {
1014 file_delete_callback = cb;
1015 }
1016
1017 void reset() {
1018 if (read_file) {
1019 read_file.seek(0);
1020 empty_files.enqueue(read_file);
1021 read_file = empty;
1022 }
1023 if (write_file) {
1024 write_file.seek(0);
1025 empty_files.enqueue(write_file);
1026 write_file = empty;
1027 }
1028 File file;
1029 while (filled_files.dequeue(file)) {
1030 file.seek(0);
1031 empty_files.enqueue(file);
1032 }
1033 }
1035 T *address() { return nullptr; }
1036
1037 protected:
1038 Queue<File> empty_files;
1039 Queue<File> filled_files;
1040 File read_file;
1041 File write_file;
1042 File empty;
1043 int number_of_objects_per_file = 0; // number of objects per file
1044 int file_count = 0; // number of files
1045 const uint16_t max_file_name = 256;
1046 Str next_file_name;
1047 void (*file_delete_callback)(const char *filename);
1048
1049 void cleanupFile(File &file) {
1050 if (!file) return;
1051 // after close the file name is gone
1052 int len = strlen(file.name());
1053 char file_name[len + 1];
1054 strncpy(file_name, file.name(), len);
1055 file.close();
1056 file_delete_callback(file_name);
1057 }
1058};
1059
1069template <typename T>
1071 public:
1072 BufferedArray(Stream &input, int len) {
1073 LOGI("BufferedArray(%d)", len);
1074 array.resize(len);
1075 p_stream = &input;
1076 }
1077 // access values, the offset and length are specified in samples of type <T>
1078 int16_t *getValues(size_t offset, size_t length) {
1079 LOGD("getValues(%d,%d) - max %d", offset, length, array.size());
1080 if (offset == 0) {
1081 // we restart at the beginning
1082 last_end = 0;
1083 actual_end = length;
1084 } else {
1085 // if first position is at end we do not want to read the full buffer
1086 last_end = actual_end >= 0 ? actual_end : offset;
1087 // increase actual end if bigger then old
1088 actual_end = offset + length > actual_end ? offset + length : actual_end;
1089 }
1090 int size = actual_end - last_end;
1091 if (size > 0) {
1092 LOGD("readBytes(%d,%d)", last_end, size);
1093 assert(last_end + size <= array.size());
1094 p_stream->readBytes((uint8_t *)(&array[last_end]), size * 2);
1095 }
1096 assert(offset < actual_end);
1097 return &array[offset];
1098 }
1099
1100 protected:
1101 int actual_end = -1;
1102 int last_end = 0;
1103 Vector<T> array;
1104 Stream *p_stream = nullptr;
1105};
1106
1107} // 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:1070
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:862
SingleBuffer< T > * getBuffer(int id)
Provides the buffer with the indicated id.
Definition Buffers.h:885
SingleBuffer< T > * readEnd()
Definition Buffers.h:878
SingleBuffer< T > * writeEnd()
Definition Buffers.h:868
Definition Buffers.h:916
const char * nextFileName()
Determines the next unique file name (after calling addFile)
Definition Buffers.h:924
void setFileDeleteCallback(void(*cb)(const char *filename))
Define the file delete operation.
Definition Buffers.h:1013
bool peek(T &data) override
peeks the actual entry from the buffer
Definition Buffers.h:965
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:972
~NBufferFile()
RAII close the files.
Definition Buffers.h:921
bool read(T &result) override
reads a single value
Definition Buffers.h:942
int available() override
provides the number of entries that are available to read
Definition Buffers.h:988
bool addFile(File &file)
Definition Buffers.h:935
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:994
NBufferFile(int fileSize)
Provide the file size in objects!
Definition Buffers.h:919
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:974
void end()
clean up files
Definition Buffers.h:1004
void reset()
clears the buffer
Definition Buffers.h:1017
T * address()
not supported
Definition Buffers.h:1035
int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:944
A lock free N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:646
size_t size()
Provides the total capacity (=buffer size * buffer count)
Definition Buffers.h:781
virtual int bufferCountEmpty()
Provides the number of entries that are available to write.
Definition Buffers.h:754
NBuffer()=default
empty constructor only allowed by subclass
bool isFull()
checks if the buffer is full
Definition Buffers.h:665
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:659
int available()
determines the available entries for the current read buffer
Definition Buffers.h:691
bool read(T &result) override
reads an entry from the buffer
Definition Buffers.h:653
bool write(T data)
write add an entry to the buffer
Definition Buffers.h:668
virtual bool resize(int size, int count)
Resize the buffers by defining a new buffer size and buffer count.
Definition Buffers.h:762
int availableForWrite()
determines the available entries for the write buffer
Definition Buffers.h:709
virtual int bufferCountFilled()
Provides the number of entries that are available to read.
Definition Buffers.h:751
void reset()
resets all buffers
Definition Buffers.h:728
unsigned long sampleRate()
provides the actual sample rate
Definition Buffers.h:739
T * address()
returns the address of the start of the phsical read buffer
Definition Buffers.h:745
virtual bool resize(int bytes)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:756
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:435
int readArray(T data[], int count) override
reads multiple values
Definition Buffers.h:460
size_t size() override
Provides the capacity.
Definition Buffers.h:556
int peekArray(T data[], int count)
gets multiple values w/o removing them
Definition Buffers.h:495
int file_write(const T *data, int count)
Reed the indicated number of objects.
Definition Buffers.h:612
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:484
bool read(T &result) override
Reads a single value from the buffer.
Definition Buffers.h:457
bool write(T data) override
write add a single entry to the buffer
Definition Buffers.h:511
int available() override
provides the number of entries that are available to read
Definition Buffers.h:550
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:553
T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:565
bool isFull() override
checks if the buffer is full
Definition Buffers.h:537
bool begin(File &bufferFile)
Assigns the p_file to be used.
Definition Buffers.h:447
bool resize(int size)
Defines the capacity.
Definition Buffers.h:559
bool file_seek(int pos)
Seeks to the given object position.
Definition Buffers.h:599
int writeArray(const T data[], int len) override
Fills the data from the buffer.
Definition Buffers.h:514
int file_read(T *result, int count)
Writes the indicated number of objects.
Definition Buffers.h:626
OffsetInfo getOffset(int pos, int len)
Definition Buffers.h:582
void reset() override
clears the buffer
Definition Buffers.h:542
Implements a typed Ringbuffer.
Definition Buffers.h:327
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:347
bool read(T &result) override
reads a single value
Definition Buffers.h:334
virtual T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:402
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:399
virtual bool write(T data) override
write add an entry to the buffer
Definition Buffers.h:377
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:414
virtual void reset() override
clears the buffer
Definition Buffers.h:389
virtual bool isFull() override
checks if the buffer is full
Definition Buffers.h:372
virtual bool resize(int len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:404
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:396
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
bool active
Optional active/inactive status.
Definition Buffers.h:309
size_t setAvailable(size_t available_size)
Definition Buffers.h:283
void trim()
Moves the unprocessed data to the beginning of the buffer.
Definition Buffers.h:260
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:301
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:220
uint64_t timestamp
Optional timestamp.
Definition Buffers.h:311
void setWritePos(int pos)
Updates the actual available data size.
Definition Buffers.h:304
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:307
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:268
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:292
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:271
void reset() override
clears the buffer
Definition Buffers.h:273
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:239
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