KT24-1110_65E-HA-651B/apps/common/audio/audio_digital_vol.c

755 lines
21 KiB
C
Raw Normal View History

2024-11-10 10:44:17 +00:00
#include "audio_digital_vol.h"
#define DIGITAL_FADE_EN 1
#define DIGITAL_FADE_STEP 4
#define BG_DVOL_MAX 14
#define BG_DVOL_MID 10
#define BG_DVOL_MIN 6
#define BG_DVOL_MAX_FADE 5 /*>= BG_DVOL_MAX:自动淡出BG_DVOL_MAX_FADE*/
#define BG_DVOL_MID_FADE 3 /*>= BG_DVOL_MID:自动淡出BG_DVOL_MID_FADE*/
#define BG_DVOL_MIN_FADE 1 /*>= BG_DVOL_MIN:自动淡出BG_DVOL_MIN_FADE*/
#define ASM_ENABLE 1
#define L_sat(b,a) __asm__ volatile("%0=sat16(%1)(s)":"=&r"(b) : "r"(a));
#define L_sat32(b,a,n) __asm__ volatile("%0=%1>>%2(s)":"=&r"(b) : "r"(a),"r"(n));
typedef struct {
u8 bg_dvol_fade_out;
struct list_head dvol_head;
} dvol_t;
static dvol_t dvol_attr;
//static struct digital_volume d_volume;
/*
* DIGITAL_VOL_MAX
* DIGITAL_VOL_MAX + 1
*/
#define DIGITAL_VOL_MAX 31
const u16 dig_vol_table[DIGITAL_VOL_MAX + 1] = {
0 , //0
93 , //1
111 , //2
132 , //3
158 , //4
189 , //5
226 , //6
270 , //7
323 , //8
386 , //9
462 , //10
552 , //11
660 , //12
789 , //13
943 , //14
1127, //15
1347, //16
1610, //17
1925, //18
2301, //19
2751, //20
3288, //21
3930, //22
4698, //23
5616, //24
6713, //25
8025, //26
9592, //27
11466,//28
15200,//29
16000,//30
16384 //31
};
int audio_digital_vol_init(void)
{
INIT_LIST_HEAD(&dvol_attr.dvol_head);
return 0;
}
/*背景音乐淡出使能*/
void audio_digital_vol_bg_fade(u8 fade_out)
{
printf("audio_digital_vol_bg_fade:%d", fade_out);
dvol_attr.bg_dvol_fade_out = fade_out;
}
/*
*fade_step一般不超过两级数字音量的最小差值
*(1)
*(2)0
*/
dvol_handle *audio_digital_vol_open(u8 vol, u8 vol_max, u16 fade_step)
{
dvol_handle *dvol = NULL;
dvol = zalloc(sizeof(dvol_handle));
if (dvol) {
u8 vol_level;
dvol->fade = DIGITAL_FADE_EN;
dvol->vol = (vol > vol_max) ? vol_max : vol;
if (vol > vol_max) {
printf("[warning]cur digital_vol(%d) > digital_vol_max(%d)!!", vol, vol_max);
}
dvol->vol_max = vol_max;
vol_level = dvol->vol * DIGITAL_VOL_MAX / vol_max;
dvol->vol_target = dig_vol_table[vol_level];
dvol->vol_fade = dvol->vol_target;
dvol->fade_step = fade_step;
dvol->toggle = 1;
#if BG_DVOL_FADE_ENABLE
dvol->vol_bk = -1;
local_irq_disable();
list_add(&dvol->entry, &dvol_attr.dvol_head);
if (dvol_attr.bg_dvol_fade_out) {
dvol_handle *hdl;
list_for_each_entry(hdl, &dvol_attr.dvol_head, entry) {
if (hdl != dvol) {
hdl->vol_bk = hdl->vol;
if (hdl->vol >= BG_DVOL_MAX) {
hdl->vol -= BG_DVOL_MAX_FADE;
} else if (hdl->vol >= BG_DVOL_MID) {
hdl->vol -= BG_DVOL_MID_FADE;
} else if (hdl->vol >= BG_DVOL_MIN) {
hdl->vol -= BG_DVOL_MIN_FADE;
} else {
hdl->vol_bk = -1;
continue;
}
u8 vol_level = hdl->vol * DIGITAL_VOL_MAX / hdl->vol_max;
hdl->vol_target = dig_vol_table[vol_level];
//y_printf("bg_dvol fade_out:%x,vol_bk:%d,vol_set:%d,tartget:%d",hdl,hdl->vol_bk,hdl->vol,hdl->vol_target);
}
}
}
local_irq_enable();
#endif
printf("digital_vol_open:%x-%d-%d-%d\n", dvol, dvol->vol, dvol->vol_max, fade_step);
}
return dvol;
}
void audio_digital_vol_close(dvol_handle *dvol)
{
printf("digital_vol_close:%x\n", dvol);
if (dvol) {
#if BG_DVOL_FADE_ENABLE
local_irq_disable();
list_del(&dvol->entry);
dvol_handle *hdl;
list_for_each_entry(hdl, &dvol_attr.dvol_head, entry) {
if ((hdl != dvol) && (hdl->vol_bk >= 0)) {
//y_printf("bg_dvol fade_in:%x,%d",hdl,hdl->vol_bk);
hdl->vol = hdl->vol_bk;
u8 vol_level = hdl->vol_bk * DIGITAL_VOL_MAX / hdl->vol_max;
hdl->vol_target = dig_vol_table[vol_level];
hdl->vol_bk = -1;
}
}
local_irq_enable();
#endif
free(dvol);
dvol = NULL;
}
}
/* u8 audio_digital_vol_get(void)
{
return d_volume.vol;
} */
void audio_digital_vol_set(dvol_handle *dvol, u8 vol)
{
if (dvol == NULL) {
return;
}
if (dvol->toggle == 0) {
return;
}
dvol->vol = (vol > dvol->vol_max) ? dvol->vol_max : vol;
#if BG_DVOL_FADE_ENABLE
if (dvol->vol_bk != -1) {
dvol->vol_bk = vol;
}
#endif
dvol->fade = DIGITAL_FADE_EN;
u8 vol_level = dvol->vol * DIGITAL_VOL_MAX / dvol->vol_max;
dvol->vol_target = dig_vol_table[vol_level];
printf("digital_vol:%d-%d-%d-%d\n", vol, vol_level, dvol->vol_fade, dvol->vol_target);
}
void audio_digital_vol_reset_fade(dvol_handle *dvol)
{
if (dvol) {
dvol->vol_fade = 0;
}
}
int audio_digital_vol_run(dvol_handle *dvol, void *data, u32 len)
{
s32 valuetemp;
s16 *buf;
if (dvol->toggle == 0) {
return -1;
}
buf = data;
len >>= 1; //byte to point
for (u32 i = 0; i < len; i += 2) {
///left channel
if (dvol->fade) {
if (dvol->vol_fade > dvol->vol_target) {
dvol->vol_fade -= dvol->fade_step;
if (dvol->vol_fade < dvol->vol_target) {
dvol->vol_fade = dvol->vol_target;
}
} else if (dvol->vol_fade < dvol->vol_target) {
dvol->vol_fade += dvol->fade_step;
if (dvol->vol_fade > dvol->vol_target) {
dvol->vol_fade = dvol->vol_target;
}
}
} else {
dvol->vol_fade = dvol->vol_target;
}
valuetemp = buf[i];
if (valuetemp < 0) {
valuetemp = -valuetemp;
valuetemp = (valuetemp * dvol->vol_fade) >> 14 ;
valuetemp = -valuetemp;
} else {
valuetemp = (valuetemp * dvol->vol_fade) >> 14 ;
}
if (valuetemp < -32768) {
valuetemp = -32768;
} else if (valuetemp > 32767) {
valuetemp = 32767;
}
buf[i] = (s16)valuetemp;
///right channel
valuetemp = buf[i + 1];
if (valuetemp < 0) {
valuetemp = -valuetemp;
valuetemp = (valuetemp * dvol->vol_fade) >> 14 ;
valuetemp = -valuetemp;
} else {
valuetemp = (valuetemp * dvol->vol_fade) >> 14 ;
}
if (valuetemp < -32768) {
valuetemp = -32768;
} else if (valuetemp > 32767) {
valuetemp = 32767;
}
buf[i + 1] = (s16)valuetemp;
}
return 0;
}
/*************************支持重入的数字音量调节****************************/
/*
*fade_step一般不超过两级数字音量的最小差值
*(1)
*(2)0
*/
void *user_audio_digital_volume_open(u8 vol, u8 vol_max, u16 fade_step)
{
struct digital_volume *d_volume = zalloc(sizeof(struct digital_volume));
if (!d_volume) {
log_e("d_volume NULL\n");
return NULL;
}
u8 vol_level;
d_volume->fade = 0;
d_volume->vol = vol;
d_volume->vol_max = vol_max;
vol_level = vol * DIGITAL_VOL_MAX / vol_max;
d_volume->vol_target = dig_vol_table[vol_level];
//d_volume->vol_fade = 0;//d_volume->vol_target;//打开时从0开始淡入
d_volume->vol_fade = d_volume->vol_target;
d_volume->fade_step = fade_step;
d_volume->toggle = 1;
d_volume->ch_num = 2;//默认双声道
d_volume->user_vol_tab = NULL;
d_volume->user_vol_max = 0;
os_mutex_create(&d_volume->mutex);
printf("digital_vol_open:%d-%d-%d\n", vol, vol_max, fade_step);
return d_volume;
}
int user_audio_digital_volume_close(void *_d_volume)
{
struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
if (!d_volume) {
log_e("d_volume NULL\n");
return -1;
}
/* os_mutex_pend(&d_volume->mutex, 0); */
d_volume->toggle = 0;
d_volume->user_vol_tab = NULL;
d_volume->user_vol_max = 0;
if (d_volume) {
free(d_volume);
d_volume = NULL;
}
/* os_mutex_post(&d_volume->mutex); */
printf("digital_vol_close\n");
return 0;
}
u8 user_audio_digital_volume_get(void *_d_volume)
{
struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
if (!d_volume) {
log_e("d_volume NULL\n");
return 0;
}
/* os_mutex_pend(&d_volume->mutex, 0); */
u8 vol = d_volume->vol;
/* os_mutex_post(&d_volume->mutex); */
return vol;
}
int user_audio_digital_volume_set(void *_d_volume, u8 vol)
{
struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
if (!d_volume) {
log_e("d_volume NULL\n");
return -1;
}
u8 vol_level;
if (d_volume->toggle == 0) {
return 0;
}
/* os_mutex_pend(&d_volume->mutex, 0); */
d_volume->vol = vol;
d_volume->fade = DIGITAL_FADE_EN;
if (!d_volume->user_vol_tab) {
vol_level = d_volume->vol * DIGITAL_VOL_MAX / d_volume->vol_max;
d_volume->vol_target = dig_vol_table[vol_level];
} else {
u8 d_vol_max = d_volume->user_vol_max - 1;
vol_level = d_volume->vol * d_vol_max / d_volume->vol_max;
d_volume->vol_target = d_volume->user_vol_tab[vol_level];
}
/* os_mutex_post(&d_volume->mutex); */
/* printf("digital_vol:%d-%d-%d-%d\n", vol, vol_level, d_volume->vol_fade, d_volume->vol_target); */
return 0;
}
int user_audio_digital_volume_reset_fade(void *_d_volume)
{
struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
if (!d_volume) {
log_e("d_volume NULL\n");
return -1;
}
os_mutex_pend(&d_volume->mutex, 0);
d_volume->vol_fade = 0;
os_mutex_post(&d_volume->mutex);
return 0;
}
#if ASM_ENABLE
#define audio_vol_mix(data,len, ch_num,volumeNOW,volumeDest,step){ \
int i, j; \
int fade = 0; \
if (volumeNOW != volumeDest) \
{ \
fade = 1; \
} \
if(d_volume->fade == 0)\
{\
fade = 0;\
d_volume->vol_fade = d_volume->vol_target;\
}\
if (ch_num == 2) \
{ \
len = len >> 1; \
} \
else if (ch_num == 3) \
{ \
len = (len*5462)>>14; /*等效除3因为5462向上取整得到的*/\
} \
else if(ch_num == 4) \
{ \
len = len >> 2; \
} \
if (fade) \
{ \
short *in_ptr = data; \
for (i = 0; i < len; i++) \
{ \
if (volumeNOW < volumeDest) \
{ \
volumeNOW = volumeNOW + step; \
if (volumeNOW > volumeDest) \
{ \
volumeNOW = volumeDest; \
} \
} \
else if (volumeNOW > volumeDest) \
{ \
volumeNOW = volumeNOW - step; \
if (volumeNOW < volumeDest) \
{ \
volumeNOW = volumeDest; \
} \
} \
{ \
int tmp; \
int reptime = ch_num; \
__asm__ volatile( \
" 1 : \n\t" \
" rep %0 { \n\t" \
" %1 = h[%2](s) \n\t" \
" %1 =%1* %3 \n\t "\
" %1 =%1 >>>14 \n\t"\
" h[%2++=2]= %1 \n\t"\
" }\n\t" \
" if(%0!=0 )goto 1b \n\t" \
: "=&r"(reptime), \
"=&r"(tmp), \
"=&r"(in_ptr) \
:"r"(volumeNOW), \
"0"(reptime),\
"2"(in_ptr)\
: "cc", "memory"); \
} \
} \
} \
else \
{ \
for (i = 0; i < ch_num; i++) \
{ \
short *in_ptr = &data[i]; \
{ \
int tmp; \
int chnumv=ch_num*2;\
int reptime = len;\
__asm__ volatile(\
" 1 : \n\t"\
" rep %0 { \n\t"\
" %1 = h[%2](s) \n\t"\
" %1 = %1 *%3 \n\t "\
" %1= %1 >>>14 \n\t"\
" h[%2++=%4]= %1 \n\t"\
" }\n\t"\
" if(%0!=0 )goto 1b \n\t"\
: "=&r"(reptime),\
"=&r"(tmp),\
"=&r"(in_ptr) \
:"r"(volumeNOW), \
"r"(chnumv),\
"0"(reptime),\
"2"(in_ptr)\
: "cc", "memory");\
} \
}\
}\
}
#else
#define audio_vol_mix(data,len, ch_num,volumeNOW,volumeDest,step){ \
int i, j; \
int fade = 0; \
if (volumeNOW != volumeDest) \
{ \
fade = 1; \
} \
if(d_volume->fade == 0)\
{\
fade = 0;\
d_volume->vol_fade = d_volume->vol_target;\
}\
if (ch_num == 2) \
{ \
len = len >> 1; \
} \
else if (ch_num == 3) \
{ \
len = (len*5462)>>14; /*等效除3因为5462向上取整得到的*/\
} \
else if(ch_num == 4) \
{ \
len = len >> 2; \
} \
if (fade) \
{ \
short *in_ptr = data; \
for (i = 0; i < len; i++) \
{ \
if (volumeNOW < volumeDest) \
{ \
volumeNOW = volumeNOW + step; \
if (volumeNOW > volumeDest) \
{ \
volumeNOW = volumeDest; \
} \
} \
else if (volumeNOW > volumeDest) \
{ \
volumeNOW = volumeNOW - step; \
if (volumeNOW < volumeDest) \
{ \
volumeNOW = volumeDest; \
} \
} \
for (j = 0; j < ch_num; j++) \
{ \
int tmp = (*in_ptr*volumeNOW) >> 14; \
L_sat(tmp, tmp); \
*in_ptr = tmp; \
in_ptr++; \
} \
} \
} \
else \
{ \
for (i = 0; i < ch_num; i++) \
{ \
short *in_ptr = &data[i]; \
for (j = 0; j < len; j++)\
{\
int tmp= (*in_ptr*volumeNOW) >> 14; \
L_sat(tmp, tmp); \
*in_ptr = tmp;\
in_ptr += ch_num;\
}\
}\
}\
}
#endif
int user_audio_digital_volume_run(void *_d_volume, void *data, u32 len, u8 ch_num)
{
struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
if (!d_volume) {
log_e("d_volume NULL\n");
return -1;
}
s32 valuetemp;
s16 *buf;
if (d_volume->toggle == 0) {
return -1;
}
if (ch_num > 4) {
return -1;
}
os_mutex_pend(&d_volume->mutex, 0);
if (ch_num) {
d_volume->ch_num = ch_num;
}
buf = data;
len >>= 1; //byte to point
/* printf("d_volume->vol_target %d %d %d %d\n", d_volume->vol_target, ch_num, d_volume->vol_fade, d_volume->fade_step); */
#if 1
audio_vol_mix(buf, len, ch_num, d_volume->vol_fade, d_volume->vol_target, d_volume->fade_step);
#else
/* printf("d_volume->vol_target %d %d\n", d_volume->vol_target, ch_num); */
for (u32 i = 0; i < len; i += d_volume->ch_num) {//ch_num 1/2/3/4
///FL channel
if (d_volume->fade) {
if (d_volume->vol_fade > d_volume->vol_target) {
d_volume->vol_fade -= d_volume->fade_step;
if (d_volume->vol_fade < d_volume->vol_target) {
d_volume->vol_fade = d_volume->vol_target;
}
} else if (d_volume->vol_fade < d_volume->vol_target) {
d_volume->vol_fade += d_volume->fade_step;
if (d_volume->vol_fade > d_volume->vol_target) {
d_volume->vol_fade = d_volume->vol_target;
}
}
} else {
d_volume->vol_fade = d_volume->vol_target;
}
valuetemp = buf[i];
if (valuetemp < 0) {
valuetemp = -valuetemp;
valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
valuetemp = -valuetemp;
} else {
valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
}
if (valuetemp < -32768) {
valuetemp = -32768;
} else if (valuetemp > 32767) {
valuetemp = 32767;
}
buf[i] = (s16)valuetemp;
if (d_volume->ch_num > 1) { //双声道
///FR channel
valuetemp = buf[i + 1];
if (valuetemp < 0) {
valuetemp = -valuetemp;
valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
valuetemp = -valuetemp;
} else {
valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
}
if (valuetemp < -32768) {
valuetemp = -32768;
} else if (valuetemp > 32767) {
valuetemp = 32767;
}
buf[i + 1] = (s16)valuetemp;
if (d_volume->ch_num > 2) { //三声道
//RL channel
valuetemp = buf[i + 2];
if (valuetemp < 0) {
valuetemp = -valuetemp;
valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
valuetemp = -valuetemp;
} else {
valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
}
if (valuetemp < -32768) {
valuetemp = -32768;
} else if (valuetemp > 32767) {
valuetemp = 32767;
}
buf[i + 2] = (s16)valuetemp;
if (d_volume->ch_num > 3) { //四声道
///RR channel
valuetemp = buf[i + 3];
if (valuetemp < 0) {
valuetemp = -valuetemp;
valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
valuetemp = -valuetemp;
} else {
valuetemp = (valuetemp * d_volume->vol_fade) >> 14 ;
}
if (valuetemp < -32768) {
valuetemp = -32768;
} else if (valuetemp > 32767) {
valuetemp = 32767;
}
buf[i + 3] = (s16)valuetemp;
}
}
}
}
#endif
os_mutex_post(&d_volume->mutex);
return 0;
}
/*
*user_vol_max:
*user_vol_tab:,user_vol_max+1
*/
void user_audio_digital_set_volume_tab(void *_d_volume, u16 *user_vol_tab, u8 user_vol_max)
{
struct digital_volume *d_volume = (struct digital_volume *)_d_volume;
if (!d_volume) {
log_e("d_volume NULL\n");
return ;
}
os_mutex_pend(&d_volume->mutex, 0);
if (user_vol_tab) {
d_volume->user_vol_tab = user_vol_tab;
d_volume->user_vol_max = user_vol_max;
}
os_mutex_post(&d_volume->mutex);
}
/*
*priv:
*void (*handler)(void *priv, void *data, int len, u8 ch_num):
* */
void *user_audio_process_open(void *parm, void *priv, void (*handler)(void *priv, void *data, int len, u8 ch_num))
{
struct user_audio_parm *user_hdl = zalloc(sizeof(struct user_audio_parm));
if (!user_hdl) {
log_e("user_hdl NULL\n");
return NULL;
}
user_hdl->priv = priv;
user_hdl->handler = handler;
struct user_audio_digital_parm *dvol_parm = (struct user_audio_digital_parm *)parm;
if (dvol_parm->en) {
log_i("vol :%d vol_max:%d fade_step:%d\n", dvol_parm->vol, dvol_parm->vol_max, dvol_parm->fade_step);
user_hdl->dvol_hdl = user_audio_digital_volume_open(dvol_parm->vol, dvol_parm->vol_max, dvol_parm->fade_step);
}
log_i("%s ok\n", __FUNCTION__);
return user_hdl;
}
int user_audio_process_close(void *_uparm_hdl)
{
struct user_audio_parm *user_hdl = (struct user_audio_parm *)_uparm_hdl;
if (!user_hdl) {
log_e("user_hdl NULL\n");
return -1;
}
if (user_hdl->dvol_hdl) {
user_audio_digital_volume_close(user_hdl->dvol_hdl);
user_hdl->dvol_hdl = NULL;
}
free(user_hdl);
user_hdl = NULL;
log_i("%s ok\n", __FUNCTION__);
return 0;
}
void user_audio_process_handler_run(void *_uparm_hdl, void *data, u32 len, u8 ch_num)
{
struct user_audio_parm *user_hdl = (struct user_audio_parm *)_uparm_hdl;
if (!user_hdl) {
log_e("user_hdl NULL\n");
return;
}
if (user_hdl->handler) {
user_hdl->handler(user_hdl->priv, data, len, ch_num);
}
if (user_hdl->dvol_hdl) {
user_audio_digital_volume_run(user_hdl->dvol_hdl, data, len, ch_num);
}
}