arduino-audio-tools
AudioKit.h
1 #pragma once
2 
3 #include "AudioTools.h"
4 #include "AudioKitHAL.h"
5 #include "AudioTools/CoreAudio/AudioI2S/I2SConfig.h"
6 #include "AudioTools/CoreAudio/AudioActions.h"
7 
8 #ifndef AUDIOKIT_V1
9 #error Upgrade the AudioKit library
10 #endif
11 
12 namespace audio_tools {
13 
14 class AudioKitStream;
15 static AudioKitStream *pt_AudioKitStream = nullptr;
16 
24 
25 friend class AudioKitStream;
26 
27  public:
28  AudioKitStreamConfig(RxTxMode mode=RXTX_MODE) { setupI2SPins(mode); };
29  // set adc channel with audio_hal_adc_input_t
30  audio_hal_adc_input_t input_device = AUDIOKIT_DEFAULT_INPUT;
31  // set dac channel
32  audio_hal_dac_output_t output_device = AUDIOKIT_DEFAULT_OUTPUT;
33  bool sd_active = true;
34  bool default_actions_active = true;
35  audio_kit_pins pins;
36  audio_hal_func_t driver = AUDIO_DRIVER;
37 
39  AudioKitConfig toAudioKitConfig() {
40  TRACED();
41  audiokit_config.driver = driver;
42  audiokit_config.pins = pins;
43  audiokit_config.i2s_num = (i2s_port_t)port_no;
44  audiokit_config.adc_input = input_device;
45  audiokit_config.dac_output = output_device;
46  audiokit_config.codec_mode = toCodecMode();
47  audiokit_config.master_slave_mode = toMode();
48  audiokit_config.fmt = toFormat();
49  audiokit_config.sample_rate = toSampleRate();
50  audiokit_config.bits_per_sample = toBits();
51 #if defined(ESP32)
52  audiokit_config.buffer_size = buffer_size;
53  audiokit_config.buffer_count = buffer_count;
54 #endif
55  // we use the AudioKit library only to set up the codec
56  audiokit_config.i2s_active = false;
57 #if AUDIOKIT_SETUP_SD
58  audiokit_config.sd_active = sd_active;
59 #else
60 // SD has been deactivated in the AudioKitConfig.h file
61  audiokit_config.sd_active = false;
62 #endif
63  LOGW("sd_active = %s", sd_active ? "true" : "false" );
64 
65  return audiokit_config;
66  }
67 
68 
69  protected:
70  AudioKitConfig audiokit_config;
71  board_driver board;
72 
74  void setupI2SPins(RxTxMode rxtx_mode) {
75  TRACED();
76  this->rx_tx_mode = rxtx_mode;
77  i2s_pin_config_t i2s_pins = {};
78  board.setup(pins);
79  board.get_i2s_pins((i2s_port_t)port_no, &i2s_pins);
80  pin_mck = i2s_pins.mck_io_num;
81  pin_bck = i2s_pins.bck_io_num;
82  pin_ws = i2s_pins.ws_io_num;
83  if (rx_tx_mode == RX_MODE){
84  pin_data = i2s_pins.data_in_num;
85  pin_data_rx = I2S_PIN_NO_CHANGE;
86  } else {
87  pin_data = i2s_pins.data_out_num;
88  pin_data_rx = i2s_pins.data_in_num;
89  }
90  };
91 
92  // convert to audio_hal_iface_samples_t
93  audio_hal_iface_bits_t toBits() {
94  TRACED();
95  static const int ia[] = {16, 24, 32};
96  static const audio_hal_iface_bits_t oa[] = {AUDIO_HAL_BIT_LENGTH_16BITS,
97  AUDIO_HAL_BIT_LENGTH_24BITS,
98  AUDIO_HAL_BIT_LENGTH_32BITS};
99  for (int j = 0; j < 3; j++) {
100  if (ia[j] == bits_per_sample) {
101  LOGD("-> %d",ia[j])
102  return oa[j];
103  }
104  }
105  LOGE("Bits per sample not supported: %d", bits_per_sample);
106  return AUDIO_HAL_BIT_LENGTH_16BITS;
107  }
108 
110  audio_hal_iface_samples_t toSampleRate() {
111  TRACED();
112  static const int ia[] = {8000, 11025, 16000, 22050,
113  24000, 32000, 44100, 48000};
114  static const audio_hal_iface_samples_t oa[] = {
115  AUDIO_HAL_08K_SAMPLES, AUDIO_HAL_11K_SAMPLES, AUDIO_HAL_16K_SAMPLES,
116  AUDIO_HAL_22K_SAMPLES, AUDIO_HAL_24K_SAMPLES, AUDIO_HAL_32K_SAMPLES,
117  AUDIO_HAL_44K_SAMPLES, AUDIO_HAL_48K_SAMPLES};
118  int diff = 99999;
119  int result = 0;
120  for (int j = 0; j < 8; j++) {
121  if (ia[j] == sample_rate) {
122  LOGD("-> %d",ia[j])
123  return oa[j];
124  } else {
125  int new_diff = abs((int)(oa[j] - sample_rate));
126  if (new_diff < diff) {
127  result = j;
128  diff = new_diff;
129  }
130  }
131  }
132  LOGE("Sample Rate not supported: %d - using %d", sample_rate, ia[result]);
133  return oa[result];
134  }
135 
137  audio_hal_iface_format_t toFormat() {
138  TRACED();
139  static const int ia[] = {I2S_STD_FORMAT,
140  I2S_LSB_FORMAT,
141  I2S_MSB_FORMAT,
142  I2S_PHILIPS_FORMAT,
143  I2S_RIGHT_JUSTIFIED_FORMAT,
144  I2S_LEFT_JUSTIFIED_FORMAT,
145  I2S_PCM};
146  static const audio_hal_iface_format_t oa[] = {
147  AUDIO_HAL_I2S_NORMAL, AUDIO_HAL_I2S_LEFT, AUDIO_HAL_I2S_RIGHT,
148  AUDIO_HAL_I2S_NORMAL, AUDIO_HAL_I2S_RIGHT, AUDIO_HAL_I2S_LEFT,
149  AUDIO_HAL_I2S_DSP};
150  for (int j = 0; j < 8; j++) {
151  if (ia[j] == i2s_format) {
152  LOGD("-> %d",j)
153  return oa[j];
154  }
155  }
156  LOGE("Format not supported: %d", i2s_format);
157  return AUDIO_HAL_I2S_NORMAL;
158  }
159 
162  audio_hal_iface_mode_t toMode() {
163  return (is_master) ? AUDIO_HAL_MODE_SLAVE : AUDIO_HAL_MODE_MASTER;
164  }
165 
167  audio_hal_codec_mode_t toCodecMode() {
168  switch (rx_tx_mode) {
169  case TX_MODE:
170  LOGD("-> %s","AUDIO_HAL_CODEC_MODE_DECODE");
171  return AUDIO_HAL_CODEC_MODE_DECODE;
172  case RX_MODE:
173  LOGD("-> %s","AUDIO_HAL_CODEC_MODE_ENCODE");
174  return AUDIO_HAL_CODEC_MODE_ENCODE;
175  default:
176  LOGD("-> %s","AUDIO_HAL_CODEC_MODE_BOTH");
177  return AUDIO_HAL_CODEC_MODE_BOTH;
178  }
179  }
180 };
181 
189 class AudioKitStream : public AudioStream {
190  public:
191  AudioKitStream() { pt_AudioKitStream = this; }
192 
195  TRACED();
196  AudioKitStreamConfig result{mode};
197  result.rx_tx_mode = mode;
198  return result;
199  }
200 
203  TRACED();
204  cfg = config;
205 
207  cfg.logInfo("AudioKitStream");
208 
209  // start codec
210  auto kit_cfg = cfg.toAudioKitConfig();
211  if (!kit.begin(kit_cfg)){
212  LOGE("begin faild: please verify your AUDIOKIT_BOARD setting: %d", AUDIOKIT_BOARD);
213  stop();
214  }
215 
216  // start i2s
217  i2s_stream.begin(cfg);
218 
219  // Volume control and headphone detection
220  if (cfg.default_actions_active){
221  setupActions();
222  }
223 
224  // set initial volume
225  setVolume(volume_value);
226  is_started = true;
227  return true;
228  }
229 
230  // restart after end with initial parameters
231  bool begin() override {
232  return begin(cfg);
233  }
234 
236  void end() override {
237  TRACED();
238  kit.end();
239  i2s_stream.end();
240  is_started = false;
241  }
242 
244  int available() {
245  return cfg.rx_tx_mode == TX_MODE ? 0 : DEFAULT_BUFFER_SIZE;
246  }
247 
248  size_t write(const uint8_t *data, size_t len) override {
249  return i2s_stream.write(data, len);
250  }
251 
253  size_t readBytes(uint8_t *data, size_t len) override {
254  return i2s_stream.readBytes(data, len);
255  }
256 
259  void setAudioInfo(AudioInfo info) override {
260  TRACEI();
261 
262  if (cfg.sample_rate != info.sample_rate
263  && cfg.bits_per_sample == info.bits_per_sample
264  && cfg.channels == info.channels
265  && is_started) {
266  // update sample rate only
267  LOGW("Update sample rate: %d", info.sample_rate);
268  cfg.sample_rate = info.sample_rate;
269  i2s_stream.setAudioInfo(cfg);
270  kit.setSampleRate(cfg.toSampleRate());
271  } else if (cfg.sample_rate != info.sample_rate
272  || cfg.bits_per_sample != info.bits_per_sample
273  || cfg.channels != info.channels
274  || !is_started) {
275  // more has changed and we need to start the processing
276  cfg.sample_rate = info.sample_rate;
277  cfg.bits_per_sample = info.bits_per_sample;
278  cfg.channels = info.channels;
279  cfg.logInfo("AudioKit");
280 
281  // Stop first
282  if(is_started){
283  end();
284  }
285  // start kit with new config
286  i2s_stream.begin(cfg);
287  kit.begin(cfg.toAudioKitConfig());
288  is_started = true;
289  }
290  }
291 
292  AudioKitStreamConfig &config() { return cfg; }
293 
295  bool setActive(bool active) { return kit.setActive(active); }
296 
298  bool setMute(bool mute) { return kit.setMute(mute); }
299 
301  bool setVolume(int vol) {
302  if (vol>100) LOGW("Volume is > 100: %d",vol);
303  // update variable, so if called before begin we set the default value
304  volume_value = vol;
305  return kit.setVolume(vol);
306  }
307 
309  bool setVolume(float vol) {
310  if (vol>1.0) LOGW("Volume is > 1.0: %f",vol);
311  // update variable, so if called before begin we set the default value
312  volume_value = 100.0 * vol;
313  return kit.setVolume(volume_value);
314  }
315 
317  bool setVolume(double vol) {
318  return setVolume((float)vol);
319  }
320 
322  int volume() { return kit.volume(); }
323 
326  void setSpeakerActive (bool active){
327  kit.setSpeakerActive(active);
328  }
329 
333  return kit.headphoneStatus();
334  }
335 
340  void processActions() {
341 // TRACED();
342  actions.processActions();
343  yield();
344  }
345 
354  void addAction(int pin, void (*action)(bool,int,void*), void* ref=nullptr ) {
355  TRACEI();
356  // determine logic from config
357  AudioActions::ActiveLogic activeLogic = getActionLogic(pin);
358  actions.add(pin, action, activeLogic, ref);
359  }
360 
370  void addAction(int pin, void (*action)(bool,int,void*), AudioActions::ActiveLogic activeLogic, void* ref=nullptr ) {
371  TRACEI();
372  actions.add(pin, action, activeLogic, ref);
373  }
374 
377  return actions;
378  }
379 
385  void incrementVolume(int vol) {
386  volume_value += vol;
387  LOGI("incrementVolume: %d -> %d",vol, volume_value);
388  kit.setVolume(volume_value);
389  }
390 
395  static void actionVolumeUp(bool, int, void*) {
396  TRACEI();
397  pt_AudioKitStream->incrementVolume(+2);
398  }
399 
404  static void actionVolumeDown(bool, int, void*) {
405  TRACEI();
406  pt_AudioKitStream->incrementVolume(-2);
407  }
408 
413  static void actionStartStop(bool, int, void*) {
414  TRACEI();
415  pt_AudioKitStream->active = !pt_AudioKitStream->active;
416  pt_AudioKitStream->setActive(pt_AudioKitStream->active);
417  }
418 
423  static void actionStart(bool, int, void*) {
424  TRACEI();
425  pt_AudioKitStream->active = true;
426  pt_AudioKitStream->setActive(pt_AudioKitStream->active);
427  }
428 
433  static void actionStop(bool, int, void*) {
434  TRACEI();
435  pt_AudioKitStream->active = false;
436  pt_AudioKitStream->setActive(pt_AudioKitStream->active);
437  }
438 
444  static void actionHeadphoneDetection(bool, int, void*) {
445  AudioKit::actionHeadphoneDetection();
446  }
447 
448 
455  int8_t pinAuxin() { return kit.pinAuxin(); }
456 
463  int8_t pinHeadphoneDetect() { return kit.pinHeadphoneDetect(); }
464 
471  int8_t pinPaEnable() { return kit.pinPaEnable(); }
472 
479  int8_t pinAdcDetect() { return kit.pinAdcDetect(); }
480 
487  int8_t pinEs7243Mclk() { return kit.pinEs7243Mclk(); }
488 
495  int8_t pinInputRec() { return kit.pinInputRec(); }
496 
503  int8_t pinInputMode() { return kit.pinInputMode(); }
504 
511  int8_t pinInputSet() { return kit.pinInputSet(); };
512 
519  int8_t pinInputPlay() { return kit.pinInputPlay(); }
520 
527  int8_t pinVolumeUp() { return kit.pinVolumeUp(); }
528 
535  int8_t pinVolumeDown() { return kit.pinVolumeDown(); }
536 
543  int8_t pinResetCodec() { return kit.pinResetCodec(); }
544 
551  int8_t pinResetBoard() { return kit.pinResetBoard(); }
552 
559  int8_t pinGreenLed() { return kit.pinGreenLed(); }
560 
567  int8_t pinBlueLed() { return kit.pinBlueLed(); }
568 
569  protected:
570  AudioKit kit;
571  I2SStream i2s_stream;
572  AudioKitStreamConfig cfg = defaultConfig(RXTX_MODE);
573  AudioActions actions;
574  int volume_value = 40;
575  bool active = true;
576  bool is_started = false;
577 
579  AudioActions::ActiveLogic getActionLogic(int pin){
580 #if defined(USE_EXT_BUTTON_LOGIC)
581  input_key_service_info_t input_key_info[] = INPUT_KEY_DEFAULT_INFO();
582  int size = sizeof(input_key_info) / sizeof(input_key_info[0]);
583  for (int j=0; j<size; j++){
584  if (pin == input_key_info[j].act_id){
585  switch(input_key_info[j].type){
586  case PERIPH_ID_ADC_BTN:
587  LOGD("getActionLogic for pin %d -> %d", pin, AudioActions::ActiveHigh);
588  return AudioActions::ActiveHigh;
589  case PERIPH_ID_BUTTON:
590  LOGD("getActionLogic for pin %d -> %d", pin, AudioActions::ActiveLow);
591  return AudioActions::ActiveLow;
592  case PERIPH_ID_TOUCH:
593  LOGD("getActionLogic for pin %d -> %d", pin, AudioActions::ActiveTouch);
594  return AudioActions::ActiveTouch;
595  }
596  }
597  }
598  LOGW("Undefined ActionLogic for pin: %d ",pin);
599 #endif
600  return AudioActions::ActiveLow;
601  }
602 
604  void setupActions() {
605  TRACEI();
606 
607  // pin conflicts with the SD CS pin for AIThinker and buttons
608  if (! (cfg.sd_active && (AUDIOKIT_BOARD==5 || AUDIOKIT_BOARD==6))){
609  LOGD("actionStartStop")
610  addAction(kit.pinInputMode(), actionStartStop);
611  } else {
612  LOGW("Mode Button ignored because of conflict: %d ",kit.pinInputMode());
613  }
614 
615  // pin conflicts with AIThinker A101 and headphone detection
616  if (! (cfg.sd_active && AUDIOKIT_BOARD==6)) {
617  LOGD("actionHeadphoneDetection pin:%d",kit.pinHeadphoneDetect())
618  actions.add(kit.pinHeadphoneDetect(), actionHeadphoneDetection, AudioActions::ActiveChange);
619  } else {
620  LOGW("Headphone detection ignored because of conflict: %d ",kit.pinHeadphoneDetect());
621  }
622 
623  // pin conflicts with SD Lyrat SD CS GpioPinand buttons / Conflict on Audiokit V. 2957
624  if (! (cfg.sd_active && (AUDIOKIT_BOARD==1 || AUDIOKIT_BOARD==7))){
625  LOGD("actionVolumeDown")
626  addAction(kit.pinVolumeDown(), actionVolumeDown);
627  LOGD("actionVolumeUp")
628  addAction(kit.pinVolumeUp(), actionVolumeUp);
629  } else {
630  LOGW("Volume Buttons ignored because of conflict: %d ",kit.pinVolumeDown());
631  }
632  }
633 };
634 
635 } // namespace audio_tools
A simple class to assign functions to gpio pins e.g. to implement a simple navigation control or volu...
Definition: AudioActions.h:29
void processActions()
Execute all actions if the corresponding pin is low To minimize the runtime: With each call we proces...
Definition: AudioActions.h:180
void add(Action &action)
Adds an Action.
Definition: AudioActions.h:133
Configuration for AudioKitStream: we use as subclass of I2SConfig.
Definition: AudioKit.h:23
AudioKitConfig toAudioKitConfig()
convert to config object needed by HAL
Definition: AudioKit.h:39
void setupI2SPins(RxTxMode rxtx_mode)
Defines the pins based on the information provided by the AudioKit project.
Definition: AudioKit.h:74
audio_hal_iface_mode_t toMode()
Definition: AudioKit.h:162
audio_hal_codec_mode_t toCodecMode()
Convert to audio_hal_codec_mode_t.
Definition: AudioKit.h:167
audio_hal_iface_samples_t toSampleRate()
Convert to audio_hal_iface_samples_t.
Definition: AudioKit.h:110
audio_hal_iface_format_t toFormat()
Convert to audio_hal_iface_format_t.
Definition: AudioKit.h:137
AudioKit Stream which uses the https://github.com/pschatzmann/arduino-audiokit library.
Definition: AudioKit.h:189
void addAction(int pin, void(*action)(bool, int, void *), void *ref=nullptr)
Defines a new action that is executed when the indicated pin is active.
Definition: AudioKit.h:354
static void actionVolumeDown(bool, int, void *)
Decrease the volume.
Definition: AudioKit.h:404
static void actionStartStop(bool, int, void *)
Toggle start stop.
Definition: AudioKit.h:413
int8_t pinGreenLed()
Get DSP reset gpio number.
Definition: AudioKit.h:559
bool setVolume(double vol)
Defines the Volume: Range 0 to 1.0.
Definition: AudioKit.h:317
void setSpeakerActive(bool active)
Definition: AudioKit.h:326
int8_t pinEs7243Mclk()
Get the mclk gpio number of es7243.
Definition: AudioKit.h:487
void addAction(int pin, void(*action)(bool, int, void *), AudioActions::ActiveLogic activeLogic, void *ref=nullptr)
Defines a new action that is executed when the indicated pin is active.
Definition: AudioKit.h:370
int8_t pinResetCodec()
Get green led gpio number.
Definition: AudioKit.h:543
int8_t pinInputPlay()
Get number for play function.
Definition: AudioKit.h:519
AudioActions::ActiveLogic getActionLogic(int pin)
Determines the action logic (ActiveLow or ActiveTouch) for the pin.
Definition: AudioKit.h:579
int available()
We get the data via I2S - we expect to fill one buffer size.
Definition: AudioKit.h:244
AudioActions & audioActions()
Provides access to the AudioActions.
Definition: AudioKit.h:376
int8_t pinBlueLed()
Get green led gpio number.
Definition: AudioKit.h:567
size_t readBytes(uint8_t *data, size_t len) override
Reads the audio data.
Definition: AudioKit.h:253
int volume()
Determines the volume.
Definition: AudioKit.h:322
void incrementVolume(int vol)
Relative volume control.
Definition: AudioKit.h:385
static void actionHeadphoneDetection(bool, int, void *)
Switch off the PA if the headphone in plugged in and switch it on again if the headphone is unplugged...
Definition: AudioKit.h:444
void end() override
Stops the processing.
Definition: AudioKit.h:236
bool setActive(bool active)
Sets the codec active / inactive.
Definition: AudioKit.h:295
bool setVolume(int vol)
Defines the Volume: Range 0 to 100.
Definition: AudioKit.h:301
int8_t pinVolumeDown()
Get number for volume down function.
Definition: AudioKit.h:535
int8_t pinInputSet()
Get number for set function.
Definition: AudioKit.h:511
void processActions()
Process input keys and pins.
Definition: AudioKit.h:340
int8_t pinInputRec()
Get the record-button id for adc-button.
Definition: AudioKit.h:495
static void actionVolumeUp(bool, int, void *)
Increase the volume.
Definition: AudioKit.h:395
AudioKitStreamConfig defaultConfig(RxTxMode mode=RXTX_MODE)
Provides the default configuration.
Definition: AudioKit.h:194
static void actionStart(bool, int, void *)
Start.
Definition: AudioKit.h:423
int8_t pinResetBoard()
Get DSP reset gpio number.
Definition: AudioKit.h:551
int8_t pinVolumeUp()
number for volume up function
Definition: AudioKit.h:527
int8_t pinHeadphoneDetect()
Get the gpio number for headphone detection.
Definition: AudioKit.h:463
bool setMute(bool mute)
Mutes the output.
Definition: AudioKit.h:298
int8_t pinAdcDetect()
Get the gpio number for adc detection.
Definition: AudioKit.h:479
void setupActions()
Setup the supported default actions.
Definition: AudioKit.h:604
static void actionStop(bool, int, void *)
Stop.
Definition: AudioKit.h:433
int8_t pinPaEnable()
Get the gpio number for PA enable.
Definition: AudioKit.h:471
void setAudioInfo(AudioInfo info) override
Definition: AudioKit.h:259
bool headphoneStatus()
Returns true if the headphone was detected.
Definition: AudioKit.h:332
bool begin(AudioKitStreamConfig config)
Starts the processing.
Definition: AudioKit.h:202
bool setVolume(float vol)
Defines the Volume: Range 0 to 1.0.
Definition: AudioKit.h:309
int8_t pinInputMode()
Get the number for mode-button.
Definition: AudioKit.h:503
int8_t pinAuxin()
Get the gpio number for auxin detection.
Definition: AudioKit.h:455
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: BaseStream.h:109
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition: BaseStream.h:117
Configuration for ESP32 legacy i2s.
Definition: I2SConfigESP32.h:23
RxTxMode rx_tx_mode
public settings
Definition: I2SConfigESP32.h:59
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:122
virtual void setAudioInfo(AudioInfo info)
updates the sample rate dynamically
Definition: I2SStream.h:92
virtual size_t write(const uint8_t *data, size_t len)
Writes the audio data to I2S.
Definition: I2SStream.h:115
void end()
Stops the I2S interface.
Definition: I2SStream.h:84
void stop()
Public generic methods.
Definition: AudioRuntime.h:27
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: AudioConfig.h:868
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:52
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