arduino-audio-tools
Loading...
Searching...
No Matches
I2SRP2040.h
1#pragma once
2
3#include "AudioTools/CoreAudio/AudioI2S/I2SConfig.h"
4#if defined(RP2040_HOWER)
5#include <I2S.h>
6
7#define IS_I2S_IMPLEMENTED
8
9namespace audio_tools {
10
18class I2SDriverRP2040 {
19 friend class I2SStream;
20
21 public:
23 I2SConfigStd defaultConfig(RxTxMode mode) {
24 I2SConfigStd c(mode);
25 return c;
26 }
28 bool setAudioInfo(AudioInfo info) {
29 if (info.sample_rate != cfg.sample_rate && !i2s.setFrequency(info.sample_rate)) {
30 LOGI("i2s.setFrequency %d failed", info.sample_rate);
31 return false;
32 }
33 if (info.bits_per_sample != cfg.bits_per_sample && !i2s.setBitsPerSample(info.bits_per_sample)) {
34 LOGI("i2s.setBitsPerSample %d failed", info.bits_per_sample);
35 return false;
36 }
37 cfg.sample_rate = info.sample_rate;
38 cfg.bits_per_sample = info.bits_per_sample;
39 cfg.channels = info.channels;
40 return true;
41 }
42
44 bool begin(RxTxMode mode = TX_MODE) {
45 TRACED();
46 return begin(defaultConfig(mode));
47 }
48
50 bool begin(I2SConfigStd cfg) {
51 TRACEI();
52 // prevent multiple begins w/o calling end
53 if (is_active) end();
54 this->cfg = cfg;
55 cfg.logInfo();
56 switch (cfg.rx_tx_mode) {
57 case TX_MODE:
58 i2s = I2S(OUTPUT);
59 break;
60 case RX_MODE:
61 i2s = I2S(INPUT);
62 has_input[0] = has_input[1] = false;
63 break;
64 default:
65 LOGE("Unsupported mode: only TX_MODE is supported");
66 return false;
67 break;
68 }
69
70// starting 5.3.0
71#if (ARDUINO_PICO_MAJOR >= 5 && ARDUINO_PICO_MINOR >= 3)
72 if (!cfg.is_master) {
73 if (!i2s.setSlave()) {
74 LOGE("Could not set slave mode");
75 return false;
76 }
77 }
78#endif
79
80 if (cfg.pin_ws == cfg.pin_bck + 1) { // normal pin order
81 if (!i2s.setBCLK(cfg.pin_bck)) {
82 LOGE("Could not set bck pin: %d", cfg.pin_bck);
83 return false;
84 }
85 } else if (cfg.pin_ws == cfg.pin_bck - 1) { // reverse pin order
86 if (!i2s.swapClocks() ||
87 !i2s.setBCLK(
88 cfg.pin_ws)) { // setBCLK() actually sets the lower pin of bck/ws
89 LOGE("Could not set bck pin: %d", cfg.pin_bck);
90 return false;
91 }
92 } else {
93 LOGE("pins bck: '%d' and ws: '%d' must be next to each other",
94 cfg.pin_bck, cfg.pin_ws);
95 return false;
96 }
97 if (!i2s.setDATA(cfg.pin_data)) {
98 LOGE("Could not set data pin: %d", cfg.pin_data);
99 return false;
100 }
101 if (cfg.pin_mck != -1) {
102 LOGI("Using MCK pin: %d with multiplier %d", cfg.pin_mck,
103 cfg.mck_multiplier);
104 i2s.setMCLKmult(cfg.mck_multiplier);
105 if (!i2s.setMCLK(cfg.pin_mck)) {
106 LOGE("Could not set data pin: %d", cfg.pin_mck);
107 return false;
108 }
109 }
110
111 if (cfg.bits_per_sample == 8 ||
112 !i2s.setBitsPerSample(cfg.bits_per_sample)) {
113 LOGE("Could not set bits per sample: %d", cfg.bits_per_sample);
114 return false;
115 }
116
117 if (!i2s.setBuffers(cfg.buffer_count, cfg.buffer_size)) {
118 LOGE("Could not set buffers: Count: '%d', size: '%d'", cfg.buffer_count,
119 cfg.buffer_size);
120 return false;
121 }
122
123 // setup format
124 if (cfg.i2s_format == I2S_STD_FORMAT ||
125 cfg.i2s_format == I2S_PHILIPS_FORMAT) {
126 // default setting: do nothing
127 } else if (cfg.i2s_format == I2S_LEFT_JUSTIFIED_FORMAT ||
128 cfg.i2s_format == I2S_LSB_FORMAT) {
129 if (!i2s.setLSBJFormat()) {
130 LOGE("Could not set LSB Format")
131 return false;
132 }
133 } else {
134 LOGE("Unsupported I2S format");
135 return false;
136 }
137
138 if (cfg.signal_type != TDM && (cfg.channels < 1 || cfg.channels > 2)) {
139 LOGE("Unsupported channels: '%d'", cfg.channels);
140 return false;
141 }
142
143 if (cfg.signal_type == TDM) {
144 i2s.setTDMFormat();
145 i2s.setTDMChannels(cfg.channels);
146 }
147
148 if (!i2s.begin(cfg.sample_rate)) {
149 LOGE("Could not start I2S");
150 return false;
151 }
152 is_active = true;
153 return true;
154 }
155
157 void end() {
158 flush();
159 i2s.end();
160 is_active = false;
161 }
162
164 I2SConfigStd config() { return cfg; }
165
167 size_t writeBytes(const void *src, size_t size_bytes) {
168 LOGD("writeBytes(%d)", size_bytes);
169 size_t result = 0;
170
171 if (cfg.channels == 1) {
172 result = writeExpandChannel(src, size_bytes);
173 } else if (cfg.channels == 2) {
174 const uint8_t *p = (const uint8_t *)src;
175 while (size_bytes >= sizeof(int32_t)) {
176 bool justWritten = i2s.write(
177 *(int32_t *)p,
178 true); // I2S::write(int32,bool) actually only returns 0 or 1
179 if (justWritten) {
180 size_bytes -= sizeof(int32_t);
181 p += sizeof(int32_t);
182 result += sizeof(int32_t);
183 } else
184 return result;
185 }
186 }
187 return result;
188 }
189
190 size_t readBytes(void *dest, size_t size_bytes) {
191 TRACED();
192 switch (cfg.channels) {
193 case 1:
194 return read1Channel(dest, size_bytes);
195 case 2:
196 return read2Channels(dest, size_bytes);
197 }
198 return 0;
199 }
200
201 int availableForWrite() {
202 if (cfg.channels == 1) {
203 return cfg.buffer_size;
204 } else {
205 return i2s.availableForWrite();
206 }
207 }
208
209 int available() { return min(i2s.available(), cfg.buffer_size); }
210
211 void flush() { i2s.flush(); }
212
213 bool getOverUnderflow() {
214 return i2s.getOverUnderflow() ;
215 }
216
217 protected:
218 I2SConfigStd cfg;
219 I2S i2s;
220 bool has_input[2];
221 bool is_active = false;
222
224 // returns amount of bytes written from src to i2s
225 size_t writeExpandChannel(const void *src, size_t size_bytes) {
226 switch (cfg.bits_per_sample) {
227 // case 8: {
228 // int8_t *pt8 = (int8_t*) src;
229 // int16_t sample16 = static_cast<int16_t>(*pt8) << 8;
230 // for (int j=0;j<size_bytes;j++){
231 // // 8 bit does not work
232 // i2s.write8(pt8[j], pt8[j]);
233 // //LOGI("%d", pt8[j]);
234 // }
235 // } break;
236 case 16: {
237 int16_t *pt16 = (int16_t *)src;
238 for (int j = 0; j < size_bytes / sizeof(int16_t); j++) {
239 i2s.write16(pt16[j], pt16[j]);
240 }
241 } break;
242 case 24: {
243 int32_t *pt24 = (int32_t *)src;
244 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
245 i2s.write24(pt24[j], pt24[j]);
246 }
247 } break;
248 case 32: {
249 int32_t *pt32 = (int32_t *)src;
250 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
251 i2s.write32(pt32[j], pt32[j]);
252 }
253 } break;
254 }
255 return size_bytes;
256 }
257
259 size_t read2Channels(void *dest, size_t size_bytes) {
260 TRACED();
261 size_t result = 0;
262 switch (cfg.bits_per_sample) {
263 // case 8:{
264 // int8_t *data = (int8_t*)dest;
265 // for (int j=0;j<size_bytes;j+=2){
266 // if (i2s.read8(data+j, data+j+1)){
267 // result+=2;;
268 // } else {
269 // return result;
270 // }
271 // }
272 // }break;
273
274 case 16: {
275 int16_t *data = (int16_t *)dest;
276 for (int j = 0; j < size_bytes / sizeof(int16_t); j += 2) {
277 if (i2s.read16(data + j, data + j + 1)) {
278 result += 4;
279 } else {
280 return result;
281 }
282 }
283 } break;
284
285 case 24: {
286 int32_t *data = (int32_t *)dest;
287 for (int j = 0; j < size_bytes / sizeof(int32_t); j += 2) {
288 if (i2s.read24(data + j, data + j + 1)) {
289 result += 8;
290 } else {
291 return result;
292 }
293 }
294 } break;
295
296 case 32: {
297 int32_t *data = (int32_t *)dest;
298 for (int j = 0; j < size_bytes / sizeof(int32_t); j += 2) {
299 if (i2s.read32(data + j, data + j + 1)) {
300 result += 8;
301 } else {
302 return result;
303 }
304 }
305
306 } break;
307 }
308 return result;
309 }
310
312 size_t read1Channel(void *dest, size_t size_bytes) {
313 TRACED();
314 size_t result = 0;
315 switch (cfg.bits_per_sample) {
316 // case 8:{
317 // int8_t tmp[2];
318 // int8_t *data = (int8_t*)dest;
319 // for (int j=0;j<size_bytes;j++){
320 // if (i2s.read8(tmp, tmp+1)){
321 // data[j] = mix(tmp[0], tmp[1]);
322 // result++;;
323 // } else {
324 // return result;
325 // }
326 // }
327 // }break;
328
329 case 16: {
330 int16_t tmp[2];
331 int16_t *data = (int16_t *)dest;
332 for (int j = 0; j < size_bytes / sizeof(int16_t); j++) {
333 if (i2s.read16(tmp, tmp + 1)) {
334 data[j] = mix(tmp[0], tmp[1]);
335 result += 2;
336 } else {
337 return result;
338 }
339 }
340 } break;
341
342 case 24: {
343 int32_t tmp[2];
344 int32_t *data = (int32_t *)dest;
345 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
346 if (i2s.read24(tmp, tmp + 1)) {
347 data[j] = mix(tmp[0], tmp[1]);
348 result += 4;
349 } else {
350 return result;
351 }
352 }
353 } break;
354
355 case 32: {
356 int32_t tmp[2];
357 int32_t *data = (int32_t *)dest;
358 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
359 if (i2s.read32(tmp, tmp + 1)) {
360 data[j] = mix(tmp[0], tmp[1]);
361 result += 4;
362 } else {
363 return result;
364 }
365 }
366 } break;
367 }
368 return result;
369 }
370
371 // we just provide the avg of both samples
372 template <class T>
373 T mix(T left, T right) {
374 if (left != 0) has_input[0] = true;
375 if (right != 0) has_input[1] = true;
376
377 // if right is always empty we return left
378 if (has_input[0] && !has_input[1]) {
379 return left;
380 }
381
382 // if left is always empty we return right
383 if (!has_input[0] && has_input[1]) {
384 return right;
385 }
386
387 return (left / 2) + (right / 2);
388 }
389};
390
391using I2SDriver = I2SDriverRP2040;
392
393} // namespace audio_tools
394
395#endif
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:30
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10