1861 lines
51 KiB
C
1861 lines
51 KiB
C
|
|
#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
|