Files
99_7018_lmx/cpu/br28/audio_dec_eff.c

1861 lines
51 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
#include "audio_dec_eff.h"
#include "debug.h"
#include "system/syscfg_id.h"
#if TCFG_AUDIO_CVP_DUT_ENABLE
#include "audio_cvp_dut.h"
#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
extern struct audio_dac_hdl dac_hdl;
extern const int const_surround_en;
void user_sat16(s32 *in, s16 *out, u32 npoint);
void a2dp_surround_set(u8 eff);
int audio_out_eq_get_filter_info(void *eq, int sr, struct audio_eq_filter_info *info);
int audio_out_eq_spec_set_info(struct audio_eq *eq, u8 idx, int freq, float gain);
void *dec_eq_drc_setup_new(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
void eq_cfg_default_init(EQ_CFG *eq_cfg);
void drc_default_init(EQ_CFG *eq_cfg, u8 mode);
/*----------------------------------------------------------------------------*/
/**@brief 环绕音效切换测试例子
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void surround_switch_test(void *p)
{
#if 0
if (!p) {
return;
}
static u8 cnt_type = 0;
if (EFFECT_OFF == cnt_type) {
//中途关开测试
static u8 en = 0;
en = !en;
audio_surround_parm_update(p, cnt_type, (surround_update_parm *)en);
} else {
//音效切换测试
audio_surround_parm_update(p, cnt_type, NULL);
}
printf("cnt_type 0x%x\n", cnt_type);
if (++cnt_type > EFFECT_OFF) {
cnt_type = EFFECT_3D_PANORAMA;
}
#endif
}
void *audio_surround_setup(u8 channel, u8 eff)
{
#if AUDIO_SURROUND_CONFIG
struct dec_sur *sur = zalloc(sizeof(struct dec_sur));
u8 nch = EFFECT_CH_L;
if (channel == AUDIO_CH_L) {
nch = EFFECT_CH_L;
} else if (channel == AUDIO_CH_R) {
nch = EFFECT_CH_R;
} else if (channel == AUDIO_CH_LR) {
nch = 2;
} else if (channel == AUDIO_CH_DUAL_L) {
nch = EFFECT_CH2_L;
} else if (channel == AUDIO_CH_DUAL_R) {
nch = EFFECT_CH2_R;
} else {
if (sur) {
free(sur);
}
log_e("surround ch_type err %d\n", channel);
return NULL;
}
surround_open_parm parm = {0};
parm.channel = nch;
parm.surround_effect_type = EFFECT_3D_PANORAMA;//打开时默认使用3d全景音,使用者,根据需求修改
sur->surround = audio_surround_open(&parm);
sur->surround_eff = eff;
audio_surround_voice(sur, sur->surround_eff);//还原按键触发的音效
//sur_test = sys_timer_add(sur->surround, surround_switch_test, 10000);
return sur;
#else
return NULL;
#endif//AUDIO_SURROUND_CONFIG
}
void audio_surround_free(void *sur)
{
#if AUDIO_SURROUND_CONFIG
struct dec_sur *surh = (struct dec_sur *)sur;
if (!surh) {
return;
}
if (surh->surround) {
audio_surround_close(surh->surround);
surh->surround = NULL;
}
free(surh);
#endif//AUDIO_SURROUND_CONFIG
}
void audio_surround_set_ch(void *sur, u8 channel)
{
#if AUDIO_SURROUND_CONFIG
struct dec_sur *surh = (struct dec_sur *)sur;
if (!surh) {
return;
}
u8 nch = EFFECT_CH_L;
if (channel == AUDIO_CH_L) {
nch = EFFECT_CH_L;
} else if (channel == AUDIO_CH_R) {
nch = EFFECT_CH_R;
} else if (channel == AUDIO_CH_LR) {
nch = 2;
} else if (channel == AUDIO_CH_DUAL_L) {
nch = EFFECT_CH2_L;
} else if (channel == AUDIO_CH_DUAL_R) {
nch = EFFECT_CH2_R;
} else {
log_e("surround ch_type err %d\n", channel);
return ;
}
if (surh->surround) {
audio_surround_switch_nch(surh->surround, nch);
}
#endif//AUDIO_SURROUND_CONFIG
}
/*
*
* */
void audio_surround_voice(void *sur, u8 en)
{
#if AUDIO_SURROUND_CONFIG
struct dec_sur *surh = (struct dec_sur *)sur;
surround_hdl *surround = (surround_hdl *)surh->surround;
if (surround) {
if (en) {
if (const_surround_en & BIT(2)) {
surround_update_parm parm = {0};
parm.surround_type = EFFECT_3D_LRDRIFT2;//音效类型
parm.rotatestep = 4; //建议1~6,环绕速度
parm.damping = 40;//混响音量0~70,空间感
parm.feedback = 100;//干声音量(0~100),清晰度
parm.roomsize = 128;//无效参数
audio_surround_parm_update(surround, EFFECT_SUR2, &parm);
} else {
audio_surround_parm_update(surround, EFFECT_3D_ROTATES, NULL);
}
} else {
surround_update_parm parm = {0};
audio_surround_parm_update(surround, EFFECT_OFF2, &parm);//关音效
}
}
#endif /* AUDIO_SURROUND_CONFIG */
}
#if AUDIO_VBASS_CONFIG
/*----------------------------------------------------------------------------*/
/**@brief 虚拟低音参数更新例子
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
#define AEID_MUSIC_VBASS 1
vbass_hdl *audio_vbass_open_demo(u32 vbass_name, u32 sample_rate, u8 ch_num)
{
VirtualBassParam parm = {0};
u8 tar = 0;
struct virtual_bass_tool_set *param = get_vbass_parm();
u8 bypass = 0;
parm.ratio = param->parm.ratio;
parm.boost = param->parm.boost;
parm.fc = param->parm.fc;
parm.channel = ch_num;
parm.SampleRate = sample_rate;
parm.pcm_info.IndataBit = DATA_INT_16BIT;
parm.pcm_info.OutdataBit = DATA_INT_16BIT;
parm.pcm_info.IndataInc = (ch_num == 2) ? 2 : 1;
parm.pcm_info.OutdataInc = (ch_num == 2) ? 2 : 1;
parm.pcm_info.Qval = 15;
//printf("vbass ratio %d, boost %d, fc %d, channel %d, SampleRate %d\n", parm.ratio, parm.boost, parm.fc,parm.channel, parm.SampleRate);
vbass_hdl *vbass = audio_vbass_open(vbass_name, &parm);
vbass->lowfreq_en = 1; //1保留低频0不保留
audio_vbass_bypass(vbass_name, bypass);
/* clock_add(DEC_VBASS_CLK); */
return vbass;
}
void audio_vbass_close_demo(vbass_hdl *vbass)
{
if (vbass) {
audio_vbass_close(vbass);
vbass = NULL;
}
/* clock_remove(DEC_VBASS_CLK); */
}
void audio_vbass_update_demo(u32 vbass_name, VirtualBassUdateParam *parm, u32 bypass)
{
audio_vbass_parm_update(vbass_name, parm);
audio_vbass_bypass(vbass_name, bypass);
}
void vbass_udate_parm_test(void *p)
{
#if 0
//虚拟低音增益调节例子
vbass_parm.ratio = 56;//比率(0~100),越大,低音强度越大
vbass_parm.boost = 1;//(低音增强0, 1)
vbass_parm.fc = 100;//截止频率(30~300Hz)
audio_vbass_parm_update(AEID_MUSIC_VBASS, &vbass_parm);
audio_vbass_bypass(AEID_MUSIC_VBASS, 0);
#endif
#if 0
//开关虚拟低音例子
static u8 bypass = 0;
/* bypass = 1;//关 */
/* bypass = 0;//开 */
bypass = !bypass;
audio_vbass_bypass(AEID_MUSIC_VBASS, bypass);
#endif
}
vbass_hdl *audio_vbass_setup(u32 sample_rate, u8 channel)
{
return audio_vbass_open_demo(AEID_MUSIC_VBASS, sample_rate, channel);
}
void audio_vbass_free(vbass_hdl *vbass)
{
audio_vbass_close_demo(vbass);
}
#endif//AUDIO_VBASS_CONFIG
void eq_32bit_out(struct dec_eq_drc *eff)
{
if (!config_eq_lite_en) {
int wlen = 0;
int point_len = 2;
#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
point_len = 4;
s32 *out_tmp = eff->eq_out_buf;
#else
s16 *out_tmp = eff->eq_out_buf;
#endif
if (eff->priv && eff->out_cb) {
wlen = eff->out_cb(eff->priv, &out_tmp[eff->eq_out_points], (eff->eq_out_total - eff->eq_out_points) * point_len);
}
eff->eq_out_points += wlen / point_len;
}
}
static int eq_output(void *priv, void *buf, u32 len)
{
if (!config_eq_lite_en) {
int wlen = 0;
int rlen = len;
s16 *data = (s16 *)buf;
struct dec_eq_drc *eff = priv;
if (!eff->async) {
return rlen;
}
if (eff->drc && eff->async) {
if (eff->eq_out_buf && (eff->eq_out_points < eff->eq_out_total)) {
eq_32bit_out(eff);
if (eff->eq_out_points < eff->eq_out_total) {
return 0;
}
}
audio_drc_run(eff->drc, data, len);
#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
if ((!eff->eq_out_buf) || (eff->eq_out_buf_len < len)) {
if (eff->eq_out_buf) {
free(eff->eq_out_buf);
}
eff->eq_out_buf_len = len;
eff->eq_out_buf = malloc(eff->eq_out_buf_len);
ASSERT(eff->eq_out_buf);
}
memcpy(eff->eq_out_buf, data, len);
eff->eq_out_points = 0;
eff->eq_out_total = len / 4;
#else
if ((!eff->eq_out_buf) || (eff->eq_out_buf_len < len / 2)) {
if (eff->eq_out_buf) {
free(eff->eq_out_buf);
}
eff->eq_out_buf_len = len / 2;
eff->eq_out_buf = malloc(eff->eq_out_buf_len);
ASSERT(eff->eq_out_buf);
}
user_sat16((s32 *)data, (s16 *)eff->eq_out_buf, len / 4);
eff->eq_out_points = 0;
eff->eq_out_total = len / 4;
#endif
eq_32bit_out(eff);
return len;
}
int out_len = 0;
if (eff->priv && eff->out_cb) {
out_len = eff->out_cb(eff->priv, data, len);
}
return out_len;
} else {
return len;
}
}
int wdrc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
{
static struct drc_ch wdrc_p = {0};
struct threshold_group threshold[5] = {{-100 + 90.3f, -91.9f + 90.3f}, {-87 + 90.3f, -72.5f + 90.3f}, {-58.6f + 90.3f, -60.3f + 90.3f}, {-43.5f + 90.3f, -29.7f + 90.3f}, {0 + 90.3f, -10.9f + 90.3f}};
/* struct threshold_group threshold[3] = {{0x42166666, 0x0}, {0x42580000, 0x42a40000},{0x42f00000, 0x42c50000}}; */
wdrc_p.nband = 1;
wdrc_p.type = 3;//wdrc
//left
int i = 0;
wdrc_p._p.wdrc[i].attacktime = 1;
wdrc_p._p.wdrc[i].releasetime = 500;
memcpy(wdrc_p._p.wdrc[i].threshold, threshold, sizeof(threshold));
wdrc_p._p.wdrc[i].threshold_num = ARRAY_SIZE(threshold);
wdrc_p._p.wdrc[i].rms_time = 25;
wdrc_p._p.wdrc[i].algorithm = 0;
wdrc_p._p.wdrc[i].mode = 1;
info->R_pch = info->pch = &wdrc_p;
return 0;
}
u8 left_or_right_earphone()
{
#if 0//TCFG_USER_TWS_ENABLE
if (config_wdrc_en) {
u8 channel = 0;
int state = 0;
u8 dac_connect_mode;
state = tws_api_get_tws_state();
if (state & TWS_STA_SIBLING_CONNECTED) {
dac_connect_mode = audio_dac_get_channel(&dac_hdl);
if (dac_connect_mode == DAC_OUTPUT_LR) {
if (tws_api_get_local_channel() == 'L') {
channel |= LL_wdrc;
} else {
channel |= RR_wdrc;
}
} else {
if (tws_api_get_local_channel() == 'L') {
channel |= L_wdrc;
} else {
channel |= R_wdrc;
}
}
}
return channel;
}
#endif
return 0;
}
void *dec_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en)
{
#if TCFG_EQ_ENABLE
if (config_eq_lite_en) { //仅支持同步方式eq处理
async = 0;//
}
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
async = 0;
#endif
#if defined(AUDIO_GAME_EFFECT_CONFIG) && AUDIO_GAME_EFFECT_CONFIG
if (drc_en & BIT(1)) { //game eff drc
return dec_eq_drc_setup_new(priv, eq_output_cb, sample_rate, channel, async, drc_en);
}
#endif/* AUDIO_GAME_EFFECT_CONFIG */
struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
struct audio_eq_param eq_param = {0};
eff->priv = priv;
eff->out_cb = eq_output_cb;
eq_param.channels = channel;
eq_param.online_en = 1;
eq_param.mode_en = 1;
eq_param.remain_en = 1;
eq_param.no_wait = async;
if (drc_en) {
eq_param.out_32bit = 1;
}
eq_param.max_nsection = EQ_SECTION_MAX;
eq_param.cb = eq_get_filter_info;
eq_param.eq_name = song_eq_mode;
eq_param.sr = sample_rate;
eq_param.priv = eff;
eq_param.output = eq_output;
eff->eq = audio_dec_eq_open(&eq_param);
eff->async = async;
#if TCFG_DRC_ENABLE
if (drc_en) {
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = channel | left_or_right_earphone();
drc_param.online_en = 1;
drc_param.remain_en = 1;
drc_param.out_32bit = 1;
drc_param.cb = drc_get_filter_info;
drc_param.drc_name = song_eq_mode;
eff->drc = audio_dec_drc_open(&drc_param);
}
#endif//TCFG_DRC_ENABLE
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
eff->spk_eq = spk_eq_open(sample_rate, channel, drc_en ? 1 : 0);
#endif/*AUDIO_SPK_EQ_CONFIG*/
return eff;
#else
return NULL;
#endif//TCFG_EQ_ENABLE
}
void dec_eq_drc_free(void *eff)
{
#if TCFG_EQ_ENABLE
struct dec_eq_drc *eff_hdl = (struct dec_eq_drc *)eff;
if (!eff_hdl) {
return;
}
u8 tmp = 0;
if (eff_hdl->drc_bef_eq) {
tmp = 1;
}
if (eff_hdl->drc_prev) {
audio_dec_drc_close(eff_hdl->drc_prev);
eff_hdl->drc_prev = NULL;
}
if (eff_hdl->eq) {
audio_dec_eq_close(eff_hdl->eq);
eff_hdl->eq = NULL;
}
if (eff_hdl->drc) {
audio_dec_drc_close(eff_hdl->drc);
eff_hdl->drc = NULL;
}
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
if (eff_hdl->spk_eq) {
spk_eq_close(eff_hdl->spk_eq);
eff_hdl->spk_eq = NULL;
}
#endif
if (eff_hdl->eq_out_buf) {
free(eff_hdl->eq_out_buf);
eff_hdl->eq_out_buf = NULL;
}
#if AUDIO_EQ_FADE_EN
if (eff_hdl->fade.tmr) {
sys_hi_timer_del(eff_hdl->fade.tmr);
eff_hdl->fade.tmr = 0;
}
#endif
free(eff_hdl);
if (tmp) { //还原非游戏音效eq drc 效果
EQ_CFG *eq_cfg = get_eq_cfg_hdl();
eq_cfg->eq_type = EQ_TYPE_MODE_TAB;
eq_cfg_default_init(get_eq_cfg_hdl());
drc_default_init(get_eq_cfg_hdl(), song_eq_mode);
if (!eq_file_get_cfg(get_eq_cfg_hdl(), (u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin")) {
eq_cfg->eq_type = EQ_TYPE_FILE;
}
}
#endif//TCFG_EQ_ENABLE
}
struct drc_ch esco_drc_p = {0};
int esco_drc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
{
float th = -0.5f;//db -60db~0db,限幅器阈值
int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
esco_drc_p.nband = 1;
esco_drc_p.type = 1;
esco_drc_p._p.limiter[0].attacktime = 5;
esco_drc_p._p.limiter[0].releasetime = 500;
esco_drc_p._p.limiter[0].threshold[0] = threshold;
esco_drc_p._p.limiter[0].threshold[1] = 32768;
info->R_pch = info->pch = &esco_drc_p;
return 0;
}
void *esco_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en)
{
#if TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE
if (config_eq_lite_en) { //仅支持同步方式eq处理
async = 0;//
}
struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
eff->spk_eq = spk_eq_open(sample_rate, channel, drc_en ? 1 : 0);
#endif/*AUDIO_SPK_EQ_CONFIG*/
struct audio_eq_param eq_param = {0};
eff->priv = priv;
eff->out_cb = eq_output_cb;
eq_param.channels = channel;
eq_param.online_en = 1;
eq_param.mode_en = 0;
eq_param.remain_en = 0;
eq_param.no_wait = async;//a2dp_low_latency ? 0 : 1;
if (drc_en) {
eq_param.out_32bit = 1;
}
eq_param.max_nsection = EQ_SECTION_MAX;
eq_param.cb = eq_phone_get_filter_info;
eq_param.eq_name = call_eq_mode;
eq_param.sr = sample_rate;
eq_param.priv = eff;
eq_param.output = eq_output;
eff->eq = audio_dec_eq_open(&eq_param);
#if TCFG_DRC_ENABLE
if (drc_en) {
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = channel;
drc_param.online_en = 0;
drc_param.remain_en = 0;
drc_param.out_32bit = 1;
drc_param.cb = esco_drc_get_filter_info;
drc_param.drc_name = call_eq_mode;
eff->drc = audio_dec_drc_open(&drc_param);
eff->async = async;
}
#endif//TCFG_DRC_ENABLE
return eff;
#else
return NULL;
#endif//TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE
}
void esco_eq_drc_free(void *eff)
{
dec_eq_drc_free(eff);
}
#define audio_out_drc_get_filter esco_drc_get_filter_info//可复用通话下行限幅器系数
void *audio_out_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en)
{
#if TCFG_EQ_ENABLE &&AUDIO_OUT_EQ_USE_SPEC_NUM
if (config_eq_lite_en) { //仅支持同步方式eq处理
async = 0;//
}
struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
struct audio_eq_param eq_param = {0};
eff->priv = priv;
eff->out_cb = eq_output_cb;
eq_param.channels = channel;
eq_param.online_en = 0;
eq_param.mode_en = 0;
eq_param.remain_en = 0;
eq_param.no_wait = async;
if (drc_en) {
eq_param.out_32bit = 1;
}
eq_param.max_nsection = AUDIO_OUT_EQ_USE_SPEC_NUM;
eq_param.cb = audio_out_eq_get_filter_info;
eq_param.eq_name = song_eq_mode;
eq_param.sr = sample_rate;
eq_param.priv = eff;
eq_param.output = eq_output;
eff->eq = audio_dec_eq_open(&eq_param);
#if TCFG_DRC_ENABLE
if (drc_en) {
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = channel;
drc_param.online_en = 0;
drc_param.remain_en = 0;
drc_param.out_32bit = 1;
drc_param.cb = audio_out_drc_get_filter;
drc_param.drc_name = song_eq_mode;
eff->drc = audio_dec_drc_open(&drc_param);
eff->async = async;
}
#endif //TCFG_DRC_ENABLE
return eff;
#else
return NULL;
#endif//TCFG_EQ_ENABLE &&AUDIO_OUT_EQ_USE_SPEC_NUM
}
void audio_out_eq_drc_free(void *eff)
{
#if AUDIO_OUT_EQ_USE_SPEC_NUM
dec_eq_drc_free(eff);
#endif//AUDIO_OUT_EQ_USE_SPEC_NUM
}
__attribute__((always_inline))
void sat16_to_sat32(s16 *in, s32 *out, u32 npoint, int factor)
{
#if 0
for (int i = 0; i < npoint; i ++) {
out[i] = in[i] * factor;
}
#else
s64 tmp;
__asm__ volatile(
"1: \n\t"
"rep %2 { \n\t" //循环
"%3 = h[%1 ++= 2]*%4(s) \n\t"
"[%0 ++= 4] = %3.l \n\t" //%3.l意思是取tmp的低32位
"} \n\t"
"if(%2 != 0) goto 1b \n\t"
:
"=&r"(out),
"=&r"(in),
"=&r"(npoint),
"=&r"(tmp)
:
"r"(factor),
"0"(out),
"1"(in),
"2"(npoint),
"3"(tmp)
:
);
#endif
}
int eq_drc_run(void *priv, void *data, u32 len)
{
#if TCFG_EQ_ENABLE
struct dec_eq_drc *eff = (struct dec_eq_drc *)priv;
if (!eff) {
return 0;
}
#if TCFG_AUDIO_CVP_DUT_ENABLE
if (audio_dec_dut_en_get(1) == AUDIO_DEC_DUT_MODE_SPK_EQ) {
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
spk_eq_run(eff->spk_eq, data, data, len);
return 0;
#endif
}
#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
if (!eff->async) {
if (eff->eq_out_buf && (eff->eq_out_points < eff->eq_out_total)) {
eq_32bit_out(eff);
if (eff->eq_out_points < eff->eq_out_total) {
return 0;
}
}
}
#endif
#if TCFG_DRC_ENABLE
if (eff->drc && !eff->async) {//同步32bit eq drc 处理
if ((!eff->eq_out_buf) || (eff->eq_out_buf_len < len * 2)) {
if (eff->eq_out_buf) {
free(eff->eq_out_buf);
}
eff->eq_out_buf_len = len * 2;
eff->eq_out_buf = malloc(eff->eq_out_buf_len);
ASSERT(eff->eq_out_buf);
}
audio_eq_set_output_buf(eff->eq, eff->eq_out_buf, len);
if (eff->drc_bef_eq && eff->drc_prev) {
sat16_to_sat32((short *)data, (int *)eff->eq_out_buf, len >> 1, 1);
audio_drc_run(eff->drc_prev, eff->eq_out_buf, len * 2);
}
}
#endif//TCFG_DRC_ENABLE
int eqlen = 0;
if (eff->drc_bef_eq) {
eqlen = audio_eq_run(eff->eq, eff->eq_out_buf, len * 2);
} else {
eqlen = audio_eq_run(eff->eq, data, len);
}
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
if (!eff->async) {
if (eff->drc) {
spk_eq_run(eff->spk_eq, eff->eq_out_buf, eff->eq_out_buf, len * 2);
} else {
spk_eq_run(eff->spk_eq, data, data, len);
}
}
#endif
#if TCFG_DRC_ENABLE
if (eff->drc && !eff->async) {//同步32bit eq drc 处理
audio_drc_run(eff->drc, eff->eq_out_buf, len * 2);
#if defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE
eff->eq_out_points = 0;
eff->eq_out_total = (len * 2) / 4;
eq_32bit_out(eff);
return len;//返回16bit位宽长度
#else
user_sat16((s32 *)eff->eq_out_buf, (s16 *)data, (len * 2) / 4);
#endif
}
#endif//TCFG_DRC_ENABLE
if (eff->drc && !eff->async) {
return len;
}
return eqlen;
#else
return len;
#endif
}
#if AUDIO_OUT_EQ_USE_SPEC_NUM
static struct eq_seg_info audio_out_eq_tab[AUDIO_OUT_EQ_USE_SPEC_NUM] = {
#ifdef EQ_CORE_V1
{0, EQ_IIR_TYPE_BAND_PASS, 125, 0, 0.7f},
{1, EQ_IIR_TYPE_BAND_PASS, 12000, 0, 0.3f},
#else
{0, EQ_IIR_TYPE_BAND_PASS, 125, 0 * (1 << 20), 0.7f * (1 << 24)},
{1, EQ_IIR_TYPE_BAND_PASS, 12000, 0 * (1 << 20), 0.3f * (1 << 24)},
#endif
};
int audio_out_eq_get_filter_info(void *eq, int sr, struct audio_eq_filter_info *info)
{
struct audio_eq *eq_hdl = (struct audio_eq *)eq;
if (!eq_hdl) {
return -1;
}
local_irq_disable();
u8 nsection = ARRAY_SIZE(audio_out_eq_tab);
if (!eq_hdl->eq_coeff_tab) {
eq_hdl->eq_coeff_tab = zalloc(sizeof(int) * 5 * nsection);
}
for (int i = 0; i < nsection; i++) {
eq_seg_design(&audio_out_eq_tab[i], sr, &eq_hdl->eq_coeff_tab[5 * i]);
}
local_irq_enable();
info->L_coeff = info->R_coeff = (void *)eq_hdl->eq_coeff_tab;
info->L_gain = info->R_gain = 0;
info->nsection = nsection;
return 0;
}
int audio_out_eq_spec_set_info(struct audio_eq *eq, u8 idx, int freq, float gain)
{
if (idx >= AUDIO_OUT_EQ_USE_SPEC_NUM) {
return false;
}
if (gain > 12) {
gain = 12;
}
if (gain < -12) {
gain = -12;
}
if (freq) {
audio_out_eq_tab[idx].freq = freq;
}
#ifdef EQ_CORE_V1
audio_out_eq_tab[idx].gain = gain;
#else
audio_out_eq_tab[idx].gain = gain * (1 << 20);
#endif
/* printf("audio out eq, idx:%d, freq:%d,%d, gain:%d,%d \n", idx, freq, audio_out_eq_tab[idx].freq, gain, audio_out_eq_tab[idx].gain); */
#if !AUDIO_EQ_FADE_EN
local_irq_disable();
if (eq) {
eq->updata = 1;
}
local_irq_enable();
#endif
return true;
}
#if AUDIO_EQ_FADE_EN
void eq_fade_run(void *p)
{
struct dec_eq_drc *eff = (struct dec_eq_drc *)p;
struct eq_filter_fade *fade = &eff->fade;
struct audio_eq *eq = (struct audio_eq *)eff->eq;
u8 update = 0;
u8 design = 0;
for (int i = 0; i < ARRAY_SIZE(audio_out_eq_tab); i++) {
if (fade->cur_gain[i] > fade->use_gain[i]) {
#ifdef EQ_CORE_V1
fade->cur_gain[i] -= HIGH_BASS_EQ_FADE_STEP;
#else
fade->cur_gain[i] -= HIGH_BASS_EQ_FADE_STEP * (1 << 20);
#endif
if (fade->cur_gain[i] < fade->use_gain[i]) {
fade->cur_gain[i] = fade->use_gain[i];
}
design = 1;
} else if (fade->cur_gain[i] < fade->use_gain[i]) {
#ifdef EQ_CORE_V1
fade->cur_gain[i] += HIGH_BASS_EQ_FADE_STEP;
#else
fade->cur_gain[i] += HIGH_BASS_EQ_FADE_STEP * (1 << 20);
#endif
if (fade->cur_gain[i] > fade->use_gain[i]) {
fade->cur_gain[i] = fade->use_gain[i];
}
design = 1;
}
if (design) {
design = 0;
update = 1;
/* audio_out_eq_spec_set_info(p, i, 0, fade->cur_gain[i]); */
/* if (eq) { */
audio_out_eq_tab[i].gain = fade->cur_gain[i];//gain;//gain << 20;
/* } */
}
}
if (update) {
update = 0;
local_irq_disable();
if (eq) {
eq->updata = 1;
}
local_irq_enable();
}
}
#endif
int audio_out_eq_set_gain(void *eff, u8 idx, int gain)
{
struct dec_eq_drc *eff_hdl = (struct dec_eq_drc *)eff;
if (!eff_hdl) {
return 0;
}
if (!idx) {
idx = 0;
} else {
idx = 1;
}
#if AUDIO_EQ_FADE_EN
eff_hdl->fade.use_gain[idx] = gain;
if (eff_hdl->fade.tmr == 0) {
eff_hdl->fade.tmr = sys_hi_timer_add(eff_hdl, eq_fade_run, 20);
}
#else
if (!idx) {
audio_out_eq_spec_set_info(eff_hdl->eq, 0, 0, gain);//低音
} else {
audio_out_eq_spec_set_info(eff_hdl->eq, 1, 0, gain);//高音
}
#endif
return true;
}
#endif /*AUDIO_OUT_EQ_USE_SPEC_NUM*/
static struct audio_drc *mix_out_drc = NULL;
static float mix_out_drc_threadhold = -0.5f;//db -60db~0db,限幅器阈值
static struct drc_ch mix_out_drc_p = {0};
int mix_out_drc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
{
float th = mix_out_drc_threadhold;//db -60db~0db,限幅器阈值
int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
mix_out_drc_p.nband = 1;
mix_out_drc_p.type = 1;
mix_out_drc_p._p.limiter[0].attacktime = 5;
mix_out_drc_p._p.limiter[0].releasetime = 500;
mix_out_drc_p._p.limiter[0].threshold[0] = threshold;
mix_out_drc_p._p.limiter[0].threshold[1] = 32768;
info->R_pch = info->pch = &mix_out_drc_p;
return 0;
}
void mix_out_drc_open(u16 sample_rate)
{
u8 ch_num;
#if TCFG_APP_FM_EMITTER_EN
ch_num = 2;
#else
u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
if (dac_connect_mode == DAC_OUTPUT_LR) {
ch_num = 2;
} else {
ch_num = 1;
}
#endif//TCFG_APP_FM_EMITTER_EN
#if TCFG_DRC_ENABLE
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = ch_num;
drc_param.online_en = 0;
drc_param.remain_en = 0;
drc_param.out_32bit = 0;
drc_param.cb = mix_out_drc_get_filter_info;
drc_param.drc_name = song_eq_mode;
mix_out_drc = audio_dec_drc_open(&drc_param);
#endif//TCFG_DRC_ENABLE
}
void mix_out_drc_close()
{
#if TCFG_DRC_ENABLE
if (mix_out_drc) {
audio_dec_drc_close(mix_out_drc);
mix_out_drc = NULL;
}
#endif//TCFG_DRC_ENABLE
}
void mix_out_drc_run(s16 *data, u32 len)
{
u8 en = 1;
#if TCFG_DRC_ENABLE
#if TCFG_AUDIO_ANC_ENABLE
en = anc_status_get();
#endif/*TCFG_AUDIO_ANC_ENABLE*/
if (mix_out_drc && en) {
audio_drc_run(mix_out_drc, data, len);
}
#endif//TCFG_DRC_ENABLE
}
/*----------------------------------------------------------------------------*/
/**@brief mix_out后限幅器系数更新
@param threadhold限幅器阈值-60~0,db
@return
@note
*/
/*----------------------------------------------------------------------------*/
void mix_out_drc_threadhold_update(float threadhold)
{
#if TCFG_DRC_ENABLE
mix_out_drc_threadhold = threadhold;
local_irq_disable();
if (mix_out_drc) {
mix_out_drc->updata = 1;
}
local_irq_enable();
#endif//TCFG_DRC_ENABLE
}
struct audio_eq *audio_dec_eq_open_new(struct audio_eq_param *parm, struct eq_parm_new *par_new)
{
struct audio_eq_param *eq_param = parm;
struct audio_eq *eq = zalloc(sizeof(struct audio_eq) + sizeof(struct hw_eq_ch));
if (eq) {
eq->eq_ch = (struct hw_eq_ch *)((int)eq + sizeof(struct audio_eq));
audio_eq_open(eq, eq_param);
audio_eq_set_samplerate(eq, eq_param->sr);
audio_eq_set_info_new(eq, eq_param->channels, par_new->in_mode, eq_param->out_32bit, par_new->run_mode, par_new->data_in_mode, par_new->data_out_mode);
/* log_info("eq_param->sr %d, eq_param->channels %d\n", eq_param->sr, eq_param->channels); */
audio_eq_set_output_handle(eq, eq_param->output, eq_param->priv);
audio_eq_start(eq);
/* log_info("audio_dec_eq_open name %d\n", eq_param->eq_name); */
}
return eq;
}
#if defined(AUDIO_GAME_EFFECT_CONFIG) && AUDIO_GAME_EFFECT_CONFIG
struct drc_ch dec_drc_p = {0};
int dec_drc_get_filter_info(void *drc, struct audio_drc_filter_info *info)
{
float th = -0.5f;//db -60db~0db,限幅器阈值
int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
dec_drc_p.nband = 1;
dec_drc_p.type = 1;
dec_drc_p._p.limiter[0].attacktime = 5;
dec_drc_p._p.limiter[0].releasetime = 500;
dec_drc_p._p.limiter[0].threshold[0] = threshold;
dec_drc_p._p.limiter[0].threshold[1] = 32768;
info->R_pch = info->pch = &dec_drc_p;
return 0;
}
void *dec_eq_drc_setup_new(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en)
{
#if TCFG_EQ_ENABLE
struct dec_eq_drc *eff = zalloc(sizeof(struct dec_eq_drc));
if (config_eq_lite_en) { //仅支持同步方式eq处理
async = 0;//
}
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
eff->spk_eq = spk_eq_open(sample_rate, channel, drc_en ? 1 : 0);
#endif/*AUDIO_SPK_EQ_CONFIG*/
#if TCFG_DRC_ENABLE
if (drc_en & BIT(1)) { //game eff drc
if (!eq_file_get_cfg(get_eq_cfg_hdl(), (u8 *)SDFILE_RES_ROOT_PATH"eq_game_eff.bin")) { //加载游戏音效
EQ_CFG *eq_cfg = get_eq_cfg_hdl();
eq_cfg->eq_type = EQ_TYPE_FILE;
}
eff->drc_bef_eq = 1;
async = 0;
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = channel;
drc_param.online_en = 1;
drc_param.remain_en = 1;
drc_param.out_32bit = 1;
drc_param.cb = drc_get_filter_info;
drc_param.drc_name = song_eq_mode;
eff->drc_prev = audio_dec_drc_open(&drc_param);
}
#endif//TCFG_DRC_ENABLE
eff->priv = priv;
eff->out_cb = eq_output_cb;
struct audio_eq_param eq_param = {0};
eq_param.channels = channel;
eq_param.online_en = 1;
eq_param.mode_en = 1;
eq_param.remain_en = 1;
eq_param.no_wait = async;
if (drc_en) {
eq_param.out_32bit = 1;
}
eq_param.max_nsection = EQ_SECTION_MAX;
eq_param.cb = eq_get_filter_info;
eq_param.eq_name = song_eq_mode;
eq_param.sr = sample_rate;
eq_param.priv = eff;
eq_param.output = eq_output;
struct eq_parm_new par_new = {0};
par_new.in_mode = DATI_INT;
par_new.run_mode = NORMAL;
par_new.data_in_mode = SEQUENCE_DAT_IN;
par_new.data_out_mode = SEQUENCE_DAT_OUT;
eff->eq = audio_dec_eq_open_new(&eq_param, &par_new);
eff->async = async;
#if TCFG_DRC_ENABLE
if (drc_en) {
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = channel;
if (eff->drc_bef_eq) {
drc_param.online_en = 0;
drc_param.remain_en = 0;
drc_param.out_32bit = 1;
drc_param.cb = dec_drc_get_filter_info;
drc_param.drc_name = mic_eq_mode;
} else {
drc_param.online_en = 1;
drc_param.remain_en = 1;
drc_param.out_32bit = 1;
drc_param.cb = drc_get_filter_info;
drc_param.drc_name = song_eq_mode;
}
eff->drc = audio_dec_drc_open(&drc_param);
}
#endif//TCFG_DRC_ENABLE
return eff;
#else
return NULL;
#endif//TCFG_EQ_ENABLE
}
#endif /*AUDIO_GAME_EFFECT_CONFIG*/
#if TCFG_AUDIO_ESCO_LIMITER_ENABLE
#if !TCFG_DRC_ENABLE
#error "需打开宏TCFG_DRC_ENABLE"
#endif
#ifndef ESCO_DL_LIMITER_THR
#define ESCO_DL_LIMITER_THR 0
#endif
static struct drc_ch esco_drc = {0};
int esco_limiter_get_filter_info(void *drc, struct audio_drc_filter_info *info)
{
float th = ESCO_DL_LIMITER_THR;//db -60db~0db,限幅器阈值
int threshold = roundf(powf(10.0f, th / 20.0f) * 32768);
esco_drc.nband = 1;
esco_drc.type = 1;
esco_drc._p.limiter[0].attacktime = 5;
esco_drc._p.limiter[0].releasetime = 500;
esco_drc._p.limiter[0].threshold[0] = threshold;
esco_drc._p.limiter[0].threshold[1] = 32768;
info->R_pch = info->pch = &esco_drc;
return 0;
}
struct audio_drc *esco_limiter_open(u16 sample_rate, u16 ch_num)
{
#if TCFG_DRC_ENABLE
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = ch_num;
drc_param.cb = esco_limiter_get_filter_info;
drc_param.drc_name = call_eq_mode;
return audio_dec_drc_open(&drc_param);
#else
return NULL;
#endif//TCFG_DRC_ENABLE
}
void esco_limiter_close(struct audio_drc *limiter)
{
#if TCFG_DRC_ENABLE
if (limiter) {
audio_dec_drc_close(limiter);
limiter = NULL;
}
#endif//TCFG_DRC_ENABLE
}
void esco_limiter_run(struct audio_drc *limiter, s16 *data, u32 len)
{
#if TCFG_DRC_ENABLE
if (limiter) {
audio_drc_run(limiter, data, len);
}
#endif//TCFG_DRC_ENABLE
}
#endif/*TCFG_AUDIO_ESCO_LIMITER_ENABLE*/
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
#define AUDIO_SPK_EQ_STERO 1//支持左右声道独立的spk_eq
/*
*spk_eq系数表
* */
static struct eq_seg_info spk_eq_seg_tab[] = {
/*L*/
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, 0.7f},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, 0.7f},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, 0.7f},
{3, EQ_IIR_TYPE_BAND_PASS, 250, 0, 0.7f},
{4, EQ_IIR_TYPE_BAND_PASS, 500, 0, 0.7f},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, 0.7f},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, 0.7f},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, 0.7f},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, 0.7f},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, 0.7f},
#if AUDIO_SPK_EQ_STERO
/*R*/
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, 0.7f},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, 0.7f},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, 0.7f},
{3, EQ_IIR_TYPE_BAND_PASS, 250, 0, 0.7f},
{4, EQ_IIR_TYPE_BAND_PASS, 500, 0, 0.7f},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, 0.7f},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, 0.7f},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, 0.7f},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, 0.7f},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, 0.7f}
#endif
};
#if AUDIO_SPK_EQ_STERO
static struct eq_seg_info *spk_eq_seg_tab_R = &spk_eq_seg_tab[10];
#endif
/*
*spk_eq系数表运算后存放的buf
* */
static float spk_eq_coeff_tab[10][5];
static float spk_eq_coeff_tab_R[10][5];
/*
*spk_eq
* */
static float spk_eq_global_gain[2] = {0};//[0]:左声道 [1]:右声道
static u32 seg_sel = 0;
static u32 seg_sel_R = 0;
static u32 spk_eq_sample_rate = 0;
/*
*spk_eq系数回调函数
* */
int spk_eq_get_filter_info(void *_eq, int sr, struct audio_eq_filter_info *info)
{
struct audio_eq *eq = _eq;
if (!sr) {
sr = spk_eq_sample_rate;
}
u8 ch_num;
#if TCFG_APP_FM_EMITTER_EN
ch_num = 2;
#else
u8 dac_connect_mode = audio_dac_get_channel(&dac_hdl);
if (dac_connect_mode == DAC_OUTPUT_LR) {
ch_num = 2;
} else {
ch_num = 1;
}
#endif//TCFG_APP_FM_EMITTER_EN
local_irq_disable();
u8 cnt = 1;
#if AUDIO_SPK_EQ_STERO
cnt = 2;
#endif
u8 nsection = ARRAY_SIZE(spk_eq_seg_tab) / cnt;
for (int i = 0; i < nsection; i++) {
if (seg_sel & BIT(i)) {
seg_sel &= ~BIT(i);
eq_seg_design(&spk_eq_seg_tab[i], sr, &spk_eq_coeff_tab[i]);
/* float *tar_buf = &spk_eq_coeff_tab[i]; */
/* printf("cal coeff:0x%x, 0x%x, 0x%x, 0x%x, 0x%x " */
/* , *(int *)&tar_buf[0] */
/* , *(int *)&tar_buf[1] */
/* , *(int *)&tar_buf[2] */
/* , *(int *)&tar_buf[3] */
/* , *(int *)&tar_buf[4] */
/* ); */
}
#if AUDIO_SPK_EQ_STERO
if (ch_num == 2) {
if (seg_sel_R & BIT(i)) {
seg_sel_R &= ~BIT(i);
eq_seg_design(&spk_eq_seg_tab_R[i], sr, &spk_eq_coeff_tab_R[i]);
}
}
#endif
}
/* printf("spk_eq_global_gain[0] %d\n",(int)spk_eq_global_gain[0]); */
/* printf("spk_eq_global_gain[1] %d\n",(int)spk_eq_global_gain[1]); */
local_irq_enable();
#if AUDIO_SPK_EQ_STERO
if (ch_num == 2) {
info->L_coeff = (void *)spk_eq_coeff_tab;//系数指针赋值
info->R_coeff = (void *)spk_eq_coeff_tab_R;//系数指针赋值
info->L_gain = spk_eq_global_gain[0];//总增益填写,用户可修改(-20~20db
info->R_gain = spk_eq_global_gain[1];//总增益填写,用户可修改(-20~20db
} else
#endif
{
info->L_coeff = info->R_coeff = (void *)spk_eq_coeff_tab;//系数指针赋值
info->L_gain = info->R_gain = spk_eq_global_gain[0];//总增益填写,用户可修改(-20~20db
}
info->nsection = nsection;//eq段数根据提供给的系数表来填写例子是2
return 0;
}
static struct audio_eq *spk_eq = NULL;
/*
*spk_eq ,eq系数
*parm: *seg
*seg->index:(0~9)
*seg->iir_type:(EQ_IIR_TYPE)
*seg->freq:(20~20kHz)
*seg->gain:-12~13dB
* */
void spk_eq_seg_update(struct eq_seg_info *seg)
{
if (!seg) {
log_e("spk_eq seg null\n");
return ;
}
u8 i = seg->index;
u8 cnt = 1;
#if AUDIO_SPK_EQ_STERO
cnt = 2;
#endif
if (i >= ARRAY_SIZE(spk_eq_seg_tab) / cnt) {
log_e("spk_eq index err: %d >= %d\n", seg->index, ARRAY_SIZE(spk_eq_seg_tab) / cnt);
return ;
}
local_irq_disable();
memcpy(&spk_eq_seg_tab[i], seg, sizeof(struct eq_seg_info));
seg_sel |= BIT(i);
if (spk_eq) {
struct audio_eq *eq = spk_eq;
eq->updata = 1;//设置更新标志
}
local_irq_enable();
}
/*
*spk_eq ,eq系数
*parm: *seg
*seg->index:(0~9)
*seg->iir_type:(EQ_IIR_TYPE)
*seg->freq:(20~20kHz)
*seg->gain:-12~13dB
* */
void spk_eq_seg_update_R(struct eq_seg_info *seg)
{
u8 cnt = 1;
#if AUDIO_SPK_EQ_STERO
if (!seg) {
log_e("spk_eq seg null\n");
return ;
}
u8 i = seg->index;
cnt = 2;
if (i >= ARRAY_SIZE(spk_eq_seg_tab) / cnt) {
log_e("spk_eq index err: %d >= %d\n", seg->index, ARRAY_SIZE(spk_eq_seg_tab) / cnt);
return ;
}
local_irq_disable();
memcpy(&spk_eq_seg_tab_R[i], seg, sizeof(struct eq_seg_info));
seg_sel_R |= BIT(i);
if (spk_eq) {
struct audio_eq *eq = spk_eq;
eq->updata = 1;//设置更新标志
}
local_irq_enable();
#endif
}
/*
*spk_eq
* */
void spk_eq_global_gain_udapte(float global_gain)
{
spk_eq_global_gain[0] = global_gain;
local_irq_disable();
if (spk_eq) {
/* printf("spk_eq_global_gain[L] %d\n",(int)spk_eq_global_gain[0]); */
struct audio_eq *eq = spk_eq;
eq->updata = 1;//设置更新标志
}
local_irq_enable();
}
void spk_eq_global_gain_udapte_R(float global_gain)
{
spk_eq_global_gain[1] = global_gain;
local_irq_disable();
if (spk_eq) {
/* printf("spk_eq_global_gain[R] %d\n",(int)spk_eq_global_gain[1]); */
struct audio_eq *eq = spk_eq;
eq->updata = 1;//设置更新标志
}
local_irq_enable();
}
/*
*spk_eq
* */
void *spk_eq_open(u32 sample_rate, u8 ch_num, u8 bitwide)
{
#if TCFG_AUDIO_CVP_DUT_ENABLE
//DEC_DUT模式默认仅保留spk_eq, 因此改为16bit位宽
if (audio_dec_dut_en_get(1) == AUDIO_DEC_DUT_MODE_SPK_EQ) {
bitwide = 0;
}
#endif/*TCFG_AUDIO_CVP_DUT_ENABLE*/
spk_eq_sample_rate = sample_rate;
seg_sel = 0xffff;
seg_sel_R = 0xffff;
struct audio_eq_param eq_param = {0};
eq_param.channels = ch_num;
eq_param.max_nsection = EQ_SECTION_MAX;
eq_param.cb = spk_eq_get_filter_info;
eq_param.eq_name = song_eq_mode;
eq_param.sr = sample_rate;
eq_param.out_32bit = bitwide ? 1 : 0;
struct eq_parm_new par_new = {0};
par_new.in_mode = bitwide ? DATI_INT : DATI_SHORT;
par_new.run_mode = NORMAL;
par_new.data_in_mode = SEQUENCE_DAT_IN;
par_new.data_out_mode = SEQUENCE_DAT_OUT;
void *eq = audio_dec_eq_open_new(&eq_param, &par_new);
local_irq_disable();
spk_eq = eq;//记录spk_eq 指针,用于系数更新调用
local_irq_enable();
/* sys_timer_add(NULL, spk_eq_global_gain_udpate_test, 5000); */
/* sys_timer_add(NULL,spk_eq_seg_udpate_test , 5000); */
return eq;
}
/*
*spk_eq
* */
void spk_eq_close(void *eq)
{
if (eq) {
local_irq_disable();
spk_eq = NULL;
local_irq_enable();
audio_dec_eq_close(eq);
}
}
/*
*spk_eq
* */
void spk_eq_run(void *eq, void *in, void *out, u16 len)
{
if (!eq) {
return ;
}
audio_eq_set_output_buf(eq, out, len);
audio_eq_run(eq, in, len);
}
/*
*spk_eq vm
* */
int spk_eq_save_to_vm(void)
{
int ret_tmp = 0;
/* puts("====jj===========to save \n"); */
/* printf("sizeof(spk_eq_seg_tab) %d, %d\n", sizeof(spk_eq_seg_tab), sizeof(float)); */
/* printf("%d %d\n", CFG_SPK_EQ_SEG_SAVE, CFG_SPK_EQ_GLOBAL_GAIN_SAVE); */
int ret = syscfg_write(CFG_SPK_EQ_SEG_SAVE, spk_eq_seg_tab, sizeof(spk_eq_seg_tab));
if (ret <= 0) {
printf("spk_eq tab write to vm err, ret %d\n", ret);
ret_tmp = -1;
}
ret = syscfg_write(CFG_SPK_EQ_GLOBAL_GAIN_SAVE, spk_eq_global_gain, sizeof(spk_eq_global_gain));
if (ret <= 0) {
printf("spk_eq global gain write to vm err ret %d\n", ret);
ret_tmp = -1;
}
/* puts("===============to save end\n"); */
return ret_tmp;
}
/*
*spk_eq vm中读取
* */
void spk_eq_read_from_vm()
{
int ret = syscfg_read(CFG_SPK_EQ_SEG_SAVE, spk_eq_seg_tab, sizeof(spk_eq_seg_tab));
if (ret <= 0) {
printf("skp_eq read from vm err\n");
}
ret = syscfg_read(CFG_SPK_EQ_GLOBAL_GAIN_SAVE, spk_eq_global_gain, sizeof(spk_eq_global_gain));
if (ret <= 0) {
printf("spk_eq global gain read from vm err\n");
}
}
/* typedef struct { */
/* u8 cmd; */
/* struct eq_seg_info seg; */
/* }spk_seg_info; */
/* typedef struct { */
/* u8 cmd; */
/* float global_gain; */
/* }spk_global_gain_info; */
typedef struct {
u16 magic; //0x3344
u16 crc; //data crc
u8 data[32]; //data
} SPK_EQ_PACK;
#define CMD_SEG 0x1
#define CMD_GLOBAL 0x2
#define CMD_SAVE_PARM 0x3
#define CMD_RESET_PARM 0x4
/*
*
* */
#define CMD_SEG_R 0x5
#define CMD_GLOBAL_R 0x6
#define CMD_SUPPORT_GLOBAL_GAIN 0x7
#define CMD_READ_SEG_L 0x8//左声道或者单声道获取系数表
#define CMD_READ_SEG_R 0x9//右声道获取系数表
#define CMD_READ_GLOBAL_L 0xa //左声道或者单声道获取总增益
#define CMD_READ_GLOBAL_R 0xb //右声道获取总增益
#define SPK_EQ_CRC_EN 0//是否使能crc校验
static u8 parse_seq = 0;
void (*send_data_handler)(u8 seq, u8 *packet, u8 size);
static spk_eq_ack_packet(u8 seq, u8 *packet, u8 size)
{
if (send_data_handler) {
send_data_handler(seq, packet, size);
} else {
app_online_db_ack(seq, packet, size);
}
}
int spk_eq_spp_rx_packet(u8 *packet, u8 len)
{
SPK_EQ_PACK pack = {0};//packet;
memcpy(&pack, packet, len);
if (pack.magic != 0x3344) {
printf("magic err 0x%x\n", pack.magic);
return -1;
}
struct eq_seg_info seg = {0};
float global_gain = 0;
u8 cmd = pack.data[0];
u16 crc;
printf("cmd %d\n", cmd);
switch (cmd) {
case CMD_SEG:
#if SPK_EQ_CRC_EN
crc = CRC16(pack.data, len - 4);
if (crc != pack.crc) {
printf("spk_seg pack crc err %x, %x\n", crc, pack.crc);
return -1;
}
#endif
memcpy(&seg, &pack.data[1], sizeof(struct eq_seg_info));
spk_eq_seg_update(&seg);
printf("idx:%d, iir:%d, frq:%d, gain:0x%x, q:0x%x \n", seg.index, seg.iir_type, seg.freq, *(int *)&seg.gain, *(int *)&seg.q);
break;
case CMD_GLOBAL:
#if SPK_EQ_CRC_EN
crc = CRC16(pack.data, len - 4);
if (crc != pack.crc) {
printf("spk global gain info pack crc err %x, %x\n", crc, pack.crc);
return -1;
}
#endif
memcpy(&global_gain, &pack.data[1], sizeof(float));
spk_eq_global_gain_udapte(global_gain);
printf("global_gain 0x%x\n", *(int *)&global_gain);
break;
case CMD_SEG_R:
#if SPK_EQ_CRC_EN
crc = CRC16(pack.data, len - 4);
if (crc != pack.crc) {
printf("spk_seg_r pack crc err %x, %x\n", crc, pack.crc);
return -1;
}
#endif
memcpy(&seg, &pack.data[1], sizeof(struct eq_seg_info));
spk_eq_seg_update_R(&seg);
printf("R idx:%d, iir:%d, frq:%d, gain:0x%x, q:0x%x \n", seg.index, seg.iir_type, seg.freq, *(int *)&seg.gain, *(int *)&seg.q);
break;
case CMD_GLOBAL_R:
#if SPK_EQ_CRC_EN
crc = CRC16(pack.data, len - 4);
if (crc != pack.crc) {
printf("spk global gain info pack crc err %x, %x\n", crc, pack.crc);
return -1;
}
#endif
memcpy(&global_gain, &pack.data[1], sizeof(float));
spk_eq_global_gain_udapte_R(global_gain);
printf("R global_gain 0x%x\n", *(int *)&global_gain);
break;
case CMD_SAVE_PARM:
return spk_eq_save_to_vm();
break;
case CMD_RESET_PARM:
local_irq_disable();
u8 cnt = 1;
#if AUDIO_SPK_EQ_STERO
cnt = 2;
#endif
for (int i = 0; i < ARRAY_SIZE(spk_eq_seg_tab) / cnt; i++) {
spk_eq_seg_tab[i].index = i;
spk_eq_seg_tab[i].freq = 100;
spk_eq_seg_tab[i].iir_type = EQ_IIR_TYPE_BAND_PASS;
spk_eq_seg_tab[i].gain = 0.0f;
spk_eq_seg_tab[i].q = 0.7f;
seg_sel |= BIT(i);
#if AUDIO_SPK_EQ_STERO
spk_eq_seg_tab_R[i].index = i;
spk_eq_seg_tab_R[i].freq = 100;
spk_eq_seg_tab_R[i].iir_type = EQ_IIR_TYPE_BAND_PASS;
spk_eq_seg_tab_R[i].gain = 0.0f;
spk_eq_seg_tab_R[i].q = 0.7f;
seg_sel_R |= BIT(i);
#endif
}
local_irq_enable();
spk_eq_global_gain_udapte(0);
spk_eq_global_gain_udapte_R(0);
return spk_eq_save_to_vm();
break;
case CMD_SUPPORT_GLOBAL_GAIN:
//support global_gain
break;
case CMD_READ_SEG_L:
spk_eq_ack_packet(parse_seq, spk_eq_seg_tab, sizeof(spk_eq_seg_tab) / 2);
return 1;
case CMD_READ_SEG_R:
spk_eq_ack_packet(parse_seq, &spk_eq_seg_tab[10], sizeof(spk_eq_seg_tab) / 2);
return 1;
case CMD_READ_GLOBAL_L:
spk_eq_ack_packet(parse_seq, &spk_eq_global_gain[0], 4);
return 1;
case CMD_READ_GLOBAL_R:
spk_eq_ack_packet(parse_seq, &spk_eq_global_gain[1], 4);
return 1;
default:
printf("crc %d\n", pack.crc);
printf("cmd err %x\n", cmd);
return -1;
}
return 0;
}
int spk_eq_read_seg_l(u8 **buf)
{
*buf = (u8 *)(&spk_eq_seg_tab[0]);
return sizeof(spk_eq_seg_tab) / 2;
}
int spk_eq_read_seg_r(u8 **buf)
{
#if AUDIO_SPK_EQ_STERO
*buf = (u8 *)(&spk_eq_seg_tab[10]);
return sizeof(spk_eq_seg_tab) / 2;
#else
return 0;
#endif
}
int spk_eq_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
{
if (ext_data) {
parse_seq = ext_data[1];
} else {
parse_seq = 0xff;
}
printf("parse_seq %x\n", parse_seq);
int ret = spk_eq_spp_rx_packet(packet, size);
if (!ret) {
u8 ack[] = "OK";
spk_eq_ack_packet(parse_seq, ack, sizeof(ack));
/* spk_eq_ack_packet(parse_seq, packet, size); */
} else if (ret != 1) {
u8 ack[] = "ER";
spk_eq_ack_packet(parse_seq, ack, sizeof(ack));
/* spk_eq_ack_packet(parse_seq, packet, size); */
}
return 0;
}
void spk_eq_set_send_data_handler(void (*handler)(u8 seq, u8 *packet, u8 size))
{
send_data_handler = handler;
}
int spk_eq_init(void)
{
#if APP_ONLINE_DEBUG
app_online_db_register_handle(DB_PKT_TYPE_SPK_EQ, spk_eq_app_online_parse);
#endif
return 0;
}
__initcall(spk_eq_init);
#endif/*AUDIO_SPK_EQ_CONFIG*/
#if defined(TCFG_AUDIO_BASS_BOOST) && TCFG_AUDIO_BASS_BOOST
#if TCFG_AUDIO_BASS_BOOST_TEST
static u8 bass_boost_run = 1;
u8 test_bass_boost = 1;
#else
static u8 bass_boost_run = 1;
#endif/*TCFG_AUDIO_BASS_BOOST_TEST*/
#if TCFG_AUDIO_BASS_BOOST_TEST
#define TWS_FUNC_ID_BASS_EFF \
((int)(('A' + '2' + 'D' + 'P') << (2 * 8)) | \
(int)(('E' + 'F' + 'F') << (1 * 8)) | \
(int)(('S' + 'Y' + 'N' + 'C') << (0 * 8)))
void audio_bass_ctrl()
{
int state = tws_api_get_tws_state();
if (state & TWS_STA_SIBLING_CONNECTED) {
test_bass_boost = !test_bass_boost;
if (test_bass_boost) { //对耳链接,进入低音增强,播个提示音
/* tone_play_index(TONE_NORMAL, 1); */
} else {
}
tws_api_send_data_to_sibling((u8 *)&test_bass_boost, sizeof(int), TWS_FUNC_ID_BASS_EFF);
} else {
test_bass_boost = !test_bass_boost;
bass_boost_run = test_bass_boost;
}
}
static void tws_a2dp_eff_align_bass(void *data, u16 len, bool rx)
{
int a2dp_eff;
memcpy(&a2dp_eff, data, sizeof(int));
bass_boost_run = a2dp_eff;
test_bass_boost = bass_boost_run;
}
REGISTER_TWS_FUNC_STUB(a2dp_align_bass) = {
.func_id = TWS_FUNC_ID_BASS_EFF,
.func = tws_a2dp_eff_align_bass,
};
#endif/*TCFG_AUDIO_BASS_BOOST_TEST*/
static int bass_boost_get_filter_info(void *drc, struct audio_drc_filter_info *info)
{
#if (TCFG_AUDIO_BASS_BOOST && TCFG_DRC_ENABLE)
static struct drc_ch wdrc_p = {0};
struct threshold_group low_threshold[] = {//低频
{0, 0},
{79, 79},
{140, 80},
};
struct threshold_group mid_threshold[] = {//中频
{0, 0},
{82, 82},
{140, 82}
};
wdrc_p.nband = 2;
wdrc_p.type = 3;//wdrc
wdrc_p.low_freq = 90; //低中分频点 20~600hz
wdrc_p.high_freq = 2000;//中高分频点 (0~20000hz)
wdrc_p.order = 2;////分频阶数 2或者4
int i = 0;
//低频
wdrc_p._p.wdrc[0].attacktime = 10;
wdrc_p._p.wdrc[0].releasetime = 100;
memcpy(wdrc_p._p.wdrc[0].threshold, low_threshold, sizeof(low_threshold));
wdrc_p._p.wdrc[0].threshold_num = ARRAY_SIZE(low_threshold);
wdrc_p._p.wdrc[0].rms_time = 25;
wdrc_p._p.wdrc[0].algorithm = 0;
wdrc_p._p.wdrc[0].mode = 1;
wdrc_p._p.wdrc[0].inputgain = 0;
wdrc_p._p.wdrc[0].outputgain = 8;
//高频
//right
wdrc_p._p.wdrc[1].attacktime = 10;
wdrc_p._p.wdrc[1].releasetime = 100;
memcpy(wdrc_p._p.wdrc[1].threshold, mid_threshold, sizeof(mid_threshold));
wdrc_p._p.wdrc[1].threshold_num = ARRAY_SIZE(mid_threshold);
wdrc_p._p.wdrc[1].rms_time = 25;
wdrc_p._p.wdrc[1].algorithm = wdrc_p._p.wdrc[0].algorithm;
wdrc_p._p.wdrc[1].mode = wdrc_p._p.wdrc[0].mode;
wdrc_p._p.wdrc[1].inputgain = wdrc_p._p.wdrc[0].inputgain;
wdrc_p._p.wdrc[1].outputgain = wdrc_p._p.wdrc[0].outputgain;
info->R_pch = info->pch = &wdrc_p;
#endif/*TCFG_AUDIO_BASS_BOOST*/
return 0;
}
void *audio_bass_boost_open(u32 sample_rate, u8 ch_num)
{
struct audio_drc *bass_boost = NULL;
struct audio_drc_param drc_param = {0};
drc_param.sr = sample_rate;
drc_param.channels = ch_num;
drc_param.cb = bass_boost_get_filter_info;
bass_boost = audio_dec_drc_open(&drc_param);
return bass_boost;
}
void audio_bass_boost_run(void *hdl, s16 *data, int len)
{
if (!hdl) {
return;
}
if (bass_boost_run) {
audio_drc_run(hdl, data, len);
}
}
void audio_bass_boost_close(void *hdl)
{
if (!hdl) {
return;
}
audio_dec_drc_close(hdl);
}
#endif