
MIC : microphone : 麦克风,话筒
把外界说话,环境声音这种模拟声波转换成电信号,是音频采集输入设备
声音 ---》 mic采集声波 ---》 转换为数字音频(PDM自带模数转换) ---》 i2s总线送入esp32 ---》 完成录音
PDM : 数字麦 INMP441
speaker : 扬声器,喇叭,,音频输出设备,,,把芯片输出的数字电信号,还原成能听见的声波
i2s : inter-ic sound : 集成电路内置音频总线,,, i two s
专门用来传输数字音频信号的通信协议,,只传声音数据,不做控制指令,,,解决芯片和麦克风或功放之间的音频传输
c
#include <stdio.h>
#include "driver/i2s_common.h"
#include "driver/i2s_std.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// 共用时钟
#define I2S_BCLK 5
#define I2S_WS 6
// max98357
#define I2S_SPK_DOUT 7
// INMP441 输入
#define I2S_MIC_DIN 8
#define audio_buf_len 1024
#define SAMPLE_RATE 16000
// 播放通道
static i2s_chan_handle_t tx_handle = NULL;
// 录音通道
static i2s_chan_handle_t rx_handle = NULL;
esp_err_t ret;
void i2s_init(void) {
i2s_chan_config_t chan_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0,I2S_ROLE_MASTER);
ret = i2s_new_channel(&chan_config,&tx_handle,&rx_handle);
printf("new_channel=%d\n", ret);
// ESP_ERROR_CHECK();
}
// 初始化max98357
void speaker_init(void) {
i2s_std_config_t tx_config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED, // master clk,, 外界立体codec声卡时,必须分配一个gpio输出MCK
.bclk = I2S_BCLK, // 时钟线,, 一个周期传一个 音频单位
.ws = I2S_WS, // write select
.dout = I2S_SPK_DOUT,
.din = I2S_GPIO_UNUSED,
.invert_flags = {// 硬件布线 / 电平相位错位 需要反转
.mclk_inv = false,// MCK主时钟是否反转
.bclk_inv = false,
.ws_inv = false,
}
}
};
tx_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;// 左声道
// ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle,&tx_config));
ret = i2s_channel_init_std_mode(tx_handle, &tx_config);
printf("tx_init=%d\n", ret);
// ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
ret = i2s_channel_enable(tx_handle);
printf("tx_enable=%d\n", ret);
}
/**
* INMP441原生输出 24bit,, 如果配置16bit,,只会取其中16bit,,音量特别小,全是噪音,数据错位,,一般用32Bit
*/
void microphone_init(void) {
i2s_std_config_t rx_config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = I2S_BCLK,
.ws = I2S_WS,
.dout = I2S_GPIO_UNUSED,
.din = I2S_MIC_DIN,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false
}
}
};
rx_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;// 左声道
// ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle,&rx_config));
ret = i2s_channel_init_std_mode(rx_handle, &rx_config);
printf("rx_init=%d\n", ret);
// ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
ret = i2s_channel_enable(rx_handle);
printf("rx_enable=%d\n", ret);
}
size_t audio_read(void *buf,size_t len) {
size_t bytes_read;
/**
*@param2 : 存储读取到的PCM
*@param3 : 缓冲区总字节数
*@param4 : 本次实际读取字节数
**/
i2s_channel_read(rx_handle,buf,len,&bytes_read,portMAX_DELAY);
return bytes_read;
}
void audio_write(void *buf,size_t len) {
size_t bytes_write;
i2s_channel_write(tx_handle,buf,len,&bytes_write,portMAX_DELAY);
}
#define AUDIO_FRAME_SIZE 1024
int16_t mic_buffer[AUDIO_FRAME_SIZE];
int16_t spk_buffer[AUDIO_FRAME_SIZE];
void audio_loopback(void) {
size_t bytes_read;
size_t bytes_write;
static int cnt = 0;
while(1) {
// i2s_channel_read(rx_handle,mic_buffer,sizeof(mic_buffer),&bytes_read,portMAX_DELAY);
//
//
// // 读了多少个样本
// int sample_count = bytes_read / sizeof(int32_t);
//
// for(int i=0;i<sample_count;i++) {
// spk_buffer[i] =
// (int16_t)(mic_buffer[i] >> 14);
// }
//
// cnt++;
// if (cnt==100) {
// printf("%ld\n", mic_buffer[0]);
// cnt=0;
// }
//
//
//
// i2s_channel_write(tx_handle,spk_buffer,sample_count * sizeof(int16_t),&bytes_write,portMAX_DELAY);
printf("before read \n");
ret = i2s_channel_read(rx_handle,mic_buffer,sizeof(mic_buffer),&bytes_read,portMAX_DELAY);
// int sample_count = bytes_read / sizeof(int16_t);
// 读多少,写多少
i2s_channel_write(tx_handle,mic_buffer, bytes_read,&bytes_write,portMAX_DELAY);
//
// printf("after read ret=%d bytes=%d\n", ret, (int)bytes_read);
// uint32_t *p=(uint32_t*)mic_buffer;
// for(int i = 0; i < 32; i++)
// {
// printf("%d\n", (int16_t)mic_buffer[i]);
// }
for(int i = 0; i < 32; i += 2)
{
printf("%6d\n", mic_buffer[i]);
}
printf("\n");
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void app_main(void)
{
i2s_init();
speaker_init();
microphone_init();
printf("audio loopback start...\n");
audio_loopback();
}
没有杂音:
c
#include <stdio.h>
#include "driver/i2s_common.h"
#include "driver/i2s_std.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// 共用时钟
#define I2S_BCLK 5
#define I2S_WS 6
// max98357
#define I2S_SPK_DOUT 7
// INMP441 输入
#define I2S_MIC_DIN 8
#define audio_buf_len 1024
#define SAMPLE_RATE 16000
// 播放通道
static i2s_chan_handle_t tx_handle = NULL;
// 录音通道
static i2s_chan_handle_t rx_handle = NULL;
esp_err_t ret;
void i2s_init(void) {
i2s_chan_config_t chan_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0,I2S_ROLE_MASTER);
ret = i2s_new_channel(&chan_config,&tx_handle,&rx_handle);
printf("new_channel=%d\n", ret);
// ESP_ERROR_CHECK();
}
// 初始化max98357
void speaker_init(void) {
i2s_std_config_t tx_config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED, // master clk,, 外界立体codec声卡时,必须分配一个gpio输出MCK
.bclk = I2S_BCLK, // 时钟线,, 一个周期传一个 音频单位
.ws = I2S_WS, // write select
.dout = I2S_SPK_DOUT,
.din = I2S_GPIO_UNUSED,
.invert_flags = {// 硬件布线 / 电平相位错位 需要反转
.mclk_inv = false,// MCK主时钟是否反转
.bclk_inv = false,
.ws_inv = false,
}
}
};
tx_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;// 左声道
// ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle,&tx_config));
ret = i2s_channel_init_std_mode(tx_handle, &tx_config);
printf("tx_init=%d\n", ret);
// ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
ret = i2s_channel_enable(tx_handle);
printf("tx_enable=%d\n", ret);
}
/**
* INMP441原生输出 24bit,, 如果配置16bit,,只会取其中16bit,,音量特别小,全是噪音,数据错位,,一般用32Bit
*/
void microphone_init(void) {
i2s_std_config_t rx_config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = I2S_BCLK,
.ws = I2S_WS,
.dout = I2S_GPIO_UNUSED,
.din = I2S_MIC_DIN,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false
}
}
};
rx_config.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT;// 左声道
// ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle,&rx_config));
ret = i2s_channel_init_std_mode(rx_handle, &rx_config);
printf("rx_init=%d\n", ret);
// ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
ret = i2s_channel_enable(rx_handle);
printf("rx_enable=%d\n", ret);
}
size_t audio_read(void *buf,size_t len) {
size_t bytes_read;
/**
*@param2 : 存储读取到的PCM
*@param3 : 缓冲区总字节数
*@param4 : 本次实际读取字节数
**/
i2s_channel_read(rx_handle,buf,len,&bytes_read,portMAX_DELAY);
return bytes_read;
}
void audio_write(void *buf,size_t len) {
size_t bytes_write;
i2s_channel_write(tx_handle,buf,len,&bytes_write,portMAX_DELAY);
}
#define AUDIO_FRAME_SIZE 1024
int16_t mic_buffer[AUDIO_FRAME_SIZE];
int16_t spk_buffer[AUDIO_FRAME_SIZE];
void audio_loopback(void) {
size_t bytes_read;
size_t bytes_write;
static int cnt = 0;
while(1) {
// i2s_channel_read(rx_handle,mic_buffer,sizeof(mic_buffer),&bytes_read,portMAX_DELAY);
//
//
// // 读了多少个样本
// int sample_count = bytes_read / sizeof(int32_t);
//
// for(int i=0;i<sample_count;i++) {
// spk_buffer[i] =
// (int16_t)(mic_buffer[i] >> 14);
// }
//
// cnt++;
// if (cnt==100) {
// printf("%ld\n", mic_buffer[0]);
// cnt=0;
// }
//
//
//
// i2s_channel_write(tx_handle,spk_buffer,sample_count * sizeof(int16_t),&bytes_write,portMAX_DELAY);
printf("before read \n");
ret = i2s_channel_read(rx_handle,mic_buffer,sizeof(mic_buffer),&bytes_read,portMAX_DELAY);
int sample_count = bytes_read / sizeof(int16_t);
for(int i=0;i<sample_count;i++) {
// int32_t sample = mic_buffer[i] >> 16;
// sample /= 8; // 衰减4-8倍
// spk_buffer[i] = (uint16_t)sample;
int16_t sample = mic_buffer[i];
sample /= 8;
spk_buffer[i] = sample;
}
// 读多少,写多少
i2s_channel_write(tx_handle,spk_buffer, sample_count*sizeof(int16_t),&bytes_write,portMAX_DELAY);
//
// printf("after read ret=%d bytes=%d\n", ret, (int)bytes_read);
// uint32_t *p=(uint32_t*)mic_buffer;
// for(int i = 0; i < 32; i++)
// {
// printf("%d\n", (int16_t)mic_buffer[i]);
// }
for(int i = 0; i < 8; i ++)
{
printf("%6d\n", spk_buffer[i]);
}
printf("\n");
// vTaskDelay(pdMS_TO_TICKS(100));
}
}
void app_main(void)
{
i2s_init();
speaker_init();
microphone_init();
printf("audio loopback start...\n");
audio_loopback();
}