diff --git a/examples/ml_synth_organ_example b/examples/ml_synth_organ_example index 4fd347f..4915dda 160000 --- a/examples/ml_synth_organ_example +++ b/examples/ml_synth_organ_example @@ -1 +1 @@ -Subproject commit 4fd347f04f9c8c58d173c6c09aad3c3fb1afbfb9 +Subproject commit 4915dda7dcc28781ff07e92f493000859b4904cb diff --git a/library.json b/library.json index 941dd9a..336ce28 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ML_SynthTools", - "version": "2.0.12", + "version": "2.0.14", "keywords": "ML_SynthTools, Synthesizer, Filter, Audio, ESP32, ESP32S2, ESP32S3, STM32, RP2040", "description": "Synthesizer Tools; contains waveform generators etc.", "repository": diff --git a/library.properties b/library.properties index b592deb..c08597b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ML SynthTools -version=2.0.12 +version=2.0.14 author=Marcel Licence maintainer=Marcel Licence sentence=Synthesizer Tools diff --git a/src/audio_module.h b/src/audio_module.h index 491e56f..6909cfb 100644 --- a/src/audio_module.h +++ b/src/audio_module.h @@ -53,6 +53,14 @@ #include +typedef enum +{ + AUDIO_PORT_0 = 0, + AUDIO_PORT_1 = 1, + // Add more outputs as needed +} AudioPortId; + + void Audio_Setup(void); void Audio_Output(const float *left, const float *right); void Audio_OutputMono(const int32_t *samples); @@ -60,6 +68,7 @@ void Audio_Output(const int32_t *samples); void Audio_Output(const int16_t *samples); void Audio_Output(const Q1_14 *samples); void Audio_Output(const int16_t *left, const int16_t *right); +void Audio_Output(AudioPortId audio_port, const int16_t *left, const int16_t *right); void Audio_Output(const Q1_14 *left, const Q1_14 *right); void Audio_Input(float *left, float *right); void Audio_Input(Q1_14 *left, Q1_14 *right); @@ -156,9 +165,8 @@ static float saw_right[SAMPLE_BUFFER_SIZE]; static int32_t saw_i32[SAMPLE_BUFFER_SIZE]; #endif #ifdef OUTPUT_SINE_TEST -static float sin_left[SAMPLE_BUFFER_SIZE]; -static float sin_right[SAMPLE_BUFFER_SIZE]; -static int32_t sine_i32[SAMPLE_BUFFER_SIZE]; +static float sin[4][SAMPLE_BUFFER_SIZE]; +static int32_t sine_i32[4][SAMPLE_BUFFER_SIZE]; #endif void Audio_Setup(void) @@ -192,22 +200,29 @@ void Audio_Setup(void) w *= 1.0f / ((float)SAMPLE_BUFFER_SIZE); w *= 2.0f * M_PI; float sine = sin(w); - sin_left[i] = sine; - sin_right[i] = sin(w * 2.0f); - sine *= 1073741824; - sine_i32[i] = sine; + for (int n = 0; n < 4; n++) + { + sine = sin(n * w * 2.0f); + sin[n][i] = sine; + sine *= 1073741824; + sine_i32[n][i] = sine; + } } #endif #ifdef ESP32_AUDIO_KIT #ifdef ES8388_ENABLED - ES8388_Setup(); - ES8388_SetIn2OoutVOL(0, 0); + ES8388_Setup(ES8388_ID0); + ES8388_SetIn2OoutVOL(ES8388_ID0, 0.0f); #else ac101_setup(); #endif #endif +#if defined(DUAL_CODEC_ENABLED) && defined(ES8388_ENABLED) + ES8388_Setup(ES8388_ID1); + ES8388_SetIn2OoutVOL(ES8388_ID1, 0.0f); +#endif #ifdef WM8978_ENABLED WM8978_Setup(); @@ -638,7 +653,7 @@ void Audio_Output(const Q1_14 *left, const Q1_14 *right) } #ifndef ARDUINO_SEEED_XIAO_M0 -void Audio_Output(const int16_t *left, const int16_t *right) +void Audio_Output(AudioPortId audio_port, const int16_t *left, const int16_t *right) { #ifdef ESP8266 for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++) @@ -703,7 +718,7 @@ void Audio_Output(const int16_t *left, const int16_t *right) } } #else - i2s_write_stereo_samples_i16(left, right, SAMPLE_BUFFER_SIZE); + i2s_write_stereo_samples_i16((uint8_t)audio_port, left, right, SAMPLE_BUFFER_SIZE); #endif #endif /* ESP32 */ @@ -830,6 +845,11 @@ void Audio_Output(const int16_t *left, const int16_t *right) #endif #endif /* PICO_AUDIO_I2S */ } + +void Audio_Output(const int16_t *left, const int16_t *right) +{ + Audio_Output(AUDIO_PORT_0, left, right); +} #endif #if (defined ESP32) || (defined TEENSYDUINO) || (defined ARDUINO_DAISY_SEED) || (defined ARDUINO_GENERIC_F407VGTX) || (defined ARDUINO_DISCO_F407VG) || (defined ARDUINO_BLACK_F407VE) || (defined ARDUINO_ARCH_RP2040) || (((defined ARDUINO_RASPBERRY_PI_PICO) || (defined ARDUINO_GENERIC_RP2040)) && (defined RP2040_AUDIO_PWM)) @@ -844,9 +864,14 @@ void Audio_Input(Q1_14 *left, Q1_14 *right) i2s_read_stereo_samples_buff((int16_t *)left, (int16_t *)right, SAMPLE_BUFFER_SIZE); } +void Audio_Input(AudioPortId audio_port, int16_t *left, int16_t *right) +{ + i2s_read_stereo_samples_buff((uint8_t)audio_port, left, right, SAMPLE_BUFFER_SIZE); +} + void Audio_Input(int16_t *left, int16_t *right) { - i2s_read_stereo_samples_buff(left, right, SAMPLE_BUFFER_SIZE); + Audio_Input(AUDIO_PORT_0, left, right); } #else void Audio_Input(float *left __attribute__((__unused__)), float *right __attribute__((__unused__))) @@ -862,8 +887,8 @@ void Audio_Output(const float *left, const float *right) right = saw_right; #endif #ifdef OUTPUT_SINE_TEST - left = sin_left; - right = sin_right; + left = sin[0]; + right = sin[1]; #endif #ifdef ESP32 diff --git a/src/es8388.h b/src/es8388.h index a1bbd3b..258e622 100644 --- a/src/es8388.h +++ b/src/es8388.h @@ -29,7 +29,7 @@ */ /** - * @file es8388.ino + * @file es8388.h * @author Marcel Licence * @date 22.08.2021 * @@ -42,6 +42,9 @@ #ifdef __CDT_PARSER__ #include +#define ES8388_ENABLED +#define ML_SYNTH_INLINE_DECLARATION +#define ML_SYNTH_INLINE_DEFINITION #endif @@ -49,14 +52,26 @@ #ifdef ES8388_ENABLED -void ES8388_Setup(void); -void ES8388_SetIn2OoutVOL(uint8_t unused, float vol); +typedef enum +{ + ES8388_ID0 = 0, + ES8388_ID1 = 1, + // Add more outputs as needed +} ES8388Id; + +bool ES8388_Setup(void); +bool ES8388_Setup(ES8388Id codec_id); + +void ES8388_MuteOutput(ES8388Id codec_id, bool mute); +void ES8388_MuteOutput(bool mute); +void ES8388_SetDACVOL(ES8388Id codec_id, float vol); void ES8388_SetDACVOL(float vol); -void ES8388_SetDACVOL(uint8_t unused, float vol); +void ES8388_SetIn2OoutVOL(ES8388Id codec_id, float vol); +void ES8388_SetIn2OoutVOL(float vol); +void ES8388_SetOUT1VOL(ES8388Id codec_id, float vol); void ES8388_SetOUT1VOL(float vol); -void ES8388_SetOUT1VOL(uint8_t unused, float vol); +void ES8388_SetOUT2VOL(ES8388Id codec_id, float vol); void ES8388_SetOUT2VOL(float vol); -void ES8388_SetOUT2VOL(uint8_t unused, float vol); #endif // ES8388_ENABLED @@ -73,9 +88,8 @@ void ES8388_SetOUT2VOL(uint8_t unused, float vol); /* ES8388 address */ -//#define ES8388_ADDR 0x20 /*!< 0x22:CE=1;0x20:CE=0*/ -#define ES8388_ADDR 0x10 /*!< 0x22:CE=1;0x20:CE=0*/ - +#define ES8388_ADDR_0 0x10 /*!< I2C address with CE = low */ +#define ES8388_ADDR_1 0x11 /*!< I2C address with CE = high */ /* ES8388 register */ #define ES8388_CONTROL1 0x00 @@ -140,14 +154,17 @@ void ES8388_SetOUT2VOL(uint8_t unused, float vol); #define ES8388_DACCONTROL30 0x34 -uint8_t ES8388_ReadReg(uint8_t reg) +static const uint16_t es8388_addr[] = {ES8388_ADDR_0, ES8388_ADDR_1}; + + +uint8_t ES8388_ReadReg(ES8388Id codec_id, uint8_t reg) { - Wire.beginTransmission(ES8388_ADDR); + Wire.beginTransmission(es8388_addr[codec_id]); Wire.write(reg); Wire.endTransmission(false); uint8_t val = 0u; - if (1 == Wire.requestFrom(uint16_t(ES8388_ADDR), uint8_t(1), true)) + if (1 == Wire.requestFrom(es8388_addr[codec_id], uint8_t(1), true)) { val = Wire.read(); } @@ -155,44 +172,67 @@ uint8_t ES8388_ReadReg(uint8_t reg) return val; } -bool ES8388_WriteReg(uint8_t reg, uint8_t val) +uint8_t ES8388_ReadReg(uint8_t reg) { - Wire.beginTransmission(ES8388_ADDR); + return ES8388_ReadReg(ES8388_ID0, reg); +} + +bool ES8388_WriteReg(ES8388Id codec_id, uint8_t reg, uint8_t val) +{ + Wire.beginTransmission(es8388_addr[codec_id]); Wire.write(reg); Wire.write(val); return 0 == Wire.endTransmission(true); } -bool ES8388_begin(int sda, int scl, uint32_t frequency) +bool ES8388_WriteReg(uint8_t reg, uint8_t val) +{ + return ES8388_WriteReg(ES8388_ID0, reg, val); +} + +bool ES8388_begin(ES8388Id codec_id, int sda, int scl, uint32_t frequency) { - bool ok = Wire.begin(sda, scl, frequency); + static bool wireInitReq = true; + + bool ok = true; + + if (wireInitReq) + { + ok = Wire.begin(sda, scl, frequency); + wireInitReq = false; + } /* Reset all registers, readback default as sanity check */ delay(100); - Serial.printf("0x00: 0x%02x\n", ES8388_ReadReg(ES8388_CONTROL1)); - Serial.printf("0x01: 0x%02x\n", ES8388_ReadReg(ES8388_CONTROL2)); + Serial.printf("0x00: 0x%02x\n", ES8388_ReadReg(codec_id, ES8388_CONTROL1)); + Serial.printf("0x01: 0x%02x\n", ES8388_ReadReg(codec_id, ES8388_CONTROL2)); - ES8388_WriteReg(ES8388_CONTROL1, 1 << 7); /* do reset! */ - ES8388_WriteReg(ES8388_CONTROL1, 0x06); - ES8388_WriteReg(ES8388_CONTROL2, 0x50); + ES8388_WriteReg(codec_id, ES8388_CONTROL1, 1 << 7); /* do reset! */ + ES8388_WriteReg(codec_id, ES8388_CONTROL1, 0x06); + ES8388_WriteReg(codec_id, ES8388_CONTROL2, 0x50); - ok &= (0x06 == ES8388_ReadReg(ES8388_CONTROL1)); - ok &= (0x50 == ES8388_ReadReg(ES8388_CONTROL2)); + ok &= (0x06 == ES8388_ReadReg(codec_id, ES8388_CONTROL1)); + ok &= (0x50 == ES8388_ReadReg(codec_id, ES8388_CONTROL2)); return ok; } -void es8388_read_all() +bool ES8388_begin(int sda, int scl, uint32_t frequency) +{ + return ES8388_begin(ES8388_ID0, sda, scl, frequency); +} + +void es8388_read_all(ES8388Id codec_id) { for (int i = 0; i < 53; i++) { uint8_t reg = 0; - reg = ES8388_ReadReg(i); + reg = ES8388_ReadReg(codec_id, i); Serial.printf("Reg 0x%02x = 0x%02x\n", i, reg); } } -void ES8388_SetADCVOL(uint8_t unused, float vol) +void ES8388_SetADCVOL(ES8388Id codec_id, float vol) { #ifdef STATUS_ENABLED Status_ValueChangedInt("ADC Volume /db", (vol - 1) * 97 + 0.5); @@ -208,11 +248,16 @@ void ES8388_SetADCVOL(uint8_t unused, float vol) volu8 = 192; } - ES8388_WriteReg(0x10, volu8); // LADCVOL - ES8388_WriteReg(0x11, volu8); // RADCVOL + ES8388_WriteReg(codec_id, 0x10, volu8); // LADCVOL + ES8388_WriteReg(codec_id, 0x11, volu8); // RADCVOL } -void ES8388_SetDACVOL(float vol) +void ES8388_SetADCVOL(float vol) +{ + ES8388_SetADCVOL(ES8388_ID0, vol); +} + +void ES8388_SetDACVOL(ES8388Id codec_id, float vol) { #ifdef STATUS_ENABLED Status_ValueChangedInt("DAC Volume /db", (vol - 1) * 97 + 0.5); @@ -228,16 +273,16 @@ void ES8388_SetDACVOL(float vol) volu8 = 192; } - ES8388_WriteReg(0x1A, volu8); // LDACVOL - ES8388_WriteReg(0x1B, volu8); // RDACVOL + ES8388_WriteReg(codec_id, 0x1A, volu8); // LDACVOL + ES8388_WriteReg(codec_id, 0x1B, volu8); // RDACVOL } -void ES8388_SetDACVOL(uint8_t unused, float vol) +void ES8388_SetDACVOL(float vol) { - ES8388_SetDACVOL(vol); + ES8388_SetDACVOL(ES8388_ID0, vol); } -void ES8388_SetPGAGain(uint8_t unused, float vol) +void ES8388_SetPGAGain(ES8388Id codec_id, float vol) { #ifdef STATUS_ENABLED Status_ValueChangedInt("PGA Gain /db", vol * 24 + 0.25); @@ -252,10 +297,15 @@ void ES8388_SetPGAGain(uint8_t unused, float vol) volu8 = 8; } /* ES8388_ADCCONTROL1 */ - ES8388_WriteReg(0x09, volu8 + (volu8 << 4)); // MicAmpL, MicAmpR + ES8388_WriteReg(codec_id, 0x09, volu8 + (volu8 << 4)); // MicAmpL, MicAmpR } -void ES8388_SetInputCh(uint8_t ch, float var) +void ES8388_SetPGAGain(float vol) +{ + ES8388_SetPGAGain(ES8388_ID0, vol); +} + +void ES8388_SetInputCh(ES8388Id codec_id, uint8_t ch, float var) { if (var > 0) { @@ -277,7 +327,7 @@ void ES8388_SetInputCh(uint8_t ch, float var) return; } /* ES8388_ADCCONTROL2 */ - ES8388_WriteReg(0x0A, (in << 6) + (in << 4)); // LINSEL , RINSEL , DSSEL , DSR + ES8388_WriteReg(codec_id, 0x0A, (in << 6) + (in << 4)); // LINSEL , RINSEL , DSSEL , DSR #ifdef STATUS_ENABLED Status_ValueChangedInt("ADC Ch", in); @@ -285,7 +335,12 @@ void ES8388_SetInputCh(uint8_t ch, float var) } } -void ES8388_SetMixInCh(uint8_t ch, float var) +void ES8388_SetInputCh(uint8_t ch, float var) +{ + ES8388_SetInputCh(ES8388_ID0, ch, var); +} + +void ES8388_SetMixInCh(ES8388Id codec_id, uint8_t ch, float var) { if (var > 0) { @@ -312,14 +367,19 @@ void ES8388_SetMixInCh(uint8_t ch, float var) return; } /* ES8388_DACCONTROL16 */ - ES8388_WriteReg(0x26, in + (in << 3)); // LMIXSEL, RMIXSEL + ES8388_WriteReg(codec_id, 0x26, in + (in << 3)); // LMIXSEL, RMIXSEL #ifdef STATUS_ENABLED Status_ValueChangedInt("Mix In Ch", in); #endif } } -void ES8388_SetIn2OoutVOL(uint8_t unused, float vol) +void ES8388_SetMixInCh(uint8_t ch, float var) +{ + ES8388_SetMixInCh(ES8388_ID0, ch, var); +} + +void ES8388_SetIn2OoutVOL(ES8388Id codec_id, float vol) { #ifdef STATUS_ENABLED Status_ValueChangedInt("In to out volume /db", (vol - 1) * 16 + 0.5); @@ -360,7 +420,12 @@ void ES8388_SetIn2OoutVOL(uint8_t unused, float vol) ES8388_WriteReg(0x2A, (volu8 << 3) + var); // RD2RO, RI2RO, RI2ROVOL } -void ES8388_SetOUT1VOL(float vol) +void ES8388_SetIn2OoutVOL(float vol) +{ + ES8388_SetIn2OoutVOL(ES8388_ID0, vol); +} + +void ES8388_SetOUT1VOL(ES8388Id codec_id, float vol) { #ifdef STATUS_ENABLED Status_ValueChangedInt("OUT1VOL /db", (vol - 1) * 31 + 0.5); @@ -375,16 +440,33 @@ void ES8388_SetOUT1VOL(float vol) volu8 = 129; } - ES8388_WriteReg(0x2E, volu8); // LOUT1VOL - ES8388_WriteReg(0x2F, volu8); // ROUT1VOL + ES8388_WriteReg(codec_id, 0x2E, volu8); // LOUT1VOL + ES8388_WriteReg(codec_id, 0x2F, volu8); // ROUT1VOL } -void ES8388_SetOUT1VOL(uint8_t unused, float vol) +void ES8388_SetOUT1VOL(float vol) { - ES8388_SetOUT1VOL(vol); + ES8388_SetOUT1VOL(ES8388_ID0, vol); } -void ES8388_SetOUT2VOL(float vol) +void ES8388_MuteOutput(ES8388Id codec_id, bool mute) +{ + if (mute) + { + ES8388_WriteReg(codec_id, ES8388_DACCONTROL3, 0x36); // DAC Mute + } + else + { + ES8388_WriteReg(codec_id, ES8388_DACCONTROL3, 0x32); // DAC Unmute + } +} + +void ES8388_MuteOutput(bool mute) +{ + ES8388_MuteOutput(ES8388_ID0, mute); +} + +void ES8388_SetOUT2VOL(ES8388Id codec_id, float vol) { #ifdef STATUS_ENABLED Status_ValueChangedInt("OUT2VOL /db", (vol - 1) * 31 + 0.5); @@ -399,37 +481,45 @@ void ES8388_SetOUT2VOL(float vol) volu8 = 129; } - ES8388_WriteReg(0x30, volu8); // LOUT2VOL - ES8388_WriteReg(0x31, volu8); // ROUT2VOL + ES8388_WriteReg(codec_id, 0x30, volu8); // LOUT2VOL + ES8388_WriteReg(codec_id, 0x31, volu8); // ROUT2VOL } -void ES8388_SetOUT2VOL(uint8_t unused, float vol) +void ES8388_SetOUT2VOL(float vol) { - ES8388_SetOUT2VOL(vol); + ES8388_SetOUT2VOL(ES8388_ID0, vol); } -void ES8388_Setup() +bool ES8388_Setup(ES8388Id codec_id) { const uint32_t i2c_freq = 400000; - Serial.printf("Connect to ES8388 codec...\n"); + Serial.printf("Connect to ES8388[%u] codec...\n", codec_id); Serial.printf(" SDA: %d\n ", ES8388_PIN_SDA); Serial.printf(" SCL: %d\n", ES8388_PIN_SCL); Serial.printf(" freq: %" PRIu32 "\n", i2c_freq); - while (not ES8388_begin(ES8388_PIN_SDA, ES8388_PIN_SCL, i2c_freq)) + uint8_t retries = 10; + + while (not ES8388_begin(codec_id, ES8388_PIN_SDA, ES8388_PIN_SCL, i2c_freq) && (retries > 10)) { Serial.printf("Failed!\n"); Serial.printf("It may be possible that SCL and SDA are incorrect\n"); Serial.printf("In boards/board_audio_kit_es8388.h you can change the define ES8388_CFG_I2C to use another pin setting\n"); delay(1000); + retries--; + if (retries == 0) + { + Serial.printf("give up!!!!\n"); + return false; + } } - ES8388_WriteReg(ES8388_CHIPPOWER, 0xFF); //reset and stop es8388 + ES8388_WriteReg(codec_id, ES8388_CHIPPOWER, 0xFF); //reset and stop es8388 - ES8388_WriteReg(0x00, 0x80); /* reset control port register to default */ - ES8388_WriteReg(0x00, 0x06); /* restore default value */ + ES8388_WriteReg(codec_id, 0x00, 0x80); /* reset control port register to default */ + ES8388_WriteReg(codec_id, 0x00, 0x06); /* restore default value */ /* @@ -439,92 +529,99 @@ void ES8388_Setup() /* * 10.5 Power Down Sequence (To Standby Mode) */ - ES8388_WriteReg(0x0F, 0x34); /* ADC Mute */ - ES8388_WriteReg(0x19, 0x36); /* DAC Mute */ + ES8388_WriteReg(codec_id, 0x0F, 0x34); /* ADC Mute */ + ES8388_WriteReg(codec_id, 0x19, 0x36); /* DAC Mute */ - ES8388_WriteReg(0x02, 0xF3); /* Power down DEM and STM */ + ES8388_WriteReg(codec_id, 0x02, 0xF3); /* Power down DEM and STM */ /* * 10.4 The sequence for Start up bypass mode */ /* Set Chip to Slave Mode */ - ES8388_WriteReg(0x08, 0x00); + ES8388_WriteReg(codec_id, 0x08, 0x00); /* Power down DEM and STM */ - ES8388_WriteReg(0x02, 0x3F); + ES8388_WriteReg(codec_id, 0x02, 0x3F); /* Set same LRCK */ - ES8388_WriteReg(0x2B, 0x80); + ES8388_WriteReg(codec_id, 0x2B, 0x80); /* Set Chip to Play&Record Mode */ - ES8388_WriteReg(0x00, 0x05); + ES8388_WriteReg(codec_id, 0x00, 0x05); /* Power Up Analog and Ibias */ - ES8388_WriteReg(0x01, 0x40); - ES8388_WriteReg(0x03, 0x3F); /* adc also on but no bias */ + ES8388_WriteReg(codec_id, 0x01, 0x40); + ES8388_WriteReg(codec_id, 0x03, 0x3F); /* adc also on but no bias */ - ES8388_WriteReg(0x03, 0x00); // PdnAINL, PdinAINR, PdnADCL, PdnADCR, PdnMICB, PdnADCBiasgen, flashLP, Int1LP + ES8388_WriteReg(codec_id, 0x03, 0x00); // PdnAINL, PdinAINR, PdnADCL, PdnADCR, PdnMICB, PdnADCBiasgen, flashLP, Int1LP /* * Power up DAC / Analog Output * for Record */ - ES8388_WriteReg(0x04, 0x3C); + ES8388_WriteReg(codec_id, 0x04, 0x3C); /* * Select Analog input channel for ADC */ - ES8388_WriteReg(0x0A, 0x80); // LINSEL , RINSEL , DSSEL , DSR + ES8388_WriteReg(codec_id, 0x0A, 0x80); // LINSEL , RINSEL , DSSEL , DSR /* Select PGA Gain for ADC analog input */ - ES8388_WriteReg(0x09, 0x00); // PGA gain? + ES8388_WriteReg(codec_id, 0x09, 0x00); // PGA gain? - ES8388_WriteReg(0x0C, 0x0C); // DATSEL, ADCLRP, ADCWL, ADCFORMAT - ES8388_WriteReg(0x0D, 0x02); // ADCFsMode , ADCFsRatio + ES8388_WriteReg(codec_id, 0x0C, 0x0C); // DATSEL, ADCLRP, ADCWL, ADCFORMAT + ES8388_WriteReg(codec_id, 0x0D, 0x02); // ADCFsMode , ADCFsRatio /* * Set ADC Digital Volume */ - ES8388_SetADCVOL(0, 1.0f); + ES8388_SetADCVOL(codec_id, 1.0f); /* UnMute ADC */ - ES8388_WriteReg(0x0F, 0x30); // + ES8388_WriteReg(codec_id, 0x0F, 0x30); // - ES8388_WriteReg(0x12, 0x16); + ES8388_WriteReg(codec_id, 0x12, 0x16); - ES8388_WriteReg(0x17, 0x18); // DACLRSWAP, DACLRP, DACWL, DACFORMAT - ES8388_WriteReg(0x18, 0x02); // DACFsMode , DACFsRatio + ES8388_WriteReg(codec_id, 0x17, 0x18); // DACLRSWAP, DACLRP, DACWL, DACFORMAT + ES8388_WriteReg(codec_id, 0x18, 0x02); // DACFsMode , DACFsRatio /* * Set ADC Digital Volume */ - ES8388_WriteReg(0x1A, 0x00); - ES8388_WriteReg(0x1B, 0x02); + ES8388_WriteReg(codec_id, 0x1A, 0x00); + ES8388_WriteReg(codec_id, 0x1B, 0x02); /* UnMute DAC */ #ifdef KEEP_CODEC_MUTED_IN_SETUP - ES8388_WriteReg(0x19, 0x32); + ES8388_WriteReg(codec_id, 0x19, 0x32); #endif /* * Setup Mixer */ - ES8388_WriteReg(0x26, 0x09); // ES8388_WriteReg(0x26, 0x00); - ES8388_WriteReg(0x27, 0xD0); // ES8388_DACCONTROL17 - ES8388_WriteReg(0x28, 0x38); - ES8388_WriteReg(0x29, 0x38); - ES8388_WriteReg(0x2A, 0xD0); + ES8388_WriteReg(codec_id, 0x26, 0x09); // ES8388_WriteReg(codec_id, 0x26, 0x00); + ES8388_WriteReg(codec_id, 0x27, 0xD0); // ES8388_DACCONTROL17 + ES8388_WriteReg(codec_id, 0x28, 0x38); + ES8388_WriteReg(codec_id, 0x29, 0x38); + ES8388_WriteReg(codec_id, 0x2A, 0xD0); /* Set Lout/Rout Volume */ - ES8388_SetOUT1VOL(1); - ES8388_SetOUT2VOL(1); + ES8388_SetOUT1VOL(codec_id, 1); + ES8388_SetOUT2VOL(codec_id, 1); /* Power up DEM and STM */ - ES8388_WriteReg(0x02, 0x00); + ES8388_WriteReg(codec_id, 0x02, 0x00); - ES8388_SetInputCh(1, 1); - ES8388_SetMixInCh(2, 1); - ES8388_SetPGAGain(0, 1); - ES8388_SetIn2OoutVOL(0, 0); + ES8388_SetInputCh(codec_id, 1, 1); + ES8388_SetMixInCh(codec_id, 2, 1); + ES8388_SetPGAGain(codec_id, 1); + ES8388_SetIn2OoutVOL(codec_id, 0); Serial.printf("ES8388 setup finished!\n"); - es8388_read_all(); + es8388_read_all(codec_id); + + return true; +} + +bool ES8388_Setup(void) +{ + return ES8388_Setup(ES8388_ID0); } #endif diff --git a/src/i2s_interface.h b/src/i2s_interface.h index e5f19eb..fe437a6 100644 --- a/src/i2s_interface.h +++ b/src/i2s_interface.h @@ -41,6 +41,12 @@ #ifdef __CDT_PARSER__ #include +#define ML_SYNTH_INLINE_DECLARATION +#define SAMPLE_BUFFER_SIZE 48 +#define SAMPLE_RATE 48000 +#define ML_SYNTH_INLINE_DEFINITION +#define ESP32 +#define SAMPLE_SIZE_16BIT #endif @@ -49,11 +55,15 @@ #ifdef ML_SYNTH_INLINE_DECLARATION -void setup_i2s(); -bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sample, const int buffLen); +void setup_i2s(void); bool i2s_write_stereo_samples_buff(const float *fl_sample, const float *fr_sample, const int buffLen); +bool i2s_write_stereo_samples_buff(uint8_t stream_id, const float *fl_sample, const float *fr_sample, const int buffLen); +bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sample, const int buffLen); +bool i2s_write_stereo_samples_i16(uint8_t stream_id, const int16_t *fl_sample, const int16_t *fr_sample, const int buffLen); void i2s_read_stereo_samples_buff(float *fl_sample, float *fr_sample, const int buffLen); void i2s_read_stereo_samples_buff(int16_t *fl_sample, int16_t *fr_sample, const int buffLen); +void i2s_read_stereo_samples_buff(uint8_t stream_id, float *fl_sample, float *fr_sample, const int buffLen); +void i2s_read_stereo_samples_buff(uint8_t stream_id, int16_t *fl_sample, int16_t *fr_sample, const int buffLen); #endif /* ML_SYNTH_INLINE_DECLARATION */ @@ -75,8 +85,8 @@ void i2s_read_stereo_samples_buff(int16_t *fl_sample, int16_t *fr_sample, const #ifdef OUTPUT_SAW_TEST -int16_t sampleDataI16SawTest[SAMPLE_BUFFER_SIZE]; -float sampleDataFSawTest[SAMPLE_BUFFER_SIZE]; +static int16_t sampleDataI16SawTest[4][SAMPLE_BUFFER_SIZE]; +static float sampleDataFSawTest[4][SAMPLE_BUFFER_SIZE]; #endif @@ -137,7 +147,13 @@ union sampleTUNT //#define I2S_NODAC -const i2s_port_t i2s_port_number = I2S_NUM_0; +i2s_port_t i2s_port_number[] = +{ + I2S_NUM_0, +#ifdef DUAL_CODEC_ENABLED + I2S_NUM_1, +#endif +}; /* * please refer to https://www.hackster.io/janost/audio-hacking-on-the-esp8266-fa9464#toc-a-simple-909-drum-synth-0 @@ -147,7 +163,7 @@ const i2s_port_t i2s_port_number = I2S_NUM_0; bool i2s_write_sample_32ch2(uint64_t sample) { static size_t bytes_written = 0; - i2s_write((i2s_port_t)i2s_port_number, (const char *)&sample, 8, &bytes_written, portMAX_DELAY); + i2s_write((i2s_port_t)i2s_port_number[0], (const char *)&sample, 8, &bytes_written, portMAX_DELAY); if (bytes_written > 0) { @@ -167,8 +183,8 @@ bool i2s_write_sample_24ch2(uint8_t *sample) { static size_t bytes_written1 = 0; static size_t bytes_written2 = 0; - i2s_write(i2s_port_number, (const char *)&sample[1], 3, &bytes_written1, portMAX_DELAY); - i2s_write(i2s_port_number, (const char *)&sample[5], 3, &bytes_written2, portMAX_DELAY); + i2s_write(i2s_port_number[0], (const char *)&sample[1], 3, &bytes_written1, portMAX_DELAY); + i2s_write(i2s_port_number[0], (const char *)&sample[5], 3, &bytes_written2, portMAX_DELAY); if ((bytes_written1 + bytes_written2) > 0) { @@ -182,7 +198,7 @@ bool i2s_write_sample_24ch2(uint8_t *sample) #endif -bool i2s_write_stereo_samples(const float *fl_sample, const float *fr_sample) +bool i2s_write_stereo_samples(uint8_t stream_id, const float *fl_sample, const float *fr_sample) { static union sampleTUNT sampleDataU; @@ -194,7 +210,7 @@ bool i2s_write_stereo_samples(const float *fl_sample, const float *fr_sample) size_t bytes_written = 0; - i2s_write(i2s_port_number, (const char *)&sampleDataU.sample, 2 * BYTES_PER_SAMPLE, &bytes_written, portMAX_DELAY); + i2s_write(i2s_port_number[stream_id], (const char *)&sampleDataU.sample, 2 * BYTES_PER_SAMPLE, &bytes_written, portMAX_DELAY); if (bytes_written > 0) { @@ -206,8 +222,13 @@ bool i2s_write_stereo_samples(const float *fl_sample, const float *fr_sample) } } +bool i2s_write_stereo_samples(const float *fl_sample, const float *fr_sample) +{ + return i2s_write_stereo_samples(0, fl_sample, fr_sample); +}; + #ifdef SAMPLE_SIZE_16BIT -bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sample) +bool i2s_write_stereo_samples_i16(uint8_t stream_id, const int16_t *fl_sample, const int16_t *fr_sample) { size_t bytes_written = 0; @@ -218,7 +239,7 @@ bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sa #ifdef CYCLE_MODULE_ENABLED calcCycleCountPre(); #endif - i2s_write(i2s_port_number, (const char *)&sampleDataU.sample, 4, &bytes_written, portMAX_DELAY); + i2s_write(i2s_port_number[stream_id], (const char *)&sampleDataU.sample, 4, &bytes_written, portMAX_DELAY); #ifdef CYCLE_MODULE_ENABLED calcCycleCount(); #endif @@ -231,20 +252,24 @@ bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sa return false; } } + +bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sample) +{ + return i2s_write_stereo_samples_i16(0, fl_sample, fr_sample); +} #endif #ifdef SAMPLE_SIZE_16BIT -bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sample, const int buffLen) +bool i2s_write_stereo_samples_i16(uint8_t stream_id, const int16_t *fl_sample, const int16_t *fr_sample, const int buffLen) { size_t bytes_written = 0; - static union sampleTUNT sampleDataU[SAMPLE_BUFFER_SIZE]; #ifdef OUTPUT_SAW_TEST for (int n = 0; n < buffLen; n++) { - sampleDataU[n].ch[1] = sampleDataI16SawTest[n]; - sampleDataU[n].ch[0] = sampleDataI16SawTest[n]; + sampleDataU[n].ch[1] = sampleDataI16SawTest[0 + stream_id * 2][n]; + sampleDataU[n].ch[0] = sampleDataI16SawTest[1 + stream_id * 2][n]; } #else for (int n = 0; n < buffLen; n++) @@ -257,7 +282,7 @@ bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sa #ifdef CYCLE_MODULE_ENABLED calcCycleCountPre(); #endif - i2s_write(i2s_port_number, (const char *)&sampleDataU[0].sample, 2 * BYTES_PER_SAMPLE * buffLen, &bytes_written, portMAX_DELAY); + i2s_write(i2s_port_number[stream_id], (const char *)&sampleDataU[0].sample, 2 * BYTES_PER_SAMPLE * buffLen, &bytes_written, portMAX_DELAY); #ifdef CYCLE_MODULE_ENABLED calcCycleCount(); #endif @@ -271,10 +296,15 @@ bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sa return false; } } + +bool i2s_write_stereo_samples_i16(const int16_t *fl_sample, const int16_t *fr_sample, const int buffLen) +{ + return i2s_write_stereo_samples_i16(0, fl_sample, fr_sample, buffLen); +} #endif #ifdef SAMPLE_BUFFER_SIZE -bool i2s_write_stereo_samples_buff(const float *fl_sample, const float *fr_sample, const int buffLen) +bool i2s_write_stereo_samples_buff(uint8_t stream_id, const float *fl_sample, const float *fr_sample, const int buffLen) { static union sampleTUNT sampleDataU[SAMPLE_BUFFER_SIZE]; @@ -335,7 +365,7 @@ bool i2s_write_stereo_samples_buff(const float *fl_sample, const float *fr_sampl #ifdef CYCLE_MODULE_ENABLED calcCycleCountPre(); #endif - i2s_write(i2s_port_number, (const char *)&sampleDataU[0].sample, 2 * BYTES_PER_SAMPLE * buffLen, &bytes_written, portMAX_DELAY); + i2s_write(i2s_port_number[stream_id], (const char *)&sampleDataU[0].sample, 2 * BYTES_PER_SAMPLE * buffLen, &bytes_written, portMAX_DELAY); #ifdef CYCLE_MODULE_ENABLED calcCycleCount(); #endif @@ -349,15 +379,20 @@ bool i2s_write_stereo_samples_buff(const float *fl_sample, const float *fr_sampl return false; } } + +bool i2s_write_stereo_samples_buff(const float *fl_sample, const float *fr_sample, const int buffLen) +{ + return i2s_write_stereo_samples_buff(0, fl_sample, fr_sample, buffLen); +} #endif /* #ifdef SAMPLE_BUFFER_SIZE */ -void i2s_read_stereo_samples(float *fl_sample, float *fr_sample) +void i2s_read_stereo_samples(uint8_t stream_id, float *fl_sample, float *fr_sample) { static size_t bytes_read = 0; static union sampleTUNT sampleData; - i2s_read(i2s_port_number, (char *)&sampleData.sample, 4, &bytes_read, portMAX_DELAY); + i2s_read(i2s_port_number[stream_id], (char *)&sampleData.sample, 4, &bytes_read, portMAX_DELAY); /* @@ -367,15 +402,20 @@ void i2s_read_stereo_samples(float *fl_sample, float *fr_sample) *fl_sample = ((float)sampleData.ch[1] * (5.5f / 65535.0f)); } +void i2s_read_stereo_samples(float *fl_sample, float *fr_sample) +{ + i2s_read_stereo_samples(0, fl_sample, fr_sample); +} + #ifdef SAMPLE_BUFFER_SIZE -void i2s_read_stereo_samples_buff(int16_t *fl_sample, int16_t *fr_sample, const int buffLen) +void i2s_read_stereo_samples_buff(uint8_t stream_id, int16_t *fl_sample, int16_t *fr_sample, const int buffLen) { #ifdef I2S_DIN_PIN static size_t bytes_read = 0; static union sampleTUNT sampleData[SAMPLE_BUFFER_SIZE]; - i2s_read(i2s_port_number, (char *)&sampleData[0].sample, 2 * BYTES_PER_SAMPLE * buffLen, &bytes_read, portMAX_DELAY); + i2s_read(i2s_port_number[stream_id], (char *)&sampleData[0].sample, 2 * BYTES_PER_SAMPLE * buffLen, &bytes_read, portMAX_DELAY); for (int n = 0; n < buffLen; n++) @@ -389,7 +429,12 @@ void i2s_read_stereo_samples_buff(int16_t *fl_sample, int16_t *fr_sample, const #endif } -void i2s_read_stereo_samples_buff(float *fl_sample, float *fr_sample, const int buffLen) +void i2s_read_stereo_samples_buff(int16_t *fl_sample, int16_t *fr_sample, const int buffLen) +{ + i2s_read_stereo_samples_buff(0, fl_sample, fr_sample, buffLen); +} + +void i2s_read_stereo_samples_buff(uint8_t stream_id, float *fl_sample, float *fr_sample, const int buffLen) { #ifdef I2S_DIN_PIN static size_t bytes_read = 0; @@ -397,7 +442,7 @@ void i2s_read_stereo_samples_buff(float *fl_sample, float *fr_sample, const int static union sampleTUNT sampleData[SAMPLE_BUFFER_SIZE]; - i2s_read(i2s_port_number, (char *)&sampleData[0].sample, 2 * BYTES_PER_SAMPLE * buffLen, &bytes_read, 0); + i2s_read(i2s_port_number[stream_id], (char *)&sampleData[0].sample, 2 * BYTES_PER_SAMPLE * buffLen, &bytes_read, 0); for (int n = 0; n < buffLen; n++) @@ -411,165 +456,316 @@ void i2s_read_stereo_samples_buff(float *fl_sample, float *fr_sample, const int } #endif } + +void i2s_read_stereo_samples_buff(float *fl_sample, float *fr_sample, const int buffLen) +{ + i2s_read_stereo_samples_buff(0, fl_sample, fr_sample, buffLen); +} + #endif /* #ifdef SAMPLE_BUFFER_SIZE */ /* * i2s configuration */ #ifdef I2S_NODAC -static const i2s_config_t i2s_configuration = +static const i2s_config_t i2s_configuration[] = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), - .sample_rate = SAMPLE_RATE * 1, - .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // only the top 8 bits will actually be used by the internal DAC, but using 8 bits straight away seems buggy - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // always use stereo output. mono seems to be buggy, and the overhead is insignifcant on the ESP32 - .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S | I2S_COMM_FORMAT_STAND_MSB), // this appears to be the correct setting for internal DAC and PT8211, but not for other dacs - .intr_alloc_flags = 0, // default interrupt priority - .dma_buf_count = 8, // 8*128 bytes of buffer corresponds to 256 samples (2 channels, see above, 2 bytes per sample per channel) - .dma_buf_len = 64, + { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), + .sample_rate = SAMPLE_RATE * 1, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // only the top 8 bits will actually be used by the internal DAC, but using 8 bits straight away seems buggy + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // always use stereo output. mono seems to be buggy, and the overhead is insignifcant on the ESP32 + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S | I2S_COMM_FORMAT_STAND_MSB), // this appears to be the correct setting for internal DAC and PT8211, but not for other dacs + .intr_alloc_flags = 0, // default interrupt priority + .dma_buf_count = 8, // 8*128 bytes of buffer corresponds to 256 samples (2 channels, see above, 2 bytes per sample per channel) + .dma_buf_len = 64, #ifdef I2S_USE_APLL - .use_apll = true, + .use_apll = true, #else - .use_apll = false, + .use_apll = false, #endif + } }; #else -i2s_config_t i2s_configuration = +i2s_config_t i2s_configuration[] = { + { #ifdef I2S_DIN_PIN - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX), // | I2S_MODE_DAC_BUILT_IN + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX), // | I2S_MODE_DAC_BUILT_IN #else - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), #endif - .sample_rate = SAMPLE_RATE * I2S_OVERSAMPLE, + .sample_rate = SAMPLE_RATE * I2S_OVERSAMPLE, #ifdef I2S_NODAC - .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, - .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, + .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, + .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, #ifdef ARDUINO_RUNNING_CORE /* tested with arduino esp32 core version 2.0.2 */ - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, #else - .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB, + .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB, #endif #else #ifdef SAMPLE_SIZE_32BIT - .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, /* the DAC module will only take the 8bits from MSB */ + .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, /* the DAC module will only take the 8bits from MSB */ #endif #ifdef SAMPLE_SIZE_24BIT - .bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT, /* the DAC module will only take the 8bits from MSB */ + .bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT, /* the DAC module will only take the 8bits from MSB */ #endif #ifdef SAMPLE_SIZE_16BIT - .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, /* the DAC module will only take the 8bits from MSB */ + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, /* the DAC module will only take the 8bits from MSB */ #endif - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, #ifdef ARDUINO_RUNNING_CORE /* tested with arduino esp32 core version 2.0.2 */ #ifdef MAX_98357A_ENABLED - .communication_format = I2S_COMM_FORMAT_STAND_PCM_LONG, + .communication_format = I2S_COMM_FORMAT_STAND_PCM_LONG, #else - .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, #endif #else - .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), #endif #endif - .intr_alloc_flags = 0, // default interrupt priority - .dma_buf_count = 2, - .dma_buf_len = SAMPLE_BUFFER_SIZE, + .intr_alloc_flags = 0, // default interrupt priority + .dma_buf_count = 2, + .dma_buf_len = SAMPLE_BUFFER_SIZE, #ifdef I2S_USE_APLL - .use_apll = true, + .use_apll = true, #else - .use_apll = false, + .use_apll = false, #endif #ifdef ARDUINO_RUNNING_CORE - .tx_desc_auto_clear = true, - .fixed_mclk = 0, + .tx_desc_auto_clear = true, + .fixed_mclk = 0, #ifdef I2S_MCLK_MULTIPLE_DEFAULT - .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, + .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, #else - .mclk_multiple = I2S_MCLK_MULTIPLE_256, /* is that the right default? */ + .mclk_multiple = I2S_MCLK_MULTIPLE_256, /* is that the right default? */ #endif #ifdef SAMPLE_SIZE_16BIT - .bits_per_chan = I2S_BITS_PER_CHAN_16BIT, + .bits_per_chan = I2S_BITS_PER_CHAN_16BIT, #endif #ifdef SAMPLE_SIZE_24BIT - .bits_per_chan = I2S_BITS_PER_CHAN_24BIT, + .bits_per_chan = I2S_BITS_PER_CHAN_24BIT, #endif #ifdef SAMPLE_SIZE_32BIT - .bits_per_chan = I2S_BITS_PER_CHAN_32BIT, + .bits_per_chan = I2S_BITS_PER_CHAN_32BIT, #endif #endif #if SOC_I2S_SUPPORTS_TDM - .chan_mask = I2S_CHANNEL_STEREO, - .total_chan = 0, - .left_align = 0, - .big_edin = 0, - .bit_order_msb = 0, - .skip_msk = 0, + .chan_mask = I2S_CHANNEL_STEREO, + .total_chan = 0, + .left_align = 0, + .big_edin = 0, + .bit_order_msb = 0, + .skip_msk = 0, +#endif + }, +#ifdef DUAL_CODEC_ENABLED + /* Secondary I2S configuration for dual codec setup */ + { + .mode = (i2s_mode_t)(I2S_MODE_SLAVE | I2S_MODE_TX | I2S_MODE_RX), + .sample_rate = SAMPLE_RATE * I2S_OVERSAMPLE, +#ifdef SAMPLE_SIZE_32BIT + .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, +#endif +#ifdef SAMPLE_SIZE_24BIT + .bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT, +#endif +#ifdef SAMPLE_SIZE_16BIT + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, +#endif + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, +#ifdef ARDUINO_RUNNING_CORE +#ifdef MAX_98357A_ENABLED + .communication_format = I2S_COMM_FORMAT_STAND_PCM_LONG, +#else + .communication_format = I2S_COMM_FORMAT_STAND_I2S, +#endif +#else + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), +#endif + .intr_alloc_flags = 0, + .dma_buf_count = 2, + .dma_buf_len = SAMPLE_BUFFER_SIZE, +#ifdef I2S_USE_APLL + .use_apll = true, +#else + .use_apll = false, +#endif + +#ifdef ARDUINO_RUNNING_CORE + .tx_desc_auto_clear = true, + .fixed_mclk = 0, +#ifdef I2S_MCLK_MULTIPLE_DEFAULT + .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, +#else + .mclk_multiple = I2S_MCLK_MULTIPLE_256, +#endif +#ifdef SAMPLE_SIZE_16BIT + .bits_per_chan = I2S_BITS_PER_CHAN_16BIT, +#endif +#ifdef SAMPLE_SIZE_24BIT + .bits_per_chan = I2S_BITS_PER_CHAN_24BIT, #endif +#ifdef SAMPLE_SIZE_32BIT + .bits_per_chan = I2S_BITS_PER_CHAN_32BIT, +#endif +#endif + +#if SOC_I2S_SUPPORTS_TDM + .chan_mask = I2S_CHANNEL_STEREO, + .total_chan = 0, + .left_align = 0, + .big_edin = 0, + .bit_order_msb = 0, + .skip_msk = 0, +#endif + }, +#endif + }; #endif #ifdef I2S_NODAC #ifdef ESP8266 -i2s_pin_config_t pins = +i2s_pin_config_t pins[] = { - .bck_io_num = I2S_PIN_NO_CHANGE, - .ws_io_num = I2S_PIN_NO_CHANGE, - .data_out_num = I2S_NODAC_OUT_PIN, - .data_in_num = I2S_PIN_NO_CHANGE + { + .bck_io_num = I2S_PIN_NO_CHANGE, + .ws_io_num = I2S_PIN_NO_CHANGE, + .data_out_num = I2S_NODAC_OUT_PIN, + .data_in_num = I2S_PIN_NO_CHANGE + }, }; #endif #else #if (defined I2S_BCLK_PIN) && (defined I2S_WCLK_PIN) && (defined I2S_DOUT_PIN) -i2s_pin_config_t pins = +i2s_pin_config_t pins[] = { + { #ifdef ARDUINO_RUNNING_CORE - .mck_io_num = I2S_MCLK_PIN, + .mck_io_num = I2S_MCLK_PIN, +#endif + .bck_io_num = I2S_BCLK_PIN, + .ws_io_num = I2S_WCLK_PIN, + .data_out_num = I2S_DOUT_PIN, + .data_in_num = I2S_DIN_PIN, + }, +#ifdef DUAL_CODEC_ENABLED +#if (defined I2S_DOUT_PIN_SECONDARY) || (defined I2S_DIN_PIN_SECONDARY) + /* Secondary I2S pin configuration for dual codec setup */ + { +#ifdef I2S_MCLK_PIN_SECONDARY + .mck_io_num = I2S_MCLK_PIN_SECONDARY, +#else + .mck_io_num = I2S_PIN_NO_CHANGE, #endif - .bck_io_num = I2S_BCLK_PIN, - .ws_io_num = I2S_WCLK_PIN, - .data_out_num = I2S_DOUT_PIN, - .data_in_num = I2S_DIN_PIN, +#ifdef I2S_BCLK_PIN_SECONDARY + .bck_io_num = I2S_BCLK_PIN_SECONDARY, +#else + .bck_io_num = I2S_PIN_NO_CHANGE, +#endif +#ifdef I2S_WCLK_PIN_SECONDARY + .ws_io_num = I2S_WCLK_PIN_SECONDARY, +#else + .ws_io_num = I2S_PIN_NO_CHANGE, +#endif +#ifdef I2S_DOUT_PIN_SECONDARY + .data_out_num = I2S_DOUT_PIN_SECONDARY, +#else + .data_out_num = I2S_PIN_NO_CHANGE, +#endif +#ifdef I2S_DIN_PIN_SECONDARY + .data_in_num = I2S_DIN_PIN_SECONDARY, +#else + .data_in_num = I2S_PIN_NO_CHANGE, +#endif + }, +#endif /* (defined I2S_BCLK_PIN_SECONDARY) && (defined I2S_WCLK_PIN_SECONDARY) && (defined I2S_DOUT_PIN_SECONDARY) */ +#endif /* DUAL_CODEC_ENABLED */ }; #endif /* (defined I2S_BCLK_PIN) && (defined I2S_WCLK_PIN) && (defined I2S_DOUT_PIN) */ #endif #if (defined I2S_BCLK_PIN) && (defined I2S_WCLK_PIN) && (defined I2S_DOUT_PIN) -void setup_i2s() +void setup_i2s(void) { - i2s_driver_install(i2s_port_number, &i2s_configuration, 0, NULL); + i2s_driver_install(i2s_port_number[0], &i2s_configuration[0], 0, NULL); Serial.printf("i2s_configuration:\n"); - Serial.printf("\ttx_desc_auto_clear: %d\n", i2s_configuration.tx_desc_auto_clear); - Serial.printf("\tfixed_mclk: %d\n", i2s_configuration.fixed_mclk); - Serial.printf("\tmclk_multiple: %d\n", i2s_configuration.mclk_multiple); - Serial.printf("\tbits_per_chan: %d\n", i2s_configuration.bits_per_chan); + Serial.printf("\ttx_desc_auto_clear: %d\n", i2s_configuration[0].tx_desc_auto_clear); + Serial.printf("\tfixed_mclk: %d\n", i2s_configuration[0].fixed_mclk); + Serial.printf("\tmclk_multiple: %d\n", i2s_configuration[0].mclk_multiple); + Serial.printf("\tbits_per_chan: %d\n", i2s_configuration[0].bits_per_chan); #if 0 /* for future use */ - Serial.printf("\tchan_mask: %d\n", i2s_configuration.chan_mask); - Serial.printf("\ttotal_chan: %d\n", i2s_configuration.total_chan); - Serial.printf("\tleft_align: %d\n", i2s_configuration.left_align); - Serial.printf("\tbig_edin: %d\n", i2s_configuration.big_edin); - Serial.printf("\tbit_order_msb: %d\n", i2s_configuration.bit_order_msb); - Serial.printf("\tskip_msk: %d\n", i2s_configuration.skip_msk); + Serial.printf("\tchan_mask: %d\n", i2s_configuration[0].chan_mask); + Serial.printf("\ttotal_chan: %d\n", i2s_configuration[0].total_chan); + Serial.printf("\tleft_align: %d\n", i2s_configuration[0].left_align); + Serial.printf("\tbig_edin: %d\n", i2s_configuration[0].big_edin); + Serial.printf("\tbit_order_msb: %d\n", i2s_configuration[0].bit_order_msb); + Serial.printf("\tskip_msk: %d\n", i2s_configuration[0].skip_msk); #endif #ifdef I2S_NODAC - i2s_set_pin(i2s_port_number, NULL); + i2s_set_pin(i2s_port_number[0], NULL); i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); - i2s_zero_dma_buffer(i2s_port_number); + i2s_zero_dma_buffer(i2s_port_number[0]); +#else + i2s_set_pin(i2s_port_number[0], &pins[0]); + + Serial.printf("I2S_NUM_%d configured using following pins:\n", i2s_port_number[0]); + Serial.printf(" BCLK,BCK: %d\n", pins[0].bck_io_num); + Serial.printf(" WCLK,LCK: %d\n", pins[0].ws_io_num); + Serial.printf(" DOUT: %d\n", pins[0].data_out_num); + Serial.printf(" DIN: %d\n", pins[0].data_in_num); + Serial.printf(" MCLK: %d\n", pins[0].mck_io_num); +#endif + i2s_set_sample_rates(i2s_port_number[0], SAMPLE_RATE); +#ifdef DUAL_CODEC_ENABLED +#if (defined I2S_BCLK_PIN_SECONDARY) || (defined I2S_WCLK_PIN_SECONDARY) || (defined I2S_DOUT_PIN_SECONDARY) || (defined I2S_DIN_PIN_SECONDARY) + /* Setup secondary codec */ + i2s_driver_install(i2s_port_number[1], &i2s_configuration[1], 0, NULL); + Serial.printf("Secondary i2s_configuration:\n"); + Serial.printf("\ttx_desc_auto_clear: %d\n", i2s_configuration[1].tx_desc_auto_clear); + Serial.printf("\tfixed_mclk: %d\n", i2s_configuration[1].fixed_mclk); + Serial.printf("\tmclk_multiple: %d\n", i2s_configuration[1].mclk_multiple); + Serial.printf("\tbits_per_chan: %d\n", i2s_configuration[1].bits_per_chan); + + i2s_set_pin(i2s_port_number[1], &pins[1]); + + Serial.printf("Secondary I2S_NUM_%d configured using following pins:\n", i2s_port_number[1]); + Serial.printf(" BCLK,BCK: %d\n", pins[1].bck_io_num); + Serial.printf(" WCLK,LCK: %d\n", pins[1].ws_io_num); + Serial.printf(" DOUT: %d\n", pins[1].data_out_num); + Serial.printf(" DIN: %d\n", pins[1].data_in_num); + Serial.printf(" MCLK: %d\n", pins[1].mck_io_num); + + i2s_set_sample_rates(i2s_port_number[1], SAMPLE_RATE); + + Serial.printf("Secondary I2S configured using following pins:\n"); + Serial.printf(" BCLK,BCK: %d\n", pins[1].bck_io_num); + Serial.printf(" WCLK,LCK: %d\n", pins[1].ws_io_num); + Serial.printf(" DOUT: %d\n", pins[1].data_out_num); + Serial.printf(" DIN: %d\n", pins[1].data_in_num); + Serial.printf(" MCLK: %d\n", pins[1].mck_io_num); + +#endif /* (defined I2S_BCLK_PIN_SECONDARY) && (defined I2S_WCLK_PIN_SECONDARY) && (defined I2S_DOUT_PIN_SECONDARY) */ +#include "esp_rom_gpio.h" +#include "soc/i2s_periph.h" + /* Connnect both BCLK signals */ + esp_rom_gpio_connect_out_signal(I2S_BCLK_PIN_SECONDARY, i2s_periph_signal[0].m_tx_bck_sig, 0, 0); + esp_rom_gpio_connect_in_signal(I2S_BCLK_PIN_SECONDARY, i2s_periph_signal[1].s_rx_bck_sig, 0); + /* Connect both WS signals */ + esp_rom_gpio_connect_out_signal(I2S_WCLK_PIN_SECONDARY, i2s_periph_signal[0].m_tx_ws_sig, 0, 0); + esp_rom_gpio_connect_in_signal(I2S_WCLK_PIN_SECONDARY, i2s_periph_signal[1].s_rx_ws_sig, 0); + i2s_start(i2s_port_number[0]); + i2s_start(i2s_port_number[1]); #else - i2s_set_pin(i2s_port_number, &pins); + i2s_start(i2s_port_number[0]); +#endif /* DUAL_CODEC_ENABLED */ - Serial.printf("I2S_NUM_%d configured using following pins:\n", i2s_port_number); - Serial.printf(" BCLK,BCK: %d\n", pins.bck_io_num); - Serial.printf(" WCLK,LCK: %d\n", pins.ws_io_num); - Serial.printf(" DOUT: %d\n", pins.data_out_num); - Serial.printf(" DIN: %d\n", pins.data_in_num); - Serial.printf(" MCLK: %d\n", pins.mck_io_num); -#endif - i2s_set_sample_rates(i2s_port_number, SAMPLE_RATE); - i2s_start(i2s_port_number); #ifdef ES8388_ENABLED #ifdef PIN_CTRL REG_WRITE(PIN_CTRL, 0xFFFFFFF0); @@ -580,11 +776,11 @@ void setup_i2s() #endif #ifndef I2S_NODAC Serial.printf("I2S configured using following pins:\n"); - Serial.printf(" BCLK,BCK: %d\n", pins.bck_io_num); - Serial.printf(" WCLK,LCK: %d\n", pins.ws_io_num); - Serial.printf(" DOUT: %d\n", pins.data_out_num); - Serial.printf(" DIN: %d\n", pins.data_in_num); - Serial.printf(" MCLK: %d\n", pins.mck_io_num); + Serial.printf(" BCLK,BCK: %d\n", pins[0].bck_io_num); + Serial.printf(" WCLK,LCK: %d\n", pins[0].ws_io_num); + Serial.printf(" DOUT: %d\n", pins[0].data_out_num); + Serial.printf(" DIN: %d\n", pins[0].data_in_num); + Serial.printf(" MCLK: %d\n", pins[0].mck_io_num); #else Serial.printf("I2S configured using internal DAC (DAC_1, DAC_2 as output)\n"); #endif @@ -596,16 +792,20 @@ void setup_i2s() */ for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++) { - float saw = ((float)i * 2.0f) / ((float)SAMPLE_BUFFER_SIZE); - sampleDataFSawTest[i] = saw; - saw -= 1; - saw *= 0x7FFF; - sampleDataI16SawTest[i] = saw; + for (int n = 0; n < 4; n++) + { + float saw = ((float)n * i * 2.0f) / ((float)SAMPLE_BUFFER_SIZE); + sampleDataFSawTest[n][i] = saw; + saw -= 1; + saw *= 0x7FFF; + sampleDataI16SawTest[n][i] = saw; + } } #endif } #endif /* (defined I2S_BCLK_PIN) && (defined I2S_WCLK_PIN) && (defined I2S_DOUT_PIN) */ + #endif /* ESP32 */ diff --git a/src/ml_delay.cpp b/src/ml_delay.cpp index 202e7e3..e3ad9c1 100644 --- a/src/ml_delay.cpp +++ b/src/ml_delay.cpp @@ -403,9 +403,20 @@ void Delay_SetOutputLevel(uint8_t unused __attribute__((unused)), uint8_t value) void Delay_SetLength(uint8_t unused __attribute__((unused)), float value) { delayLen = (uint32_t)(((float)delayLenMax - 1.0f) * value); + if (delayLen<1) + { + delayLen = 1; + } Status_ValueChangedFloat("Delay_SetLength", value); } +void Delay_SetLength(uint8_t unused __attribute__((unused)), uint8_t value) +{ + float value_f = value; + value_f *= 1.0f / 127.0f; + Delay_SetLength(unused, value_f); +} + void Delay_SetLength(uint8_t unused __attribute__((unused)), uint32_t value) { if (value != delayLen) diff --git a/src/ml_delay.h b/src/ml_delay.h index 8ea0b33..5687352 100644 --- a/src/ml_delay.h +++ b/src/ml_delay.h @@ -61,6 +61,7 @@ void Delay_SetOutputLevel(uint8_t unused __attribute__((unused)), float value); void Delay_SetOutputLevel(uint8_t unused __attribute__((unused)), uint8_t value); void Delay_SetLength(uint8_t unused __attribute__((unused)), float value); void Delay_SetLength(uint8_t unused __attribute__((unused)), uint32_t value); +void Delay_SetLength(uint8_t unused __attribute__((unused)), uint8_t value); void Delay_SetShift(uint8_t unused __attribute__((unused)), float value); diff --git a/src/ml_wavfile.h b/src/ml_wavfile.h index 5ac5303..efb3416 100644 --- a/src/ml_wavfile.h +++ b/src/ml_wavfile.h @@ -58,9 +58,15 @@ union wavHeader char riff[4]; /*!< 'RIFF' */ uint32_t fileSize; /*!< bytes to write containing all data (header + data) */ char waveType[4]; /*!< 'WAVE' */ - - char format[4]; /*!< 'fmt ' */ - uint32_t lengthOfData; /*!< length of the fmt header (16 bytes) */ + union + { + struct + { + char format[4]; /*!< 'fmt ' */ + uint32_t lengthOfData; /*!< length of the fmt header (16 bytes) */ + }; + union wav_tag__header_u fmtTag; + }; uint16_t format_tag; /*!< 0x0001: PCM */ uint16_t numberOfChannels; /*!< 'WAVE' */ uint32_t sampleRate;