From 2fd0ff0b2af796a71debb3d1cede11584cb2aa54 Mon Sep 17 00:00:00 2001 From: Xiaoxia Date: Thu, 2 Oct 2025 09:55:45 +0800 Subject: [PATCH] Add SetInputGain(float gain) to AudioCodec (#1252) --- main/audio/audio_codec.cc | 5 + main/audio/audio_codec.h | 4 +- main/audio/codecs/box_audio_codec.cc | 3 +- main/audio/codecs/es8311_audio_codec.cc | 3 +- main/audio/codecs/es8374_audio_codec.cc | 4 +- main/audio/codecs/es8388_audio_codec.cc | 4 +- main/audio/codecs/es8389_audio_codec.cc | 3 +- main/audio/codecs/no_audio_codec.cc | 163 ++++++------------ .../m5stack-core-s3/cores3_audio_codec.cc | 3 +- main/boards/m5stack-tab5/tab5_audio_codec.cc | 3 +- 10 files changed, 80 insertions(+), 115 deletions(-) diff --git a/main/audio/audio_codec.cc b/main/audio/audio_codec.cc index cef61803..055cd82a 100644 --- a/main/audio/audio_codec.cc +++ b/main/audio/audio_codec.cc @@ -55,6 +55,11 @@ void AudioCodec::SetOutputVolume(int volume) { settings.SetInt("output_volume", output_volume_); } +void AudioCodec::SetInputGain(float gain) { + input_gain_ = gain; + ESP_LOGI(TAG, "Set input gain to %.1f", input_gain_); +} + void AudioCodec::EnableInput(bool enable) { if (enable == input_enabled_) { return; diff --git a/main/audio/audio_codec.h b/main/audio/audio_codec.h index fb561061..819e6462 100644 --- a/main/audio/audio_codec.h +++ b/main/audio/audio_codec.h @@ -13,7 +13,6 @@ #define AUDIO_CODEC_DMA_DESC_NUM 6 #define AUDIO_CODEC_DMA_FRAME_NUM 240 -#define AUDIO_CODEC_DEFAULT_MIC_GAIN 30.0 class AudioCodec { public: @@ -21,6 +20,7 @@ public: virtual ~AudioCodec(); virtual void SetOutputVolume(int volume); + virtual void SetInputGain(float gain); virtual void EnableInput(bool enable); virtual void EnableOutput(bool enable); @@ -35,6 +35,7 @@ public: inline int input_channels() const { return input_channels_; } inline int output_channels() const { return output_channels_; } inline int output_volume() const { return output_volume_; } + inline float input_gain() const { return input_gain_; } inline bool input_enabled() const { return input_enabled_; } inline bool output_enabled() const { return output_enabled_; } @@ -51,6 +52,7 @@ protected: int input_channels_ = 1; int output_channels_ = 1; int output_volume_ = 70; + float input_gain_ = 0.0; virtual int Read(int16_t* dest, int samples) = 0; virtual int Write(const int16_t* data, int samples) = 0; diff --git a/main/audio/codecs/box_audio_codec.cc b/main/audio/codecs/box_audio_codec.cc index a4a3eeef..a3db34fa 100644 --- a/main/audio/codecs/box_audio_codec.cc +++ b/main/audio/codecs/box_audio_codec.cc @@ -14,6 +14,7 @@ BoxAudioCodec::BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int input_channels_ = input_reference_ ? 2 : 1; // 输入通道数 input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; + input_gain_ = 30; CreateDuplexChannels(mclk, bclk, ws, dout, din); @@ -200,7 +201,7 @@ void BoxAudioCodec::EnableInput(bool enable) { fs.channel_mask |= ESP_CODEC_DEV_MAKE_CHANNEL_MASK(1); } ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs)); - ESP_ERROR_CHECK(esp_codec_dev_set_in_channel_gain(input_dev_, ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0), AUDIO_CODEC_DEFAULT_MIC_GAIN)); + ESP_ERROR_CHECK(esp_codec_dev_set_in_channel_gain(input_dev_, ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0), input_gain_)); } else { ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_)); } diff --git a/main/audio/codecs/es8311_audio_codec.cc b/main/audio/codecs/es8311_audio_codec.cc index 33c8c9dc..ea425f35 100644 --- a/main/audio/codecs/es8311_audio_codec.cc +++ b/main/audio/codecs/es8311_audio_codec.cc @@ -14,6 +14,7 @@ Es8311AudioCodec::Es8311AudioCodec(void* i2c_master_handle, i2c_port_t i2c_port, output_sample_rate_ = output_sample_rate; pa_pin_ = pa_pin; pa_inverted_ = pa_inverted; + input_gain_ = 30; assert(input_sample_rate_ == output_sample_rate_); CreateDuplexChannels(mclk, bclk, ws, dout, din); @@ -81,7 +82,7 @@ void Es8311AudioCodec::UpdateDeviceState() { .mclk_multiple = 0, }; ESP_ERROR_CHECK(esp_codec_dev_open(dev_, &fs)); - ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(dev_, AUDIO_CODEC_DEFAULT_MIC_GAIN)); + ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(dev_, input_gain_)); ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(dev_, output_volume_)); } else if (!input_enabled_ && !output_enabled_ && dev_ != nullptr) { esp_codec_dev_close(dev_); diff --git a/main/audio/codecs/es8374_audio_codec.cc b/main/audio/codecs/es8374_audio_codec.cc index 11dea586..30b1ba36 100644 --- a/main/audio/codecs/es8374_audio_codec.cc +++ b/main/audio/codecs/es8374_audio_codec.cc @@ -12,6 +12,8 @@ Es8374AudioCodec::Es8374AudioCodec(void* i2c_master_handle, i2c_port_t i2c_port, input_channels_ = 1; // 输入通道数 input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; + input_gain_ = 30; + pa_pin_ = pa_pin; CreateDuplexChannels(mclk, bclk, ws, dout, din); @@ -146,7 +148,7 @@ void Es8374AudioCodec::EnableInput(bool enable) { .mclk_multiple = 0, }; ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs)); - ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, AUDIO_CODEC_DEFAULT_MIC_GAIN)); + ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, input_gain_)); } else { ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_)); } diff --git a/main/audio/codecs/es8388_audio_codec.cc b/main/audio/codecs/es8388_audio_codec.cc index 3fd327bd..aa26ae77 100644 --- a/main/audio/codecs/es8388_audio_codec.cc +++ b/main/audio/codecs/es8388_audio_codec.cc @@ -12,6 +12,8 @@ Es8388AudioCodec::Es8388AudioCodec(void* i2c_master_handle, i2c_port_t i2c_port, input_channels_ = input_reference_ ? 2 : 1; // 输入通道数 input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; + input_gain_ = 24; + pa_pin_ = pa_pin; CreateDuplexChannels(mclk, bclk, ws, dout, din); @@ -158,7 +160,7 @@ void Es8388AudioCodec::EnableInput(bool enable) { uint8_t gain = (11 << 4) + 0; ctrl_if_->write_reg(ctrl_if_, 0x09, 1, &gain, 1); }else{ - ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, 24.0)); + ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, input_gain_)); } } else { ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_)); diff --git a/main/audio/codecs/es8389_audio_codec.cc b/main/audio/codecs/es8389_audio_codec.cc index ece34b9d..351ad454 100644 --- a/main/audio/codecs/es8389_audio_codec.cc +++ b/main/audio/codecs/es8389_audio_codec.cc @@ -12,6 +12,7 @@ Es8389AudioCodec::Es8389AudioCodec(void* i2c_master_handle, i2c_port_t i2c_port, input_channels_ = 1; // 输入通道数 input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; + input_gain_ = 40; pa_pin_ = pa_pin; CreateDuplexChannels(mclk, bclk, ws, dout, din); @@ -153,7 +154,7 @@ void Es8389AudioCodec::EnableInput(bool enable) { .mclk_multiple = 0, }; ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs)); - ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, 40.0)); + ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, input_gain_)); } else { ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_)); } diff --git a/main/audio/codecs/no_audio_codec.cc b/main/audio/codecs/no_audio_codec.cc index c6f0ed4b..4c839c87 100644 --- a/main/audio/codecs/no_audio_codec.cc +++ b/main/audio/codecs/no_audio_codec.cc @@ -214,7 +214,53 @@ NoAudioCodecSimplex::NoAudioCodecSimplex(int input_sample_rate, int output_sampl ESP_LOGI(TAG, "Simplex channels created"); } -NoAudioCodecSimplexPdm::NoAudioCodecSimplexPdm(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, i2s_std_slot_mask_t spk_slot_mask,gpio_num_t mic_sck, gpio_num_t mic_din) { +int NoAudioCodec::Write(const int16_t* data, int samples) { + std::lock_guard lock(data_if_mutex_); + std::vector buffer(samples); + + // output_volume_: 0-100 + // volume_factor_: 0-65536 + int32_t volume_factor = pow(double(output_volume_) / 100.0, 2) * 65536; + for (int i = 0; i < samples; i++) { + int64_t temp = int64_t(data[i]) * volume_factor; // 使用 int64_t 进行乘法运算 + if (temp > INT32_MAX) { + buffer[i] = INT32_MAX; + } else if (temp < INT32_MIN) { + buffer[i] = INT32_MIN; + } else { + buffer[i] = static_cast(temp); + } + } + + size_t bytes_written; + ESP_ERROR_CHECK(i2s_channel_write(tx_handle_, buffer.data(), samples * sizeof(int32_t), &bytes_written, portMAX_DELAY)); + return bytes_written / sizeof(int32_t); +} + +int NoAudioCodec::Read(int16_t* dest, int samples) { + size_t bytes_read; + + std::vector bit32_buffer(samples); + if (i2s_channel_read(rx_handle_, bit32_buffer.data(), samples * sizeof(int32_t), &bytes_read, portMAX_DELAY) != ESP_OK) { + ESP_LOGE(TAG, "Read Failed!"); + return 0; + } + + samples = bytes_read / sizeof(int32_t); + for (int i = 0; i < samples; i++) { + int32_t value = bit32_buffer[i] >> 12; + dest[i] = (value > INT16_MAX) ? INT16_MAX : (value < -INT16_MAX) ? -INT16_MAX : (int16_t)value; + } + return samples; +} + +// Delegating constructor: calls the main constructor with default slot mask +NoAudioCodecSimplexPdm::NoAudioCodecSimplexPdm(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, gpio_num_t mic_sck, gpio_num_t mic_din) + : NoAudioCodecSimplexPdm(input_sample_rate, output_sample_rate, spk_bclk, spk_ws, spk_dout, I2S_STD_SLOT_LEFT, mic_sck, mic_din) { + // All initialization is handled by the delegated constructor +} + +NoAudioCodecSimplexPdm::NoAudioCodecSimplexPdm(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, i2s_std_slot_mask_t spk_slot_mask, gpio_num_t mic_sck, gpio_num_t mic_din) { duplex_ = false; input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; @@ -292,110 +338,6 @@ NoAudioCodecSimplexPdm::NoAudioCodecSimplexPdm(int input_sample_rate, int output ESP_LOGI(TAG, "Simplex channels created"); } -NoAudioCodecSimplexPdm::NoAudioCodecSimplexPdm(int input_sample_rate, int output_sample_rate, gpio_num_t spk_bclk, gpio_num_t spk_ws, gpio_num_t spk_dout, gpio_num_t mic_sck, gpio_num_t mic_din) { - duplex_ = false; - input_sample_rate_ = input_sample_rate; - output_sample_rate_ = output_sample_rate; - - // Create a new channel for speaker - i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG((i2s_port_t)1, I2S_ROLE_MASTER); - tx_chan_cfg.dma_desc_num = AUDIO_CODEC_DMA_DESC_NUM; - tx_chan_cfg.dma_frame_num = AUDIO_CODEC_DMA_FRAME_NUM; - tx_chan_cfg.auto_clear_after_cb = true; - tx_chan_cfg.auto_clear_before_cb = false; - tx_chan_cfg.intr_priority = 0; - ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_handle_, NULL)); - - - i2s_std_config_t tx_std_cfg = { - .clk_cfg = { - .sample_rate_hz = (uint32_t)output_sample_rate_, - .clk_src = I2S_CLK_SRC_DEFAULT, - .mclk_multiple = I2S_MCLK_MULTIPLE_256, - #ifdef I2S_HW_VERSION_2 - .ext_clk_freq_hz = 0, - #endif - - }, - .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_MONO), - .gpio_cfg = { - .mclk = I2S_GPIO_UNUSED, - .bclk = spk_bclk, - .ws = spk_ws, - .dout = spk_dout, - .din = I2S_GPIO_UNUSED, - .invert_flags = { - .mclk_inv = false, - .bclk_inv = false, - .ws_inv = false, - }, - }, - }; - ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &tx_std_cfg)); -#if SOC_I2S_SUPPORTS_PDM_RX - // Create a new channel for MIC in PDM mode - i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG((i2s_port_t)0, I2S_ROLE_MASTER); - ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, NULL, &rx_handle_)); - i2s_pdm_rx_config_t pdm_rx_cfg = { - .clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG((uint32_t)input_sample_rate_), - /* The data bit-width of PDM mode is fixed to 16 */ - .slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), - .gpio_cfg = { - .clk = mic_sck, - .din = mic_din, - - .invert_flags = { - .clk_inv = false, - }, - }, - }; - ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_handle_, &pdm_rx_cfg)); -#else - ESP_LOGE(TAG, "PDM is not supported"); -#endif - ESP_LOGI(TAG, "Simplex channels created"); -} - -int NoAudioCodec::Write(const int16_t* data, int samples) { - std::lock_guard lock(data_if_mutex_); - std::vector buffer(samples); - - // output_volume_: 0-100 - // volume_factor_: 0-65536 - int32_t volume_factor = pow(double(output_volume_) / 100.0, 2) * 65536; - for (int i = 0; i < samples; i++) { - int64_t temp = int64_t(data[i]) * volume_factor; // 使用 int64_t 进行乘法运算 - if (temp > INT32_MAX) { - buffer[i] = INT32_MAX; - } else if (temp < INT32_MIN) { - buffer[i] = INT32_MIN; - } else { - buffer[i] = static_cast(temp); - } - } - - size_t bytes_written; - ESP_ERROR_CHECK(i2s_channel_write(tx_handle_, buffer.data(), samples * sizeof(int32_t), &bytes_written, portMAX_DELAY)); - return bytes_written / sizeof(int32_t); -} - -int NoAudioCodec::Read(int16_t* dest, int samples) { - size_t bytes_read; - - std::vector bit32_buffer(samples); - if (i2s_channel_read(rx_handle_, bit32_buffer.data(), samples * sizeof(int32_t), &bytes_read, portMAX_DELAY) != ESP_OK) { - ESP_LOGE(TAG, "Read Failed!"); - return 0; - } - - samples = bytes_read / sizeof(int32_t); - for (int i = 0; i < samples; i++) { - int32_t value = bit32_buffer[i] >> 12; - dest[i] = (value > INT16_MAX) ? INT16_MAX : (value < -INT16_MAX) ? -INT16_MAX : (int16_t)value; - } - return samples; -} - int NoAudioCodecSimplexPdm::Read(int16_t* dest, int samples) { size_t bytes_read; @@ -405,6 +347,13 @@ int NoAudioCodecSimplexPdm::Read(int16_t* dest, int samples) { return 0; } - // 计算实际读取的样本数 - return bytes_read / sizeof(int16_t); + samples = bytes_read / sizeof(int16_t); + if (input_gain_ > 0) { + int gain_factor = (int)input_gain_; + for (int i = 0; i < samples; i++) { + int32_t amplified = dest[i] * gain_factor; + dest[i] = (amplified > INT16_MAX) ? INT16_MAX : (amplified < -INT16_MAX) ? -INT16_MAX : (int16_t)amplified; + } + } + return samples; } diff --git a/main/boards/m5stack-core-s3/cores3_audio_codec.cc b/main/boards/m5stack-core-s3/cores3_audio_codec.cc index ea132779..25963918 100644 --- a/main/boards/m5stack-core-s3/cores3_audio_codec.cc +++ b/main/boards/m5stack-core-s3/cores3_audio_codec.cc @@ -14,6 +14,7 @@ CoreS3AudioCodec::CoreS3AudioCodec(void* i2c_master_handle, int input_sample_rat input_channels_ = input_reference_ ? 2 : 1; // 输入通道数 input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; + input_gain_ = 30; CreateDuplexChannels(mclk, bclk, ws, dout, din); @@ -200,7 +201,7 @@ void CoreS3AudioCodec::EnableInput(bool enable) { fs.channel_mask |= ESP_CODEC_DEV_MAKE_CHANNEL_MASK(1); } ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs)); - ESP_ERROR_CHECK(esp_codec_dev_set_in_channel_gain(input_dev_, ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0), AUDIO_CODEC_DEFAULT_MIC_GAIN)); + ESP_ERROR_CHECK(esp_codec_dev_set_in_channel_gain(input_dev_, ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0), input_gain_)); } else { ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_)); } diff --git a/main/boards/m5stack-tab5/tab5_audio_codec.cc b/main/boards/m5stack-tab5/tab5_audio_codec.cc index a8e1a968..74dfe2e4 100644 --- a/main/boards/m5stack-tab5/tab5_audio_codec.cc +++ b/main/boards/m5stack-tab5/tab5_audio_codec.cc @@ -14,6 +14,7 @@ Tab5AudioCodec::Tab5AudioCodec(void* i2c_master_handle, int input_sample_rate, i input_channels_ = input_reference_ ? 2 : 1; // 输入通道数 input_sample_rate_ = input_sample_rate; output_sample_rate_ = output_sample_rate; + input_gain_ = 30; CreateDuplexChannels(mclk, bclk, ws, dout, din); @@ -199,7 +200,7 @@ void Tab5AudioCodec::EnableInput(bool enable) { fs.channel_mask |= ESP_CODEC_DEV_MAKE_CHANNEL_MASK(1); } ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs)); - ESP_ERROR_CHECK(esp_codec_dev_set_in_channel_gain(input_dev_, ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0), AUDIO_CODEC_DEFAULT_MIC_GAIN)); + ESP_ERROR_CHECK(esp_codec_dev_set_in_channel_gain(input_dev_, ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0), input_gain_)); } else { ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_)); }