mirror of
https://github.com/pelgraine/Meck.git
synced 2026-08-06 16:52:46 +02:00
Fixed audiobookplayer crowded footer text and filtering out m4b files for now until we get that sorted. Fixed voice message recording playback for the max.
This commit is contained in:
@@ -73,7 +73,9 @@ void meck_audio_codec_init();
|
||||
static bool isAudiobookFile(const String& name) {
|
||||
String lower = name;
|
||||
lower.toLowerCase();
|
||||
return lower.endsWith(".m4b") || lower.endsWith(".m4a") ||
|
||||
// .m4b excluded: these can't currently be played, so they are hidden from
|
||||
// the file explorer. (.m4a/.mp3/.wav remain listed.)
|
||||
return lower.endsWith(".m4a") ||
|
||||
lower.endsWith(".mp3") || lower.endsWith(".wav");
|
||||
}
|
||||
|
||||
@@ -1361,21 +1363,10 @@ private:
|
||||
}
|
||||
|
||||
// Footer (stays at size 1 for readability)
|
||||
// Left label is always the file count — the folder path was overflowing and
|
||||
// colliding with the right-hand nav text, so it is no longer shown here.
|
||||
char leftBuf[32];
|
||||
if (_currentPath == String(AUDIOBOOKS_FOLDER)) {
|
||||
snprintf(leftBuf, sizeof(leftBuf), "%d files", (int)_fileList.size());
|
||||
} else {
|
||||
// Show current subfolder name
|
||||
int lastSlash = _currentPath.lastIndexOf('/');
|
||||
String folderName = (lastSlash >= 0) ? _currentPath.substring(lastSlash + 1) : _currentPath;
|
||||
snprintf(leftBuf, sizeof(leftBuf), "/%s", folderName.c_str());
|
||||
if ((int)strlen(leftBuf) > 16) {
|
||||
leftBuf[13] = '.';
|
||||
leftBuf[14] = '.';
|
||||
leftBuf[15] = '.';
|
||||
leftBuf[16] = '\0';
|
||||
}
|
||||
}
|
||||
snprintf(leftBuf, sizeof(leftBuf), "%d files", (int)_fileList.size());
|
||||
drawFooter(display, leftBuf, "W/S:Nav Enter:Open");
|
||||
}
|
||||
|
||||
|
||||
@@ -256,6 +256,197 @@ static inline bool es8311_init_44100_16bit() {
|
||||
return id == 0x83;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// es8311_init_capture_16k() -- ANALOGUE-MIC CAPTURE (ADC) init, 16 kHz, 16-bit
|
||||
//
|
||||
// Recording counterpart to es8311_init_44100_16bit(). Brings up the ES8311 ADC
|
||||
// path (mic -> ADC -> I2S SDOUT/ASDOUT) so the ESP32 I2S RX can read PCM. It
|
||||
// does NOT power the DAC; call es8311_init_44100_16bit() afterwards to restore
|
||||
// the playback path.
|
||||
//
|
||||
// Same authority as the DAC init: transcribed from esp_codec_dev es8311.c
|
||||
// (es8311_open + es8311_set_bits_per_sample(16) + es8311_config_fmt(I2S) +
|
||||
// es8311_config_sample(16000) + es8311_start) for the configuration:
|
||||
// master_mode = false (ESP32 I2S is master, drives MCLK/BCLK/LRCK)
|
||||
// use_mclk = true (real MCLK on BOARD_I2S_MCLK / GPIO38, 256 * fs)
|
||||
// invert_mclk = false, invert_sclk = false
|
||||
// codec_mode = ADC, digital_mic = false (analogue mic), no_dac_ref = false
|
||||
// mclk_div = 256 -> MCLK = 16000 * 256 = 4.096 MHz
|
||||
// using the {4096000, 16000} coefficient row:
|
||||
// pre_div=1 pre_multi=1 adc_div=1 dac_div=1 fs_mode=0
|
||||
// lrck_h=0x00 lrck_l=0xFF bclk_div=0x04 adc_osr=0x10 dac_osr=0x20
|
||||
//
|
||||
// mic_gain -> REG16 ADC PGA gain (ES8311 mic-gain enum, low 3 bits):
|
||||
// 0=0dB 1=6dB 2=12dB 3=18dB 4=24dB 5=30dB 6=36dB 7=42dB
|
||||
// 30 dB (5) is a reasonable starting point for the MAX analogue mic; this is
|
||||
// the first knob to tune on the bench if recordings are too quiet or clip.
|
||||
//
|
||||
// Returns true if the chip ID read back as 0x83.
|
||||
// =============================================================================
|
||||
static inline bool es8311_init_capture_16k(uint8_t mic_gain = 0x05) {
|
||||
uint8_t id = es8311_read(ES8311_REGFD_CHIPID1);
|
||||
Serial.printf("[ES8311] (capture) chip ID REGFD = 0x%02X (expect 0x83)\n", id);
|
||||
|
||||
// ---- open(): base register setup (from es8311_open) ----
|
||||
es8311_write(ES8311_REG44_GPIO, 0x08); // double write: first I2C write can be unreliable
|
||||
es8311_write(ES8311_REG44_GPIO, 0x08);
|
||||
|
||||
es8311_write(ES8311_REG01_CLK_MANAGER, 0x30);
|
||||
es8311_write(ES8311_REG02_CLK_MANAGER, 0x00);
|
||||
es8311_write(ES8311_REG03_CLK_MANAGER, 0x10);
|
||||
es8311_write(ES8311_REG16_ADC, 0x24);
|
||||
es8311_write(ES8311_REG04_CLK_MANAGER, 0x10);
|
||||
es8311_write(ES8311_REG05_CLK_MANAGER, 0x00);
|
||||
es8311_write(ES8311_REG0B_SYSTEM, 0x00);
|
||||
es8311_write(ES8311_REG0C_SYSTEM, 0x00);
|
||||
es8311_write(ES8311_REG10_SYSTEM, 0x1F);
|
||||
es8311_write(ES8311_REG11_SYSTEM, 0x7F);
|
||||
es8311_write(ES8311_REG00_RESET, 0x80); // CSM power up
|
||||
|
||||
// Slave mode: REG00 bit6 = 0 (read-modify-write)
|
||||
{
|
||||
uint8_t regv = es8311_read(ES8311_REG00_RESET);
|
||||
regv &= 0xBF;
|
||||
es8311_write(ES8311_REG00_RESET, regv);
|
||||
}
|
||||
|
||||
// REG01 clock source: use_mclk=true (&=0x7F), not inverted (&=~0x40) => 0x3F
|
||||
{
|
||||
uint8_t regv = 0x3F;
|
||||
regv &= 0x7F;
|
||||
regv &= ~0x40;
|
||||
es8311_write(ES8311_REG01_CLK_MANAGER, regv);
|
||||
}
|
||||
|
||||
// SCLK not inverted (REG06)
|
||||
{
|
||||
uint8_t regv = es8311_read(ES8311_REG06_CLK_MANAGER);
|
||||
regv &= ~0x20;
|
||||
es8311_write(ES8311_REG06_CLK_MANAGER, regv);
|
||||
}
|
||||
|
||||
es8311_write(ES8311_REG13_SYSTEM, 0x10);
|
||||
es8311_write(ES8311_REG1B_ADC, 0x0A);
|
||||
es8311_write(ES8311_REG1C_ADC, 0x6A);
|
||||
// no_dac_ref == false: internal reference signal (ADCL + DACR) -> REG44 = 0x58
|
||||
es8311_write(ES8311_REG44_GPIO, 0x58);
|
||||
|
||||
// ---- set_bits_per_sample(16): 16-bit on both SDP regs (REG09 DAC, REG0A ADC) ----
|
||||
{
|
||||
uint8_t dac_iface = es8311_read(ES8311_REG09_SDPIN);
|
||||
uint8_t adc_iface = es8311_read(ES8311_REG0A_SDPOUT);
|
||||
dac_iface |= 0x0C;
|
||||
adc_iface |= 0x0C;
|
||||
es8311_write(ES8311_REG09_SDPIN, dac_iface);
|
||||
es8311_write(ES8311_REG0A_SDPOUT, adc_iface);
|
||||
}
|
||||
|
||||
// ---- config_fmt(ES_I2S_NORMAL): clear format bits [1:0] on REG09/REG0A ----
|
||||
{
|
||||
uint8_t dac_iface = es8311_read(ES8311_REG09_SDPIN);
|
||||
uint8_t adc_iface = es8311_read(ES8311_REG0A_SDPOUT);
|
||||
dac_iface &= 0xFC;
|
||||
adc_iface &= 0xFC;
|
||||
es8311_write(ES8311_REG09_SDPIN, dac_iface);
|
||||
es8311_write(ES8311_REG0A_SDPOUT, adc_iface);
|
||||
}
|
||||
|
||||
// ---- config_sample(16000): {4096000,16000} coeff row, write order from es8311.c ----
|
||||
{
|
||||
const uint8_t pre_div = 1, datmp = 0; // pre_multi=1, use_mclk=true -> datmp=0
|
||||
const uint8_t adc_div = 1, dac_div = 1, fs_mode = 0;
|
||||
const uint8_t lrck_h = 0x00, lrck_l = 0xFF, bclk_div = 0x04;
|
||||
const uint8_t adc_osr = 0x10, dac_osr = 0x20;
|
||||
|
||||
uint8_t regv = es8311_read(ES8311_REG02_CLK_MANAGER);
|
||||
regv &= 0x07;
|
||||
regv |= (pre_div - 1) << 5;
|
||||
regv |= datmp << 3;
|
||||
es8311_write(ES8311_REG02_CLK_MANAGER, regv);
|
||||
|
||||
regv = ((adc_div - 1) << 4) | (dac_div - 1);
|
||||
es8311_write(ES8311_REG05_CLK_MANAGER, regv);
|
||||
|
||||
regv = es8311_read(ES8311_REG03_CLK_MANAGER);
|
||||
regv &= 0x80;
|
||||
regv |= (fs_mode << 6) | adc_osr;
|
||||
es8311_write(ES8311_REG03_CLK_MANAGER, regv);
|
||||
|
||||
regv = es8311_read(ES8311_REG04_CLK_MANAGER);
|
||||
regv &= 0x80;
|
||||
regv |= dac_osr;
|
||||
es8311_write(ES8311_REG04_CLK_MANAGER, regv);
|
||||
|
||||
regv = es8311_read(ES8311_REG07_CLK_MANAGER);
|
||||
regv &= 0xC0;
|
||||
regv |= lrck_h;
|
||||
es8311_write(ES8311_REG07_CLK_MANAGER, regv);
|
||||
|
||||
es8311_write(ES8311_REG08_CLK_MANAGER, lrck_l);
|
||||
|
||||
regv = es8311_read(ES8311_REG06_CLK_MANAGER);
|
||||
regv &= 0xE0;
|
||||
if (bclk_div < 19) regv |= (bclk_div - 1);
|
||||
else regv |= bclk_div;
|
||||
es8311_write(ES8311_REG06_CLK_MANAGER, regv);
|
||||
}
|
||||
|
||||
// ---- start(): ADC-mode power-up (from es8311_start, codec_mode == ADC) ----
|
||||
{
|
||||
uint8_t regv = 0x80;
|
||||
regv &= 0xBF; // slave
|
||||
es8311_write(ES8311_REG00_RESET, regv);
|
||||
|
||||
uint8_t r01 = 0x3F;
|
||||
r01 &= 0x7F; // use_mclk = true
|
||||
r01 &= ~0x40; // not inverted
|
||||
es8311_write(ES8311_REG01_CLK_MANAGER, r01);
|
||||
|
||||
uint8_t dac_iface = es8311_read(ES8311_REG09_SDPIN);
|
||||
uint8_t adc_iface = es8311_read(ES8311_REG0A_SDPOUT);
|
||||
dac_iface &= 0xBF;
|
||||
adc_iface &= 0xBF;
|
||||
adc_iface &= ~(1 << 6); // ADC mode: power up ADC serial-port output
|
||||
es8311_write(ES8311_REG09_SDPIN, dac_iface);
|
||||
es8311_write(ES8311_REG0A_SDPOUT, adc_iface);
|
||||
|
||||
es8311_write(ES8311_REG17_ADC, 0xBF); // ADC full-scale / volume
|
||||
es8311_write(ES8311_REG0E_SYSTEM, 0x02);
|
||||
// REG12 (DAC enable) intentionally NOT written -- this is the ADC-only path.
|
||||
es8311_write(ES8311_REG14_SYSTEM, 0x1A);
|
||||
|
||||
// digital_mic == false: clear DMIC-enable bit (0x40) on REG14 (analogue mic)
|
||||
{
|
||||
uint8_t r14 = es8311_read(ES8311_REG14_SYSTEM);
|
||||
r14 &= ~0x40;
|
||||
es8311_write(ES8311_REG14_SYSTEM, r14);
|
||||
}
|
||||
|
||||
es8311_write(ES8311_REG0D_SYSTEM, 0x01);
|
||||
es8311_write(ES8311_REG15_ADC, 0x40);
|
||||
es8311_write(ES8311_REG37_DAC, 0x08);
|
||||
es8311_write(ES8311_REG45_GP, 0x00);
|
||||
}
|
||||
|
||||
// ADC PGA / mic gain (REG16). Overwrites the open() default (0x24), mirroring
|
||||
// esp_codec_dev es8311_set_mic_gain which writes the raw enum (0..7) to REG16.
|
||||
es8311_write(ES8311_REG16_ADC, (uint8_t)(mic_gain & 0x07));
|
||||
|
||||
// DIAG: read back the key ADC/clock/format registers to confirm the writes.
|
||||
Serial.printf("[ES8311] (capture) readback R00=%02X R01=%02X R02=%02X R09=%02X R0A=%02X R14=%02X R15=%02X R16=%02X R17=%02X\n",
|
||||
es8311_read(ES8311_REG00_RESET),
|
||||
es8311_read(ES8311_REG01_CLK_MANAGER),
|
||||
es8311_read(ES8311_REG02_CLK_MANAGER),
|
||||
es8311_read(ES8311_REG09_SDPIN),
|
||||
es8311_read(ES8311_REG0A_SDPOUT),
|
||||
es8311_read(ES8311_REG14_SYSTEM),
|
||||
es8311_read(ES8311_REG15_ADC),
|
||||
es8311_read(ES8311_REG16_ADC),
|
||||
es8311_read(ES8311_REG17_ADC));
|
||||
|
||||
return id == 0x83;
|
||||
}
|
||||
|
||||
// DAC volume, 0..255 (0 = mute-ish, 191 = 0 dB, 255 = +32 dB).
|
||||
static inline void es8311_set_dac_volume(uint8_t vol) {
|
||||
es8311_write(ES8311_REG32_DAC, vol);
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
#include "Audio.h"
|
||||
#include "variant.h"
|
||||
|
||||
// MAX (ES8311) capture path: the codec must be configured for ADC over I2C.
|
||||
// ES8311.h self-guards on HAS_ES8311_AUDIO, so this is a no-op on the Pro V1.1.
|
||||
#if defined(HAS_ES8311_AUDIO)
|
||||
#include "ES8311.h"
|
||||
#endif
|
||||
|
||||
// Codec2 low-bitrate voice codec
|
||||
#include <codec2.h>
|
||||
|
||||
@@ -79,6 +85,12 @@ class MyMesh;
|
||||
// stop audio before recording, uninstall driver after, let audio lib reclaim.
|
||||
#define VOICE_I2S_PORT I2S_NUM_0
|
||||
|
||||
// Default DAC sample rate the rest of the firmware (audiobooks, tones) runs at.
|
||||
// On the MAX, ESP32-audioI2S leaves the hardware I2S clock fixed at this rate
|
||||
// (its setSampleRate is a no-op under HAS_ES8311_AUDIO), so voice playback has
|
||||
// to switch the hardware to VOICE_SAMPLE_RATE and switch it back afterwards.
|
||||
#define VOICE_PLAYBACK_DEFAULT_RATE 44100
|
||||
|
||||
// DMA buffer config for mic capture
|
||||
// E-ink refreshes block the CPU for ~650ms. At 16kHz, that's 10,400 samples.
|
||||
// We need enough DMA buffer to hold audio during those blocks.
|
||||
@@ -258,6 +270,53 @@ private:
|
||||
_i2sInitialized = false;
|
||||
|
||||
i2s_config_t mic_cfg = {};
|
||||
#if defined(HAS_ES8311_AUDIO)
|
||||
// ---- MAX: standard I2S master RX, MCLK driven, ES8311 ADC as the source ----
|
||||
// The MAX has no PDM mic. Audio is captured by the ES8311's ADC, which sits
|
||||
// on the standard I2S bus in SLAVE mode (ESP32 is master and drives
|
||||
// MCLK=IO38 / BCLK=IO39 / WS=IO18; mic data returns on ASDOUT=IO17).
|
||||
// APLL + fixed_mclk forces MCLK = 256 * fs (4.096 MHz at 16 kHz), which the
|
||||
// ES8311 needs for its ADC clock derivation.
|
||||
mic_cfg.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX);
|
||||
mic_cfg.sample_rate = VOICE_SAMPLE_RATE;
|
||||
mic_cfg.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
|
||||
mic_cfg.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
|
||||
mic_cfg.communication_format = I2S_COMM_FORMAT_STAND_I2S;
|
||||
mic_cfg.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
|
||||
mic_cfg.dma_buf_count = VOICE_DMA_BUF_COUNT;
|
||||
mic_cfg.dma_buf_len = VOICE_DMA_BUF_LEN;
|
||||
mic_cfg.use_apll = true; // clean MCLK for the ES8311
|
||||
mic_cfg.tx_desc_auto_clear = false;
|
||||
mic_cfg.fixed_mclk = VOICE_SAMPLE_RATE * 256; // 4.096 MHz = 256 * fs
|
||||
|
||||
esp_err_t err = i2s_driver_install(VOICE_I2S_PORT, &mic_cfg, 0, NULL);
|
||||
if (err != ESP_OK) {
|
||||
Serial.printf("Voice: i2s_driver_install failed: %d\n", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
i2s_pin_config_t mic_pins = {};
|
||||
mic_pins.mck_io_num = BOARD_ES8311_MCLK; // IO38 — drive MCLK to codec
|
||||
mic_pins.bck_io_num = BOARD_ES8311_SCLK; // IO39 — BCLK
|
||||
mic_pins.ws_io_num = BOARD_ES8311_LRCK; // IO18 — LRCK/WS
|
||||
mic_pins.data_out_num = I2S_PIN_NO_CHANGE;
|
||||
mic_pins.data_in_num = BOARD_MIC_I2S_DIN; // IO17 — ASDOUT (mic in)
|
||||
|
||||
err = i2s_set_pin(VOICE_I2S_PORT, &mic_pins);
|
||||
if (err != ESP_OK) {
|
||||
Serial.printf("Voice: i2s_set_pin failed: %d\n", err);
|
||||
i2s_driver_uninstall(VOICE_I2S_PORT);
|
||||
return false;
|
||||
}
|
||||
|
||||
// MCLK is now live on IO38; bring up the ES8311 ADC capture path over I2C.
|
||||
delay(10);
|
||||
es8311_init_capture_16k();
|
||||
|
||||
_micInitialized = true;
|
||||
Serial.println("Voice: ES8311 ADC mic initialised (16k I2S RX on I2S_NUM_0)");
|
||||
return true;
|
||||
#else
|
||||
mic_cfg.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
|
||||
mic_cfg.sample_rate = VOICE_SAMPLE_RATE;
|
||||
mic_cfg.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
|
||||
@@ -292,15 +351,25 @@ private:
|
||||
_micInitialized = true;
|
||||
Serial.println("Voice: PDM mic initialised on I2S_NUM_0");
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void deinitMic() {
|
||||
if (!_micInitialized) return;
|
||||
i2s_driver_uninstall(VOICE_I2S_PORT);
|
||||
_micInitialized = false;
|
||||
#if defined(HAS_ES8311_AUDIO)
|
||||
// Recording reconfigured the ES8311 for ADC capture. Restore the codec to
|
||||
// its playback (DAC) state by re-running the same init used at audio start,
|
||||
// so subsequent voice/audiobook playback works. ESP32-audioI2S only manages
|
||||
// the I2S stream; it does not touch the codec's registers.
|
||||
es8311_init_44100_16bit();
|
||||
Serial.println("Voice: ES8311 mic deinitialised, codec restored to DAC, I2S_NUM_0 released");
|
||||
#else
|
||||
// _i2sInitialized already cleared in initMic() — ESP32-audioI2S
|
||||
// will reconfigure I2S_NUM_0 on next connecttoFS() call.
|
||||
Serial.println("Voice: PDM mic deinitialised, I2S_NUM_0 released");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Allocate PSRAM capture buffer (once, reused across recordings)
|
||||
@@ -584,9 +653,23 @@ private:
|
||||
Serial.println("Voice: Recreating Audio object for clean I2S state");
|
||||
delete _audio;
|
||||
_audio = new Audio();
|
||||
#if defined(HAS_ES8311_AUDIO)
|
||||
// MAX: the ES8311 runs as I2S slave and needs a real MCLK on BOARD_I2S_MCLK
|
||||
// (IO38). Use the 5-arg setPinout (4th = DIN, unused; 5th = MCLK) exactly
|
||||
// as the boot/notification audio bring-up in main.cpp does. The 4-arg form
|
||||
// used on the Pro leaves MCLK unset, which silences the ES8311 DAC — this
|
||||
// is why a just-recorded note played silent while received notes (which
|
||||
// never recreate the Audio object) play fine.
|
||||
bool ok = _audio->setPinout(BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT,
|
||||
I2S_PIN_NO_CHANGE, BOARD_I2S_MCLK);
|
||||
Serial.printf("Voice: DAC setPinout(BCLK=%d LRC=%d DOUT=%d MCK=%d) -> %s\n",
|
||||
BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT, BOARD_I2S_MCLK,
|
||||
ok ? "OK" : "FAIL");
|
||||
#else
|
||||
bool ok = _audio->setPinout(BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT, 0);
|
||||
if (!ok) ok = _audio->setPinout(BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT);
|
||||
if (!ok) Serial.println("Voice: DAC setPinout FAILED");
|
||||
#endif
|
||||
_i2sInitialized = true;
|
||||
}
|
||||
|
||||
@@ -594,6 +677,14 @@ private:
|
||||
snprintf(fullPath, sizeof(fullPath), "%s/%s", VOICE_FOLDER, filename);
|
||||
|
||||
_audio->setVolume(21); // Max volume for voice playback
|
||||
#if defined(HAS_ES8311_AUDIO)
|
||||
// ESP32-audioI2S's setSampleRate() is a no-op on the MAX (it deliberately
|
||||
// skips i2s_set_sample_rates to avoid disrupting the APLL MCLK mid-stream),
|
||||
// so the hardware I2S stays at VOICE_PLAYBACK_DEFAULT_RATE. A 16 kHz voice
|
||||
// WAV would then clock out ~2.76x too fast (chipmunk). Force the hardware to
|
||||
// the voice rate here; restored on playback end so audiobooks are unaffected.
|
||||
i2s_set_sample_rates((i2s_port_t)VOICE_I2S_PORT, VOICE_SAMPLE_RATE);
|
||||
#endif
|
||||
bool ok = _audio->connecttoFS(SD, fullPath);
|
||||
if (!ok) {
|
||||
Serial.printf("Voice: Failed to open %s for playback\n", fullPath);
|
||||
@@ -608,6 +699,11 @@ private:
|
||||
if (_audio && _i2sInitialized) {
|
||||
_audio->stopSong();
|
||||
}
|
||||
#if defined(HAS_ES8311_AUDIO)
|
||||
// Restore the hardware I2S clock to the default rate so audiobook/tone
|
||||
// playback (which the library won't re-rate on this platform) is correct.
|
||||
i2s_set_sample_rates((i2s_port_t)VOICE_I2S_PORT, VOICE_PLAYBACK_DEFAULT_RATE);
|
||||
#endif
|
||||
_reviewPlaying = false;
|
||||
_listPlaying = false;
|
||||
}
|
||||
@@ -986,7 +1082,10 @@ private:
|
||||
|
||||
char countStr[16];
|
||||
snprintf(countStr, sizeof(countStr), "%d files", (int)_fileList.size());
|
||||
display.setCursor(display.width() - display.getTextWidth(countStr) - 2, 0);
|
||||
// Place the count just after the title rather than right-aligned to the
|
||||
// screen edge. The right-aligned position pushed the trailing 's' of
|
||||
// "files" off the right edge, where it wrapped onto the next line.
|
||||
display.setCursor(display.getTextWidth("Voice Messages") + 6, 0);
|
||||
display.print(countStr);
|
||||
|
||||
display.fillRect(0, 11, display.width(), 1); // horizontal rule
|
||||
@@ -1397,6 +1496,11 @@ public:
|
||||
_reviewPlaying = false;
|
||||
_listPlaying = false;
|
||||
_playbackJustFinished = true;
|
||||
#if defined(HAS_ES8311_AUDIO)
|
||||
// Restore the hardware I2S clock to the default rate (see playFile) so the
|
||||
// next audiobook/tone plays at the correct speed.
|
||||
i2s_set_sample_rates((i2s_port_t)VOICE_I2S_PORT, VOICE_PLAYBACK_DEFAULT_RATE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user