Skip to content

[I2S][SR] Add new I2S library and Sound Recognition support #8714

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Oct 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
@@ -86,6 +86,7 @@ jobs:
name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
# The version names here correspond to the versions of espressif/idf Docker image.
# See https://hub.docker.com/r/espressif/idf/tags and
7 changes: 5 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -82,6 +82,9 @@ set(LIBRARY_SRCS
libraries/BluetoothSerial/src/BTScanResultsSet.cpp
libraries/DNSServer/src/DNSServer.cpp
libraries/EEPROM/src/EEPROM.cpp
libraries/ESP_I2S/src/ESP_I2S.cpp
libraries/ESP_SR/src/ESP_SR.cpp
libraries/ESP_SR/src/esp32-hal-sr.c
libraries/ESPmDNS/src/ESPmDNS.cpp
libraries/Ethernet/src/ETH.cpp
libraries/FFat/src/FFat.cpp
@@ -91,7 +94,6 @@ set(LIBRARY_SRCS
libraries/HTTPUpdate/src/HTTPUpdate.cpp
libraries/LittleFS/src/LittleFS.cpp
libraries/Insights/src/Insights.cpp
libraries/I2S/src/I2S.cpp
libraries/NetBIOS/src/NetBIOS.cpp
libraries/Preferences/src/Preferences.cpp
libraries/RainMaker/src/RMaker.cpp
@@ -179,6 +181,8 @@ set(includedirs
libraries/BluetoothSerial/src
libraries/DNSServer/src
libraries/EEPROM/src
libraries/ESP_I2S/src
libraries/ESP_SR/src
libraries/ESP32/src
libraries/ESPmDNS/src
libraries/Ethernet/src
@@ -188,7 +192,6 @@ set(includedirs
libraries/HTTPUpdate/src
libraries/LittleFS/src
libraries/Insights/src
libraries/I2S/src
libraries/NetBIOS/src
libraries/Preferences/src
libraries/RainMaker/src
Empty file.
136 changes: 0 additions & 136 deletions libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino

This file was deleted.

21 changes: 21 additions & 0 deletions libraries/ESP_I2S/keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#######################################
# Syntax Coloring Map For ESP_I2S
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

ESP_I2S KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

onEvent KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################

SR_EVENT_WAKEWORD LITERAL1
9 changes: 9 additions & 0 deletions libraries/ESP_I2S/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=ESP_I2S
version=1.0.0
author=me-no-dev
maintainer=me-no-dev
sentence=Library for ESP I2S communication
paragraph=Supports ESP32 Arduino platforms.
category=Sound
url=https://github.com/espressif/arduino-esp32/
architectures=esp32
807 changes: 807 additions & 0 deletions libraries/ESP_I2S/src/ESP_I2S.cpp

Large diffs are not rendered by default.

145 changes: 145 additions & 0 deletions libraries/ESP_I2S/src/ESP_I2S.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#pragma once

#include "soc/soc_caps.h"
#if SOC_I2S_SUPPORTED

#include "Arduino.h"
#include "esp_err.h"
#include "driver/i2s_std.h"
#if SOC_I2S_SUPPORTS_TDM
#include "driver/i2s_tdm.h"
#endif
#if SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX
#include "driver/i2s_pdm.h"
#endif

typedef esp_err_t (*i2s_channel_read_fn)(i2s_chan_handle_t handle, char * tmp_buf, void *dest, size_t size, size_t *bytes_read, uint32_t timeout_ms);

typedef enum {
I2S_MODE_STD,
#if SOC_I2S_SUPPORTS_TDM
I2S_MODE_TDM,
#endif
#if SOC_I2S_SUPPORTS_PDM_TX
I2S_MODE_PDM_TX,
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
I2S_MODE_PDM_RX,
#endif
I2S_MODE_MAX
} i2s_mode_t;

typedef enum {
I2S_RX_TRANSFORM_NONE,
I2S_RX_TRANSFORM_32_TO_16,
I2S_RX_TRANSFORM_16_STEREO_TO_MONO,
I2S_RX_TRANSFORM_MAX
} i2s_rx_transform_t;

class I2SClass: public Stream {
public:
I2SClass();
~I2SClass();

//STD + TDM mode
void setPins(int8_t bclk, int8_t ws, int8_t dout, int8_t din=-1, int8_t mclk=-1);
void setInverted(bool bclk, bool ws, bool mclk=false);

//PDM TX + PDM RX mode
#if SOC_I2S_SUPPORTS_PDM_TX
void setPinsPdmTx(int8_t clk, int8_t dout0, int8_t dout1=-1);
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
void setPinsPdmRx(int8_t clk, int8_t din0, int8_t din1=-1, int8_t din2=-1, int8_t din3=-1);
#endif
#if SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX
void setInvertedPdm(bool clk);
#endif

bool begin(i2s_mode_t mode, uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch
#if SOC_I2S_SUPPORTS_TDM
, int8_t slot_mask=-1
#endif
);
bool configureTX(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch);
bool configureRX(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, i2s_rx_transform_t transform=I2S_RX_TRANSFORM_NONE);
bool end();

size_t readBytes(char *buffer, size_t size);
size_t write(uint8_t *buffer, size_t size);

i2s_chan_handle_t txChan();
uint32_t txSampleRate();
i2s_data_bit_width_t txDataWidth();
i2s_slot_mode_t txSlotMode();

i2s_chan_handle_t rxChan();
uint32_t rxSampleRate();
i2s_data_bit_width_t rxDataWidth();
i2s_slot_mode_t rxSlotMode();

int lastError();

int available();
int peek();
int read();
size_t write(uint8_t d);

// Record short PCM WAV to memory with current RX settings. Returns buffer that must be freed by the user.
uint8_t * recordWAV(size_t rec_seconds, size_t * out_size);
// Play short PCM WAV from memory
void playWAV(uint8_t * data, size_t len);
// Play short MP3 from memory
bool playMP3(uint8_t *src, size_t src_len);


private:
esp_err_t last_error;
i2s_mode_t _mode;

i2s_chan_handle_t tx_chan;
uint32_t tx_sample_rate;
i2s_data_bit_width_t tx_data_bit_width;
i2s_slot_mode_t tx_slot_mode;

i2s_channel_read_fn rx_fn;
i2s_rx_transform_t rx_transform;
char * rx_transform_buf;
size_t rx_transform_buf_len;

i2s_chan_handle_t rx_chan;
uint32_t rx_sample_rate;
i2s_data_bit_width_t rx_data_bit_width;
i2s_slot_mode_t rx_slot_mode;

//STD and TDM mode
int8_t _mclk, _bclk, _ws, _dout, _din;
bool _mclk_inv, _bclk_inv, _ws_inv;

//PDM mode
#if SOC_I2S_SUPPORTS_PDM_RX
int8_t _rx_clk, _rx_din0, _rx_din1, _rx_din2, _rx_din3; //TODO: soc_caps.h 1/4
bool _rx_clk_inv;
#endif
#if SOC_I2S_SUPPORTS_PDM_TX
int8_t _tx_clk, _tx_dout0, _tx_dout1;
bool _tx_clk_inv;
#endif

bool allocTranformRX(size_t buf_len);
bool transformRX(i2s_rx_transform_t transform);

static bool i2sDetachBus(void * bus_pointer);
bool initSTD(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch);
#if SOC_I2S_SUPPORTS_TDM
bool initTDM(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, int8_t slot_mask);
#endif
#if SOC_I2S_SUPPORTS_PDM_TX
bool initPDMtx(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch);
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
bool initPDMrx(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch);
#endif
};

#endif /* SOC_I2S_SUPPORTED */
91 changes: 91 additions & 0 deletions libraries/ESP_I2S/src/wav_header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#pragma once
#include <stdint.h>

/**
* @brief Header structure for WAV file with only one data chunk
*
* @note See this for reference: http://soundfile.sapp.org/doc/WaveFormat/
*
* @note Assignment to variables in this struct directly is only possible for little endian architectures
* (including Xtensa & RISC-V)
*/

typedef struct {
char chunk_id[4]; /*!< Contains the letters "RIFF" in ASCII form */
uint32_t chunk_size; /*!< This is the size of the rest of the chunk following this number */
char chunk_format[4]; /*!< Contains the letters "WAVE" */
} __attribute__((packed)) wav_descriptor_chunk_t; /*!< Canonical WAVE format starts with the RIFF header */

typedef struct {
char subchunk_id[4]; /*!< Contains the letters "fmt " */
uint32_t subchunk_size; /*!< PCM = 16, This is the size of the rest of the Subchunk which follows this number */
uint16_t audio_format; /*!< PCM = 1, values other than 1 indicate some form of compression */
uint16_t num_of_channels; /*!< Mono = 1, Stereo = 2, etc. */
uint32_t sample_rate; /*!< 8000, 44100, etc. */
uint32_t byte_rate; /*!< ==SampleRate * NumChannels * BitsPerSample s/ 8 */
uint16_t block_align; /*!< ==NumChannels * BitsPerSample / 8 */
uint16_t bits_per_sample; /*!< 8 bits = 8, 16 bits = 16, etc. */
} __attribute__((packed)) pcm_wav_fmt_chunk_t; /*!< The "fmt " subchunk describes the sound data's format */

typedef struct {
char subchunk_id[4]; /*!< Contains the letters "fmt " */
uint32_t subchunk_size; /*!< ALAW/MULAW = 18, This is the size of the rest of the Subchunk which follows this number */
uint16_t audio_format; /*!< ALAW = 6, MULAW = 7, values other than 1 indicate some form of compression */
uint16_t num_of_channels; /*!< ALAW/MULAW = 1, Mono = 1, Stereo = 2, etc. */
uint32_t sample_rate; /*!< ALAW/MULAW = 8000, 8000, 44100, etc. */
uint32_t byte_rate; /*!< ALAW/MULAW = 8000, ==SampleRate * NumChannels * BitsPerSample s/ 8 */
uint16_t block_align; /*!< ALAW/MULAW = 1, ==NumChannels * BitsPerSample / 8 */
uint16_t bits_per_sample; /*!< ALAW/MULAW = 8, 8 bits = 8, 16 bits = 16, etc. */
uint16_t ext_size; /*!< ALAW/MULAW = 0, Size of the extension (0 or 22) */
} __attribute__((packed)) non_pcm_wav_fmt_chunk_t; /*!< The "fmt " subchunk describes the sound data's format */

typedef struct {
char subchunk_id[4]; /*!< Contains the letters "data" */
uint32_t subchunk_size; /*!< ==NumSamples * NumChannels * BitsPerSample / 8 */
} __attribute__((packed)) wav_data_chunk_t; /*!< The "data" subchunk contains the size of the data and the actual sound */

typedef struct {
wav_descriptor_chunk_t descriptor_chunk; /*!< Canonical WAVE format starts with the RIFF header */
pcm_wav_fmt_chunk_t fmt_chunk; /*!< The "fmt " subchunk describes the sound data's format */
wav_data_chunk_t data_chunk; /*!< The "data" subchunk contains the size of the data and the actual sound */
} __attribute__((packed)) pcm_wav_header_t;

typedef struct {
wav_descriptor_chunk_t descriptor_chunk; /*!< Canonical WAVE format starts with the RIFF header */
non_pcm_wav_fmt_chunk_t fmt_chunk; /*!< The "fmt " subchunk describes the sound data's format */
wav_data_chunk_t data_chunk; /*!< The "data" subchunk contains the size of the data and the actual sound */
} __attribute__((packed)) non_pcm_wav_header_t;

#define WAVE_FORMAT_PCM 1 // PCM
#define WAVE_FORMAT_IEEE_FLOAT 3 // IEEE float
#define WAVE_FORMAT_ALAW 6 // 8-bit ITU-T G.711 A-law
#define WAVE_FORMAT_MULAW 7 // 8-bit ITU-T G.711 µ-law

#define PCM_WAV_HEADER_SIZE 44
#define NON_PCM_WAV_HEADER_SIZE 46

/**
* @brief Default header for PCM format WAV files
*
*/
#define PCM_WAV_HEADER_DEFAULT(wav_sample_size, wav_sample_bits, wav_sample_rate, wav_channel_num) { \
.descriptor_chunk = { \
.chunk_id = {'R', 'I', 'F', 'F'}, \
.chunk_size = (wav_sample_size) + sizeof(pcm_wav_header_t) - 8, \
.chunk_format = {'W', 'A', 'V', 'E'} \
}, \
.fmt_chunk = { \
.subchunk_id = {'f', 'm', 't', ' '}, \
.subchunk_size = 16, /* 16 for PCM */ \
.audio_format = WAVE_FORMAT_PCM, /* 1 for PCM */ \
.num_of_channels = (uint16_t)(wav_channel_num), \
.sample_rate = (wav_sample_rate), \
.byte_rate = (wav_sample_bits) * (wav_sample_rate) * (wav_channel_num) / 8, \
.block_align = (uint16_t)((wav_sample_bits) * (wav_channel_num) / 8), \
.bits_per_sample = (uint16_t)(wav_sample_bits)\
}, \
.data_chunk = { \
.subchunk_id = {'d', 'a', 't', 'a'}, \
.subchunk_size = (wav_sample_size) \
} \
}
92 changes: 92 additions & 0 deletions libraries/ESP_SR/examples/Basic/Basic.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@

#include "ESP_I2S.h"
#include "ESP_SR.h"

#define I2S_PIN_BCK 17
#define I2S_PIN_WS 47
#define I2S_PIN_DIN 16

#define LIGHT_PIN 40
#define FAN_PIN 41

I2SClass i2s;

// Generated using the following command:
// python3 tools/gen_sr_commands.py "Turn on the light,Switch on the light;Turn off the light,Switch off the light,Go dark;Start fan;Stop fan"
enum {
SR_CMD_TURN_ON_THE_LIGHT,
SR_CMD_TURN_OFF_THE_LIGHT,
SR_CMD_START_FAN,
SR_CMD_STOP_FAN,
};
static const sr_cmd_t sr_commands[] = {
{ 0, "Turn on the light", "TkN nN jc LiT"},
{ 0, "Switch on the light", "SWgp nN jc LiT"},
{ 1, "Turn off the light", "TkN eF jc LiT"},
{ 1, "Switch off the light", "SWgp eF jc LiT"},
{ 1, "Go dark", "Gb DnRK"},
{ 2, "Start fan", "STnRT FaN"},
{ 3, "Stop fan", "STnP FaN"},
};

void onSrEvent(sr_event_t event, int command_id, int phrase_id){
switch(event){
case SR_EVENT_WAKEWORD:
Serial.println("WakeWord Detected!");
break;
case SR_EVENT_WAKEWORD_CHANNEL:
Serial.printf("WakeWord Channel %d Verified!\n", command_id);
ESP_SR.setMode(SR_MODE_COMMAND); // Switch to Command detection
break;
case SR_EVENT_TIMEOUT:
Serial.println("Timeout Detected!");
ESP_SR.setMode(SR_MODE_WAKEWORD); // Switch back to WakeWord detection
break;
case SR_EVENT_COMMAND:
Serial.printf("Command %d Detected! %s\n", command_id, sr_commands[phrase_id].str);
switch(command_id){
case SR_CMD_TURN_ON_THE_LIGHT:
digitalWrite(LIGHT_PIN, HIGH);
break;
case SR_CMD_TURN_OFF_THE_LIGHT:
digitalWrite(LIGHT_PIN, LOW);
break;
case SR_CMD_START_FAN:
digitalWrite(FAN_PIN, HIGH);
break;
case SR_CMD_STOP_FAN:
digitalWrite(FAN_PIN, LOW);
break;
default:
Serial.println("Unknown Command!");
break;
}
ESP_SR.setMode(SR_MODE_COMMAND); // Allow for more commands to be given, before timeout
// ESP_SR.setMode(SR_MODE_WAKEWORD); // Switch back to WakeWord detection
break;
default:
Serial.println("Unknown Event!");
break;
}
}

void setup(){
Serial.begin(115200);

pinMode(LIGHT_PIN, OUTPUT);
digitalWrite(LIGHT_PIN, LOW);
pinMode(FAN_PIN, OUTPUT);
digitalWrite(FAN_PIN, LOW);

i2s.setPins(I2S_PIN_BCK, I2S_PIN_WS, -1, I2S_PIN_DIN);
i2s.setTimeout(1000);
i2s.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);


ESP_SR.onEvent(onSrEvent);
ESP_SR.begin(i2s, sr_commands, sizeof(sr_commands) / sizeof(sr_cmd_t), SR_CHANNELS_STEREO, SR_MODE_WAKEWORD);
}

void loop(){

}
40 changes: 40 additions & 0 deletions libraries/ESP_SR/keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#######################################
# Syntax Coloring Map For ESP_SR
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

ESP_SR KEYWORD1
ESP_SR_Class KEYWORD1
sr_cmd_t KEYWORD1
sr_event_t KEYWORD1
sr_mode_t KEYWORD1
sr_channels_t KEYWORD1
sr_cb KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

onEvent KEYWORD2
setMode KEYWORD2
pause KEYWORD2
resume KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################

SR_EVENT_WAKEWORD LITERAL1
SR_EVENT_WAKEWORD_CHANNEL LITERAL1
SR_EVENT_COMMAND LITERAL1
SR_EVENT_TIMEOUT LITERAL1
SR_MODE_OFF LITERAL1
SR_MODE_WAKEWORD LITERAL1
SR_MODE_COMMAND LITERAL1
SR_MODE_MAX LITERAL1
SR_CHANNELS_MONO LITERAL1
SR_CHANNELS_STEREO LITERAL1
SR_CHANNELS_MAX LITERAL1
9 changes: 9 additions & 0 deletions libraries/ESP_SR/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=ESP_SR
version=1.0.0
author=me-no-dev
maintainer=me-no-dev
sentence=Library for ESP Sound Recognition
paragraph=Supports ESP32 Arduino platforms.
category=Sound
url=https://github.com/espressif/arduino-esp32/
architectures=esp32
72 changes: 72 additions & 0 deletions libraries/ESP_SR/src/ESP_SR.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32S3 && (CONFIG_USE_WAKENET || CONFIG_USE_MULTINET)
#include "ESP_SR.h"

static esp_err_t on_sr_fill(void * arg, void * out, size_t len, size_t *bytes_read, uint32_t timeout_ms){
return ((ESP_SR_Class*)arg)->_fill(out, len, bytes_read, timeout_ms);
}

static void on_sr_event(void * arg, sr_event_t event, int command_id, int phrase_id){
((ESP_SR_Class*)arg)->_sr_event(event, command_id, phrase_id);
}

ESP_SR_Class::ESP_SR_Class()
: cb(NULL)
, i2s(NULL)
{

}

ESP_SR_Class::~ESP_SR_Class(){
end();
}

void ESP_SR_Class::onEvent(sr_cb event_cb){
cb = event_cb;
}

bool ESP_SR_Class::begin(I2SClass & _i2s, const sr_cmd_t * sr_commands, size_t sr_commands_len, sr_channels_t rx_chan, sr_mode_t mode){
i2s = &_i2s;
esp_err_t err = sr_start(on_sr_fill, this, rx_chan, mode, sr_commands, sr_commands_len, on_sr_event, this);
return (err == ESP_OK);
}

bool ESP_SR_Class::end(void){
return sr_stop() == ESP_OK;
}

bool ESP_SR_Class::setMode(sr_mode_t mode){
return sr_set_mode(mode) == ESP_OK;
}

bool ESP_SR_Class::pause(void){
return sr_pause() == ESP_OK;
}

bool ESP_SR_Class::resume(void){
return sr_resume() == ESP_OK;
}

void ESP_SR_Class::_sr_event(sr_event_t event, int command_id, int phrase_id){
if(cb){
cb(event, command_id, phrase_id);
}
}

esp_err_t ESP_SR_Class::_fill(void * out, size_t len, size_t *bytes_read, uint32_t timeout_ms){
if(i2s == NULL){
return ESP_FAIL;
}
i2s->setTimeout(timeout_ms);
*bytes_read = i2s->readBytes((char *)out, len);
return (esp_err_t)i2s->lastError();
}

ESP_SR_Class ESP_SR;

#endif // CONFIG_IDF_TARGET_ESP32S3
38 changes: 38 additions & 0 deletions libraries/ESP_SR/src/ESP_SR.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/

#pragma once
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32S3 && (CONFIG_USE_WAKENET || CONFIG_USE_MULTINET)

#include "ESP_I2S.h"
#include "esp32-hal-sr.h"

typedef void (*sr_cb)(sr_event_t event, int command_id, int phrase_id);

class ESP_SR_Class {
private:
sr_cb cb;
I2SClass * i2s;
public:
ESP_SR_Class();
~ESP_SR_Class();

void onEvent(sr_cb cb);
bool begin(I2SClass & i2s, const sr_cmd_t * sr_commands, size_t sr_commands_len, sr_channels_t rx_chan=SR_CHANNELS_STEREO, sr_mode_t mode=SR_MODE_WAKEWORD);
bool end(void);
bool setMode(sr_mode_t mode);
bool pause(void);
bool resume(void);

void _sr_event(sr_event_t event, int command_id, int phrase_id);
esp_err_t _fill(void * out, size_t len, size_t *bytes_read, uint32_t timeout_ms);
};

extern ESP_SR_Class ESP_SR;


#endif // CONFIG_IDF_TARGET_ESP32S3
445 changes: 445 additions & 0 deletions libraries/ESP_SR/src/esp32-hal-sr.c

Large diffs are not rendered by default.

76 changes: 76 additions & 0 deletions libraries/ESP_SR/src/esp32-hal-sr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/

#pragma once
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32S3 && (CONFIG_USE_WAKENET || CONFIG_USE_MULTINET)

#include "driver/i2s_types.h"
#include "esp_err.h"

#ifdef __cplusplus
extern "C" {
#endif

#define SR_CMD_STR_LEN_MAX 64
#define SR_CMD_PHONEME_LEN_MAX 64

typedef struct sr_cmd_t {
int command_id;
char str[SR_CMD_STR_LEN_MAX];
char phoneme[SR_CMD_PHONEME_LEN_MAX];
} sr_cmd_t;

typedef enum {
SR_EVENT_WAKEWORD,//WakeWord Detected
SR_EVENT_WAKEWORD_CHANNEL,//WakeWord Channel Verified
SR_EVENT_COMMAND,//Command Detected
SR_EVENT_TIMEOUT,//Command Timeout
SR_EVENT_MAX
} sr_event_t;

typedef enum {
SR_MODE_OFF,//Detection Off
SR_MODE_WAKEWORD,//WakeWord Detection
SR_MODE_COMMAND,//Command Detection
SR_MODE_MAX
} sr_mode_t;

typedef enum {
SR_CHANNELS_MONO,
SR_CHANNELS_STEREO,
SR_CHANNELS_MAX
} sr_channels_t;

typedef void (*sr_event_cb)(void * arg, sr_event_t event, int command_id, int phrase_id);
typedef esp_err_t (*sr_fill_cb)(void * arg, void * out, size_t len, size_t *bytes_read, uint32_t timeout_ms);

esp_err_t sr_start(sr_fill_cb fill_cb, void * fill_cb_arg, sr_channels_t rx_chan, sr_mode_t mode, const sr_cmd_t * sr_commands, size_t cmd_number, sr_event_cb cb, void * cb_arg);
esp_err_t sr_stop(void);
esp_err_t sr_pause(void);
esp_err_t sr_resume(void);
esp_err_t sr_set_mode(sr_mode_t mode);

// static const sr_cmd_t sr_commands[] = {
// {0, "Turn On the Light", "TkN nN jc LiT"},
// {0, "Switch On the Light", "SWgp nN jc LiT"},
// {1, "Switch Off the Light", "SWgp eF jc LiT"},
// {1, "Turn Off the Light", "TkN eF jc LiT"},
// {2, "Turn Red", "TkN RfD"},
// {3, "Turn Green", "TkN GRmN"},
// {4, "Turn Blue", "TkN BLo"},
// {5, "Customize Color", "KcSTcMiZ KcLk"},
// {6, "Sing a song", "Sgl c Sel"},
// {7, "Play Music", "PLd MYoZgK"},
// {8, "Next Song", "NfKST Sel"},
// {9, "Pause Playing", "PeZ PLdgl"},
// };

#ifdef __cplusplus
}
#endif

#endif // CONFIG_IDF_TARGET_ESP32S3
73 changes: 73 additions & 0 deletions libraries/ESP_SR/tools/gen_sr_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# pip3 install g2p_en
from g2p_en import G2p
import argparse

# python3 gen_sr_commands.py "Turn on the light,Switch on the light;Turn off the light,Switch off the light,Go dark;Start fan;Stop fan;Volume down,Turn down;Mute sound;Next song;Pause playback"
# enum {
# SR_CMD_TURN_ON_THE_LIGHT,
# SR_CMD_TURN_OFF_THE_LIGHT,
# SR_CMD_START_FAN,
# SR_CMD_STOP_FAN,
# SR_CMD_VOLUME_DOWN,
# SR_CMD_MUTE_SOUND,
# SR_CMD_NEXT_SONG,
# SR_CMD_PAUSE_PLAYBACK,
# };
# static const sr_cmd_t sr_commands[] = {
# { 0, "Turn on the light", "TkN nN jc LiT"},
# { 0, "Switch on the light", "SWgp nN jc LiT"},
# { 1, "Turn off the light", "TkN eF jc LiT"},
# { 1, "Switch off the light", "SWgp eF jc LiT"},
# { 1, "Go dark", "Gb DnRK"},
# { 2, "Start fan", "STnRT FaN"},
# { 3, "Stop fan", "STnP FaN"},
# { 4, "Volume down", "VnLYoM DtN"},
# { 4, "Turn down", "TkN DtN"},
# { 5, "Mute sound", "MYoT StND"},
# { 6, "Next song", "NfKST Sel"},
# { 7, "Pause playback", "PeZ PLdBaK"},
# };

def english_g2p(text):
g2p = G2p()
out = "static const sr_cmd_t sr_commands[] = {\n"
enum = "enum {\n"
alphabet={"AE1": "a", "N": "N", " ": " ", "OW1": "b", "V": "V", "AH0": "c", "L": "L", "F": "F", "EY1": "d", "S": "S", "B": "B", "R": "R", "AO1": "e", "D": "D", "AH1": "c", "EH1": "f", "OW0": "b", "IH0": "g", "G": "G", "HH": "h", "K": "K", "IH1": "g", "W": "W", "AY1": "i", "T": "T", "M": "M", "Z": "Z", "DH": "j", "ER0": "k", "P": "P", "NG": "l", "IY1": "m", "AA1": "n", "Y": "Y", "UW1": "o", "IY0": "m", "EH2": "f", "CH": "p", "AE0": "a", "JH": "q", "ZH": "r", "AA2": "n", "SH": "s", "AW1": "t", "OY1": "u", "AW2": "t", "IH2": "g", "AE2": "a", "EY2": "d", "ER1": "k", "TH": "v", "UH1": "w", "UW2": "o", "OW2": "b", "AY2": "i", "UW0": "o", "AH2": "c", "EH0": "f", "AW0": "t", "AO2": "e", "AO0": "e", "UH0": "w", "UH2": "w", "AA0": "n", "AY0": "i", "IY2": "m", "EY0": "d", "ER2": "k", "OY2": "u", "OY0": "u"}

cmd_id = 0
phrase_id = 0
text_list = text.split(";")
for item in text_list:
item = item.split(",")
phrase_id = 0
for phrase in item:
labels = g2p(phrase)
phoneme = ""
for char in labels:
if char not in alphabet:
print("skip %s, not found in alphabet")
continue
else:
phoneme += alphabet[char]
out += " { "+str(cmd_id)+", \""+phrase+"\", \""+phoneme+"\"},\n"
if phrase_id == 0:
enum += " SR_CMD_"+phrase.upper().replace(" ", "_")+",\n"
phrase_id += 1
cmd_id += 1
out += "};"
enum += "};"
# print(text)
print(enum)
print(out)

return out

if __name__ == "__main__":

parser = argparse.ArgumentParser(prog="English Speech Commands G2P")
parser.add_argument("text", type=str, default=None, help="input text")
args = parser.parse_args()

if args.text is not None:
english_g2p(args.text)

Empty file.
Empty file.
86 changes: 0 additions & 86 deletions libraries/I2S/examples/ADCPlotter/ADCPlotter.ino

This file was deleted.

Empty file.
Empty file.
Empty file.
59 changes: 0 additions & 59 deletions libraries/I2S/examples/FullDuplex/FullDuplex.ino

This file was deleted.

Empty file.
Empty file.
Empty file.

This file was deleted.

Empty file.
Empty file.
Empty file.
79 changes: 0 additions & 79 deletions libraries/I2S/examples/SimpleTone/SimpleTone.ino

This file was deleted.

61 changes: 0 additions & 61 deletions libraries/I2S/keywords.txt

This file was deleted.

9 changes: 0 additions & 9 deletions libraries/I2S/library.properties

This file was deleted.

1,222 changes: 0 additions & 1,222 deletions libraries/I2S/src/I2S.cpp

This file was deleted.

195 changes: 0 additions & 195 deletions libraries/I2S/src/I2S.h

This file was deleted.