arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
I2SCodecStream.h
1#pragma once
2#include "AudioBoard.h" // install audio-driver library
3#include "AudioToolsConfig.h"
4#include "AudioTools/CoreAudio/AudioI2S/I2SStream.h"
5
6//#pragma GCC diagnostic ignored "-Wclass-memaccess"
7
8// Added to be compatible with the AudioKitStream.h
9#ifndef PIN_AUDIO_KIT_SD_CARD_CS
10#define PIN_AUDIO_KIT_SD_CARD_CS 13
11#define PIN_AUDIO_KIT_SD_CARD_MISO 2
12#define PIN_AUDIO_KIT_SD_CARD_MOSI 15
13#define PIN_AUDIO_KIT_SD_CARD_CLK 14
14#endif
15
16namespace audio_tools {
17
24struct I2SCodecConfig : public I2SConfig {
25 input_device_t input_device = ADC_INPUT_LINE1;
26 output_device_t output_device = DAC_OUTPUT_ALL;
27 // to be compatible with the AudioKitStream -> do not activate SD spi if false
28 bool sd_active = true;
29 // define pin source in driver configuration
30 PinFunction i2s_function = PinFunction::UNDEFINED; //CODEC;
31 bool operator==(I2SCodecConfig alt) {
32 return input_device == alt.input_device &&
33 output_device == alt.output_device && *((AudioInfo *)this) == alt;
34 }
35
36 bool operator!=(I2SCodecConfig alt) { return !(*this == alt); }
37};
38
46 public:
48 I2SCodecStream() = default;
59
62 auto cfg1 = i2s.defaultConfig(mode);
64 memcpy(&cfg, &cfg1, sizeof(cfg1));
65 cfg.input_device = ADC_INPUT_LINE1;
66 cfg.output_device = DAC_OUTPUT_ALL;
67 cfg.sd_active = true;
68 cfg.rx_tx_mode = mode;
69 return cfg;
70 }
71
72 bool begin() {
73 TRACED();
74 return begin(cfg);
75 }
76
78 virtual bool begin(I2SCodecConfig cfg) {
79 TRACED();
80 this->cfg = cfg;
81 this->info = cfg;
82 return begin1();
83 }
84
86 void end() {
87 TRACED();
88 if (p_board) p_board->end();
89 i2s.end();
90 is_active = false;
91 }
92
94 virtual void setAudioInfo(AudioInfo info) {
95 TRACEI();
97 i2s.setAudioInfo(info);
98
99 cfg.sample_rate = info.sample_rate;
101 cfg.channels = info.channels;
102
103 // update codec_cfg
104 codec_cfg.i2s.bits = toCodecBits(cfg.bits_per_sample);
105 codec_cfg.i2s.rate = toRate(cfg.sample_rate);
106
107 // return if we we are not ready
108 if (!is_active || p_board == nullptr) {
109 return;
110 }
111
112 // return if there is nothing to do
113 if (cfg.sample_rate == info.sample_rate &&
114 cfg.bits_per_sample == info.bits_per_sample &&
115 cfg.channels == info.channels) {
116 return;
117 }
118
119 // update cfg
120 p_board->setConfig(codec_cfg);
121 }
122
124 virtual size_t write(const uint8_t *data, size_t len) {
125 LOGD("I2SStream::write: %d", len);
126 return i2s.write(data, len);
127 }
128
130 virtual size_t readBytes(uint8_t *data, size_t len) override {
131 return i2s.readBytes(data, len);
132 }
133
135 virtual int available() override { return i2s.available(); }
136
138 virtual int availableForWrite() override { return i2s.availableForWrite(); }
139
141 bool setVolume(float vol) override {
143 if (!is_active || p_board == nullptr) return false;
144 return p_board->setVolume(vol * 100.0);
145 }
146
148 float volume() override {
149 if (p_board == nullptr) return 0.0f;
150 return static_cast<float>(p_board->getVolume()) / 100.0f;
151 }
153 float getVolume() { return volume(); }
154
156 bool setMute(bool mute) {
157 if (p_board == nullptr) return false;
158 return p_board->setMute(mute);
159 }
161 bool setMute(bool mute, int line) {
162 if (p_board == nullptr) return false;
163 return p_board->setMute(mute, line);
164 }
165
167 bool setPAPower(bool active) {
168 if (p_board == nullptr) return false;
169 return p_board->setPAPower(active);
170 }
171
173 bool setInputVolume(float vol){
174 if (!is_active || p_board == nullptr) return false;
175 return p_board->setInputVolume(100.0 * vol);
176 }
177
179 AudioBoard &board() { return *p_board; }
181 void setBoard(AudioBoard &board) { p_board = &board; }
183 void setBoard(AudioBoard *board) { p_board = board; }
185 bool hasBoard() { return p_board != nullptr; }
186
188 GpioPin getPinID(PinFunction function) {
189 if (p_board == nullptr) return -1;
190 return p_board->getPins().getPinID(function);
191 }
192
194 GpioPin getPinID(PinFunction function, int pos) {
195 if (p_board == nullptr) return -1;
196 return p_board->getPins().getPinID(function, pos);
197 }
198
200 GpioPin getKey(int pos) { return getPinID(PinFunction::KEY, pos); }
201
203 DriverPins &getPins() { return p_board->getPins(); }
204
206 I2SDriver *driver() { return i2s.driver(); }
207
208 protected:
209 I2SStream i2s;
210 I2SCodecConfig cfg;
211 CodecConfig codec_cfg;
212 AudioBoard *p_board = nullptr;
213 bool is_active = false;
214
215 bool begin1() {
216 TRACED();
218 setupI2SPins();
219 if (!beginCodec(cfg)) {
220 TRACEE();
221 is_active = false;
222 return false;
223 }
224 is_active = i2s.begin(cfg);
225
226 // if setvolume was called before begin
227 float tobeVol = VolumeSupport::volume();
228 if (is_active && tobeVol >= 0.0f) {
229 setVolume(tobeVol);
230 }
231 return is_active;
232 }
233
236 if (cfg.i2s_function == PinFunction::UNDEFINED){
237 if (cfg.rx_tx_mode == RX_MODE){
238 auto i2s = p_board->getPins().getI2SPins(PinFunction::CODEC_ADC);
239 if (i2s){
240 cfg.i2s_function = PinFunction::CODEC_ADC;
241 LOGI("using i2s_function: CODEC_ADC");
242 } else {
243 cfg.i2s_function = PinFunction::CODEC;
244 }
245 } else {
246 cfg.i2s_function = PinFunction::CODEC;
247 }
248 }
249 }
250
253 TRACED();
254 // determine relevant I2S pins from driver configuration
255 auto i2s = getI2SPins();
256 if (i2s) {
257 // determine i2s pins from board definition
258 PinsI2S i2s_pins = i2s.value();
259 cfg.pin_bck = i2s_pins.bck;
260 cfg.pin_mck = i2s_pins.mclk;
261 cfg.pin_ws = i2s_pins.ws;
262 switch (cfg.rx_tx_mode) {
263 case RX_MODE:
264 cfg.pin_data = i2s_pins.data_in;
265 break;
266 case TX_MODE:
267 cfg.pin_data = i2s_pins.data_out;
268 break;
269 default:
270 cfg.pin_data = i2s_pins.data_out;
271 cfg.pin_data_rx = i2s_pins.data_in;
272 break;
273 }
274 }
275 }
276
277 audio_driver_local::Optional<PinsI2S> getI2SPins(){
278 TRACED();
279 audio_driver_local::Optional<PinsI2S> i2s;
280 // Deterine I2S pins
281 return p_board->getPins().getI2SPins(cfg.i2s_function);
282 }
283
284 bool beginCodec(I2SCodecConfig info) {
285 TRACED();
286 switch (cfg.rx_tx_mode) {
287 case RX_MODE:
288 codec_cfg.input_device = info.input_device;
289 codec_cfg.output_device = DAC_OUTPUT_NONE;
290 break;
291 case TX_MODE:
292 codec_cfg.output_device = info.output_device;
293 codec_cfg.input_device = ADC_INPUT_NONE;
294 break;
295 default:
296 codec_cfg.input_device = info.input_device;
297 codec_cfg.output_device = info.output_device;
298 break;
299 }
300 codec_cfg.sd_active = info.sd_active;
301 LOGD("input: %d", info.input_device);
302 LOGD("output: %d", info.output_device);
303 codec_cfg.i2s.bits = toCodecBits(info.bits_per_sample);
304 codec_cfg.i2s.rate = toRate(info.sample_rate);
305 codec_cfg.i2s.fmt = toFormat(info.i2s_format);
306 codec_cfg.i2s.signal_type = (signal_t) info.signal_type;
307 // use reverse logic for codec setting
308 codec_cfg.i2s.mode = info.is_master ? MODE_SLAVE : MODE_MASTER;
309 if (p_board == nullptr) return false;
310
311 // setup driver only on changes
312 return p_board->begin(codec_cfg);
313 }
314
315 sample_bits_t toCodecBits(int bits) {
316 switch (bits) {
317 case 16:
318 LOGD("BIT_LENGTH_16BITS");
319 return BIT_LENGTH_16BITS;
320 case 24:
321 LOGD("BIT_LENGTH_24BITS");
322 return BIT_LENGTH_24BITS;
323 case 32:
324 LOGD("BIT_LENGTH_32BITS");
325 return BIT_LENGTH_32BITS;
326 }
327 LOGE("Unsupported bits: %d", bits);
328 return BIT_LENGTH_16BITS;
329 }
330 samplerate_t toRate(int rate) {
331 if (rate <= 8000) {
332 LOGD("RATE_8K");
333 return RATE_8K;
334 }
335 if (rate <= 11000) {
336 LOGD("RATE_11K");
337 return RATE_11K;
338 }
339 if (rate <= 16000) {
340 LOGD("RATE_16K");
341 return RATE_16K;
342 }
343 if (rate <= 22050) {
344 LOGD("RATE_22K");
345 return RATE_22K;
346 }
347 if (rate <= 32000) {
348 LOGD("RATE_32K");
349 return RATE_32K;
350 }
351 if (rate <= 44100) {
352 LOGD("RATE_44K");
353 return RATE_44K;
354 }
355 if (rate <= 48000 || rate > 48000) {
356 LOGD("RATE_48K");
357 return RATE_44K;
358 }
359 LOGE("Invalid rate: %d using 44K", rate);
360 return RATE_44K;
361 }
362
363 i2s_format_t toFormat(I2SFormat fmt) {
364 switch (fmt) {
365 case I2S_PHILIPS_FORMAT:
366 case I2S_STD_FORMAT:
367 LOGD("I2S_NORMAL");
368 return I2S_NORMAL;
369 case I2S_LEFT_JUSTIFIED_FORMAT:
370 case I2S_MSB_FORMAT:
371 LOGD("I2S_LEFT");
372 return I2S_LEFT;
373 case I2S_RIGHT_JUSTIFIED_FORMAT:
374 case I2S_LSB_FORMAT:
375 LOGD("I2S_RIGHT");
376 return I2S_RIGHT;
377 case I2S_PCM:
378 LOGD("I2S_DSP");
379 return I2S_DSP;
380 default:
381 LOGE("unsupported mode");
382 return I2S_NORMAL;
383 }
384 }
385};
386
387} // namespace audio_tools
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:119
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:127
I2S Stream which also sets up a codec chip and i2s.
Definition I2SCodecStream.h:45
bool hasBoard()
checks if a board has been defined
Definition I2SCodecStream.h:185
DriverPins & getPins()
Provides access to the pin information.
Definition I2SCodecStream.h:203
I2SCodecStream(AudioBoard &board)
Default constructor: for available AudioBoard values check audioboard variables in https://pschatzman...
Definition I2SCodecStream.h:56
bool setMute(bool mute, int line)
Mute / unmute of an individual line (codec)
Definition I2SCodecStream.h:161
virtual size_t readBytes(uint8_t *data, size_t len) override
Reads the audio data.
Definition I2SCodecStream.h:130
void setBoard(AudioBoard &board)
(re)defines the board
Definition I2SCodecStream.h:181
I2SCodecStream(AudioBoard *board)
Provide board via pointer.
Definition I2SCodecStream.h:58
virtual int availableForWrite() override
Provides the available audio data.
Definition I2SCodecStream.h:138
bool setInputVolume(float vol)
Sets the volume of the microphone (if available)
Definition I2SCodecStream.h:173
I2SCodecConfig defaultConfig(RxTxMode mode=TX_MODE)
Provides the default configuration.
Definition I2SCodecStream.h:61
float volume() override
Provides the actual volume (0.0f - 1.0f)
Definition I2SCodecStream.h:148
I2SDriver * driver()
Provides the i2s driver.
Definition I2SCodecStream.h:206
virtual void setAudioInfo(AudioInfo info)
updates the sample rate dynamically
Definition I2SCodecStream.h:94
virtual size_t write(const uint8_t *data, size_t len)
Writes the audio data to I2S.
Definition I2SCodecStream.h:124
GpioPin getKey(int pos)
Provides the gpio for the indicated key pos.
Definition I2SCodecStream.h:200
AudioBoard & board()
Provides the board.
Definition I2SCodecStream.h:179
I2SCodecStream()=default
Default Constructor (w/o codec)
bool setMute(bool mute)
Mute / unmote.
Definition I2SCodecStream.h:156
virtual bool begin(I2SCodecConfig cfg)
Starts the I2S interface.
Definition I2SCodecStream.h:78
void setupI2SFunction()
if the cfg.i2s_function was not defined we determine the "correct" default value
Definition I2SCodecStream.h:235
void end()
Stops the I2S interface.
Definition I2SCodecStream.h:86
void setupI2SPins()
We use the board pins if they are available.
Definition I2SCodecStream.h:252
GpioPin getPinID(PinFunction function, int pos)
Provides the gpio for the indicated function.
Definition I2SCodecStream.h:194
float getVolume()
legacy: same as volume()
Definition I2SCodecStream.h:153
void setBoard(AudioBoard *board)
(re)defines the board
Definition I2SCodecStream.h:183
bool setPAPower(bool active)
Sets the output of the PA Power Pin.
Definition I2SCodecStream.h:167
bool setVolume(float vol) override
sets the volume (range 0.0f - 1.0f)
Definition I2SCodecStream.h:141
GpioPin getPinID(PinFunction function)
Provides the gpio for the indicated function.
Definition I2SCodecStream.h:188
virtual int available() override
Provides the available audio data.
Definition I2SCodecStream.h:135
Configuration for ESP32 legacy i2s.
Definition I2SConfigESP32.h:23
RxTxMode rx_tx_mode
public settings
Definition I2SConfigESP32.h:59
Basic I2S API - for the ESP32. If we receive 1 channel, we expand the result to 2 channels.
Definition I2SESP32.h:27
We support the Stream interface for the I2S access. In addition we allow a separate mute pin which mi...
Definition I2SStream.h:33
virtual size_t readBytes(uint8_t *data, size_t len) override
Reads the audio data.
Definition I2SStream.h:125
virtual int availableForWrite() override
Provides the available audio data.
Definition I2SStream.h:133
I2SConfig defaultConfig(RxTxMode mode=TX_MODE)
Provides the default configuration.
Definition I2SStream.h:50
I2SDriver * driver()
Provides access to the driver.
Definition I2SStream.h:138
virtual void setAudioInfo(AudioInfo info)
updates the sample rate dynamically
Definition I2SStream.h:95
virtual size_t write(const uint8_t *data, size_t len)
Writes the audio data to I2S.
Definition I2SStream.h:118
void end()
Stops the I2S interface.
Definition I2SStream.h:85
virtual int available() override
Provides the available audio data.
Definition I2SStream.h:130
Supports the setting and getting of the volume.
Definition AudioTypes.h:189
virtual float volume()
provides the actual volume in the range of 0.0f to 1.0f
Definition AudioTypes.h:192
virtual bool setVolume(float volume)
define the actual volume in the range of 0.0f to 1.0f
Definition AudioTypes.h:194
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
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59
Configuration for I2SCodecStream.
Definition I2SCodecStream.h:24