arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros 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) {
424 if (max_size == 0) return 0;
425 return (uint32_t)(index + 1) % max_size; }
426};
427
436template <class File, typename T>
437class RingBufferFile : public BaseBuffer<T> {
438 public:
439 RingBufferFile(int size) { resize(size); }
440 RingBufferFile(int size, File &file) {
441 resize(size);
442 begin(file);
443 }
445 if (p_file) p_file->close();
446 }
447
449 bool begin(File &bufferFile) {
450 if (bufferFile) {
451 p_file = &bufferFile;
452 } else {
453 LOGE("file is not valid");
454 }
455 return bufferFile;
456 }
457
459 bool read(T &result) override { return readArray(&result, 1) == 1; }
460
462 int readArray(T data[], int count) override {
463 if (p_file == nullptr) return 0;
464 int read_count = min(count, available());
465
466 OffsetInfo offset = getOffset(read_pos, read_count);
467 if (!file_seek(offset.pos)) return false;
468 int n = file_read(data, offset.len);
469 if (offset.len1 > 0) {
470 file_seek(0);
471 n += file_read(data + offset.len, offset.len1);
472 read_pos = offset.len1;
473 } else {
474 read_pos += read_count;
475 }
476
477 for (int i = 0; i < count; i++) {
478 LOGI("read #%d value %d", offset.pos, (int)data[i]);
479 }
480
481 element_count -= read_count;
482 return read_count;
483 }
484
486 bool peek(T &result) override {
487 if (p_file == nullptr || isEmpty()) {
488 return false;
489 }
490
491 if (!file_seek(read_pos)) return false;
492 size_t count = file_read(&result, 1);
493 return count == 1;
494 }
495
497 int peekArray(T data[], int count) {
498 if (p_file == nullptr) return 0;
499 int read_count = min(count, available());
500
501 OffsetInfo offset = getOffset(read_pos, read_count);
502 if (!file_seek(offset.pos)) return false;
503 int n = file_read(data, offset.len);
504 if (offset.len1 > 0) {
505 file_seek(0);
506 n += file_read(data + offset.len, offset.len1);
507 }
508 assert(n == read_count);
509 return read_count;
510 }
511
513 bool write(T data) override { return writeArray(&data, 1); }
514
516 int writeArray(const T data[], int len) override {
517 if (p_file == nullptr) return 0;
518 for (int i = 0; i < len; i++) {
519 LOGI("write #%d value %d", write_pos, (int)data[i]);
520 }
521
522 int write_count = min(len, availableForWrite());
523 OffsetInfo offset = getOffset(write_pos, write_count);
524
525 if (!file_seek(offset.pos)) return false;
526 int n = file_write(data, offset.len);
527 if (offset.len1 > 0) {
528 file_seek(0);
529 n += file_write(data + offset.len, offset.len1);
530 write_pos = offset.len1;
531 } else {
532 write_pos += write_count;
533 }
534 element_count += write_count;
535 return write_count;
536 }
537
539 bool isFull() override { return available() == max_size; }
540
541 bool isEmpty() { return available() == 0; }
542
544 void reset() override {
545 write_pos = 0;
546 read_pos = 0;
547 element_count = 0;
548 if (p_file != nullptr) file_seek(0);
549 }
550
552 int available() override { return element_count; }
553
555 int availableForWrite() override { return (max_size - element_count); }
556
558 size_t size() override { return max_size; }
559
561 bool resize(int size) {
562 max_size = size;
563 return true;
564 }
565
566 // not supported
567 T *address() override { return nullptr; }
568
569 protected:
570 File *p_file = nullptr;
571 int write_pos = 0;
572 int read_pos = 0;
573 int element_count = 0;
574 int max_size = 0;
575
576 struct OffsetInfo {
577 int pos = 0; // start pos
578 int len = 0; // length of first part
579 int len1 = 0; // length of second part on overflow
580 };
581
584 OffsetInfo getOffset(int pos, int len) {
585 OffsetInfo result;
586 result.pos = pos;
587 int overflow = (pos + len) - max_size;
588 if (overflow <= 0) {
589 // we can write the complete data
590 result.len = len;
591 result.len1 = 0;
592 } else {
593 // we need to split the data
594 result.len = len - overflow;
595 result.len1 = overflow;
596 }
597 return result;
598 }
599
601 bool file_seek(int pos) {
602 int file_pos = pos * sizeof(T);
603 if (p_file->position() != file_pos) {
604 LOGD("file_seek: %d", pos);
605 if (!p_file->seek(file_pos)) {
606 LOGE("seek %d", file_pos);
607 return false;
608 }
609 }
610 return true;
611 }
612
614 int file_write(const T *data, int count) {
615 LOGD("file_write: %d", count);
616 if (p_file == nullptr) return 0;
617 int to_write_bytes = sizeof(T) * count;
618 int bytes_written = p_file->write((const uint8_t *)data, to_write_bytes);
619 p_file->flush();
620 int elements_written = bytes_written / sizeof(T);
621 if (bytes_written != to_write_bytes) {
622 LOGE("write: %d -> %d bytes", to_write_bytes, bytes_written);
623 }
624 return elements_written;
625 }
626
628 int file_read(T *result, int count) {
629 LOGD("file_read: %d", count);
630 int read_bytes = count * sizeof(T);
631 int result_bytes = p_file->readBytes((char *)result, read_bytes);
632 int result_count = result_bytes / sizeof(T);
633 if (result_count != count) {
634 LOGE("readBytes: %d -> %d", read_bytes, result_bytes);
635 }
636 return result_count;
637 }
638};
639
647template <typename T>
648class NBuffer : public BaseBuffer<T> {
649 public:
650 NBuffer(int size, int count) { resize(size, count); }
651
652 virtual ~NBuffer() { freeMemory(); }
653
655 bool read(T &result) override {
656 if (available() == 0) return false;
657 return actual_read_buffer->read(result);
658 }
659
661 bool peek(T &result) override {
662 if (available() == 0) return false;
663 return actual_read_buffer->peek(result);
664 }
665
667 bool isFull() { return availableForWrite() == 0; }
668
670 bool write(T data) {
671 bool result = false;
672 if (actual_write_buffer == nullptr) {
673 actual_write_buffer = getNextAvailableBuffer();
674 }
675 if (actual_write_buffer != nullptr) {
676 result = actual_write_buffer->write(data);
677 // if buffer is full move to next available
678 if (actual_write_buffer->isFull()) {
679 addFilledBuffer(actual_write_buffer);
680 actual_write_buffer = getNextAvailableBuffer();
681 }
682 }
683
684 if (start_time == 0l) {
685 start_time = millis();
686 }
687 if (result) sample_count++;
688
689 return result;
690 }
691
693 int available() {
694 if (actual_read_buffer == nullptr) {
695 actual_read_buffer = getNextFilledBuffer();
696 }
697 if (actual_read_buffer == nullptr) {
698 return 0;
699 }
700 int result = actual_read_buffer->available();
701 if (result == 0) {
702 // make current read buffer available again
703 resetCurrent();
704 result =
705 (actual_read_buffer == nullptr) ? 0 : actual_read_buffer->available();
706 }
707 return result;
708 }
709
712 if (actual_write_buffer == nullptr) {
713 actual_write_buffer = getNextAvailableBuffer();
714 }
715 // if we used up all buffers - there is nothing available any more
716 if (actual_write_buffer == nullptr) {
717 return 0;
718 }
719 // check on actual buffer
720 if (actual_write_buffer->isFull()) {
721 // if buffer is full we move it to filled buffers ang get the next
722 // available
723 addFilledBuffer(actual_write_buffer);
724 actual_write_buffer = getNextAvailableBuffer();
725 }
726 return actual_write_buffer->availableForWrite();
727 }
728
730 void reset() {
731 TRACED();
732 while (actual_read_buffer != nullptr) {
733 actual_read_buffer->reset();
734 addAvailableBuffer(actual_read_buffer);
735 // get next read buffer
736 actual_read_buffer = getNextFilledBuffer();
737 }
738 }
739
741 unsigned long sampleRate() {
742 unsigned long run_time = (millis() - start_time);
743 return run_time == 0 ? 0 : sample_count * 1000 / run_time;
744 }
745
747 T *address() {
748 return actual_read_buffer == nullptr ? nullptr
749 : actual_read_buffer->address();
750 }
751
753 virtual int bufferCountFilled() { return filled_buffers.size(); }
754
756 virtual int bufferCountEmpty() { return available_buffers.size(); }
757
758 virtual bool resize(int bytes) {
759 int count = bytes / buffer_size;
760 return resize(buffer_size, count);
761 }
762
764 virtual bool resize(int size, int count) {
765 if (buffer_size == size && buffer_count == count) return true;
766 freeMemory();
767 filled_buffers.resize(count);
768 available_buffers.resize(count);
769 // filled_buffers.clear();
770 // available_buffers.clear();
771
772 buffer_count = count;
773 buffer_size = size;
774 for (int j = 0; j < count; j++) {
775 BaseBuffer<T> *buffer = new SingleBuffer<T>(size);
776 LOGD("new buffer %p", buffer);
777 available_buffers.enqueue(buffer);
778 }
779 return true;
780 }
781
783 size_t size() { return buffer_size * buffer_count; }
784
785 protected:
786 int buffer_size = 1024;
787 uint16_t buffer_count = 0;
788 BaseBuffer<T> *actual_read_buffer = nullptr;
789 BaseBuffer<T> *actual_write_buffer = nullptr;
790 QueueFromVector<BaseBuffer<T> *> available_buffers{0, nullptr};
791 QueueFromVector<BaseBuffer<T> *> filled_buffers{0, nullptr};
792 unsigned long start_time = 0;
793 unsigned long sample_count = 0;
794
796 NBuffer() = default;
797
798 void freeMemory() {
799 if (actual_write_buffer) {
800 LOGD("deleting %p", actual_write_buffer);
801 delete actual_write_buffer;
802 actual_write_buffer = nullptr;
803 }
804 if (actual_read_buffer) {
805 LOGD("deleting %p", actual_read_buffer);
806 delete actual_read_buffer;
807 actual_read_buffer = nullptr;
808 }
809
810 BaseBuffer<T> *ptr = getNextAvailableBuffer();
811 while (ptr != nullptr) {
812 LOGD("deleting %p", ptr);
813 delete ptr;
814 ptr = getNextAvailableBuffer();
815 }
816
817 ptr = getNextFilledBuffer();
818 while (ptr != nullptr) {
819 LOGD("deleting %p", ptr);
820 delete ptr;
821 ptr = getNextFilledBuffer();
822 }
823 }
824
825 void resetCurrent() {
826 if (actual_read_buffer != nullptr) {
827 actual_read_buffer->reset();
828 addAvailableBuffer(actual_read_buffer);
829 }
830 // get next read buffer
831 actual_read_buffer = getNextFilledBuffer();
832 }
833
834 virtual BaseBuffer<T> *getNextAvailableBuffer() {
835 if (available_buffers.empty()) return nullptr;
836 BaseBuffer<T> *result = nullptr;
837 available_buffers.dequeue(result);
838 return result;
839 }
840
841 virtual bool addAvailableBuffer(BaseBuffer<T> *buffer) {
842 return available_buffers.enqueue(buffer);
843 }
844
845 virtual BaseBuffer<T> *getNextFilledBuffer() {
846 if (filled_buffers.empty()) return nullptr;
847 BaseBuffer<T> *result = nullptr;
848 filled_buffers.dequeue(result);
849 return result;
850 }
851
852 virtual bool addFilledBuffer(BaseBuffer<T> *buffer) {
853 return filled_buffers.enqueue(buffer);
854 }
855};
856
863template <typename T>
864class NBufferExt : public NBuffer<T> {
865 public:
866 NBufferExt(int size, int count) { resize(size, count); }
867
871 actual_write_buffer = getNextAvailableBuffer();
872 if (actual_write_buffer != nullptr) {
873 addFilledBuffer(actual_write_buffer);
874 }
875 return (SingleBuffer<T> *)actual_write_buffer;
876 }
877
881 // make current read buffer available again
882 resetCurrent();
883 return (SingleBuffer<T> *)actual_read_buffer;
884 }
885
888 for (auto &buffer : this->filled_buffers.toVector()) {
889 SingleBuffer<T> *sbuffer = (SingleBuffer<T> *)&buffer;
890 if (sbuffer->id == id) {
891 return sbuffer;
892 }
893 }
894 return nullptr;
895 }
896
897 using NBuffer<T>::resize;
898
899 protected:
900 using NBuffer<T>::resetCurrent;
901 using NBuffer<T>::addFilledBuffer;
902 using NBuffer<T>::getNextAvailableBuffer;
903 using NBuffer<T>::actual_write_buffer;
904 using NBuffer<T>::actual_read_buffer;
905 using NBuffer<T>::buffer_size;
906};
907
908/***
909 * @brief A File backed buffer which uses the provided files for buffering with
910 * the indicated max size. A file is made available for reading as soon as it
911 * reached the size limit. You must provide the files opened in "Write" mode
912 * with the addFile() method!
913 * @ingroup buffers
914 * @tparam File: file class
915 * @tparam T: buffered data type
916 */
917template <class File, typename T>
918class NBufferFile : public BaseBuffer<T> {
919 public:
921 NBufferFile(int fileSize) { number_of_objects_per_file = fileSize; }
924
926 const char *nextFileName() {
927 next_file_name.set("buffer-");
928 char number[40];
929 snprintf(number, 40, "%d", file_count);
930 next_file_name.add(number);
931 next_file_name.add(".tmp");
932 return next_file_name.c_str();
933 }
934
937 bool addFile(File &file) {
938 if (!file) return false;
939 empty_files.enqueue(file);
940 file_count++;
941 return true;
942 }
943
944 bool read(T &result) override { return readArray(&result, 1) == 1; }
945
946 int readArray(T data[], int len) override {
947 // make sure we have a read file
948 if (!read_file) {
949 if (!filled_files.dequeue(read_file)) {
950 // no more data
951 return 0;
952 }
953 read_file.seek(0);
954 }
955 // read the data
956 int result = read_file.readBytes((char *)data, len * sizeof(T)) / sizeof(T);
957
958 // if we have consumed all content
959 if (result < len) {
960 read_file.seek(0);
961 empty_files.enqueue(read_file);
962 read_file = empty;
963 }
964 return result;
965 }
966
967 bool peek(T &data) override {
968 size_t pos = read_file.position();
969 bool result = read(data);
970 read_file.seek(pos);
971 return result;
972 }
973
974 bool write(T sample) override { return writeArray(&sample, 1) == 1; }
975
976 int writeArray(const T data[], int len) override {
977 if (!write_file || write_file.size() + len > number_of_objects_per_file) {
978 // moved to filled files
979 if (write_file) {
980 write_file.seek(0);
981 filled_files.enqueue(write_file);
982 }
983 // get next empty file
984 if (!empty_files.dequeue(write_file)) return false;
985 }
986 int result = write_file.write((uint8_t *)data, len * sizeof(T));
987 return result / sizeof(T);
988 }
989
990 int available() override {
991 return filled_files.size() * number_of_objects_per_file +
992 (read_file.available() / sizeof(T));
993 }
994
995 // provides the number of entries that are available to write
996 int availableForWrite() override {
997 int open_current =
998 number_of_objects_per_file - (write_file.available() / sizeof(T));
999 return empty_files.size() * number_of_objects_per_file +
1000 write_file.available() + open_current;
1001 }
1002
1003 size_t size() override { return number_of_objects_per_file * file_count; }
1004
1006 void end() {
1007 cleanupFile(read_file);
1008 cleanupFile(write_file);
1009 File file;
1010 while (empty_files.dequeue(file)) cleanupFile(file);
1011 while (filled_files.dequeue(file)) cleanupFile(file);
1012 }
1013
1015 void setFileDeleteCallback(void (*cb)(const char *filename)) {
1016 file_delete_callback = cb;
1017 }
1018
1019 void reset() {
1020 if (read_file) {
1021 read_file.seek(0);
1022 empty_files.enqueue(read_file);
1023 read_file = empty;
1024 }
1025 if (write_file) {
1026 write_file.seek(0);
1027 empty_files.enqueue(write_file);
1028 write_file = empty;
1029 }
1030 File file;
1031 while (filled_files.dequeue(file)) {
1032 file.seek(0);
1033 empty_files.enqueue(file);
1034 }
1035 }
1037 T *address() { return nullptr; }
1038
1039 protected:
1040 Queue<File> empty_files;
1041 Queue<File> filled_files;
1042 File read_file;
1043 File write_file;
1044 File empty;
1045 int number_of_objects_per_file = 0; // number of objects per file
1046 int file_count = 0; // number of files
1047 const uint16_t max_file_name = 256;
1048 Str next_file_name;
1049 void (*file_delete_callback)(const char *filename);
1050
1051 void cleanupFile(File &file) {
1052 if (!file) return;
1053 // after close the file name is gone
1054 int len = strlen(file.name());
1055 char file_name[len + 1];
1056 strncpy(file_name, file.name(), len);
1057 file.close();
1058 file_delete_callback(file_name);
1059 }
1060};
1061
1071template <typename T>
1073 public:
1074 BufferedArray(Stream &input, int len) {
1075 LOGI("BufferedArray(%d)", len);
1076 array.resize(len);
1077 p_stream = &input;
1078 }
1079 // access values, the offset and length are specified in samples of type <T>
1080 int16_t *getValues(size_t offset, size_t length) {
1081 LOGD("getValues(%d,%d) - max %d", offset, length, array.size());
1082 if (offset == 0) {
1083 // we restart at the beginning
1084 last_end = 0;
1085 actual_end = length;
1086 } else {
1087 // if first position is at end we do not want to read the full buffer
1088 last_end = actual_end >= 0 ? actual_end : offset;
1089 // increase actual end if bigger then old
1090 actual_end = offset + length > actual_end ? offset + length : actual_end;
1091 }
1092 int size = actual_end - last_end;
1093 if (size > 0) {
1094 LOGD("readBytes(%d,%d)", last_end, size);
1095 assert(last_end + size <= array.size());
1096 p_stream->readBytes((uint8_t *)(&array[last_end]), size * 2);
1097 }
1098 assert(offset < actual_end);
1099 return &array[offset];
1100 }
1101
1102 protected:
1103 int actual_end = -1;
1104 int last_end = 0;
1105 Vector<T> array;
1106 Stream *p_stream = nullptr;
1107};
1108
1109} // 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:1072
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:864
SingleBuffer< T > * getBuffer(int id)
Provides the buffer with the indicated id.
Definition Buffers.h:887
SingleBuffer< T > * readEnd()
Definition Buffers.h:880
SingleBuffer< T > * writeEnd()
Definition Buffers.h:870
Definition Buffers.h:918
const char * nextFileName()
Determines the next unique file name (after calling addFile)
Definition Buffers.h:926
void setFileDeleteCallback(void(*cb)(const char *filename))
Define the file delete operation.
Definition Buffers.h:1015
bool peek(T &data) override
peeks the actual entry from the buffer
Definition Buffers.h:967
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:974
~NBufferFile()
RAII close the files.
Definition Buffers.h:923
bool read(T &result) override
reads a single value
Definition Buffers.h:944
int available() override
provides the number of entries that are available to read
Definition Buffers.h:990
bool addFile(File &file)
Definition Buffers.h:937
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:996
NBufferFile(int fileSize)
Provide the file size in objects!
Definition Buffers.h:921
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:976
void end()
clean up files
Definition Buffers.h:1006
void reset()
clears the buffer
Definition Buffers.h:1019
T * address()
not supported
Definition Buffers.h:1037
int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:946
A lock free N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:648
size_t size()
Provides the total capacity (=buffer size * buffer count)
Definition Buffers.h:783
virtual int bufferCountEmpty()
Provides the number of entries that are available to write.
Definition Buffers.h:756
NBuffer()=default
empty constructor only allowed by subclass
bool isFull()
checks if the buffer is full
Definition Buffers.h:667
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:661
int available()
determines the available entries for the current read buffer
Definition Buffers.h:693
bool read(T &result) override
reads an entry from the buffer
Definition Buffers.h:655
bool write(T data)
write add an entry to the buffer
Definition Buffers.h:670
virtual bool resize(int size, int count)
Resize the buffers by defining a new buffer size and buffer count.
Definition Buffers.h:764
int availableForWrite()
determines the available entries for the write buffer
Definition Buffers.h:711
virtual int bufferCountFilled()
Provides the number of entries that are available to read.
Definition Buffers.h:753
void reset()
resets all buffers
Definition Buffers.h:730
unsigned long sampleRate()
provides the actual sample rate
Definition Buffers.h:741
T * address()
returns the address of the start of the phsical read buffer
Definition Buffers.h:747
virtual bool resize(int bytes)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:758
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:437
int readArray(T data[], int count) override
reads multiple values
Definition Buffers.h:462
size_t size() override
Provides the capacity.
Definition Buffers.h:558
int peekArray(T data[], int count)
gets multiple values w/o removing them
Definition Buffers.h:497
int file_write(const T *data, int count)
Reed the indicated number of objects.
Definition Buffers.h:614
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:486
bool read(T &result) override
Reads a single value from the buffer.
Definition Buffers.h:459
bool write(T data) override
write add a single entry to the buffer
Definition Buffers.h:513
int available() override
provides the number of entries that are available to read
Definition Buffers.h:552
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:555
T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:567
bool isFull() override
checks if the buffer is full
Definition Buffers.h:539
bool begin(File &bufferFile)
Assigns the p_file to be used.
Definition Buffers.h:449
bool resize(int size)
Defines the capacity.
Definition Buffers.h:561
bool file_seek(int pos)
Seeks to the given object position.
Definition Buffers.h:601
int writeArray(const T data[], int len) override
Fills the data from the buffer.
Definition Buffers.h:516
int file_read(T *result, int count)
Writes the indicated number of objects.
Definition Buffers.h:628
OffsetInfo getOffset(int pos, int len)
Definition Buffers.h:584
void reset() override
clears the buffer
Definition Buffers.h:544
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