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 if (!cfg.is_master) {
71 if (!i2s.setSlave()) {
72 LOGE("Could not set slave mode");
73 return false;
74 }
75 }
76
77 if (cfg.pin_ws == cfg.pin_bck + 1) { // normal pin order
78 if (!i2s.setBCLK(cfg.pin_bck)) {
79 LOGE("Could not set bck pin: %d", cfg.pin_bck);
80 return false;
81 }
82 } else if (cfg.pin_ws == cfg.pin_bck - 1) { // reverse pin order
83 if (!i2s.swapClocks() ||
84 !i2s.setBCLK(
85 cfg.pin_ws)) { // setBCLK() actually sets the lower pin of bck/ws
86 LOGE("Could not set bck pin: %d", cfg.pin_bck);
87 return false;
88 }
89 } else {
90 LOGE("pins bck: '%d' and ws: '%d' must be next to each other",
91 cfg.pin_bck, cfg.pin_ws);
92 return false;
93 }
94 if (!i2s.setDATA(cfg.pin_data)) {
95 LOGE("Could not set data pin: %d", cfg.pin_data);
96 return false;
97 }
98 if (cfg.pin_mck != -1) {
99 LOGI("Using MCK pin: %d with multiplier %d", cfg.pin_mck,
100 cfg.mck_multiplier);
101 i2s.setMCLKmult(cfg.mck_multiplier);
102 if (!i2s.setMCLK(cfg.pin_mck)) {
103 LOGE("Could not set data pin: %d", cfg.pin_mck);
104 return false;
105 }
106 }
107
108 if (cfg.bits_per_sample == 8 ||
109 !i2s.setBitsPerSample(cfg.bits_per_sample)) {
110 LOGE("Could not set bits per sample: %d", cfg.bits_per_sample);
111 return false;
112 }
113
114 if (!i2s.setBuffers(cfg.buffer_count, cfg.buffer_size)) {
115 LOGE("Could not set buffers: Count: '%d', size: '%d'", cfg.buffer_count,
116 cfg.buffer_size);
117 return false;
118 }
119
120 // setup format
121 if (cfg.i2s_format == I2S_STD_FORMAT ||
122 cfg.i2s_format == I2S_PHILIPS_FORMAT) {
123 // default setting: do nothing
124 } else if (cfg.i2s_format == I2S_LEFT_JUSTIFIED_FORMAT ||
125 cfg.i2s_format == I2S_LSB_FORMAT) {
126 if (!i2s.setLSBJFormat()) {
127 LOGE("Could not set LSB Format")
128 return false;
129 }
130 } else {
131 LOGE("Unsupported I2S format");
132 return false;
133 }
134
135 if (cfg.signal_type != TDM && (cfg.channels < 1 || cfg.channels > 2)) {
136 LOGE("Unsupported channels: '%d'", cfg.channels);
137 return false;
138 }
139
140 if (cfg.signal_type == TDM) {
141 i2s.setTDMFormat();
142 i2s.setTDMChannels(cfg.channels);
143 }
144
145 if (!i2s.begin(cfg.sample_rate)) {
146 LOGE("Could not start I2S");
147 return false;
148 }
149 is_active = true;
150 return true;
151 }
152
154 void end() {
155 flush();
156 i2s.end();
157 is_active = false;
158 }
159
161 I2SConfigStd config() { return cfg; }
162
164 size_t writeBytes(const void *src, size_t size_bytes) {
165 LOGD("writeBytes(%d)", size_bytes);
166 size_t result = 0;
167
168 if (cfg.channels == 1) {
169 result = writeExpandChannel(src, size_bytes);
170 } else if (cfg.channels == 2) {
171 const uint8_t *p = (const uint8_t *)src;
172 while (size_bytes >= sizeof(int32_t)) {
173 bool justWritten = i2s.write(
174 *(int32_t *)p,
175 true); // I2S::write(int32,bool) actually only returns 0 or 1
176 if (justWritten) {
177 size_bytes -= sizeof(int32_t);
178 p += sizeof(int32_t);
179 result += sizeof(int32_t);
180 } else
181 return result;
182 }
183 }
184 return result;
185 }
186
187 size_t readBytes(void *dest, size_t size_bytes) {
188 TRACED();
189 switch (cfg.channels) {
190 case 1:
191 return read1Channel(dest, size_bytes);
192 case 2:
193 return read2Channels(dest, size_bytes);
194 }
195 return 0;
196 }
197
198 int availableForWrite() {
199 if (cfg.channels == 1) {
200 return cfg.buffer_size;
201 } else {
202 return i2s.availableForWrite();
203 }
204 }
205
206 int available() { return min(i2s.available(), cfg.buffer_size); }
207
208 void flush() { i2s.flush(); }
209
210 bool getOverUnderflow() {
211 return i2s.getOverUnderflow() ;
212 }
213
214 protected:
215 I2SConfigStd cfg;
216 I2S i2s;
217 bool has_input[2];
218 bool is_active = false;
219
221 // returns amount of bytes written from src to i2s
222 size_t writeExpandChannel(const void *src, size_t size_bytes) {
223 switch (cfg.bits_per_sample) {
224 // case 8: {
225 // int8_t *pt8 = (int8_t*) src;
226 // int16_t sample16 = static_cast<int16_t>(*pt8) << 8;
227 // for (int j=0;j<size_bytes;j++){
228 // // 8 bit does not work
229 // i2s.write8(pt8[j], pt8[j]);
230 // //LOGI("%d", pt8[j]);
231 // }
232 // } break;
233 case 16: {
234 int16_t *pt16 = (int16_t *)src;
235 for (int j = 0; j < size_bytes / sizeof(int16_t); j++) {
236 i2s.write16(pt16[j], pt16[j]);
237 }
238 } break;
239 case 24: {
240 int32_t *pt24 = (int32_t *)src;
241 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
242 i2s.write24(pt24[j], pt24[j]);
243 }
244 } break;
245 case 32: {
246 int32_t *pt32 = (int32_t *)src;
247 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
248 i2s.write32(pt32[j], pt32[j]);
249 }
250 } break;
251 }
252 return size_bytes;
253 }
254
256 size_t read2Channels(void *dest, size_t size_bytes) {
257 TRACED();
258 size_t result = 0;
259 switch (cfg.bits_per_sample) {
260 // case 8:{
261 // int8_t *data = (int8_t*)dest;
262 // for (int j=0;j<size_bytes;j+=2){
263 // if (i2s.read8(data+j, data+j+1)){
264 // result+=2;;
265 // } else {
266 // return result;
267 // }
268 // }
269 // }break;
270
271 case 16: {
272 int16_t *data = (int16_t *)dest;
273 for (int j = 0; j < size_bytes / sizeof(int16_t); j += 2) {
274 if (i2s.read16(data + j, data + j + 1)) {
275 result += 4;
276 } else {
277 return result;
278 }
279 }
280 } break;
281
282 case 24: {
283 int32_t *data = (int32_t *)dest;
284 for (int j = 0; j < size_bytes / sizeof(int32_t); j += 2) {
285 if (i2s.read24(data + j, data + j + 1)) {
286 result += 8;
287 } else {
288 return result;
289 }
290 }
291 } break;
292
293 case 32: {
294 int32_t *data = (int32_t *)dest;
295 for (int j = 0; j < size_bytes / sizeof(int32_t); j += 2) {
296 if (i2s.read32(data + j, data + j + 1)) {
297 result += 8;
298 } else {
299 return result;
300 }
301 }
302
303 } break;
304 }
305 return result;
306 }
307
309 size_t read1Channel(void *dest, size_t size_bytes) {
310 TRACED();
311 size_t result = 0;
312 switch (cfg.bits_per_sample) {
313 // case 8:{
314 // int8_t tmp[2];
315 // int8_t *data = (int8_t*)dest;
316 // for (int j=0;j<size_bytes;j++){
317 // if (i2s.read8(tmp, tmp+1)){
318 // data[j] = mix(tmp[0], tmp[1]);
319 // result++;;
320 // } else {
321 // return result;
322 // }
323 // }
324 // }break;
325
326 case 16: {
327 int16_t tmp[2];
328 int16_t *data = (int16_t *)dest;
329 for (int j = 0; j < size_bytes / sizeof(int16_t); j++) {
330 if (i2s.read16(tmp, tmp + 1)) {
331 data[j] = mix(tmp[0], tmp[1]);
332 result += 2;
333 } else {
334 return result;
335 }
336 }
337 } break;
338
339 case 24: {
340 int32_t tmp[2];
341 int32_t *data = (int32_t *)dest;
342 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
343 if (i2s.read24(tmp, tmp + 1)) {
344 data[j] = mix(tmp[0], tmp[1]);
345 result += 4;
346 } else {
347 return result;
348 }
349 }
350 } break;
351
352 case 32: {
353 int32_t tmp[2];
354 int32_t *data = (int32_t *)dest;
355 for (int j = 0; j < size_bytes / sizeof(int32_t); j++) {
356 if (i2s.read32(tmp, tmp + 1)) {
357 data[j] = mix(tmp[0], tmp[1]);
358 result += 4;
359 } else {
360 return result;
361 }
362 }
363 } break;
364 }
365 return result;
366 }
367
368 // we just provide the avg of both samples
369 template <class T>
370 T mix(T left, T right) {
371 if (left != 0) has_input[0] = true;
372 if (right != 0) has_input[1] = true;
373
374 // if right is always empty we return left
375 if (has_input[0] && !has_input[1]) {
376 return left;
377 }
378
379 // if left is always empty we return right
380 if (!has_input[0] && has_input[1]) {
381 return right;
382 }
383
384 return (left / 2) + (right / 2);
385 }
386};
387
388using I2SDriver = I2SDriverRP2040;
389
390} // namespace audio_tools
391
392#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