mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-02 09:01:48 -05:00
Add handling of linear volume in simple mixer
Added the handling of linear volume TLV in the simple mixer layer.
This commit is contained in:
parent
4962ec5a5c
commit
b0bbcd0697
2 changed files with 69 additions and 4 deletions
|
|
@ -170,6 +170,11 @@ typedef enum _snd_ctl_event_type {
|
||||||
#define SND_CTL_TLVT_CONTAINER 0x0000
|
#define SND_CTL_TLVT_CONTAINER 0x0000
|
||||||
/** TLV type - basic dB scale */
|
/** TLV type - basic dB scale */
|
||||||
#define SND_CTL_TLVT_DB_SCALE 0x0001
|
#define SND_CTL_TLVT_DB_SCALE 0x0001
|
||||||
|
/** TLV type - linear volume */
|
||||||
|
#define SND_CTL_TLVT_DB_LINEAR 0x0002
|
||||||
|
|
||||||
|
/** Mute state */
|
||||||
|
#define SND_CTL_TLV_DB_GAIN_MUTE -9999999
|
||||||
|
|
||||||
/** CTL type */
|
/** CTL type */
|
||||||
typedef enum _snd_ctl_type {
|
typedef enum _snd_ctl_type {
|
||||||
|
|
|
||||||
|
|
@ -1008,6 +1008,13 @@ static int parse_db_range(struct selem_str *rec, unsigned int *tlv,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SND_CTL_TLVT_DB_SCALE:
|
case SND_CTL_TLVT_DB_SCALE:
|
||||||
|
#ifndef HAVE_SOFT_FLOAT
|
||||||
|
case SND_CTL_TLVT_DB_LINEAR:
|
||||||
|
#endif
|
||||||
|
if (size < 2 * sizeof(int)) {
|
||||||
|
SNDERR("Invalid dB_scale TLV size");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
rec->db_info = malloc(size + sizeof(int) * 2);
|
rec->db_info = malloc(size + sizeof(int) * 2);
|
||||||
if (! rec->db_info)
|
if (! rec->db_info)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
@ -1025,22 +1032,47 @@ static int parse_db_range(struct selem_str *rec, unsigned int *tlv,
|
||||||
static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
|
static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
|
||||||
long volume, long *db_gain)
|
long volume, long *db_gain)
|
||||||
{
|
{
|
||||||
int min, step, mute;
|
|
||||||
|
|
||||||
if (init_db_range(ctl, rec) < 0)
|
if (init_db_range(ctl, rec) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
switch (rec->db_info[0]) {
|
switch (rec->db_info[0]) {
|
||||||
case SND_CTL_TLVT_DB_SCALE:
|
case SND_CTL_TLVT_DB_SCALE: {
|
||||||
|
int min, step, mute;
|
||||||
min = rec->db_info[2];
|
min = rec->db_info[2];
|
||||||
step = (rec->db_info[3] & 0xffff);
|
step = (rec->db_info[3] & 0xffff);
|
||||||
mute = (rec->db_info[3] >> 16) & 1;
|
mute = (rec->db_info[3] >> 16) & 1;
|
||||||
if (mute && volume == rec->min)
|
if (mute && volume == rec->min)
|
||||||
*db_gain = -9999999;
|
*db_gain = SND_CTL_TLV_DB_GAIN_MUTE;
|
||||||
else
|
else
|
||||||
*db_gain = (volume - rec->min) * step + min;
|
*db_gain = (volume - rec->min) * step + min;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#ifndef HAVE_SOFT_FLOAT
|
||||||
|
case SND_CTL_TLVT_DB_LINEAR: {
|
||||||
|
int mindb = rec->db_info[2];
|
||||||
|
int maxdb = rec->db_info[3];
|
||||||
|
if (volume <= rec->min || rec->max <= rec->min)
|
||||||
|
*db_gain = mindb;
|
||||||
|
else if (volume >= rec->max)
|
||||||
|
*db_gain = maxdb;
|
||||||
|
else {
|
||||||
|
double val = (double)(volume - rec->min) /
|
||||||
|
(double)(rec->max - rec->min);
|
||||||
|
if (mindb <= SND_CTL_TLV_DB_GAIN_MUTE)
|
||||||
|
*db_gain = (long)(100.0 * 20.0 * log10(val)) +
|
||||||
|
maxdb;
|
||||||
|
else {
|
||||||
|
/* FIXME: precalculate and cache these values */
|
||||||
|
double lmin = pow(10.0, mindb/20.0);
|
||||||
|
double lmax = pow(10.0, maxdb/20.0);
|
||||||
|
val = (lmax - lmin) * val + lmin;
|
||||||
|
*db_gain = (long)(100.0 * 20.0 * log10(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1115,6 +1147,10 @@ static int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec,
|
||||||
step = (rec->db_info[3] & 0xffff);
|
step = (rec->db_info[3] & 0xffff);
|
||||||
*max = *min + (long)(step * (rec->max - rec->min));
|
*max = *min + (long)(step * (rec->max - rec->min));
|
||||||
return 0;
|
return 0;
|
||||||
|
case SND_CTL_TLVT_DB_LINEAR:
|
||||||
|
*min = (int)rec->db_info[2];
|
||||||
|
*max = (int)rec->db_info[3];
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
@ -1160,6 +1196,30 @@ static int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#ifndef HAVE_SOFT_FLOAT
|
||||||
|
case SND_CTL_TLVT_DB_LINEAR: {
|
||||||
|
int min, max;
|
||||||
|
min = rec->db_info[2];
|
||||||
|
max = rec->db_info[3];
|
||||||
|
if (db_gain <= min)
|
||||||
|
*value = rec->min;
|
||||||
|
else if (db_gain >= max)
|
||||||
|
*value = rec->max;
|
||||||
|
else {
|
||||||
|
/* FIXME: precalculate and cache vmin and vmax */
|
||||||
|
double vmin, vmax, v;
|
||||||
|
vmin = (min <= SND_CTL_TLV_DB_GAIN_MUTE) ? 0.0 :
|
||||||
|
pow(10.0, (double)min / 20.0);
|
||||||
|
vmax = !max ? 1.0 : pow(10.0, (double)max / 20.0);
|
||||||
|
v = pow(10.0, (double)db_gain / 20.0);
|
||||||
|
v = (v - vmin) * (rec->max - rec->min) / (vmax - vmin);
|
||||||
|
if (xdir > 0)
|
||||||
|
v = ceil(v);
|
||||||
|
*value = (long)v + rec->min;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue