arduino-audio-tools
BufferRP2040.h
1 #pragma once
2 
3 #ifndef ARDUINO_ARCH_RP2040
4 # error "Unsupported architecture"
5 #endif
6 
7 #include "AudioConfig.h"
8 #include "AudioTools/CoreAudio/AudioLogger.h"
9 #include "AudioTools/CoreAudio/Buffers.h"
10 
11 namespace audio_tools {
12 
13 // #if ESP_IDF_VERSION_MAJOR >= 4
14 
25 template <typename T>
26 class BufferRP2040T : public BaseBuffer<T> {
27  public:
28  BufferRP2040T(size_t bufferSize, int bufferCount = 2) : BaseBuffer<T>() {
29  buffer_size = bufferSize * sizeof(T);
30  buffer_size_req_bytes = buffer_size * bufferCount;
31  }
32 
33  ~BufferRP2040T() { reset(); }
34 
36  bool resize(size_t size) {
37  buffer_size_req_bytes = size;
38  if (buffer_size_total_bytes != buffer_size_req_bytes) {
39  LOGI("resize %d -> %d", buffer_size_total_bytes, buffer_size_req_bytes);
40  assert(buffer_size > 0);
41  if (is_blocking_write){
42  write_buffer.resize(buffer_size);
43  read_buffer.resize(buffer_size * 2);
44  }
45  // release existing queue
46  if (buffer_size_total_bytes > 0) {
47  queue_free(&queue);
48  }
49  // create new queu
50  if (buffer_size_req_bytes > 0) {
51  int count = buffer_size_req_bytes / buffer_size;
52  LOGI("queue_init(size:%d, count:%d)", buffer_size, count);
53  queue_init(&queue, buffer_size, count);
54  }
55  buffer_size_total_bytes = buffer_size_req_bytes;
56  }
57  return true;
58  }
59 
60  // reads a single value
61  T read() {
62  T data = 0;
63  readArray(&data, 1);
64  return data;
65  }
66 
67  // peeks the actual entry from the buffer
68  T peek() {
69  LOGE("peek not implmented");
70  return 0;
71  }
72 
73  // reads multiple values
74  int readArray(T data[], int len) override {
75  LOGD("readArray: %d", len);
76  if (!is_blocking_write && read_buffer.size()==0){
77  // make sure that the read buffer is big enough
78  read_buffer.resize(len + buffer_size);
79  }
80  // handle unalloc;ated queue
81  if (buffer_size_total_bytes == 0) return 0;
82  if (isEmpty() && read_buffer.isEmpty()) return 0;
83  // fill read buffer if necessary
84  while (read_buffer.availableForWrite() >= buffer_size) {
85  LOGD("reading %d %d ", buffer_size, read_buffer.availableForWrite());
86  T tmp[buffer_size];
87  if (queue_try_remove(&queue, tmp)){
88  LOGD("queue_try_remove -> success");
89  read_buffer.writeArray(tmp, buffer_size);
90  } else {
91  LOGD("queue_try_remove -> failed");
92  break;
93  }
94  }
95  LOGD("read_buffer.available: %d, availableForWrite: %d ", read_buffer.available(), read_buffer.availableForWrite());
96  int result = read_buffer.readArray(data, len);
97  LOGD("=> readArray: %d -> %d", len, result);
98  return result;
99  }
100 
101  int writeArray(const T data[], int len) override {
102  LOGD("writeArray: %d", len);
103  int result = 0;
104  // make sure that we have the data allocated
105  resize(buffer_size_req_bytes);
106 
107  if (is_blocking_write) {
108  result = writeBlocking(data, len);
109  } else {
110  result = writeNonBlocking(data, len);
111  }
112 
113  return result;
114  }
115 
116  // checks if the buffer is full
117  bool isFull() override {
118  if (buffer_size_total_bytes == 0) return false;
119  return queue_is_full(&queue);
120  }
121 
122  bool isEmpty() {
123  if (buffer_size_total_bytes == 0) return true;
124  return queue_is_empty(&queue);
125  }
126 
127  // write add an entry to the buffer
128  bool write(T data) override { return writeArray(&data, 1) == 1; }
129 
130  // clears the buffer
131  void reset() override {
132  queue_free(&queue);
133  buffer_size_total_bytes = 0;
134  }
135 
136  // provides the number of entries that are available to read
137  int available() override {
138  return buffer_size / sizeof(T);
139  }
140 
141  // provides the number of entries that are available to write
142  int availableForWrite() override { return size() - available(); }
143 
144  // returns the address of the start of the physical read buffer
145  T *address() override {
146  LOGE("address() not implemented");
147  return nullptr;
148  }
149 
150  size_t size() { return buffer_size_req_bytes / sizeof(T); }
151 
153  void setBlockingWrite(bool flag){
154  is_blocking_write = flag;
155  }
156 
157  protected:
158  queue_t queue;
159  int buffer_size_total_bytes = 0;
160  int buffer_size_req_bytes = 0;
161  int buffer_size = 0;
162  SingleBuffer<T> write_buffer{0};
163  audio_tools::RingBuffer<T> read_buffer{0};
164  bool is_blocking_write = true;
165 
166  int writeBlocking(const T data[], int len) {
167  LOGD("writeArray: %d", len);
168 
169  if (len > buffer_size){
170  LOGE("write %d too big for buffer_size: %d", len, buffer_size);
171  return 0;
172  }
173 
174  // fill the write buffer and when it is full flush it to the queue
175  for (int j = 0; j < len; j++) {
176  write_buffer.write(data[j]);
177  if (write_buffer.isFull()) {
178  LOGD("queue_add_blocking");
179  queue_add_blocking(&queue, write_buffer.data());
180  write_buffer.reset();
181  }
182  }
183  return len;
184  }
185 
186  int writeNonBlocking(const T data[], int len) {
187  if (len != buffer_size){
188  LOGE("write %d must be buffer_size: %d", len, buffer_size);
189  return 0;
190  }
191 
192  if (queue_try_add(&queue, write_buffer.data())){
193  return len;
194  }
195  return 0;
196  }
197 
198 };
199 
200 using BufferRP2040 = BufferRP2040T<uint8_t>;
201 
202 } // namespace audio_tools
Shared functionality of all buffers.
Definition: Buffers.h:30
Buffer implementation which is based on a RP2040 queue. This class is intended to be used to exchange...
Definition: BufferRP2040.h:26
T * address() override
returns the address of the start of the physical read buffer
Definition: BufferRP2040.h:145
void setBlockingWrite(bool flag)
When we use a non blocking write, the write size must be identical with the buffer size.
Definition: BufferRP2040.h:153
bool write(T data) override
write add an entry to the buffer
Definition: BufferRP2040.h:128
int available() override
provides the number of entries that are available to read
Definition: BufferRP2040.h:137
T peek()
peeks the actual entry from the buffer
Definition: BufferRP2040.h:68
int availableForWrite() override
provides the number of entries that are available to write
Definition: BufferRP2040.h:142
bool isFull() override
checks if the buffer is full
Definition: BufferRP2040.h:117
T read()
reads a single value
Definition: BufferRP2040.h:61
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition: BufferRP2040.h:101
bool resize(size_t size)
Re-Allocats the memory and the queue.
Definition: BufferRP2040.h:36
void reset() override
clears the buffer
Definition: BufferRP2040.h:131
int readArray(T data[], int len) override
reads multiple values
Definition: BufferRP2040.h:74
Implements a typed Ringbuffer.
Definition: Buffers.h:302
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition: Buffers.h:169
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:872