KT24-1110_65E-HA-651B/apps/common/audio/audio_digital_vol.c
2024-11-10 18:44:17 +08:00

755 lines
21 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}
}