arduino-audio-tools
Loading...
Searching...
No Matches
I2SESP32.h
1#pragma once
2
3#include "AudioToolsConfig.h"
4#if defined(ESP32) && USE_LEGACY_I2S || defined(DOXYGEN)
5
6#include "AudioTools/CoreAudio/AudioI2S/I2SConfig.h"
7#include "driver/i2s.h"
8#include "esp_system.h"
9
10#ifndef I2S_MCLK_MULTIPLE_DEFAULT
11# define I2S_MCLK_MULTIPLE_DEFAULT ((i2s_mclk_multiple_t)0)
12#endif
13
14#define IS_I2S_IMPLEMENTED
15
16namespace audio_tools {
17
26 friend class AnalogAudio;
27 friend class AudioKitStream;
28
29 public:
32 I2SConfigESP32 c(mode);
33 return c;
34 }
35
38 // nothing to do
39 if (is_started) {
40 if (info.equals(cfg)) return true;
41 if (info.equalsExSampleRate(cfg)) {
42 cfg.sample_rate = info.sample_rate;
43 LOGI("i2s_set_sample_rates: %d", info.sample_rate);
44 return i2s_set_sample_rates((i2s_port_t)cfg.port_no, cfg.sample_rate) == ESP_OK;
45 }
46 } else {
47 LOGE("not started");
48 }
49 return false;
50 }
51
53 bool begin(RxTxMode mode) { return begin(defaultConfig(mode)); }
54
57 bool begin() { return !is_started ? begin(cfg) : true; }
58
61 TRACED();
62 this->cfg = cfg;
63 switch (cfg.rx_tx_mode) {
64 case TX_MODE:
65 return begin(cfg, cfg.pin_data, I2S_PIN_NO_CHANGE);
66 case RX_MODE:
67 // usually we expet cfg.pin_data but if the used assinged rx we might
68 // consider this one
69 return begin(
70 cfg, I2S_PIN_NO_CHANGE,
71 cfg.pin_data != I2S_PIN_NO_CHANGE ? cfg.pin_data : cfg.pin_data_rx);
72 default:
73 return begin(cfg, cfg.pin_data, cfg.pin_data_rx);
74 }
75 LOGE("Did not expect go get here");
76 }
77
79 int available() { return I2S_BUFFER_COUNT * I2S_BUFFER_SIZE; }
80
82 int availableForWrite() { return I2S_BUFFER_COUNT * I2S_BUFFER_SIZE; }
83
85 void end() {
86 TRACED();
87 i2s_driver_uninstall(i2s_num);
88 is_started = false;
89 }
90
92 I2SConfigESP32 config() { return cfg; }
93
95 size_t writeBytes(const void *src, size_t size_bytes) {
96 TRACED();
97
98 size_t result = 0;
99 if (isNoChannelConversion(cfg)) {
100 if (i2s_write(i2s_num, src, size_bytes, &result, ticks_to_wait_write) !=
101 ESP_OK) {
102 TRACEE();
103 }
104 LOGD("i2s_write %d -> %d bytes", size_bytes, result);
105 } else {
106 result =
107 writeExpandChannel(i2s_num, cfg.bits_per_sample, src, size_bytes);
108 }
109 return result;
110 }
111
112 size_t readBytes(void *dest, size_t size_bytes) {
113 size_t result = 0;
114 if (isNoChannelConversion(cfg)) {
115 if (i2s_read(i2s_num, dest, size_bytes, &result, ticks_to_wait_read) !=
116 ESP_OK) {
117 TRACEE();
118 }
119 } else if (cfg.channels == 1) {
120 // I2S has always 2 channels. We support to reduce it to 1
121 uint8_t temp[size_bytes * 2];
122 if (i2s_read(i2s_num, temp, size_bytes * 2, &result,
123 ticks_to_wait_read) != ESP_OK) {
124 TRACEE();
125 }
126 // convert to 1 channel
127 switch (cfg.bits_per_sample) {
128 case 16: {
129 ChannelReducerT<int16_t> reducer16(1, 2);
130 result = reducer16.convert((uint8_t *)dest, temp, result);
131 } break;
132 case 24: {
133 ChannelReducerT<int24_t> reducer24(1, 2);
134 result = reducer24.convert((uint8_t *)dest, temp, result);
135 } break;
136 case 32: {
137 ChannelReducerT<int32_t> reducer32(1, 2);
138 result = reducer32.convert((uint8_t *)dest, temp, result);
139 } break;
140 default:
141 LOGE("invalid bits_per_sample: %d", cfg.bits_per_sample);
142 break;
143 }
144 } else {
145 LOGE("Invalid channels: %d", cfg.channels);
146 }
147 return result;
148 }
149
150 void setWaitTimeReadMs(TickType_t ms) {
151 ticks_to_wait_read = pdMS_TO_TICKS(ms);
152 }
153 void setWaitTimeWriteMs(TickType_t ms) {
154 ticks_to_wait_write = pdMS_TO_TICKS(ms);
155 }
156
157 protected:
158 I2SConfigESP32 cfg = defaultConfig(RX_MODE);
159 i2s_port_t i2s_num;
160 i2s_config_t i2s_config;
161 bool is_started = false;
162 TickType_t ticks_to_wait_read = portMAX_DELAY;
163 TickType_t ticks_to_wait_write = portMAX_DELAY;
164
165 bool isNoChannelConversion(I2SConfigESP32 cfg) {
166 if (cfg.channels == 2) return true;
167 if (cfg.channels == 1 && cfg.channel_format == I2S_CHANNEL_FMT_ALL_RIGHT)
168 return true;
169 if (cfg.channels == 1 && cfg.channel_format == I2S_CHANNEL_FMT_ALL_LEFT)
170 return true;
171 if (cfg.channels == 1 && cfg.channel_format == I2S_CHANNEL_FMT_ONLY_RIGHT)
172 return true;
173 if (cfg.channels == 1 && cfg.channel_format == I2S_CHANNEL_FMT_ONLY_LEFT)
174 return true;
175 return false;
176 }
177
179 bool begin(I2SConfigESP32 cfg, int txPin, int rxPin) {
180 TRACED();
181 cfg.logInfo();
182 this->cfg = cfg;
183 this->i2s_num = (i2s_port_t)cfg.port_no;
184 setChannels(cfg.channels);
185
186 i2s_config_t i2s_config_new = {
187 .mode = toMode(cfg),
188 .sample_rate = (eps32_i2s_sample_rate_type)cfg.sample_rate,
189 .bits_per_sample = (i2s_bits_per_sample_t)cfg.bits_per_sample,
190 .channel_format = (i2s_channel_fmt_t)cfg.channel_format,
191 .communication_format = toCommFormat(cfg.i2s_format),
192 .intr_alloc_flags = 0, // default interrupt priority
193 .dma_buf_count = cfg.buffer_count,
194 .dma_buf_len = cfg.buffer_size,
195 .use_apll = (bool)cfg.use_apll,
196 .tx_desc_auto_clear = cfg.auto_clear,
197#if ESP_IDF_VERSION_MAJOR >= 4
198 .fixed_mclk = (int)(cfg.fixed_mclk > 0 ? cfg.fixed_mclk : 0),
199 .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT,
200 .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
201#endif
202 };
203 i2s_config = i2s_config_new;
204
205 // We make sure that we can reconfigure
206 if (is_started) {
207 end();
208 LOGD("%s", "I2S restarting");
209 }
210
211 // setup config
212 LOGD("i2s_driver_install");
213 if (i2s_driver_install(i2s_num, &i2s_config, 0, NULL) != ESP_OK) {
214 LOGE("%s - %s", __func__, "i2s_driver_install");
215 }
216
217 // setup pin config
218 if (this->cfg.signal_type == Digital || this->cfg.signal_type == PDM) {
219 i2s_pin_config_t pin_config = {
220#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 4, 0)
221 .mck_io_num = cfg.pin_mck,
222#endif
223 .bck_io_num = cfg.pin_bck,
224 .ws_io_num = cfg.pin_ws,
225 .data_out_num = txPin,
226 .data_in_num = rxPin};
227
228 LOGD("i2s_set_pin");
229 if (i2s_set_pin(i2s_num, &pin_config) != ESP_OK) {
230 LOGE("%s - %s", __func__, "i2s_set_pin");
231 }
232 } else {
233 LOGD("Using built in DAC");
234 // for internal DAC, this will enable both of the internal channels
235 i2s_set_pin(i2s_num, NULL);
236 }
237
238 // clear initial buffer
239 LOGD("i2s_zero_dma_buffer");
240 i2s_zero_dma_buffer(i2s_num);
241
242 is_started = true;
243 LOGD("%s - %s", __func__, "started");
244 return true;
245 }
246
247 // update the cfg.i2s.channel_format based on the number of channels
248 void setChannels(int channels) { cfg.channels = channels; }
249
251 size_t writeExpandChannel(i2s_port_t i2s_num, const int bits_per_sample,
252 const void *src, size_t size_bytes) {
253 size_t result = 0;
254 int j;
255 switch (bits_per_sample) {
256 case 8:
257 for (j = 0; j < size_bytes; j++) {
258 int8_t frame[2];
259 int8_t *data = (int8_t *)src;
260 frame[0] = data[j];
261 frame[1] = data[j];
262 size_t result_call = 0;
263 if (i2s_write(i2s_num, frame, sizeof(int8_t) * 2, &result_call,
264 ticks_to_wait_write) != ESP_OK) {
265 TRACEE();
266 } else {
267 result += result_call;
268 }
269 }
270 break;
271
272 case 16:
273 for (j = 0; j < size_bytes / 2; j++) {
274 int16_t frame[2];
275 int16_t *data = (int16_t *)src;
276 frame[0] = data[j];
277 frame[1] = data[j];
278 size_t result_call = 0;
279 if (i2s_write(i2s_num, frame, sizeof(int16_t) * 2, &result_call,
280 ticks_to_wait_write) != ESP_OK) {
281 TRACEE();
282 } else {
283 result += result_call;
284 }
285 }
286 break;
287
288 case 24:
289 for (j = 0; j < size_bytes / 4; j++) {
290 int24_t frame[2];
291 int24_t *data = (int24_t *)src;
292 frame[0] = data[j];
293 frame[1] = data[j];
294 size_t result_call = 0;
295 if (i2s_write(i2s_num, frame, sizeof(int24_t) * 2, &result_call,
296 ticks_to_wait_write) != ESP_OK) {
297 TRACEE();
298 } else {
299 result += result_call;
300 }
301 }
302 break;
303
304 case 32:
305 for (j = 0; j < size_bytes / 4; j++) {
306 int32_t frame[2];
307 int32_t *data = (int32_t *)src;
308 frame[0] = data[j];
309 frame[1] = data[j];
310 size_t result_call = 0;
311 if (i2s_write(i2s_num, frame, sizeof(int32_t) * 2, &result_call,
312 ticks_to_wait_write) != ESP_OK) {
313 TRACEE();
314 } else {
315 result += result_call;
316 }
317 }
318 break;
319 }
320 return size_bytes;
321 }
322
323#pragma GCC diagnostic push
324#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
325
326 // determines the i2s_comm_format_t - by default we use
327 // I2S_COMM_FORMAT_STAND_I2S
328 i2s_comm_format_t toCommFormat(I2SFormat mode) {
329 switch (mode) {
330 case I2S_PHILIPS_FORMAT:
331 case I2S_STD_FORMAT:
332 return (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S;
333 case I2S_LEFT_JUSTIFIED_FORMAT:
334 case I2S_MSB_FORMAT:
335 return (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S |
336 I2S_COMM_FORMAT_I2S_MSB);
337 case I2S_RIGHT_JUSTIFIED_FORMAT:
338 case I2S_LSB_FORMAT:
339 return (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S |
340 I2S_COMM_FORMAT_I2S_LSB);
341 case I2S_PCM:
342 return (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_PCM_SHORT;
343
344 default:
345 LOGE("unsupported mode");
346 return (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S;
347 }
348 }
349#pragma GCC diagnostic pop
350
351 int getModeDigital(I2SConfigESP32 &cfg) {
352 int i2s_format = cfg.is_master ? I2S_MODE_MASTER : I2S_MODE_SLAVE;
353 int i2s_rx_tx = 0;
354 switch (cfg.rx_tx_mode) {
355 case TX_MODE:
356 i2s_rx_tx = I2S_MODE_TX;
357 break;
358 case RX_MODE:
359 i2s_rx_tx = I2S_MODE_RX;
360 break;
361 case RXTX_MODE:
362 i2s_rx_tx = I2S_MODE_RX | I2S_MODE_TX;
363 break;
364 default:
365 LOGE("Undefined rx_tx_mode: %d", cfg.rx_tx_mode);
366 }
367 return (i2s_format | i2s_rx_tx);
368 }
369
370 // determines the i2s_format_t
371 i2s_mode_t toMode(I2SConfigESP32 &cfg) {
372 i2s_mode_t mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX);
373 switch (cfg.signal_type) {
374 case Digital:
375 mode = (i2s_mode_t)getModeDigital(cfg);
376 break;
377
378 case PDM:
379 mode = (i2s_mode_t)(getModeDigital(cfg) | I2S_MODE_PDM);
380 break;
381
382 case Analog:
383#if defined(USE_ANALOG)
384 mode = (i2s_mode_t)(cfg.rx_tx_mode ? I2S_MODE_DAC_BUILT_IN
385 : I2S_MODE_ADC_BUILT_IN);
386#else
387 LOGE("mode not supported");
388#endif
389 break;
390
391 default:
392 LOGW("signal_type undefined");
393 mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
394 break;
395 }
396 return mode;
397 }
398};
399
400using I2SDriver = I2SDriverESP32;
401
402} // namespace audio_tools
403
404#endif
AudioKit Stream which uses the https://github.com/pschatzmann/arduino-audiokit library.
Definition AudioKit.h:189
Configuration for ESP32 legacy i2s.
Definition I2SConfigESP32.h:24
RxTxMode rx_tx_mode
public settings
Definition I2SConfigESP32.h:60
Basic I2S API - for the ESP32. If we receive 1 channel, we expand the result to 2 channels.
Definition I2SESP32.h:25
bool begin(I2SConfigESP32 cfg)
starts the DAC
Definition I2SESP32.h:60
int available()
we assume the data is already available in the buffer
Definition I2SESP32.h:79
bool begin()
Definition I2SESP32.h:57
bool setAudioInfo(AudioInfo info)
Potentially updates the sample rate (if supported)
Definition I2SESP32.h:37
size_t writeExpandChannel(i2s_port_t i2s_num, const int bits_per_sample, const void *src, size_t size_bytes)
writes the data by making sure that we send 2 channels
Definition I2SESP32.h:251
int availableForWrite()
We limit the write size to the buffer size.
Definition I2SESP32.h:82
I2SConfigESP32 config()
provides the actual configuration
Definition I2SESP32.h:92
void end()
stops the I2C and unistalls the driver
Definition I2SESP32.h:85
bool begin(RxTxMode mode)
starts the DAC with the default config
Definition I2SESP32.h:53
I2SConfigESP32 defaultConfig(RxTxMode mode)
Provides the default configuration.
Definition I2SESP32.h:31
size_t writeBytes(const void *src, size_t size_bytes)
writes the data to the I2S interface
Definition I2SESP32.h:95
bool begin(I2SConfigESP32 cfg, int txPin, int rxPin)
starts the DAC
Definition I2SESP32.h:179
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition Int24_4bytes_t.h:16
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition AudioTypes.h:28
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
I2SFormat
I2S Formats.
Definition AudioTypes.h:416
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
bool equals(AudioInfo alt)
Returns true if alt values are the same like the current values.
Definition AudioTypes.h:85
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
bool equalsExSampleRate(AudioInfo alt)
Checks if only the sample rate is different.
Definition AudioTypes.h:88
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59