add i2s initial microphone support

This commit is contained in:
gemu2015 2020-12-26 09:44:46 +01:00
parent 8b5adb3095
commit 9b890bcd98
1 changed files with 223 additions and 35 deletions

View File

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH)) #if (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH) || defined(USE_M5STACK_CORE2))
#include "AudioFileSourcePROGMEM.h" #include "AudioFileSourcePROGMEM.h"
#include "AudioFileSourceID3.h" #include "AudioFileSourceID3.h"
#include "AudioGeneratorMP3.h" #include "AudioGeneratorMP3.h"
@ -31,18 +31,32 @@
#include "AudioFileSourceBuffer.h" #include "AudioFileSourceBuffer.h"
#include "AudioGeneratorAAC.h" #include "AudioGeneratorAAC.h"
#undef AUDIO_PWR_ON
#undef AUDIO_PWR_OFF
#define AUDIO_PWR_ON
#define AUDIO_PWR_OFF
#ifdef USE_TTGO_WATCH #ifdef USE_TTGO_WATCH
#undef TTGO_PWR_ON #undef AUDIO_PWR_ON
#undef TTGO_PWR_OFF #undef AUDIO_PWR_OFF
#define TTGO_PWR_ON TTGO_audio_power(true); #define AUDIO_PWR_ON TTGO_audio_power(true);
#define TTGO_PWR_OFF TTGO_audio_power(false); #define AUDIO_PWR_OFF TTGO_audio_power(false);
#else
#undef TTGO_PWR_ON
#undef TTGO_PWR_OFF
#define TTGO_PWR_ON
#define TTGO_PWR_OFF
#endif // USE_TTGO_WATCH #endif // USE_TTGO_WATCH
#ifdef USE_M5STACK_CORE2
#undef AUDIO_PWR_ON
#undef AUDIO_PWR_OFF
#define AUDIO_PWR_ON CORE2_audio_power(true);
#define AUDIO_PWR_OFF CORE2_audio_power(false);
#undef DAC_IIS_BCK
#undef DAC_IIS_WS
#undef DAC_IIS_DOUT
#define DAC_IIS_BCK 12
#define DAC_IIS_WS 0
#define DAC_IIS_DOUT 2
#endif // USE_M5STACK_CORE2
#define EXTERNAL_DAC_PLAY 1 #define EXTERNAL_DAC_PLAY 1
#define XDRV_42 42 #define XDRV_42 42
@ -82,26 +96,36 @@ AudioGeneratorTalkie *talkie = nullptr;
//! MAX98357A + INMP441 DOUBLE I2S BOARD //! MAX98357A + INMP441 DOUBLE I2S BOARD
#ifdef ESP8266 #ifdef ESP8266
#undef TWATCH_DAC_IIS_BCK #undef DAC_IIS_BCK
#undef TWATCH_DAC_IIS_WS #undef DAC_IIS_WS
#undef TWATCH_DAC_IIS_DOUT #undef DAC_IIS_DOUT
#define TWATCH_DAC_IIS_BCK 15 #define DAC_IIS_BCK 15
#define TWATCH_DAC_IIS_WS 2 #define DAC_IIS_WS 2
#define TWATCH_DAC_IIS_DOUT 3 #define DAC_IIS_DOUT 3
#endif // ESP8266 #endif // ESP8266
// defaults to TTGO WATCH
#ifdef ESP32 #ifdef ESP32
#ifndef TWATCH_DAC_IIS_BCK #ifndef DAC_IIS_BCK
#undef TWATCH_DAC_IIS_BCK #undef DAC_IIS_BCK
#define TWATCH_DAC_IIS_BCK 26 #define DAC_IIS_BCK 26
#endif #endif
#ifndef TWATCH_DAC_IIS_WS
#undef TWATCH_DAC_IIS_WS #ifndef DAC_IIS_WS
#define TWATCH_DAC_IIS_WS 25 #undef DAC_IIS_WS
#define DAC_IIS_WS 25
#endif #endif
#ifndef TWATCH_DAC_IIS_DOUT
#undef TWATCH_DAC_IIS_DOUT #ifndef DAC_IIS_DOUT
#define TWATCH_DAC_IIS_DOUT 33 #undef DAC_IIS_DOUT
#define DAC_IIS_DOUT 33
#endif #endif
#ifndef DAC_IIS_DIN
#undef DAC_IIS_DIN
#define DAC_IIS_DIN 34
#endif
#endif // ESP32 #endif // ESP32
#ifdef SAY_TIME #ifdef SAY_TIME
@ -147,7 +171,10 @@ uint8_t spPAUSE1[] PROGMEM = {0x00,0x00,0x00,0x00,0xFF,0x0F};
void sayTime(int hour, int minutes, AudioGeneratorTalkie *talkie) ; void sayTime(int hour, int minutes, AudioGeneratorTalkie *talkie) ;
void sayTime(int hour, int minutes, AudioGeneratorTalkie *talkie) { void sayTime(int hour, int minutes, AudioGeneratorTalkie *talkie) {
TTGO_PWR_ON
if (!out) return;
AUDIO_PWR_ON
talkie = new AudioGeneratorTalkie(); talkie = new AudioGeneratorTalkie();
talkie->begin(nullptr, out); talkie->begin(nullptr, out);
@ -198,7 +225,7 @@ void sayTime(int hour, int minutes, AudioGeneratorTalkie *talkie) {
} }
delete talkie; delete talkie;
out->stop(); out->stop();
TTGO_PWR_OFF AUDIO_PWR_OFF
} }
#endif #endif
@ -210,11 +237,11 @@ void I2S_Init(void) {
#if EXTERNAL_DAC_PLAY #if EXTERNAL_DAC_PLAY
out = new AudioOutputI2S(); out = new AudioOutputI2S();
#ifdef ESP32 #ifdef ESP32
out->SetPinout(TWATCH_DAC_IIS_BCK, TWATCH_DAC_IIS_WS, TWATCH_DAC_IIS_DOUT); out->SetPinout(DAC_IIS_BCK, DAC_IIS_WS, DAC_IIS_DOUT);
#endif // ESP32 #endif // ESP32
#else #else
out = new AudioOutputI2S(0, 1); out = new AudioOutputI2S(0, 1);
#endif #endif // EXTERNAL_DAC_PLAY
is2_volume=10; is2_volume=10;
out->SetGain(((float)is2_volume/100.0)*4.0); out->SetGain(((float)is2_volume/100.0)*4.0);
@ -241,6 +268,163 @@ void I2S_Init(void) {
#endif // ESP32 #endif // ESP32
} }
#ifdef ESP32
#define MODE_MIC 0
#define MODE_SPK 1
#define Speak_I2S_NUMBER I2S_NUM_0
//#define MICSRATE 44100
#define MICSRATE 16000
#include <driver/i2s.h>
uint32_t SpeakerMic(uint8_t spkr) {
esp_err_t err = ESP_OK;
if (out) {
out->stop();
delete out;
out = nullptr;
}
i2s_driver_uninstall(Speak_I2S_NUMBER);
if (spkr==MODE_SPK) {
out = new AudioOutputI2S();
out->SetPinout(DAC_IIS_BCK, DAC_IIS_WS, DAC_IIS_DOUT);
out->SetGain(((float)is2_volume/100.0)*4.0);
out->stop();
} else {
// config mic
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER),
.sample_rate = MICSRATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 2,
//.dma_buf_len = 128,
.dma_buf_len = 1024,
};
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
err += i2s_driver_install(Speak_I2S_NUMBER, &i2s_config, 0, NULL);
i2s_pin_config_t tx_pin_config;
tx_pin_config.bck_io_num = DAC_IIS_BCK;
tx_pin_config.ws_io_num = DAC_IIS_WS;
tx_pin_config.data_out_num = DAC_IIS_DOUT;
tx_pin_config.data_in_num = DAC_IIS_DIN;
err += i2s_set_pin(Speak_I2S_NUMBER, &tx_pin_config);
err += i2s_set_clk(Speak_I2S_NUMBER, MICSRATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
}
return err;
}
#define DATA_SIZE 1024
TaskHandle_t mic_task_h;
uint32_t mic_size;
uint8_t *mic_buff;
char mic_path[32];
void mic_task(void *arg){
uint32_t data_offset = 0;
while (1) {
uint32_t bytes_read;
i2s_read(Speak_I2S_NUMBER, (char *)(mic_buff + data_offset), DATA_SIZE, &bytes_read, (100 / portTICK_RATE_MS));
if (bytes_read != DATA_SIZE) break;
data_offset += DATA_SIZE;
if (data_offset >= mic_size-DATA_SIZE) break;
}
SpeakerMic(MODE_SPK);
SaveWav(mic_path, mic_buff, mic_size);
free(mic_buff);
vTaskDelete(mic_task_h);
}
uint32_t i2s_record(char *path, uint32_t secs) {
esp_err_t err = ESP_OK;
if (decoder || mp3) return 0;
err = SpeakerMic(MODE_MIC);
if (err) {
SpeakerMic(MODE_SPK);
return err;
}
mic_size = secs * MICSRATE * 2;
mic_buff = (uint8_t*)heap_caps_malloc(mic_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if (!mic_buff) return 2;
if (*path=='+') {
path++;
strlcpy(mic_path, path , sizeof(mic_path));
xTaskCreatePinnedToCore(mic_task, "MIC", 4096, NULL, 3, &mic_task_h, 1);
return 0;
}
uint32_t data_offset = 0;
uint32_t stime=millis();
while (1) {
uint32_t bytes_read;
i2s_read(Speak_I2S_NUMBER, (char *)(mic_buff + data_offset), DATA_SIZE, &bytes_read, (100 / portTICK_RATE_MS));
if (bytes_read != DATA_SIZE) break;
data_offset += DATA_SIZE;
if (data_offset >= mic_size-DATA_SIZE) break;
delay(0);
}
//AddLog_P(LOG_LEVEL_INFO, PSTR("rectime: %d ms"), millis()-stime);
SpeakerMic(MODE_SPK);
// save to path
SaveWav(mic_path, mic_buff, mic_size);
free(mic_buff);
return 0;
}
static const uint8_t wavHTemplate[] PROGMEM = { // Hardcoded simple WAV header with 0xffffffff lengths all around
0x52, 0x49, 0x46, 0x46, 0xff, 0xff, 0xff, 0xff, 0x57, 0x41, 0x56, 0x45,
0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x22, 0x56, 0x00, 0x00, 0x88, 0x58, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00,
0x64, 0x61, 0x74, 0x61, 0xff, 0xff, 0xff, 0xff };
bool SaveWav(char *path, uint8_t *buff, uint32_t size) {
File fwp = fsp->open(path, FILE_WRITE);
uint8_t wavHeader[sizeof(wavHTemplate)];
memcpy_P(wavHeader, wavHTemplate, sizeof(wavHTemplate));
uint8_t channels = 1;
uint32_t hertz = MICSRATE;
uint8_t bps = 16;
wavHeader[22] = channels & 0xff;
wavHeader[23] = 0;
wavHeader[24] = hertz & 0xff;
wavHeader[25] = (hertz >> 8) & 0xff;
wavHeader[26] = (hertz >> 16) & 0xff;
wavHeader[27] = (hertz >> 24) & 0xff;
int byteRate = hertz * bps * channels / 8;
wavHeader[28] = byteRate & 0xff;
wavHeader[29] = (byteRate >> 8) & 0xff;
wavHeader[30] = (byteRate >> 16) & 0xff;
wavHeader[31] = (byteRate >> 24) & 0xff;
wavHeader[32] = channels * bps / 8;
wavHeader[33] = 0;
wavHeader[34] = bps;
wavHeader[35] = 0;
fwp.write(wavHeader, sizeof(wavHeader));
fwp.write(buff, size);
fwp.close();
return true;
}
#endif // ESP32
#ifdef ESP32 #ifdef ESP32
TaskHandle_t mp3_task_h; TaskHandle_t mp3_task_h;
@ -286,7 +470,8 @@ void StatusCallback(void *cbData, int code, const char *string) {
void Webradio(const char *url) { void Webradio(const char *url) {
if (decoder || mp3) return; if (decoder || mp3) return;
TTGO_PWR_ON if (!out) return;
AUDIO_PWR_ON
ifile = new AudioFileSourceICYStream(url); ifile = new AudioFileSourceICYStream(url);
ifile->RegisterMetadataCB(MDCallback, NULL); ifile->RegisterMetadataCB(MDCallback, NULL);
buff = new AudioFileSourceBuffer(ifile, preallocateBuffer, preallocateBufferSize); buff = new AudioFileSourceBuffer(ifile, preallocateBuffer, preallocateBufferSize);
@ -338,7 +523,7 @@ void StopPlaying() {
delete ifile; delete ifile;
ifile = NULL; ifile = NULL;
} }
TTGO_PWR_OFF AUDIO_PWR_OFF
} }
void Cmd_WebRadio(void) { void Cmd_WebRadio(void) {
@ -369,10 +554,11 @@ void I2S_WR_Show(void) {
void Play_mp3(const char *path) { void Play_mp3(const char *path) {
#if defined(USE_SCRIPT) && defined(USE_SCRIPT_FATFS) #if defined(USE_SCRIPT) && defined(USE_SCRIPT_FATFS)
if (decoder || mp3) return; if (decoder || mp3) return;
if (!out) return;
bool I2S_Task; bool I2S_Task;
TTGO_PWR_ON AUDIO_PWR_ON
if (*path=='+') { if (*path=='+') {
I2S_Task = true; I2S_Task = true;
path++; path++;
@ -411,13 +597,15 @@ void mp3_delete(void) {
delete id3; delete id3;
delete mp3; delete mp3;
mp3=nullptr; mp3=nullptr;
TTGO_PWR_OFF AUDIO_PWR_OFF
} }
#endif // ESP32 #endif // ESP32
void Say(char *text) { void Say(char *text) {
TTGO_PWR_ON if (!out) return;
AUDIO_PWR_ON
out->begin(); out->begin();
ESP8266SAM *sam = new ESP8266SAM; ESP8266SAM *sam = new ESP8266SAM;
@ -425,7 +613,7 @@ void Say(char *text) {
delete sam; delete sam;
out->stop(); out->stop();
TTGO_PWR_OFF AUDIO_PWR_OFF
} }