Files
99_7018_lmx/apps/earphone/aec/br28/audio_cvp_3mic.c

1331 lines
42 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
/*
****************************************************************
* AUDIO DMS(DualMic System)
* File : audio_aec_dms.c
* By :
* Notes : AEC回音消除 + mic降噪(ENC)
*
****************************************************************
*/
#include "aec_user.h"
#include "system/includes.h"
#include "media/includes.h"
#include "application/eq_config.h"
#include "application/audio_pitch.h"
#include "application/audio_drc.h"
#include "circular_buf.h"
#include "audio_aec_online.h"
#include "amplitude_statistic.h"
#include "audio_gain_process.h"
#include "audio_config.h"
#include "app_main.h"
#include "lib_h/jlsp_ns.h"
#if !defined(TCFG_CVP_DEVELOP_ENABLE) || (TCFG_CVP_DEVELOP_ENABLE == 0)
#if TCFG_AUDIO_CVP_DUT_ENABLE
#include "audio_cvp_dut.h"
#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
#if TCFG_USER_TWS_ENABLE
#include "bt_tws.h"
#endif/*TCFG_USER_TWS_ENABLE*/
#include "overlay_code.h"
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
#define LOG_TAG_CONST AEC_USER
#define LOG_TAG "[AEC_USER]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#include "audio_aec_debug.c"
#include "commproc_tms.h"
#define AEC_USER_MALLOC_ENABLE 1
/*AEC_TOGGLE:AEC模块使能开关Disable则数据完全不经过处理AEC模块不占用资源*/
#define AEC_TOGGLE 1 /*回音消除模块开关*/
#if TCFG_EQ_ENABLE
/*mic去直流滤波eq*/
#define AEC_DCCS_EN TCFG_AEC_DCCS_EQ_ENABLE
/*mic普通eq*/
#define AEC_UL_EQ_EN TCFG_AEC_UL_EQ_ENABLE
#else
#define AEC_DCCS_EN 0
#define AEC_UL_EQ_EN 0
#endif /*TCFG_EQ_ENABLE*/
#if TCFG_DRC_ENABLE
#define CVP_UL_DRC_EN TCFG_CVP_UL_DRC_ENABLE
#else
#define CVP_UL_DRC_EN 0
#endif/*TCFG_DRC_ENABLE*/
extern int ul_presets_eq_get_filter_info(void *_eq, int sr, struct audio_eq_filter_info *info);
extern const int VC_KINDO_TVM;
extern struct adc_platform_data adc_data;
extern struct audio_dac_hdl dac_hdl;
#ifdef CONFIG_FPGA_ENABLE
const u8 CONST_AEC_ENABLE = 1;
#else
const u8 CONST_AEC_ENABLE = 1;
#endif/*CONFIG_FPGA_ENABLE*/
/*
*
* 0 :
* 1 : mic0 mic1 mic2 far out
*/
#ifdef AUDIO_PCM_DEBUG
const u8 CONST_AEC_EXPORT = 1;
#else
const u8 CONST_AEC_EXPORT = 0;
#endif
//*********************************************************************************//
// 预处理配置(Pre-process Config) //
//*********************************************************************************//
/*预增益配置*/
#define CVP_PRE_GAIN_ENABLE 0 //算法处理前预加数字增益放大
/*响度指示器*/
#define CVP_LOUDNESS_TRACE_ENABLE 0 //跟踪获取当前mic输入幅值
//*********************************************************************************//
// 调试配置(Debug Config) //
//*********************************************************************************//
/*使能即可跟踪通话过程的内存情况*/
#define CVP_MEM_TRACE_ENABLE 0
/*
*使
*
*
*/
const u8 CONST_AEC_DLY_EST = 0;
#if TCFG_AEC_SIMPLEX
const u8 CONST_AEC_SIMPLEX = 1;
#else
const u8 CONST_AEC_SIMPLEX = 0;
#endif/*TCFG_AEC_SIMPLEX*/
/*
* 线
* JLSP_NLP_MODE1: 1NLP回声抑制NLP模块可以单独开启
* JLSP_NLP_MODE2: 2AEC线性压制NLP非线性压制
* NLP不能单独打开需要同时打开AEC,使AEC模块压制不够时
*/
const u8 CONST_JLSP_NLP_MODE = JLSP_NLP_MODE1;
/*
*
* JLSP_WD_MODE1: 1
* JLSP_WD_MODE2: 231kb的flash
*/
const u8 CONST_JLSP_WD_MODE = JLSP_WD_MODE1;
/*参考数据变采样处理*/
#if TCFG_USB_MIC_CVP_ENABLE
const u8 CONST_REF_SRC = 1;
#else
const u8 CONST_REF_SRC = 0;
#endif /*TCFG_USB_MIC_CVP_ENABLE*/
/*数据输出开头丢掉的数据包数*/
#define AEC_OUT_DUMP_PACKET 15
/*数据输出开头丢掉的数据包数*/
#define AEC_IN_DUMP_PACKET 1
__attribute__((weak))u32 usb_mic_is_running()
{
return 0;
}
/*复用lmp rx buf(一般通话的时候复用)
*rx_buf概率产生碎片alloc失败0
*/
#define MALLOC_MULTIPLEX_EN 0
extern void *lmp_malloc(int);
extern void lmp_free(void *);
void *zalloc_mux(int size)
{
#if MALLOC_MULTIPLEX_EN
void *p = NULL;
do {
p = lmp_malloc(size);
if (p) {
break;
}
printf("aec_malloc wait...\n");
os_time_dly(2);
} while (1);
if (p) {
memset(p, 0, size);
}
printf("[malloc_mux]p = 0x%x,size = %d\n", p, size);
return p;
#else
return zalloc(size);
#endif
}
void free_mux(void *p)
{
#if MALLOC_MULTIPLEX_EN
printf("[free_mux]p = 0x%x\n", p);
lmp_free(p);
#else
free(p);
#endif
}
struct audio_aec_hdl {
volatile u8 start; //aec模块状态
u8 inbuf_clear_cnt; //aec输入数据丢掉
u8 output_fade_in; //aec输出淡入使能
u8 output_fade_in_gain; //aec输出淡入增益
u8 EnableBit; //aec使能模块
u8 input_clear; //清0输入数据标志
u16 dump_packet; //前面如果有杂音,丢掉几包
u8 output_buf[1000]; //aec数据输出缓存
cbuffer_t output_cbuf;
#if AEC_UL_EQ_EN
struct audio_eq *ul_eq;
#endif/*AEC_UL_EQ_EN*/
#if AEC_DCCS_EN
struct audio_eq *dccs_eq;
#endif/*AEC_DCCS_EN*/
#if CVP_UL_DRC_EN
struct audio_drc *ul_drc;
#endif/*CVP_UL_DRC_EN*/
struct tms_attr attr; //aec模块参数属性
#if AEC_PITCHSHIFTER_CONFIG
s_pitch_hdl *pitch ; //变声
u8 pitch_mode_L; //记录变声模式
u8 pitch_mode_R; //记录变声模式
#endif/* AEC_PITCHSHIFTER_CONFIG */
float *TransferFunc;
};
#if AEC_USER_MALLOC_ENABLE
struct audio_aec_hdl *aec_hdl = NULL;
#else
struct audio_aec_hdl aec_handle;
struct audio_aec_hdl *aec_hdl = &aec_handle;
#endif/*AEC_USER_MALLOC_ENABLE*/
#if AEC_DCCS_EN
//一段高通滤波器 可调中心截止频率、带宽
// 默认 /*freq:100*/ /*quality:0.7f*/
const struct eq_seg_info dccs_eq_tab_8k[] = {
{0, EQ_IIR_TYPE_HIGH_PASS, 100, 0, 0.7f},
};
const struct eq_seg_info dccs_eq_tab_16k[] = {
{0, EQ_IIR_TYPE_HIGH_PASS, 100, 0, 0.7f},
};
static float dccs_tab[5];
int aec_dccs_eq_filter(void *eq, int sr, struct audio_eq_filter_info *info)
{
if (!sr) {
sr = 16000;
}
u8 nsection = ARRAY_SIZE(dccs_eq_tab_8k);
local_irq_disable();
if (sr == 16000) {
for (int i = 0; i < nsection; i++) {
eq_seg_design((struct eq_seg_info *)&dccs_eq_tab_16k[i], sr, &dccs_tab[5 * i]);
}
} else {
for (int i = 0; i < nsection; i++) {
eq_seg_design((struct eq_seg_info *)&dccs_eq_tab_8k[i], sr, &dccs_tab[5 * i]);
}
}
local_irq_enable();
info->L_coeff = (float *)dccs_tab;
info->R_coeff = (float *)dccs_tab;
info->L_gain = 0;
info->R_gain = 0;
info->nsection = nsection;
return 0;
}
#endif/*AEC_DCCS_EN*/
#if CVP_UL_DRC_EN
static float Gain_dB = 0;
static int cvp_ul_drc_filter(struct audio_drc *drc, struct audio_drc_filter_info *info)
{
static struct drc_ch wdrc_p = {0};
struct threshold_group threshold[3] = {{0, 0}, {75.f, 75.f}, {140.f, 75.f}}; //这里减去90才是具体的db数
/*倍数对应放大的dB数
* 20lg(2) = 6dB
* 20lg(3) = 9.5dB
* 20lg(4) = 12dB
* 20lg(5) = 14dB
* 20lg(6) = 15.5dB
* 20lg(7) = 17dB
* 20lg(8) = 18dB
* 20lg(9) = 19dB
* 20lg(10) = 20dB*/
Gain_dB = 4.0f; /*drc压制后要放大的倍数*/
wdrc_p.nband = 1;
wdrc_p.type = 3;//wdrc
//left
int i = 0;
wdrc_p._p.wdrc[i][0].attacktime = 1;
wdrc_p._p.wdrc[i][0].releasetime = 200;
memcpy(wdrc_p._p.wdrc[i][0].threshold, threshold, sizeof(threshold));
wdrc_p._p.wdrc[i][0].threshold_num = ARRAY_SIZE(threshold);
wdrc_p._p.wdrc[i][0].rms_time = 25;
wdrc_p._p.wdrc[i][0].algorithm = 0;
wdrc_p._p.wdrc[i][0].mode = 1;
//right
wdrc_p._p.wdrc[i][1].attacktime = 1;
wdrc_p._p.wdrc[i][1].releasetime = 200;
memcpy(wdrc_p._p.wdrc[i][1].threshold, threshold, sizeof(threshold));
wdrc_p._p.wdrc[i][1].threshold_num = ARRAY_SIZE(threshold);
wdrc_p._p.wdrc[i][1].rms_time = 25;
wdrc_p._p.wdrc[i][1].algorithm = wdrc_p._p.wdrc[i][0].algorithm;
wdrc_p._p.wdrc[i][1].mode = wdrc_p._p.wdrc[i][0].mode;
info->R_pch = info->pch = &wdrc_p;
return 0;
}
#endif/*CVP_UL_DRC_EN*/
/*
*********************************************************************
* Audio AEC Process_Probe
* Description: AEC模块数据前处理回调()
* Arguments : talk_mic
* talk_ref_mic
* fb_mic FB麦数据地址
* ref
* len (Unit:byte)
* Return : 0
* Note(s) : CVP模块前
*********************************************************************
*/
static LOUDNESS_M_STRUCT mic_loudness;
static int audio_aec_probe(short *talk_mic, short *talk_ref_mic, short *fb_mic, short *ref, u16 len)
{
#if TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE
if (app_var.audio_mic_array_trim_en) {
//表示使用主副麦差值计算,且仅减小增益
if (app_var.audio_mic_array_diff_cmp != 1.0f) {
if (app_var.audio_mic_array_diff_cmp > 1.0f) {
float talk_mic_gain = 1.0 / app_var.audio_mic_array_diff_cmp;
GainProcess_16Bit(talk_mic, talk_mic, talk_mic_gain, 1, 1, 1, len >> 1);
} else {
float talk_ref_mic_gain = app_var.audio_mic_array_diff_cmp;
GainProcess_16Bit(talk_ref_mic, talk_ref_mic, talk_ref_mic_gain, 1, 1, 1, len >> 1);
}
} else { //表示使用每个MIC与金机曲线的差值
GainProcess_16Bit(talk_mic, talk_mic, app_var.audio_mic_cmp.talk, 1, 1, 1, len >> 1);
GainProcess_16Bit(talk_ref_mic, talk_ref_mic, app_var.audio_mic_cmp.ff, 1, 1, 1, len >> 1);
GainProcess_16Bit(fb_mic, fb_mic, app_var.audio_mic_cmp.fb, 1, 1, 1, len >> 1);
}
}
#endif
#if CVP_PRE_GAIN_ENABLE
GainProcess_16Bit(talk_mic, talk_mic, 12.f, 1, 1, 1, len >> 1);
GainProcess_16Bit(talk_ref_mic, talk_ref_mic, 12.f, 1, 1, 1, len >> 1);
#endif/*CVP_PRE_GAIN_ENABLE*/
#if CVP_LOUDNESS_TRACE_ENABLE
loudness_meter_short(&mic_loudness, talk_mic, len >> 1);
#endif/*CVP_LOUDNESS_TRACE_ENABLE*/
#if AEC_DCCS_EN
if (aec_hdl->dccs_eq) {
audio_eq_run(aec_hdl->dccs_eq, talk_mic, len);
}
#endif/*AEC_DCCS_EN*/
return 0;
}
/*
*********************************************************************
* Audio AEC Process_Post
* Description: AEC模块数据后处理回调
* Arguments : data
* len
* Return : 0
* Note(s) :
*********************************************************************
*/
static int audio_aec_post(s16 *data, u16 len)
{
#if AEC_UL_EQ_EN
if (aec_hdl->ul_eq) {
audio_eq_run(aec_hdl->ul_eq, data, len);
}
#endif/*AEC_UL_EQ_EN*/
#if CVP_UL_DRC_EN
if (aec_hdl->ul_drc) {
audio_drc_run(aec_hdl->ul_drc, data, len);
GainProcess_16Bit(data, data, Gain_dB, 1, 1, 1, len >> 1);
}
#endif/*CVP_UL_DRC_EN*/
#if AEC_PITCHSHIFTER_CONFIG
if (aec_hdl && aec_hdl->pitch) {
pitch_run(aec_hdl->pitch, data, data, len, 1);
}
#endif/* AEC_PITCHSHIFTER_CONFIG */
return 0;
}
static int audio_aec_update(u8 EnableBit)
{
y_printf("aec_update:%d,%d", aec_hdl->attr.wideband, EnableBit);
clk_set("sys", CONFIG_BT_CALL_DNS_HZ);
return 0;
if (aec_hdl->attr.wideband) {
if ((EnableBit & AEC_EN) && (EnableBit & NLP_EN)) {
clk_set("sys", BT_CALL_16k_ADVANCE_HZ);
} else {
clk_set("sys", BT_CALL_16k_HZ);
}
} else {
if ((EnableBit & AEC_EN) && (EnableBit & NLP_EN)) {
clk_set("sys", BT_CALL_ADVANCE_HZ);
} else {
clk_set("sys", BT_CALL_HZ);
}
}
return 0;
}
/*跟踪系统内存使用情况:physics memory size xxxx bytes*/
static void sys_memory_trace(void)
{
static int cnt = 0;
if (cnt++ > 200) {
cnt = 0;
mem_stats();
}
}
/*
*********************************************************************
* Audio AEC Output Handle
* Description: AEC模块数据输出回调
* Arguments : data
* len
* Return :
* Note(s) : None.
*********************************************************************
*/
extern void esco_enc_resume(void);
static int audio_aec_output(s16 *data, u16 len)
{
#if (((defined TCFG_KWS_VOICE_RECOGNITION_ENABLE) && TCFG_KWS_VOICE_RECOGNITION_ENABLE) || \
((defined TCFG_CALL_KWS_SWITCH_ENABLE) && TCFG_CALL_KWS_SWITCH_ENABLE))
//Voice Recognition get mic data here
extern void kws_aec_data_output(void *priv, s16 * data, int len);
kws_aec_data_output(NULL, data, len);
#endif/*TCFG_KWS_VOICE_RECOGNITION_ENABLE*/
#if CVP_MEM_TRACE_ENABLE
sys_memory_trace();
#endif/*CVP_MEM_TRACE_ENABLE*/
if (aec_hdl->dump_packet) {
aec_hdl->dump_packet--;
memset(data, 0, len);
} else {
if (aec_hdl->output_fade_in) {
s32 tmp_data;
//printf("fade:%d\n",aec_hdl->output_fade_in_gain);
for (int i = 0; i < len / 2; i++) {
tmp_data = data[i];
data[i] = tmp_data * aec_hdl->output_fade_in_gain >> 7;
}
aec_hdl->output_fade_in_gain += 12;
if (aec_hdl->output_fade_in_gain >= 128) {
aec_hdl->output_fade_in = 0;
}
}
}
u16 wlen = cbuf_write(&aec_hdl->output_cbuf, data, len);
//printf("wlen:%d-%d\n",len,aec_hdl.output_cbuf.data_len);
esco_enc_resume();
#if 1
static u32 aec_output_max = 0;
if (aec_output_max < aec_hdl->output_cbuf.data_len) {
aec_output_max = aec_hdl->output_cbuf.data_len;
y_printf("o_max:%d", aec_output_max);
}
#endif
if (wlen != len) {
putchar('f');
}
return wlen;
}
/*
*********************************************************************
* Audio AEC Output Read
* Description: aec模块的输出数据
* Arguments : buf
* len
* Return :
* Note(s) : None.
*********************************************************************
*/
int audio_aec_output_read(s16 *buf, u16 len)
{
//printf("rlen:%d-%d\n",len,aec_hdl.output_cbuf.data_len);
local_irq_disable();
if (!aec_hdl || !aec_hdl->start) {
printf("audio_aec close now");
local_irq_enable();
return -EINVAL;
}
u16 rlen = cbuf_read(&aec_hdl->output_cbuf, buf, len);
if (rlen == 0) {
//putchar('N');
}
local_irq_enable();
return rlen;
}
#define AUDIO_3MIC_PARAM_FILE SDFILE_RES_ROOT_PATH"3mic_coeff.bin"
void *read_triple_mic_param()
{
if (aec_hdl == NULL) {
return NULL;
}
FILE *fp = NULL;
u8 *param_ptr = NULL;
u32 param_len = 0;
struct vfs_attr param_attr = {0};
//===============================//
// 打开参数文件 //
//===============================//
fp = fopen(AUDIO_3MIC_PARAM_FILE, "r");
if (!fp) {
printf("[err] read 3mic_coeff.bin fail !!!");
return NULL;
}
fget_attrs(fp, &param_attr);
param_len = param_attr.fsize;
printf("param_len %d", param_len);
param_ptr = (void *)param_attr.sclust;
fclose(fp);
aec_hdl->TransferFunc = zalloc(param_len);
if (aec_hdl->TransferFunc == NULL) {
return NULL;
}
memcpy(aec_hdl->TransferFunc, param_ptr, param_len);
return aec_hdl->TransferFunc;
}
/*
*********************************************************************
* Audio AEC Parameters
* Description: AEC模块配置参数
* Arguments : p
* Return : None.
* Note(s) : 使使
*
*********************************************************************
*/
static void audio_aec_param_init(struct tms_attr *p)
{
int ret = 0;
AEC_TMS_CONFIG cfg;
#if TCFG_AEC_TOOL_ONLINE_ENABLE
ret = aec_cfg_online_update_fill(&cfg, sizeof(AEC_TMS_CONFIG));
#endif/*TCFG_AEC_TOOL_ONLINE_ENABLE*/
if (ret == 0) {
ret = syscfg_read(CFG_TMS_DNS_ID, &cfg, sizeof(AEC_TMS_CONFIG));
}
if (ret == sizeof(AEC_TMS_CONFIG)) {
log_info("read tms_param ok\n");
p->EnableBit = cfg.enable_module;
p->ul_eq_en = cfg.ul_eq_en;
p->agc_type = cfg.agc_type;
if (p->agc_type == AGC_EXTERNAL) {
p->AGC_NDT_fade_in_step = cfg.agc.agc_ext.ndt_fade_in;
p->AGC_NDT_fade_out_step = cfg.agc.agc_ext.ndt_fade_out;
p->AGC_DT_fade_in_step = cfg.agc.agc_ext.dt_fade_in;
p->AGC_DT_fade_out_step = cfg.agc.agc_ext.dt_fade_out;
p->AGC_NDT_max_gain = cfg.agc.agc_ext.ndt_max_gain;
p->AGC_NDT_min_gain = cfg.agc.agc_ext.ndt_min_gain;
p->AGC_NDT_speech_thr = cfg.agc.agc_ext.ndt_speech_thr;
p->AGC_DT_max_gain = cfg.agc.agc_ext.dt_max_gain;
p->AGC_DT_min_gain = cfg.agc.agc_ext.dt_min_gain;
p->AGC_DT_speech_thr = cfg.agc.agc_ext.dt_speech_thr;
p->AGC_echo_present_thr = cfg.agc.agc_ext.echo_present_thr;
} else {
p->min_mag_db_level = cfg.agc.agc_int.min_mag_db_level;
p->max_mag_db_level = cfg.agc.agc_int.max_mag_db_level;
p->addition_mag_db_level = cfg.agc.agc_int.addition_mag_db_level;
p->clip_mag_db_level = cfg.agc.agc_int.clip_mag_db_level;
p->floor_mag_db_level = cfg.agc.agc_int.floor_mag_db_level;
}
p->aec_process_maxfrequency = cfg.aec_process_maxfrequency;
p->aec_process_minfrequency = cfg.aec_process_minfrequency;
p->af_length = cfg.af_length;
p->nlp_process_maxfrequency = cfg.nlp_process_maxfrequency;
p->nlp_process_minfrequency = cfg.nlp_process_minfrequency;
p->overdrive = cfg.overdrive;
p->aggressfactor = cfg.aggressfactor;
p->minsuppress = cfg.minsuppress;
p->init_noise_lvl = cfg.init_noise_lvl;
p->DNS_highGain = 1.0f; /*EQ强度, 范围1.0f~3.5f,越大越强*/
p->DNS_rbRate = 0.1f; /*混响强度范围0~0.9f,越大越强*/
p->enhance_flag = 1;
p->enc_process_maxfreq = cfg.enc_process_maxfreq;
p->enc_process_minfreq = cfg.enc_process_minfreq;
p->sir_maxfreq = cfg.sir_maxfreq;
p->mic_distance = cfg.mic_distance;
p->target_signal_degradation = cfg.target_signal_degradation;
p->enc_aggressfactor = cfg.enc_aggressfactor;
p->enc_minsuppress = cfg.enc_minsuppress;
p->Tri_SnrThreshold0 = cfg.Tri_SnrThreshold0;//sir设定阈值
p->Tri_SnrThreshold1 = cfg.Tri_SnrThreshold1;//sir设定阈值
p->Tri_CompenDb = cfg.Tri_CompenDb; //mic增益补偿, dB
p->wn_msc_th = cfg.wn_msc_th;
p->ms_th = cfg.ms_th;
p->wn_gain_offset = cfg.wn_gain_offset;
} else {
p->EnableBit = WNC_EN | AEC_EN | ANS_EN | ENC_EN | AGC_EN;
p->ul_eq_en = 1;
p->agc_type = AGC_INTERNAL;
p->AGC_NDT_fade_in_step = 1.3f;
p->AGC_NDT_fade_out_step = 0.9f;
p->AGC_DT_fade_in_step = 1.3f;
p->AGC_DT_fade_out_step = 0.9f;
p->AGC_NDT_max_gain = 12.f;
p->AGC_NDT_min_gain = 0.f;
p->AGC_NDT_speech_thr = -50.f;
p->AGC_DT_max_gain = 12.f;
p->AGC_DT_min_gain = 0.f;
p->AGC_DT_speech_thr = -40.f;
p->AGC_echo_present_thr = -70.f;
p->aec_process_maxfrequency = 8000;
p->aec_process_minfrequency = 0;
p->af_length = 128;
p->nlp_process_maxfrequency = 8000;
p->nlp_process_minfrequency = 0;
p->overdrive = 1;
p->aggressfactor = 1.0f;
p->minsuppress = 0.05f;
p->init_noise_lvl = -75.f;
p->DNS_highGain = 1.0f; /*EQ强度, 范围1.0f~3.5f,越大越强*/
p->DNS_rbRate = 0.01f; /*混响强度范围0~0.9f,越大越强*/
p->enhance_flag = 1;
p->enc_process_maxfreq = 8000;
p->enc_process_minfreq = 0;
p->sir_maxfreq = 3000;
p->mic_distance = 0.025f;
p->target_signal_degradation = 0.78;
p->enc_aggressfactor = 1.f;
p->enc_minsuppress = 0.05f;
p->Tri_SnrThreshold0 = 0.5f;//sir设定阈值
p->Tri_SnrThreshold1 = 0.5f;//sir设定阈值
p->Tri_CompenDb = 17; //mic增益补偿, dB
p->wn_msc_th = 0.6f;
p->ms_th = 80.0f;
p->wn_gain_offset = 5;
p->min_mag_db_level = -50; //语音能量放大下限阈值单位db,默认-50范围-90db~-35db
p->max_mag_db_level = -3; //语音能量放大上限阈值单位db,默认-3范围-90db~0db
p->addition_mag_db_level = 0; //语音补偿能量值单位db,默认0范围0db~20db
p->clip_mag_db_level = -3; //语音最大截断能量值单位db,默认-3范围-10db~db
p->floor_mag_db_level = -70; //语音最小截断能量值单位db,默认-70范围-90db~-35db
log_error("read tms_param default\n");
}
log_info("TMS:WNC[%d] AEC[%d] NLP[%d] NS[%d] ENC[%d] AGC[%d]", !!(p->EnableBit & WNC_EN), !!(p->EnableBit & AEC_EN), !!(p->EnableBit & NLP_EN), !!(p->EnableBit & ANS_EN), !!(p->EnableBit & ENC_EN), !!(p->EnableBit & AGC_EN));
p->FB_EnableBit = AEC_EN | NLP_EN;
p->Tri_CutTh = 2000; //fb麦统计截止频率
p->Tri_FbCompenDb = 0.0f;//fb补偿增益
p->Tri_TfEqSel = 0;//eq,传递函数的选择0选择eq1选择传递函数2选择传递函数和eq
p->Tri_Bf_Enhance = 0; //bf是否高频增强
p->Tri_TransferFunc = read_triple_mic_param();
if (p->Tri_TransferFunc) {
printf("3mic_coeff read ok %x", p->Tri_TransferFunc);
} else {
printf("3mic_coeff read eror %x !!!", p->Tri_TransferFunc);
}
p->AGC_echo_hold = 0;
p->AGC_echo_look_ahead = 0;
/*开通话上行DRC时关闭AGC*/
#if CVP_UL_DRC_EN
p->EnableBit &= ~AGC_EN;
#endif/*CVP_UL_DRC_EN*/
/* aec_param_dump(p); */
}
int audio_aec_toggle_set(u8 toggle)
{
if (aec_hdl) {
aec_tms_toggle(toggle);
return 0;
}
return 1;
}
/*
*********************************************************************
* Audio AEC Open
* Description: AEC模块
* Arguments : sr (8000/16000)
* enablebit 使(AEC/NLP/AGC/ANS...)
* out_hdl NULL则用默认的回调
* Return : 0
* Note(s) : audio_aec_init的扩展使
*
*********************************************************************
*/
int audio_aec_open(u16 sample_rate, s16 enablebit, int (*out_hdl)(s16 *data, u16 len))
{
struct tms_attr *aec_param;
printf("audio_tms_open\n");
mem_stats();
#if AEC_USER_MALLOC_ENABLE
aec_hdl = zalloc(sizeof(struct audio_aec_hdl));
if (aec_hdl == NULL) {
log_error("aec_hdl malloc failed");
return -ENOMEM;
}
#endif/*AEC_USER_MALLOC_ENABLE*/
overlay_load_code(OVERLAY_AEC);
#if CVP_LOUDNESS_TRACE_ENABLE
loudness_meter_init(&mic_loudness, sample_rate, 50, 0);
#endif/*CVP_LOUDNESS_TRACE_ENABLE*/
cbuf_init(&aec_hdl->output_cbuf, aec_hdl->output_buf, sizeof(aec_hdl->output_buf));
aec_hdl->dump_packet = AEC_OUT_DUMP_PACKET;
aec_hdl->inbuf_clear_cnt = AEC_IN_DUMP_PACKET;
aec_hdl->output_fade_in = 1;
aec_hdl->output_fade_in_gain = 0;
aec_param = &aec_hdl->attr;
aec_param->aec_probe = audio_aec_probe;
aec_param->aec_post = audio_aec_post;
#if TCFG_AEC_TOOL_ONLINE_ENABLE
aec_param->aec_update = audio_aec_update;
#endif/*TCFG_AEC_TOOL_ONLINE_ENABLE*/
aec_param->output_handle = audio_aec_output;
aec_param->ref_sr = usb_mic_is_running();
if (aec_param->ref_sr == 0) {
aec_param->ref_sr = sample_rate;
}
audio_aec_param_init(aec_param);
if (enablebit >= 0) {
aec_param->EnableBit = enablebit;
}
if (out_hdl) {
aec_param->output_handle = out_hdl;
}
#if TCFG_AEC_SIMPLEX
aec_param->wn_en = 1;
aec_param->EnableBit = AEC_MODE_SIMPLEX;
if (sr == 8000) {
aec_param->SimplexTail = aec_param->SimplexTail / 2;
}
#else
aec_param->wn_en = 0;
#endif/*TCFG_AEC_SIMPLEX*/
if (sample_rate == 16000) { //WideBand宽带
aec_param->wideband = 1;
aec_param->hw_delay_offset = 60;
if ((aec_param->EnableBit & AEC_EN) && (aec_param->EnableBit & NLP_EN)) {
clk_set("sys", BT_CALL_16k_ADVANCE_HZ);
} else {
clk_set("sys", BT_CALL_16k_HZ);
}
} else {//NarrowBand窄带
aec_param->wideband = 0;
aec_param->hw_delay_offset = 55;
if ((aec_param->EnableBit & AEC_EN) && (aec_param->EnableBit & NLP_EN)) {
clk_set("sys", BT_CALL_ADVANCE_HZ);
} else {
clk_set("sys", BT_CALL_HZ);
}
}
clk_set("sys", CONFIG_BT_CALL_DNS_HZ);
y_printf("[aec_user]clock config ok\n");
#if AEC_UL_EQ_EN
if (aec_param->ul_eq_en) {
struct audio_eq_param ul_eq_param = {0};
ul_eq_param.sr = sample_rate;
ul_eq_param.channels = 1;
ul_eq_param.online_en = 1;
ul_eq_param.mode_en = 0;
ul_eq_param.remain_en = 0;
ul_eq_param.max_nsection = EQ_SECTION_MAX;
#if defined(AEC_PRESETS_UL_EQ_CONFIG) && AEC_PRESETS_UL_EQ_CONFIG
ul_eq_param.cb = ul_presets_eq_get_filter_info;
#else
ul_eq_param.cb = aec_ul_eq_filter;
#endif
ul_eq_param.eq_name = aec_eq_mode;
aec_hdl->ul_eq = audio_dec_eq_open(&ul_eq_param);
}
#endif/*AEC_UL_EQ_EN*/
#if AEC_DCCS_EN
if (adc_data.mic_mode == AUDIO_MIC_CAPLESS_MODE) {
struct audio_eq_param dccs_eq_param = {0};
dccs_eq_param.sr = sample_rate;
dccs_eq_param.channels = 1;
dccs_eq_param.online_en = 0;
dccs_eq_param.mode_en = 0;
dccs_eq_param.remain_en = 0;
dccs_eq_param.max_nsection = EQ_SECTION_MAX;
dccs_eq_param.cb = aec_dccs_eq_filter;
aec_hdl->dccs_eq = audio_dec_eq_open(&dccs_eq_param);
}
#endif/*AEC_DCCS_EN*/
#if CVP_UL_DRC_EN
printf("audio cvp ul drc open start\n");
struct audio_drc_param ul_drc_param = {0};
ul_drc_param.channels = 1;
ul_drc_param.sr = sample_rate;
ul_drc_param.out_32bit = 0;
/* ul_drc_param.online_en = 0; */
/* ul_drc_param.remain_en = 0; */
/* ul_drc_param.stero_div = 0; */
ul_drc_param.cb = cvp_ul_drc_filter;
ul_drc_param.drc_name = 0;
u8 index = 0;
if (sample_rate == 8000) { //窄频
index = 1;
}
/* ul_drc_param.wdrc = &phone_mode[index].drc_parm; */
aec_hdl->ul_drc = audio_dec_drc_open(&ul_drc_param);
if (aec_hdl->ul_drc) {
printf("audio cvp ul drc open succ %x\n", aec_hdl->ul_drc);
} else {
printf("audio cvp ul drc open fail \n");
}
#endif/*CVP_UL_DRC_EN*/
#if AEC_PITCHSHIFTER_CONFIG
PITCH_SHIFT_PARM sparm = {0};
sparm.sr = sample_rate;
sparm.shiftv = 100;
sparm.effect_v = EFFECT_PITCH_SHIFT;
sparm.formant_shift = 100;
aec_hdl->pitch = open_pitch(&sparm);
pause_pitch(aec_hdl->pitch, 1);
aec_hdl->pitch_mode_L = 0;
aec_hdl->pitch_mode_R = 0;
#endif/* AEC_PITCHSHIFTER_CONFIG */
//aec_param_dump(aec_param);
aec_hdl->EnableBit = aec_param->EnableBit;
aec_param->aptfilt_only = 0;
aec_param->output_sel = DMS_OUTPUT_SEL_DEFAULT;
#if (((defined TCFG_KWS_VOICE_RECOGNITION_ENABLE) && TCFG_KWS_VOICE_RECOGNITION_ENABLE) || \
((defined TCFG_CALL_KWS_SWITCH_ENABLE) && TCFG_CALL_KWS_SWITCH_ENABLE))
extern u8 kws_get_state(void);
if (kws_get_state()) {
aec_param->EnableBit = AEC_EN;
aec_param->aptfilt_only = 1;
printf("kws open,aec_enablebit=%x", aec_param->EnableBit);
//临时关闭aec, 对比测试
//aec_param->toggle = 0;
}
#endif/*TCFG_KWS_VOICE_RECOGNITION_ENABLE*/
y_printf("[aec_user]aec_open\n");
#if AEC_TOGGLE
int ret = aec_open(aec_param);
if (ret == -EPERM) {
//该芯片不支持双mic ENC功能请选择大于等于8Mbit容量的芯片
printf("Chip not support ENC(tms+aec):Please select >= 8Mbit flash!");
}
//ASSERT(ret != -EPERM, "Chip not support dms+aec mode!!");
#endif
aec_hdl->start = 1;
audio_tms_mode_choose(1);
mem_stats();
printf("audio_tms_open succ\n");
return 0;
}
/*
*********************************************************************
* Audio AEC Init
* Description: AEC模块
* Arguments : sample_rate (8000/16000)
* Return : 0
* Note(s) : None.
*********************************************************************
*/
int audio_aec_init(u16 sample_rate)
{
return audio_aec_open(sample_rate, -1, NULL);
}
/*
*********************************************************************
* Audio AEC Reboot
* Description: AEC模块复位接口
* Arguments : reduce /
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_aec_reboot(u8 reduce)
{
if (aec_hdl) {
printf("audio_aec_tms_reboot:%x,%x,start:%d", aec_hdl->EnableBit, aec_hdl->attr.EnableBit, aec_hdl->start);
if (aec_hdl->start) {
if (reduce) {
aec_hdl->attr.EnableBit = AEC_EN;
aec_hdl->attr.aptfilt_only = 1;
aec_tms_reboot(aec_hdl->attr.EnableBit);
} else {
if (aec_hdl->EnableBit != aec_hdl->attr.EnableBit) {
aec_hdl->attr.aptfilt_only = 0;
aec_tms_reboot(aec_hdl->EnableBit);
}
}
}
} else {
printf("audio_aec close now\n");
}
}
/*
*********************************************************************
* Audio AEC Output Select
* Description:
* Arguments : sel = DMS_OUTPUT_SEL_DEFAULT
* = DMS_OUTPUT_SEL_MASTER mic(mic)
* = DMS_OUTPUT_SEL_SLAVE mic(mic)
* agc agc自动增益控制模块
* Return : None.
* Note(s) : mic的频响和ENC指标
*********************************************************************
*/
void audio_aec_output_sel(CVP_OUTPUT_ENUM sel, u8 agc)
{
if (aec_hdl) {
printf("tms_output_sel:%d\n", sel);
if (agc) {
aec_hdl->attr.EnableBit |= AGC_EN;
} else {
aec_hdl->attr.EnableBit &= ~AGC_EN;
}
aec_hdl->attr.output_sel = sel;
}
}
/*
*********************************************************************
* Audio AEC Close
* Description: AEC模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_aec_close(void)
{
printf("audio_aec_close:%x", (u32)aec_hdl);
if (aec_hdl) {
aec_hdl->start = 0;
#if AEC_TOGGLE
aec_close();
#endif
#if AEC_DCCS_EN
if (aec_hdl->dccs_eq) {
audio_dec_eq_close(aec_hdl->dccs_eq);
aec_hdl->dccs_eq = NULL;
}
#endif/*AEC_DCCS_EN*/
#if AEC_UL_EQ_EN
if (aec_hdl->ul_eq) {
audio_dec_eq_close(aec_hdl->ul_eq);
aec_hdl->ul_eq = NULL;
}
#endif/*AEC_UL_EQ_EN*/
#if CVP_UL_DRC_EN
if (aec_hdl->ul_drc) {
audio_dec_drc_close(aec_hdl->ul_drc);
aec_hdl->ul_drc = NULL;
}
#endif/*CVP_UL_DRC_EN*/
#if AEC_PITCHSHIFTER_CONFIG
if (aec_hdl && aec_hdl->pitch) {
close_pitch(aec_hdl->pitch);
aec_hdl->pitch = NULL;
}
#endif/* AEC_PITCHSHIFTER_CONFIG */
if (aec_hdl->TransferFunc) {
free(aec_hdl->TransferFunc);
aec_hdl->TransferFunc = NULL;
}
local_irq_disable();
#if AEC_USER_MALLOC_ENABLE
free(aec_hdl);
#endif/*AEC_USER_MALLOC_ENABLE*/
aec_hdl = NULL;
local_irq_enable();
}
}
/*
*********************************************************************
* Audio AEC Status
* Description: AEC模块当前状态
* Arguments : None.
* Return : 0
* Note(s) : None.
*********************************************************************
*/
u8 audio_aec_status(void)
{
if (aec_hdl) {
return aec_hdl->start;
}
return 0;
}
/*
*********************************************************************
* Audio AEC Input
* Description: AEC源数据输入
* Arguments : buf
* len
* Return : None.
* Note(s) : 256
*********************************************************************
*/
void audio_aec_inbuf(s16 *buf, u16 len)
{
if (aec_hdl && aec_hdl->start) {
if (aec_hdl->input_clear) {
memset(buf, 0, len);
}
#if TCFG_AUDIO_CVP_DUT_ENABLE
if (cvp_dut_mode_get() == CVP_DUT_MODE_BYPASS) {
audio_aec_output(buf, len);
return;
}
#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
#if AEC_TOGGLE
if (aec_hdl->inbuf_clear_cnt) {
aec_hdl->inbuf_clear_cnt--;
memset(buf, 0, len);
}
int ret = aec_in_data(buf, len);
if (ret == -1) {
} else if (ret == -2) {
log_error("aec inbuf full\n");
}
#else
audio_aec_output(buf, len);
#endif/*AEC_TOGGLE*/
}
}
/*
*********************************************************************
* Audio AEC Input Reference
* Description: AEC源参考数据输入
* Arguments : buf
* len
* Return : None.
* Note(s) : mic ENC的参考mic数据输入,mic的无须调用该接口
*********************************************************************
*/
void audio_aec_inbuf_ref(s16 *buf, u16 len)
{
if (aec_hdl && aec_hdl->start) {
aec_in_data_ref(buf, len);
}
}
void audio_aec_inbuf_ref_1(s16 *buf, u16 len)
{
if (aec_hdl && aec_hdl->start) {
aec_in_data_ref_1(buf, len);
}
}
/*
*********************************************************************
* Audio AEC Reference
* Description: AEC模块参考数据输入
* Arguments : buf
* len
* Return : None.
* Note(s) : DAC
*********************************************************************
*/
void audio_aec_refbuf(s16 *buf, u16 len)
{
if (aec_hdl && aec_hdl->start) {
#if AEC_TOGGLE
aec_ref_data(buf, len);
#endif/*AEC_TOGGLE*/
}
}
/*
*********************************************************************
* Audio CVP IOCTL
* Description: CVP功能配置
* Arguments : cmd
* value
* priv
* Return : 0
* Note(s) : (1)NS模块:
* audio_cvp_ioctl(CVP_NS_SWITCH,1,NULL); //降噪关
* audio_cvp_ioctl(CVP_NS_SWITCH,0,NULL); //降噪开
*********************************************************************
*/
int audio_cvp_ioctl(int cmd, int value, void *priv)
{
if (aec_hdl && aec_hdl->start) {
return aec_dms_ioctl(cmd, value, priv);
} else {
return -1;
}
}
/*tri_en: 1 正常3MIC降噪
* 0 2MIC降噪使 FB MIC数据*/
int audio_tms_mode_choose(u8 tri_en)
{
if (aec_hdl && aec_hdl->start) {
return jlsp_tms_mode_choose(tri_en);
}
return -1;
}
/**
*
*/
//pbg profile use it,don't delete
void aec_input_clear_enable(u8 enable)
{
if (aec_hdl) {
aec_hdl->input_clear = enable;
log_info("aec_input_clear_enable= %d\n", enable);
}
}
#if AEC_PITCHSHIFTER_CONFIG
/*----------------------------------------------------------------------------*/
/**@brief 变声参数直接更新
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void set_pitch_para(u32 shiftv, u32 sr, u8 effect, u32 formant_shift)
{
if (aec_hdl && aec_hdl->pitch) {
PITCH_SHIFT_PARM parm = {0};
parm.sr = sr;
parm.shiftv = shiftv;
parm.effect_v = effect;
parm.formant_shift = formant_shift;
//printf("\n\n\nshiftv[%d],sr[%d],effect[%d],formant_shift[%d] \n\n", parm.shiftv, parm.sr, parm.effect_v, parm.formant_shift);
update_picth_parm(aec_hdl->pitch, &parm);
}
}
/*----------------------------------------------------------------------------*/
/**@brief 变声效果设置
@param sound:SOUND_ORIGINAL,SOUND_UNCLE, SOUND_GODDESS
@return
@note
*/
/*----------------------------------------------------------------------------*/
void audio_aec_pitch_change(u32 sound)
{
if (aec_hdl && aec_hdl->pitch) {
switch (sound) {
case SOUND_ORIGINAL:
pause_pitch(aec_hdl->pitch, 1);
log_info("pitch origin\n");
break;
case SOUND_UNCLE:
set_pitch_para(136, aec_hdl->pitch->parm.sr, EFFECT_PITCH_SHIFT, 0);
pause_pitch(aec_hdl->pitch, 0);
log_info("pitch uncle\n");
break;
case SOUND_GODDESS:
if (VC_KINDO_TVM) {
set_pitch_para(56, aec_hdl->pitch->parm.sr, EFFECT_VOICECHANGE_KIN0, 150);
} else {
set_pitch_para(46, aec_hdl->pitch->parm.sr, EFFECT_VOICECHANGE_KIN2, 80);
}
/* set_pitch_para(66, aec_hdl->pitch->parm.sr, EFFECT_VOICECHANGE_KIN0, 150); */
pause_pitch(aec_hdl->pitch, 0);
log_info("pitch goddess\n");
break;
default:
break;
}
}
}
struct _esco_eff {
u16 eff_L;
u16 eff_R;
};
struct _esco_eff esco_eff;
#define TWS_FUNC_ID_ESCO_EFF \
((int)(('E' + 'S' + 'C' + 'O') << (2 * 8)) | \
(int)(('E' + 'F' + 'F') << (1 * 8)) | \
(int)(('S' + 'Y' + 'N' + 'C') << (0 * 8)))
/*----------------------------------------------------------------------------*/
/**@brief 变声控制
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void audio_aec_pitch_change_ctrl()
{
if (!aec_hdl) {
return;
}
#if TCFG_USER_TWS_ENABLE
int state = tws_api_get_tws_state();
if (state & TWS_STA_SIBLING_CONNECTED) {// tws链接时左耳触发男声 右耳触发女声
enum audio_channel channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
if (channel == AUDIO_CH_L) {
log_info("aec_hdl->pitch_mode_L %d\n", aec_hdl->pitch_mode_L);
if (aec_hdl->pitch_mode_L != SOUND_UNCLE) {
aec_hdl->pitch_mode_L = SOUND_UNCLE;
aec_hdl->pitch_mode_R = SOUND_UNCLE;
} else {
aec_hdl->pitch_mode_L = SOUND_ORIGINAL;
aec_hdl->pitch_mode_R = SOUND_ORIGINAL;
}
} else if (channel == AUDIO_CH_R) {
log_info("aec_hdl->pitch_mode_R %d\n", aec_hdl->pitch_mode_R);
if (aec_hdl->pitch_mode_R != SOUND_GODDESS) {
aec_hdl->pitch_mode_R = SOUND_GODDESS;
aec_hdl->pitch_mode_L = SOUND_GODDESS;
} else {
aec_hdl->pitch_mode_R = SOUND_ORIGINAL;
aec_hdl->pitch_mode_L = SOUND_ORIGINAL;
}
}
esco_eff.eff_L = aec_hdl->pitch_mode_L;
esco_eff.eff_R = aec_hdl->pitch_mode_R;
tws_api_send_data_to_sibling((u8 *)&esco_eff, sizeof(struct _esco_eff), TWS_FUNC_ID_ESCO_EFF);//发送左右耳的变声模式
} else
#endif/*TCFG_USER_TWS_ENABLE*/
{
//tws未连接时变声直接切换男声->女声->原声
if (aec_hdl->pitch_mode_L != SOUND_UNCLE) {
aec_hdl->pitch_mode_L = SOUND_UNCLE;
} else if (aec_hdl->pitch_mode_L == SOUND_UNCLE) {
aec_hdl->pitch_mode_L = SOUND_GODDESS;
} else {
aec_hdl->pitch_mode_L = SOUND_ORIGINAL;
}
audio_aec_pitch_change(aec_hdl->pitch_mode_L);
}
}
#if TCFG_USER_TWS_ENABLE
static void tws_esco_pitch_align(void *data, u16 len, bool rx)
{
memcpy(&esco_eff, data, sizeof(struct _esco_eff));
int state = tws_api_get_tws_state();
enum audio_channel channel;
if (state & TWS_STA_SIBLING_CONNECTED) {
channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
if (channel == AUDIO_CH_L) {//左耳设置变声
log_info("channel %d============= eff_L %d\n", channel, esco_eff.eff_L);
audio_aec_pitch_change(esco_eff.eff_L);
if (aec_hdl) {
aec_hdl->pitch_mode_L = esco_eff.eff_L;
}
} else {//右耳设置变声
log_info("channel %d============= eff_R %d\n", channel, esco_eff.eff_R);
audio_aec_pitch_change(esco_eff.eff_R);
if (aec_hdl) {
aec_hdl->pitch_mode_R = esco_eff.eff_R;
}
}
}
}
REGISTER_TWS_FUNC_STUB(esco_align_eff) = {
.func_id = TWS_FUNC_ID_ESCO_EFF,
.func = tws_esco_pitch_align,
};
#endif/*TCFG_USER_TWS_ENABLE*/
#endif/* AEC_PITCHSHIFTER_CONFIG */
/*
*ul eq
* */
void aec_ul_eq_update()
{
#if AEC_UL_EQ_EN
local_irq_disable();
if (aec_hdl && aec_hdl->ul_eq) {
aec_hdl->ul_eq->updata = 1;
}
local_irq_enable();
#endif/*AEC_UL_EQ_EN*/
}
#endif/*TCFG_AUDIO_TRIPLE_MIC_ENABLE == 1*/
#endif /*TCFG_CVP_DEVELOP_ENABLE */