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