arduino-audio-tools
Loading...
Searching...
No Matches
Buffers.h
1#pragma once
2
3#include "AudioTools/CoreAudio/AudioBasic/Collections.h"
4#include "AudioTools/CoreAudio/AudioBasic/Str.h"
5#include "AudioTools/CoreAudio/AudioLogger.h"
6
13namespace audio_tools {
14
21template <typename T = int16_t>
23 public:
24 BaseBuffer() = default;
25 virtual ~BaseBuffer() = default;
26 BaseBuffer(BaseBuffer&) = default;
27 BaseBuffer &operator=(BaseBuffer &) = default;
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
126template <typename T = int16_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 = int16_t>
172class SingleBuffer : public BaseBuffer<T> {
173 public:
179 SingleBuffer(int size, Allocator &allocator = DefaultAllocator)
180 : _allocator(allocator) {
181 buffer.resize(size);
182 reset();
183 }
184
185 SingleBuffer(SingleBuffer&) = default;
186 SingleBuffer& operator=(SingleBuffer&) = default;
187
192
194 void onExternalBufferRefilled(void *data, int len) {
195 this->owns_buffer = false;
196 this->buffer = (uint8_t *)data;
197 this->current_read_pos = 0;
198 this->current_write_pos = len;
199 }
200
201 int writeArray(const T data[], int len) override {
202 if (size() == 0) resize(len);
203 return BaseBuffer<T>::writeArray(data, len);
204 }
205
206 bool write(T sample) override {
207 bool result = false;
208 if (current_write_pos < buffer.size()) {
209 buffer[current_write_pos++] = sample;
210 result = true;
211 }
212 return result;
213 }
214
215 bool read(T &result) override {
216 bool success = false;
217 if (current_read_pos < current_write_pos) {
218 result = buffer[current_read_pos++];
219 success = true;
220 }
221 return success;
222 }
223
224 bool peek(T &result) override {
225 bool success = false;
226 if (current_read_pos < current_write_pos) {
227 result = buffer[current_read_pos];
228 success = true;
229 }
230 return success;
231 }
232
233 int available() override {
234 int result = current_write_pos - current_read_pos;
235 return max(result, 0);
236 }
237
238 int availableForWrite() override { return buffer.size() - current_write_pos; }
239
240 bool isFull() override { return availableForWrite() <= 0; }
241
242 int peekArray(uint8_t *data, int len) {
243 int len_available = available();
244 if (len > len_available) {
245 len = len_available;
246 }
247 memcpy(data, buffer.data() + current_read_pos, len);
248 return len;
249 }
250
252 int clearArray(int len) override {
253 int len_available = available();
254 if (len > available()) {
255 reset();
256 return len_available;
257 }
258 current_read_pos += len;
259 len_available -= len;
260 memmove(buffer.data(), buffer.data() + current_read_pos, len_available * sizeof(T));
261 current_read_pos = 0;
262 current_write_pos = len_available;
263
264 if (is_clear_with_zero) {
265 memset(buffer.data() + current_write_pos, 0,
266 buffer.size() - current_write_pos);
267 }
268
269 return len;
270 }
271
273 void trim() {
274 int av = available();
275 memmove(buffer.data(), buffer.data() + current_read_pos, av * sizeof(T));
276 current_write_pos = av;
277 current_read_pos = 0;
278 }
279
281 T *address() override { return buffer.data(); }
282
284 T *data() { return buffer.data() + current_read_pos; }
285
286 void reset() override {
287 current_read_pos = 0;
288 current_write_pos = 0;
289 if (is_clear_with_zero) {
290 memset(buffer.data(), 0, buffer.size());
291 }
292 }
293
296 size_t setAvailable(size_t available_size) {
297 size_t result = min(available_size, (size_t)buffer.size());
298 current_read_pos = 0;
299 current_write_pos = result;
300 return result;
301 }
302
303 size_t size() override { return buffer.size(); }
304
305 bool resize(int size) {
306 if (buffer.size() < size) {
307 TRACED();
308 buffer.resize(size);
309 }
310 return true;
311 }
312
314 void setClearWithZero(bool flag) { is_clear_with_zero = flag; }
315
317 void setWritePos(int pos) { current_write_pos = pos; }
318
320 int id = 0;
322 bool active = true;
324 uint64_t timestamp = 0;
325
326 protected:
327 Allocator _allocator;
328 int current_read_pos = 0;
329 int current_write_pos = 0;
330 bool owns_buffer = true;
331 bool is_clear_with_zero = false;
332 Vector<T> buffer{0, _allocator};
333};
334
340template <typename T = int16_t>
341class RingBuffer : public BaseBuffer<T> {
342 public:
343 RingBuffer(int size, Allocator &allocator = DefaultAllocator) : _allocator(allocator) {
344 resize(size);
345 reset();
346 }
347
348 bool read(T &result) override {
349 if (isEmpty()) {
350 return false;
351 }
352
353 result = _aucBuffer[_iTail];
354 _iTail = nextIndex(_iTail);
355 _numElems--;
356
357 return true;
358 }
359
360 // peeks the actual entry from the buffer
361 bool peek(T &result) override {
362 if (isEmpty()) {
363 return false;
364 }
365
366 result = _aucBuffer[_iTail];
367 return true;
368 }
369
370 virtual int peekArray(T *data, int n) {
371 if (isEmpty()) return -1;
372 int result = 0;
373 int count = _numElems;
374 int tail = _iTail;
375 for (int j = 0; j < n; j++) {
376 data[j] = _aucBuffer[tail];
377 tail = nextIndex(tail);
378 count--;
379 result++;
380 if (count == 0) break;
381 }
382 return result;
383 }
384
385 // checks if the buffer is full
386 virtual bool isFull() override { return available() == max_size; }
387
388 bool isEmpty() { return available() == 0; }
389
390 // write add an entry to the buffer
391 virtual bool write(T data) override {
392 bool result = false;
393 if (!isFull()) {
394 _aucBuffer[_iHead] = data;
395 _iHead = nextIndex(_iHead);
396 _numElems++;
397 result = true;
398 }
399 return result;
400 }
401
402 // clears the buffer
403 virtual void reset() override {
404 _iHead = 0;
405 _iTail = 0;
406 _numElems = 0;
407 }
408
409 // provides the number of entries that are available to read
410 virtual int available() override { return _numElems; }
411
412 // provides the number of entries that are available to write
413 virtual int availableForWrite() override { return (max_size - _numElems); }
414
415 // returns the address of the start of the physical read buffer
416 virtual T *address() override { return _aucBuffer.data(); }
417
418 virtual bool resize(int len) {
419 if (max_size != len && len > 0) {
420 LOGI("resize: %d", len);
421 _aucBuffer.resize(len);
422 max_size = len;
423 }
424 return true;
425 }
426
428 virtual size_t size() override { return max_size; }
429
430 protected:
431 Allocator &_allocator;
432 Vector<T> _aucBuffer{_allocator};
433 int _iHead;
434 int _iTail;
435 int _numElems;
436 int max_size = 0;
437
438 int nextIndex(int index) {
439 if (max_size == 0) return 0;
440 return (uint32_t)(index + 1) % max_size; }
441};
442
451template <class File, typename T>
452class RingBufferFile : public BaseBuffer<T> {
453 public:
454 RingBufferFile(int size) { resize(size); }
455 RingBufferFile(int size, File &file) {
456 resize(size);
457 begin(file);
458 }
460 if (p_file) p_file->close();
461 }
462
464 bool begin(File &bufferFile) {
465 if (bufferFile) {
466 p_file = &bufferFile;
467 } else {
468 LOGE("file is not valid");
469 }
470 return bufferFile;
471 }
472
474 bool read(T &result) override { return readArray(&result, 1) == 1; }
475
477 int readArray(T data[], int count) override {
478 if (p_file == nullptr) return 0;
479 int read_count = min(count, available());
480
481 OffsetInfo offset = getOffset(read_pos, read_count);
482 if (!file_seek(offset.pos)) return false;
483 int n = file_read(data, offset.len);
484 if (offset.len1 > 0) {
485 file_seek(0);
486 n += file_read(data + offset.len, offset.len1);
487 read_pos = offset.len1;
488 } else {
489 read_pos += read_count;
490 }
491
492 for (int i = 0; i < count; i++) {
493 LOGI("read #%d value %d", offset.pos, (int)data[i]);
494 }
495
496 element_count -= read_count;
497 return read_count;
498 }
499
501 bool peek(T &result) override {
502 if (p_file == nullptr || isEmpty()) {
503 return false;
504 }
505
506 if (!file_seek(read_pos)) return false;
507 size_t count = file_read(&result, 1);
508 return count == 1;
509 }
510
512 int peekArray(T data[], int count) {
513 if (p_file == nullptr) return 0;
514 int read_count = min(count, available());
515
516 OffsetInfo offset = getOffset(read_pos, read_count);
517 if (!file_seek(offset.pos)) return false;
518 int n = file_read(data, offset.len);
519 if (offset.len1 > 0) {
520 file_seek(0);
521 n += file_read(data + offset.len, offset.len1);
522 }
523 assert(n == read_count);
524 return read_count;
525 }
526
528 bool write(T data) override { return writeArray(&data, 1); }
529
531 int writeArray(const T data[], int len) override {
532 if (p_file == nullptr) return 0;
533 for (int i = 0; i < len; i++) {
534 LOGI("write #%d value %d", write_pos, (int)data[i]);
535 }
536
537 int write_count = min(len, availableForWrite());
538 OffsetInfo offset = getOffset(write_pos, write_count);
539
540 if (!file_seek(offset.pos)) return false;
541 int n = file_write(data, offset.len);
542 if (offset.len1 > 0) {
543 file_seek(0);
544 n += file_write(data + offset.len, offset.len1);
545 write_pos = offset.len1;
546 } else {
547 write_pos += write_count;
548 }
549 element_count += write_count;
550 return write_count;
551 }
552
554 bool isFull() override { return available() == max_size; }
555
556 bool isEmpty() { return available() == 0; }
557
559 void reset() override {
560 write_pos = 0;
561 read_pos = 0;
562 element_count = 0;
563 if (p_file != nullptr) file_seek(0);
564 }
565
567 int available() override { return element_count; }
568
570 int availableForWrite() override { return (max_size - element_count); }
571
573 size_t size() override { return max_size; }
574
576 bool resize(int size) {
577 max_size = size;
578 return true;
579 }
580
581 // not supported
582 T *address() override { return nullptr; }
583
584 protected:
585 File *p_file = nullptr;
586 int write_pos = 0;
587 int read_pos = 0;
588 int element_count = 0;
589 int max_size = 0;
590
591 struct OffsetInfo {
592 int pos = 0; // start pos
593 int len = 0; // length of first part
594 int len1 = 0; // length of second part on overflow
595 };
596
599 OffsetInfo getOffset(int pos, int len) {
600 OffsetInfo result;
601 result.pos = pos;
602 int overflow = (pos + len) - max_size;
603 if (overflow <= 0) {
604 // we can write the complete data
605 result.len = len;
606 result.len1 = 0;
607 } else {
608 // we need to split the data
609 result.len = len - overflow;
610 result.len1 = overflow;
611 }
612 return result;
613 }
614
616 bool file_seek(int pos) {
617 int file_pos = pos * sizeof(T);
618 if (p_file->position() != file_pos) {
619 LOGD("file_seek: %d", pos);
620 if (!p_file->seek(file_pos)) {
621 LOGE("seek %d", file_pos);
622 return false;
623 }
624 }
625 return true;
626 }
627
629 int file_write(const T *data, int count) {
630 LOGD("file_write: %d", count);
631 if (p_file == nullptr) return 0;
632 int to_write_bytes = sizeof(T) * count;
633 int bytes_written = p_file->write((const uint8_t *)data, to_write_bytes);
634 p_file->flush();
635 int elements_written = bytes_written / sizeof(T);
636 if (bytes_written != to_write_bytes) {
637 LOGE("write: %d -> %d bytes", to_write_bytes, bytes_written);
638 }
639 return elements_written;
640 }
641
643 int file_read(T *result, int count) {
644 LOGD("file_read: %d", count);
645 int read_bytes = count * sizeof(T);
646 int result_bytes = p_file->readBytes((char *)result, read_bytes);
647 int result_count = result_bytes / sizeof(T);
648 if (result_count != count) {
649 LOGE("readBytes: %d -> %d", read_bytes, result_bytes);
650 }
651 return result_count;
652 }
653};
654
662template <typename T = int16_t>
663class NBuffer : public BaseBuffer<T> {
664 public:
665 NBuffer(int size, int count) { resize(size, count); }
666
667 virtual ~NBuffer() { freeMemory(); }
668
670 bool read(T &result) override {
671 if (available() == 0) return false;
672 return actual_read_buffer->read(result);
673 }
674
676 bool peek(T &result) override {
677 if (available() == 0) return false;
678 return actual_read_buffer->peek(result);
679 }
680
682 bool isFull() { return availableForWrite() == 0; }
683
685 bool write(T data) {
686 bool result = false;
687 if (actual_write_buffer == nullptr) {
688 actual_write_buffer = getNextAvailableBuffer();
689 }
690 if (actual_write_buffer != nullptr) {
691 result = actual_write_buffer->write(data);
692 // if buffer is full move to next available
693 if (actual_write_buffer->isFull()) {
694 addFilledBuffer(actual_write_buffer);
695 actual_write_buffer = getNextAvailableBuffer();
696 }
697 }
698
699 if (start_time == 0l) {
700 start_time = millis();
701 }
702 if (result) sample_count++;
703
704 return result;
705 }
706
708 int available() {
709 if (actual_read_buffer == nullptr) {
710 actual_read_buffer = getNextFilledBuffer();
711 }
712 if (actual_read_buffer == nullptr) {
713 return 0;
714 }
715 int result = actual_read_buffer->available();
716 if (result == 0) {
717 // make current read buffer available again
718 resetCurrent();
719 result =
720 (actual_read_buffer == nullptr) ? 0 : actual_read_buffer->available();
721 }
722 return result;
723 }
724
727 if (actual_write_buffer == nullptr) {
728 actual_write_buffer = getNextAvailableBuffer();
729 }
730 // if we used up all buffers - there is nothing available any more
731 if (actual_write_buffer == nullptr) {
732 return 0;
733 }
734 // check on actual buffer
735 if (actual_write_buffer->isFull()) {
736 // if buffer is full we move it to filled buffers ang get the next
737 // available
738 addFilledBuffer(actual_write_buffer);
739 actual_write_buffer = getNextAvailableBuffer();
740 }
741 return actual_write_buffer->availableForWrite();
742 }
743
745 void reset() {
746 TRACED();
747 while (actual_read_buffer != nullptr) {
748 actual_read_buffer->reset();
749 addAvailableBuffer(actual_read_buffer);
750 // get next read buffer
751 actual_read_buffer = getNextFilledBuffer();
752 }
753 }
754
756 unsigned long sampleRate() {
757 unsigned long run_time = (millis() - start_time);
758 return run_time == 0 ? 0 : sample_count * 1000 / run_time;
759 }
760
762 T *address() {
763 return actual_read_buffer == nullptr ? nullptr
764 : actual_read_buffer->address();
765 }
766
768 virtual int bufferCountFilled() { return filled_buffers.size(); }
769
771 virtual int bufferCountEmpty() { return available_buffers.size(); }
772
773 virtual bool resize(int bytes) {
774 int count = bytes / buffer_size;
775 return resize(buffer_size, count);
776 }
777
779 virtual bool resize(int size, int count) {
780 if (buffer_size == size && buffer_count == count) return true;
781 freeMemory();
782 filled_buffers.resize(count);
783 available_buffers.resize(count);
784 // filled_buffers.clear();
785 // available_buffers.clear();
786
787 buffer_count = count;
788 buffer_size = size;
789 for (int j = 0; j < count; j++) {
790 BaseBuffer<T> *buffer = new SingleBuffer<T>(size);
791 LOGD("new buffer %p", buffer);
792 available_buffers.enqueue(buffer);
793 }
794 return true;
795 }
796
798 size_t size() { return buffer_size * buffer_count; }
799
800 protected:
801 int buffer_size = 1024;
802 uint16_t buffer_count = 0;
803 BaseBuffer<T> *actual_read_buffer = nullptr;
804 BaseBuffer<T> *actual_write_buffer = nullptr;
805 QueueFromVector<BaseBuffer<T> *> available_buffers{0, nullptr};
806 QueueFromVector<BaseBuffer<T> *> filled_buffers{0, nullptr};
807 unsigned long start_time = 0;
808 unsigned long sample_count = 0;
809
811 NBuffer() = default;
812
813 void freeMemory() {
814 if (actual_write_buffer) {
815 LOGD("deleting %p", actual_write_buffer);
816 delete actual_write_buffer;
817 actual_write_buffer = nullptr;
818 }
819 if (actual_read_buffer) {
820 LOGD("deleting %p", actual_read_buffer);
821 delete actual_read_buffer;
822 actual_read_buffer = nullptr;
823 }
824
825 BaseBuffer<T> *ptr = getNextAvailableBuffer();
826 while (ptr != nullptr) {
827 LOGD("deleting %p", ptr);
828 delete ptr;
829 ptr = getNextAvailableBuffer();
830 }
831
832 ptr = getNextFilledBuffer();
833 while (ptr != nullptr) {
834 LOGD("deleting %p", ptr);
835 delete ptr;
836 ptr = getNextFilledBuffer();
837 }
838 }
839
840 void resetCurrent() {
841 if (actual_read_buffer != nullptr) {
842 actual_read_buffer->reset();
843 addAvailableBuffer(actual_read_buffer);
844 }
845 // get next read buffer
846 actual_read_buffer = getNextFilledBuffer();
847 }
848
849 virtual BaseBuffer<T> *getNextAvailableBuffer() {
850 if (available_buffers.empty()) return nullptr;
851 BaseBuffer<T> *result = nullptr;
852 available_buffers.dequeue(result);
853 return result;
854 }
855
856 virtual bool addAvailableBuffer(BaseBuffer<T> *buffer) {
857 return available_buffers.enqueue(buffer);
858 }
859
860 virtual BaseBuffer<T> *getNextFilledBuffer() {
861 if (filled_buffers.empty()) return nullptr;
862 BaseBuffer<T> *result = nullptr;
863 filled_buffers.dequeue(result);
864 return result;
865 }
866
867 virtual bool addFilledBuffer(BaseBuffer<T> *buffer) {
868 return filled_buffers.enqueue(buffer);
869 }
870};
871
878template <typename T = int16_t>
879class NBufferExt : public NBuffer<T> {
880 public:
881 NBufferExt(int size, int count) { resize(size, count); }
882
886 actual_write_buffer = getNextAvailableBuffer();
887 if (actual_write_buffer != nullptr) {
888 addFilledBuffer(actual_write_buffer);
889 }
890 return (SingleBuffer<T> *)actual_write_buffer;
891 }
892
896 // make current read buffer available again
897 resetCurrent();
898 return (SingleBuffer<T> *)actual_read_buffer;
899 }
900
903 for (auto &buffer : this->filled_buffers.toVector()) {
904 SingleBuffer<T> *sbuffer = (SingleBuffer<T> *)&buffer;
905 if (sbuffer->id == id) {
906 return sbuffer;
907 }
908 }
909 return nullptr;
910 }
911
912 using NBuffer<T>::resize;
913
914 protected:
915 using NBuffer<T>::resetCurrent;
916 using NBuffer<T>::addFilledBuffer;
917 using NBuffer<T>::getNextAvailableBuffer;
918 using NBuffer<T>::actual_write_buffer;
919 using NBuffer<T>::actual_read_buffer;
920 using NBuffer<T>::buffer_size;
921};
922
932template <class File, typename T>
933class NBufferFile : public BaseBuffer<T> {
934 public:
936 NBufferFile(int fileSize) { number_of_objects_per_file = fileSize; }
939
941 const char *nextFileName() {
942 next_file_name.set("buffer-");
943 char number[40];
944 snprintf(number, 40, "%d", file_count);
945 next_file_name.add(number);
946 next_file_name.add(".tmp");
947 return next_file_name.c_str();
948 }
949
952 bool addFile(File &file) {
953 if (!file) return false;
954 empty_files.enqueue(file);
955 file_count++;
956 return true;
957 }
958
959 bool read(T &result) override { return readArray(&result, 1) == 1; }
960
961 int readArray(T data[], int len) override {
962 // make sure we have a read file
963 if (!read_file) {
964 if (!filled_files.dequeue(read_file)) {
965 // no more data
966 return 0;
967 }
968 read_file.seek(0);
969 }
970 // read the data
971 int result = read_file.readBytes((char *)data, len * sizeof(T)) / sizeof(T);
972
973 // if we have consumed all content
974 if (result < len) {
975 read_file.seek(0);
976 empty_files.enqueue(read_file);
977 read_file = empty;
978 }
979 return result;
980 }
981
982 bool peek(T &data) override {
983 size_t pos = read_file.position();
984 bool result = read(data);
985 read_file.seek(pos);
986 return result;
987 }
988
989 bool write(T sample) override { return writeArray(&sample, 1) == 1; }
990
991 int writeArray(const T data[], int len) override {
992 if (!write_file || write_file.size() + len > number_of_objects_per_file) {
993 // moved to filled files
994 if (write_file) {
995 write_file.seek(0);
996 filled_files.enqueue(write_file);
997 }
998 // get next empty file
999 if (!empty_files.dequeue(write_file)) return false;
1000 }
1001 int result = write_file.write((uint8_t *)data, len * sizeof(T));
1002 return result / sizeof(T);
1003 }
1004
1005 int available() override {
1006 return filled_files.size() * number_of_objects_per_file +
1007 (read_file.available() / sizeof(T));
1008 }
1009
1010 // provides the number of entries that are available to write
1011 int availableForWrite() override {
1012 int open_current =
1013 number_of_objects_per_file - (write_file.available() / sizeof(T));
1014 return empty_files.size() * number_of_objects_per_file +
1015 write_file.available() + open_current;
1016 }
1017
1018 size_t size() override { return number_of_objects_per_file * file_count; }
1019
1021 void end() {
1022 cleanupFile(read_file);
1023 cleanupFile(write_file);
1024 File file;
1025 while (empty_files.dequeue(file)) cleanupFile(file);
1026 while (filled_files.dequeue(file)) cleanupFile(file);
1027 }
1028
1030 void setFileDeleteCallback(void (*cb)(const char *filename)) {
1031 file_delete_callback = cb;
1032 }
1033
1034 void reset() {
1035 if (read_file) {
1036 read_file.seek(0);
1037 empty_files.enqueue(read_file);
1038 read_file = empty;
1039 }
1040 if (write_file) {
1041 write_file.seek(0);
1042 empty_files.enqueue(write_file);
1043 write_file = empty;
1044 }
1045 File file;
1046 while (filled_files.dequeue(file)) {
1047 file.seek(0);
1048 empty_files.enqueue(file);
1049 }
1050 }
1052 T *address() { return nullptr; }
1053
1054 protected:
1055 Queue<File> empty_files;
1056 Queue<File> filled_files;
1057 File read_file;
1058 File write_file;
1059 File empty;
1060 int number_of_objects_per_file = 0; // number of objects per file
1061 int file_count = 0; // number of files
1062 const uint16_t max_file_name = 256;
1063 Str next_file_name;
1064 void (*file_delete_callback)(const char *filename);
1065
1066 void cleanupFile(File &file) {
1067 if (!file) return;
1068 // after close the file name is gone
1069 int len = strlen(file.name());
1070 char file_name[len + 1];
1071 strncpy(file_name, file.name(), len);
1072 file.close();
1073 file_delete_callback(file_name);
1074 }
1075};
1076
1086template <typename T = int16_t>
1088 public:
1089 BufferedArray(Stream &input, int len) {
1090 LOGI("BufferedArray(%d)", len);
1091 array.resize(len);
1092 p_stream = &input;
1093 }
1094 // access values, the offset and length are specified in samples of type <T>
1095 int16_t *getValues(size_t offset, size_t length) {
1096 LOGD("getValues(%d,%d) - max %d", offset, length, array.size());
1097 if (offset == 0) {
1098 // we restart at the beginning
1099 last_end = 0;
1100 actual_end = length;
1101 } else {
1102 // if first position is at end we do not want to read the full buffer
1103 last_end = actual_end >= 0 ? actual_end : offset;
1104 // increase actual end if bigger then old
1105 actual_end = offset + length > actual_end ? offset + length : actual_end;
1106 }
1107 int size = actual_end - last_end;
1108 if (size > 0) {
1109 LOGD("readBytes(%d,%d)", last_end, size);
1110 assert(last_end + size <= array.size());
1111 p_stream->readBytes((uint8_t *)(&array[last_end]), size * 2);
1112 }
1113 assert(offset < actual_end);
1114 return &array[offset];
1115 }
1116
1117 protected:
1118 int actual_end = -1;
1119 int last_end = 0;
1120 Vector<T> array;
1121 Stream *p_stream = nullptr;
1122};
1123
1124} // namespace audio_tools
Memory allocateator which uses malloc.
Definition Allocator.h:23
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:1087
A FrameBuffer reads multiple values for array of 2 dimensional frames.
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:879
SingleBuffer< T > * getBuffer(int id)
Provides the buffer with the indicated id.
Definition Buffers.h:902
SingleBuffer< T > * readEnd()
Definition Buffers.h:895
SingleBuffer< T > * writeEnd()
Definition Buffers.h:885
A File backed buffer which uses the provided files for buffering with the indicated max size....
Definition Buffers.h:933
const char * nextFileName()
Determines the next unique file name (after calling addFile)
Definition Buffers.h:941
void setFileDeleteCallback(void(*cb)(const char *filename))
Define the file delete operation.
Definition Buffers.h:1030
bool peek(T &data) override
peeks the actual entry from the buffer
Definition Buffers.h:982
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:989
~NBufferFile()
RAII close the files.
Definition Buffers.h:938
bool read(T &result) override
reads a single value
Definition Buffers.h:959
int available() override
provides the number of entries that are available to read
Definition Buffers.h:1005
bool addFile(File &file)
Definition Buffers.h:952
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:1011
NBufferFile(int fileSize)
Provide the file size in objects!
Definition Buffers.h:936
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:991
void end()
clean up files
Definition Buffers.h:1021
void reset()
clears the buffer
Definition Buffers.h:1034
T * address()
not supported
Definition Buffers.h:1052
int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:961
A lock free N buffer. If count=2 we create a DoubleBuffer, if count=3 a TripleBuffer etc.
Definition Buffers.h:663
size_t size()
Provides the total capacity (=buffer size * buffer count)
Definition Buffers.h:798
virtual int bufferCountEmpty()
Provides the number of entries that are available to write.
Definition Buffers.h:771
NBuffer()=default
empty constructor only allowed by subclass
bool isFull()
checks if the buffer is full
Definition Buffers.h:682
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:676
int available()
determines the available entries for the current read buffer
Definition Buffers.h:708
bool read(T &result) override
reads an entry from the buffer
Definition Buffers.h:670
bool write(T data)
write add an entry to the buffer
Definition Buffers.h:685
virtual bool resize(int size, int count)
Resize the buffers by defining a new buffer size and buffer count.
Definition Buffers.h:779
int availableForWrite()
determines the available entries for the write buffer
Definition Buffers.h:726
virtual int bufferCountFilled()
Provides the number of entries that are available to read.
Definition Buffers.h:768
void reset()
resets all buffers
Definition Buffers.h:745
unsigned long sampleRate()
provides the actual sample rate
Definition Buffers.h:756
T * address()
returns the address of the start of the phsical read buffer
Definition Buffers.h:762
virtual bool resize(int bytes)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:773
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:452
int readArray(T data[], int count) override
reads multiple values
Definition Buffers.h:477
size_t size() override
Provides the capacity.
Definition Buffers.h:573
int peekArray(T data[], int count)
gets multiple values w/o removing them
Definition Buffers.h:512
int file_write(const T *data, int count)
Reed the indicated number of objects.
Definition Buffers.h:629
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:501
bool read(T &result) override
Reads a single value from the buffer.
Definition Buffers.h:474
bool write(T data) override
write add a single entry to the buffer
Definition Buffers.h:528
int available() override
provides the number of entries that are available to read
Definition Buffers.h:567
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:570
T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:582
bool isFull() override
checks if the buffer is full
Definition Buffers.h:554
bool begin(File &bufferFile)
Assigns the p_file to be used.
Definition Buffers.h:464
bool resize(int size)
Defines the capacity.
Definition Buffers.h:576
bool file_seek(int pos)
Seeks to the given object position.
Definition Buffers.h:616
int writeArray(const T data[], int len) override
Fills the data from the buffer.
Definition Buffers.h:531
int file_read(T *result, int count)
Writes the indicated number of objects.
Definition Buffers.h:643
OffsetInfo getOffset(int pos, int len)
Definition Buffers.h:599
void reset() override
clears the buffer
Definition Buffers.h:559
Implements a typed Ringbuffer.
Definition Buffers.h:341
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:361
bool read(T &result) override
reads a single value
Definition Buffers.h:348
virtual T * address() override
returns the address of the start of the physical read buffer
Definition Buffers.h:416
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:413
virtual bool write(T data) override
write add an entry to the buffer
Definition Buffers.h:391
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:428
virtual void reset() override
clears the buffer
Definition Buffers.h:403
virtual bool isFull() override
checks if the buffer is full
Definition Buffers.h:386
virtual bool resize(int len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:418
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:410
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
bool active
Optional active/inactive status.
Definition Buffers.h:322
size_t setAvailable(size_t available_size)
Definition Buffers.h:296
void trim()
Moves the unprocessed data to the beginning of the buffer.
Definition Buffers.h:273
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:206
void setClearWithZero(bool flag)
Sets the buffer to 0 on clear.
Definition Buffers.h:314
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:224
uint64_t timestamp
Optional timestamp.
Definition Buffers.h:324
void setWritePos(int pos)
Updates the actual available data size.
Definition Buffers.h:317
bool read(T &result) override
reads a single value
Definition Buffers.h:215
int available() override
provides the number of entries that are available to read
Definition Buffers.h:233
int id
Optional ID.
Definition Buffers.h:320
int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:238
T * address() override
Provides address to beginning of the buffer.
Definition Buffers.h:281
bool isFull() override
checks if the buffer is full
Definition Buffers.h:240
void onExternalBufferRefilled(void *data, int len)
notifies that the external buffer has been refilled
Definition Buffers.h:194
bool resize(int size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:305
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:201
SingleBuffer(int size, Allocator &allocator=DefaultAllocator)
Construct a new Single Buffer object.
Definition Buffers.h:179
SingleBuffer()
Construct a new Single Buffer w/o allocating any memory.
Definition Buffers.h:191
T * data()
Provides address of actual data.
Definition Buffers.h:284
void reset() override
clears the buffer
Definition Buffers.h:286
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:252
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