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 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
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy