24位INMP441的相关配置,原本是16位mic数据,麦克风音质不高

NoAudioCodecDuplex::NoAudioCodecDuplex(int input_sample_rate, int output_sample_rate, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din) {

duplex_ = true;

input_sample_rate_ = input_sample_rate;

output_sample_rate_ = output_sample_rate;

i2s_chan_config_t chan_cfg = {

.id = I2S_NUM_0,

.role = I2S_ROLE_MASTER,

.dma_desc_num = AUDIO_CODEC_DMA_DESC_NUM,

.dma_frame_num = AUDIO_CODEC_DMA_FRAME_NUM,

.auto_clear_after_cb = true, //true

.auto_clear_before_cb = false,

.intr_priority = 0,

};

ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle_, &rx_handle_));

// 假设原始可用的 TX 设置(左对齐)

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 = {

.data_bit_width = I2S_DATA_BIT_WIDTH_32BIT,

.slot_bit_width = I2S_SLOT_BIT_WIDTH_32BIT,

.slot_mode = I2S_SLOT_MODE_MONO,

.slot_mask = I2S_STD_SLOT_LEFT,

.ws_width = I2S_DATA_BIT_WIDTH_32BIT,

.ws_pol = false,

.bit_shift = false,

.left_align = true, // 这是以前能出声的关键

.big_endian = false,

.bit_order_lsb = false

},

.gpio_cfg = {

.mclk = I2S_GPIO_UNUSED,

.bclk = bclk,

.ws = ws,

.dout = dout,

.din = din,

.invert_flags = {

.mclk_inv = false,

.bclk_inv = false,

.ws_inv = false

}

}

};

// 正确的 RX 设置(标准 I2S)

i2s_std_config_t rx_std_cfg = {

.clk_cfg = {

.sample_rate_hz = (uint32_t)input_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 = {

.data_bit_width = I2S_DATA_BIT_WIDTH_32BIT,

.slot_bit_width = I2S_SLOT_BIT_WIDTH_32BIT,

.slot_mode = I2S_SLOT_MODE_MONO,

.slot_mask = I2S_STD_SLOT_LEFT,//I2S_STD_SLOT_LEFT, // 检查麦克风 L/R 引脚

.ws_width = I2S_DATA_BIT_WIDTH_32BIT,

.ws_pol = false,

.bit_shift =false,// true, // 标准 I2S 特征

.left_align = true ,

.big_endian = false,

.bit_order_lsb = false

},

/*

.slot_cfg = {

.data_bit_width = I2S_DATA_BIT_WIDTH_16BIT,

.slot_bit_width = I2S_SLOT_BIT_WIDTH_16BIT,

.slot_mode = I2S_SLOT_MODE_MONO,

.slot_mask = I2S_STD_SLOT_LEFT, // 检查麦克风 L/R 引脚

.ws_width = I2S_DATA_BIT_WIDTH_16BIT,

.ws_pol = false,

.bit_shift =false,// true, // 标准 I2S 特征

.left_align = true ,

.big_endian = false,

.bit_order_lsb = false

},

*/

.gpio_cfg = {

.mclk = I2S_GPIO_UNUSED,

.bclk = bclk,

.ws = ws,

.dout = dout,

.din = din,

.invert_flags = {

.mclk_inv = false,

.bclk_inv = false,

.ws_inv = false

}

}

};

// 分别初始化

ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &tx_std_cfg));

ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &rx_std_cfg));

return;

===========================================================================

raw_buf = (int32_t *)malloc(RECV2_BUF_SIZE*2);//变为4个字节的了,所以多采集2倍,才能保持原样本数

===========================================================================

// 1. 读取一帧麦克风数据

memset(mic_data, 0, RECV2_BUF_SIZE);

ret = i2s_channel_read(ref_audioCodec->rx_handle_, raw_buf, RECV2_BUF_SIZE*2, &bytes_read, 1000);

if (ret != ESP_OK) {

ESP_LOGE(TAG, "feed_wakeup_data i2s read failed, %s", err_reasonret == ESP_ERR_TIMEOUT);

vTaskDelay(10 / portTICK_PERIOD_MS);

continue;

}

// ----- 播放状态下丢弃所有麦克风数据 -----

if (is_playback_active()) {

vTaskDelay(10 / portTICK_PERIOD_MS);

continue;

}

int samples_read = bytes_read / sizeof(int32_t);

for (int i = 0; i < samples_read; i++) {

// 关键补偿:左移 1 位,让 MSB 回归最高位

int32_t corrected = raw_bufi << 1;

// 取高 16 位作为最终样本

int32_t sample_16 = corrected >> 16;//24位数据右移 16 位

// 限幅(防止左移后溢出,但通常不会)

if (sample_16 > 32767) sample_16 = 32767;

if (sample_16 < -32768) sample_16 = -32768;

mic_datai = (int16_t)sample_16;

}

===========================================================================

#define AUDIO_CODEC_DMA_DESC_NUM 4//6

#define AUDIO_CODEC_DMA_FRAME_NUM 120//240

===========================================================================

for (int i = 0; i < output_samples1; i++) {

// 将 16 位有符号数左移 16 位,放入 32 位高半部

tx_buf_32i = ((int32_t)pcm_output_2i) << 16;

}

esp_err_t err = i2s_channel_write(ref_audioCodec->tx_handle_, (char *)tx_buf_32, output_samples1*4, &bytes_write,portMAX_DELAY );//pdMS_TO_TICKS(50)

相关推荐
殷忆枫2 天前
基于ESP32 的局域网全双工对讲系统
单片机·嵌入式硬件·esp32·对讲系统
ITKEY_3 天前
嵌入式ESP32初学踩坑记录
esp32
EatFan14 天前
全栈自造 Status Deck(四):硬件终于到了,从点亮屏幕到跑通第一个 Demo
单片机·物联网·esp32
攸尔的笔记本~17 天前
ESP32-C3的WIFI信号飘忽不定、连接不了
esp32·射频·硬件设计
乐鑫科技 Espressif19 天前
案例研究:基于 ESP32-C5 与 ESP RainMaker 构建符合 EN 18031 标准的 IoT 解决方案
esp32·乐鑫科技·rainmaker
jianqiang.xue21 天前
ESP-IDF保姆级入门41|产品级故障排查与稳定性优化全解:死机复位排查/内存泄漏定位/性能瓶颈分析/长期稳定性测试,掌握量产运维问题定位方法论
单片机·mcu·物联网·esp32
jianqiang.xue22 天前
ESP-IDF保姆级入门40|量产烧录与产线测试全解:批量烧录方案/校准流程/功能测试/不良分拣/产线追溯,掌握工业级量产交付全流程
单片机·物联网·esp32
jianqiang.xue22 天前
ESP-IDF保姆级入门39|固件安全与安全启动全解:签名校验/Flash加密/防回滚/OTP密钥/知识产权保护,掌握工业级固件安全防护体系
单片机·物联网·esp32
jianqiang.xue23 天前
ESP-IDF保姆级入门38|电源管理与锂电池充电全解:充电拓扑/电源路径控制/充放电保护/电量检测/低功耗策略,掌握嵌入式电池供电系统设计
单片机·嵌入式·esp32
jianqiang.xue24 天前
ESP-IDF保姆级入门35|SDMMC高速SD卡全解:SDIO接口/4位高速模式/FATFS文件系统/热插拔检测/磨损均衡,掌握嵌入式大容量存储扩展
单片机·esp32