diff --git a/Apps/VoiceRecorder/main/CMakeLists.txt b/Apps/VoiceRecorder/main/CMakeLists.txt index db2068e..a26245a 100644 --- a/Apps/VoiceRecorder/main/CMakeLists.txt +++ b/Apps/VoiceRecorder/main/CMakeLists.txt @@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c) idf_component_register( SRCS ${SOURCE_FILES} - REQUIRES TactilitySDK + REQUIRES TactilitySDK esp_driver_gpio ) diff --git a/Apps/VoiceRecorder/main/Source/main.c b/Apps/VoiceRecorder/main/Source/main.c index 9e880db..58e41df 100644 --- a/Apps/VoiceRecorder/main/Source/main.c +++ b/Apps/VoiceRecorder/main/Source/main.c @@ -20,18 +20,22 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" +#include "driver/gpio.h" #define TAG "VoiceRecorder" -#define SAMPLE_RATE 16000 +#define SAMPLE_RATE 44100 #define BITS_PER_SAMPLE 16 #define CHUNK_SAMPLES 1024 #define CHUNK_BYTES (CHUNK_SAMPLES * (BITS_PER_SAMPLE / 8)) // 2048 bytes #define AUDIO_BUF_SIZE 8192 -// Software mic boost (digital gain) to compensate quiet MEMS mic even at 100% hw gain (24dB) -// 200 = 2x, 300 = 3x – clipping protection via int16 limits -#define MIC_BOOST_PERCENT 250 +// 3x boost + low-pass + high-pass (band-pass for voice) +#define MIC_BOOST_PERCENT 300 +#define ENABLE_LOWPASS 1 +#define LOWPASS_ALPHA 0.25f // ~2.5kHz cutoff, reduces high-pitch MCLK hiss +#define ENABLE_HIGHPASS 1 +#define HIGHPASS_ALPHA 0.985f // ~100Hz cutoff, removes DC/rumble/pop // ─── Scroll animation flags ─── // LVGL label scroll animation (LV_LABEL_LONG_SCROLL_*) causes continuous @@ -264,10 +268,15 @@ static void record_task(void* arg) { error_t err = audio_stream_open_input(ctx->stream_dev, &in_cfg, &ctx->input_handle); if (err == ERROR_NONE) { - // Ensure mic is unmuted and at max gain (ES8311 0..24dB) + // Disable speaker amp (GPIO1 active-low) to avoid FM8002E pop/hiss during recording + // Board es3c35p/es3c28p: amp_enable on GPIO1 low = enabled + gpio_set_level(GPIO_NUM_1, 1); + // Also mute output codec path + audio_stream_set_mute(ctx->stream_dev, AUDIO_CODEC_DIR_OUTPUT, true); + // Ensure mic is unmuted and at max gain (42dB HW max) audio_stream_set_mute(ctx->stream_dev, AUDIO_CODEC_DIR_INPUT, false); audio_stream_set_volume(ctx->stream_dev, AUDIO_CODEC_DIR_INPUT, 100.0f); - ESP_LOGI(TAG, "Mic unmuted, gain 100%%"); + ESP_LOGI(TAG, "Amp disabled (GPIO1 HIGH), mic unmuted 42dB"); } if (err != ERROR_NONE) { ESP_LOGE(TAG, "audio_stream_open_input failed: %d", err); @@ -289,22 +298,45 @@ static void record_task(void* arg) { uint32_t start_time = xTaskGetTickCount(); uint32_t last_ui_sec = 0; bool first_ui = true; +#if ENABLE_LOWPASS + float lp_prev = 0.0f; +#endif +#if ENABLE_HIGHPASS + float hp_x_prev = 0.0f; + float hp_y_prev = 0.0f; +#endif while (ctx->state == STATE_RECORDING) { size_t bytes_read = 0; err = audio_stream_read(ctx->input_handle, ctx->audio_buf, AUDIO_BUF_SIZE, &bytes_read, pdMS_TO_TICKS(200)); if (err == ERROR_NONE && bytes_read > 0) { - // Software boost: 16-bit mono, apply MIC_BOOST_PERCENT with clipping -#if MIC_BOOST_PERCENT != 100 int16_t* samples = (int16_t*)ctx->audio_buf; size_t sample_cnt = bytes_read / sizeof(int16_t); for (size_t i = 0; i < sample_cnt; i++) { - int32_t boosted = (int32_t)samples[i] * MIC_BOOST_PERCENT / 100; + float in = (float)samples[i]; +#if ENABLE_HIGHPASS + // 1st-order high-pass ~100Hz to remove DC, rumble, pop + float hp_out = HIGHPASS_ALPHA * (hp_y_prev + in - hp_x_prev); + hp_x_prev = in; + hp_y_prev = hp_out; + in = hp_out; +#endif +#if ENABLE_LOWPASS + float lp_out = LOWPASS_ALPHA * in + (1.0f - LOWPASS_ALPHA) * lp_prev; + lp_prev = lp_out; + in = lp_out; +#endif +#if MIC_BOOST_PERCENT != 100 + int32_t boosted = (int32_t)(in * MIC_BOOST_PERCENT / 100); if (boosted > 32767) boosted = 32767; if (boosted < -32768) boosted = -32768; samples[i] = (int16_t)boosted; - } +#else + if (in > 32767) in = 32767; + if (in < -32768) in = -32768; + samples[i] = (int16_t)in; #endif + } size_t written = fwrite(ctx->audio_buf, 1, bytes_read, f); if (written != bytes_read) { ESP_LOGE(TAG, "SD write error: wrote %d of %d", (int)written, (int)bytes_read); @@ -335,6 +367,10 @@ static void record_task(void* arg) { audio_stream_close(ctx->input_handle); ctx->input_handle = NULL; + // Re-enable speaker amp and unmute output after recording + audio_stream_set_mute(ctx->stream_dev, AUDIO_CODEC_DIR_OUTPUT, false); + gpio_set_level(GPIO_NUM_1, 0); + ESP_LOGI(TAG, "Recording done, amp re-enabled (GPIO1 LOW)"); fseek(f, 0, SEEK_SET); write_wav_header(f, SAMPLE_RATE, BITS_PER_SAMPLE, 1, total_written);