diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-01-24 18:03:38 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-01-24 18:03:38 +0100 |
commit | 6ce026d9cd06415f71a81bc69f43a9427fdf1eb2 (patch) | |
tree | f91a7cf84cecadd4b61515fba420f824edf976de | |
parent | e4fdf44119b4460eb3be0f762bd214032c882461 (diff) | |
download | salsa-lib-6ce026d9cd06415f71a81bc69f43a9427fdf1eb2.tar.gz |
Add snd_ctl_*dB* functions
Added snd_ctl_*_dB* functions. Changed mixer dB functions to use them.
-rw-r--r-- | src/control.c | 147 | ||||
-rw-r--r-- | src/control.h | 24 | ||||
-rw-r--r-- | src/ctl_macros.h | 49 | ||||
-rw-r--r-- | src/mixer.c | 162 |
4 files changed, 234 insertions, 148 deletions
diff --git a/src/control.c b/src/control.c index 0a08b45..8275b70 100644 --- a/src/control.c +++ b/src/control.c @@ -342,3 +342,150 @@ int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl, return 0; } #endif /* SALSA_HAS_ASYNC_SUPPORT */ + + +#if SALSA_HAS_TLV_SUPPORT + +/* convert to index of integer array */ +#define int_index(size) (((size) + sizeof(int) - 1) / sizeof(int)) + +/* max size of a TLV entry for dB information (including compound one) */ +#define MAX_TLV_RANGE_SIZE 256 + +/* convert the given raw volume value to a dB gain + */ +int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, + long volume, long *db_gain) +{ + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + while (pos + 4 <= len) { + rangemin = (int)tlv[pos]; + rangemax = (int)tlv[pos + 1]; + if (volume >= rangemin && volume <= rangemax) + return snd_tlv_convert_to_dB(tlv + pos + 2, + rangemin, rangemax, + volume, db_gain); + pos += int_index(tlv[pos + 3]) + 4; + } + return -EINVAL; + } + case SND_CTL_TLVT_DB_SCALE: { + int min, step, mute; + min = tlv[2]; + step = (tlv[3] & 0xffff); + mute = (tlv[3] >> 16) & 1; + if (mute && volume == rangemin) + *db_gain = SND_CTL_TLV_DB_GAIN_MUTE; + else + *db_gain = (volume - rangemin) * step + min; + return 0; + } + } + return -EINVAL; +} + +/* Get the dB min/max values + */ +int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, + long *min, long *max) +{ + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + while (pos + 4 <= len) { + long rmin, rmax; + rangemin = (int)tlv[pos]; + rangemax = (int)tlv[pos + 1]; + snd_tlv_get_dB_range(tlv + pos + 2, rangemin, rangemax, + &rmin, &rmax); + if (pos > 2) { + if (rmin < *min) + *min = rmin; + if (rmax > *max) + *max = rmax; + } else { + *min = rmin; + *max = rmax; + } + pos += int_index(tlv[pos + 3]) + 4; + } + return 0; + } + case SND_CTL_TLVT_DB_SCALE: { + int step; + *min = (int)tlv[2]; + step = (tlv[3] & 0xffff); + *max = *min + (long)(step * (rangemax - rangemin)); + return 0; + } + case SND_CTL_TLVT_DB_LINEAR: + *min = (int)tlv[2]; + *max = (int)tlv[3]; + return 0; + } + return -EINVAL; +} + +/* Convert from dB gain to the corresponding raw value. + * The value is round up when xdir > 0. + */ +int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, + long db_gain, long *value, int xdir) +{ + switch (tlv[0]) { + case SND_CTL_TLVT_DB_RANGE: { + unsigned int pos, len; + len = int_index(tlv[1]); + if (len > MAX_TLV_RANGE_SIZE) + return -EINVAL; + pos = 2; + while (pos + 4 <= len) { + long dbmin, dbmax; + rangemin = (int)tlv[pos]; + rangemax = (int)tlv[pos + 1]; + if (!snd_tlv_get_dB_range(tlv + pos + 2, + rangemin, rangemax, + &dbmin, &dbmax) && + db_gain >= dbmin && db_gain <= dbmax) + return snd_tlv_convert_from_dB(tlv + pos + 2, + rangemin, rangemax, + db_gain, value, xdir); + pos += int_index(tlv[pos + 3]) + 4; + } + return -EINVAL; + } + case SND_CTL_TLVT_DB_SCALE: { + int min, step, max; + min = tlv[2]; + step = (tlv[3] & 0xffff); + max = min + (int)(step * (rangemax - rangemin)); + if (db_gain <= min) + *value = rangemin; + else if (db_gain >= max) + *value = rangemax; + else { + long v = (db_gain - min) * (rangemax - rangemin); + if (xdir > 0) + v += (max - min) - 1; + v = v / (max - min) + rangemin; + *value = v; + } + return 0; + } + default: + break; + } + return -EINVAL; +} + +#endif /* TLV */ diff --git a/src/control.h b/src/control.h index 57be1b6..e74f418 100644 --- a/src/control.h +++ b/src/control.h @@ -69,4 +69,28 @@ int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count); int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id); +#if SALSA_HAS_TLV_SUPPORT +static inline +int snd_tlv_parse_dB_info(unsigned int *tlv, unsigned int tlv_size, + unsigned int **db_tlvp) +{ + /* just for simplicity */ + *db_tlvp = tlv; + return 0; +} + +int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, + long *min, long *max); +int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, + long volume, long *db_gain); +int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, + long db_gain, long *value, int xdir); +int snd_ctl_get_dB_range(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long *min, long *max); +int snd_ctl_convert_to_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long volume, long *db_gain); +int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long db_gain, long *value, int xdir); +#endif + #endif /* __ALSA_CONTROL_H */ diff --git a/src/ctl_macros.h b/src/ctl_macros.h index cb90dff..508b93d 100644 --- a/src/ctl_macros.h +++ b/src/ctl_macros.h @@ -958,6 +958,55 @@ int snd_ctl_elem_tlv_command(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, { return -ENXIO; } + +static inline __SALSA_NOT_IMPLEMENTED +int snd_tlv_parse_dB_info(unsigned int *tlv, unsigned int tlv_size, + unsigned int **db_tlvp) +{ + return -ENXIO; +} + +static inline __SALSA_NOT_IMPLEMENTED +int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, + long *min, long *max) +{ + return -ENXIO; +} + +static inline __SALSA_NOT_IMPLEMENTED +int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, + long volume, long *db_gain) +{ + return -ENXIO; +} + +static inline __SALSA_NOT_IMPLEMENTED +int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, + long db_gain, long *value, int xdir) +{ + return -ENXIO; +} + +static inline __SALSA_NOT_IMPLEMENTED +int snd_ctl_get_dB_range(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long *min, long *max) +{ + return -ENXIO; +} + +static inline __SALSA_NOT_IMPLEMENTED +int snd_ctl_convert_to_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long volume, long *db_gain) +{ + return -ENXIO; +} + +static inline __SALSA_NOT_IMPLEMENTED +int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, + long db_gain, long *value, int xdir) +{ + return -ENXIO; +} #endif /* !SALSA_HAS_TLV_SUPPORT */ /* diff --git a/src/mixer.c b/src/mixer.c index a866963..737db08 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -1001,12 +1001,6 @@ int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, #if SALSA_HAS_TLV_SUPPORT -/* - * dB conversion - * - * For simplicity, we don't support the linear - log conversion - */ - /* convert to index of integer array */ #define int_index(size) (((size) + sizeof(int) - 1) / sizeof(int)) @@ -1067,6 +1061,12 @@ static int parse_db_range(snd_selem_vol_item_t *item, unsigned int *tlv, return -EINVAL; /* not found */ } +/* + * dB conversion + * + * For simplicity, we don't support the linear - log conversion + */ + /* initialize dB range information, reading TLV via hcontrol */ static int init_db_info(snd_selem_vol_item_t *item) @@ -1102,45 +1102,6 @@ static int init_db_info(snd_selem_vol_item_t *item) } -/* convert the given raw volume value to a dB gain - */ - -static int convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, - long volume, long *db_gain) -{ - switch (tlv[0]) { - case SND_CTL_TLVT_DB_RANGE: { - unsigned int pos, len; - len = int_index(tlv[1]); - if (len > MAX_TLV_RANGE_SIZE) - return -EINVAL; - pos = 2; - while (pos + 4 <= len) { - rangemin = (int)tlv[pos]; - rangemax = (int)tlv[pos + 1]; - if (volume >= rangemin && volume <= rangemax) - return convert_to_dB(tlv + pos + 2, - rangemin, rangemax, - volume, db_gain); - pos += int_index(tlv[pos + 3]) + 4; - } - return -EINVAL; - } - case SND_CTL_TLVT_DB_SCALE: { - int min, step, mute; - min = tlv[2]; - step = (tlv[3] & 0xffff); - mute = (tlv[3] >> 16) & 1; - if (mute && volume == rangemin) - *db_gain = SND_CTL_TLV_DB_GAIN_MUTE; - else - *db_gain = (volume - rangemin) * step + min; - return 0; - } - } - return -EINVAL; -} - int _snd_selem_vol_get_dB(snd_selem_vol_item_t *item, int channel, long *value) { @@ -1148,54 +1109,9 @@ int _snd_selem_vol_get_dB(snd_selem_vol_item_t *item, int channel, return -EINVAL; if (channel >= item->head.channels) channel = 0; - return convert_to_dB(item->db_info, item->raw_min, item->raw_max, - item->vol[RAW_IDX(channel)], value); -} - -/* Get the dB min/max values - */ -static int get_dB_range(unsigned int *tlv, long rangemin, long rangemax, - long *min, long *max) -{ - switch (tlv[0]) { - case SND_CTL_TLVT_DB_RANGE: { - unsigned int pos, len; - len = int_index(tlv[1]); - if (len > MAX_TLV_RANGE_SIZE) - return -EINVAL; - pos = 2; - while (pos + 4 <= len) { - long rmin, rmax; - rangemin = (int)tlv[pos]; - rangemax = (int)tlv[pos + 1]; - get_dB_range(tlv + pos + 2, rangemin, rangemax, - &rmin, &rmax); - if (pos > 2) { - if (rmin < *min) - *min = rmin; - if (rmax > *max) - *max = rmax; - } else { - *min = rmin; - *max = rmax; - } - pos += int_index(tlv[pos + 3]) + 4; - } - return 0; - } - case SND_CTL_TLVT_DB_SCALE: { - int step; - *min = (int)tlv[2]; - step = (tlv[3] & 0xffff); - *max = *min + (long)(step * (rangemax - rangemin)); - return 0; - } - case SND_CTL_TLVT_DB_LINEAR: - *min = (int)tlv[2]; - *max = (int)tlv[3]; - return 0; - } - return -EINVAL; + return snd_tlv_convert_to_dB(item->db_info, + item->raw_min, item->raw_max, + item->vol[RAW_IDX(channel)], value); } int _snd_selem_vol_get_dB_range(snd_selem_vol_item_t *item, @@ -1203,61 +1119,10 @@ int _snd_selem_vol_get_dB_range(snd_selem_vol_item_t *item, { if (init_db_info(item) < 0) return -EINVAL; - return get_dB_range(item->db_info, item->raw_min, item->raw_max, - min, max); + return snd_tlv_get_dB_range(item->db_info, item->raw_min, item->raw_max, + min, max); } -/* Convert from dB gain to the corresponding raw value. - * The value is round up when xdir > 0. - */ -static int convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, - long db_gain, long *value, int xdir) -{ - switch (tlv[0]) { - case SND_CTL_TLVT_DB_RANGE: { - unsigned int pos, len; - len = int_index(tlv[1]); - if (len > MAX_TLV_RANGE_SIZE) - return -EINVAL; - pos = 2; - while (pos + 4 <= len) { - long dbmin, dbmax; - rangemin = (int)tlv[pos]; - rangemax = (int)tlv[pos + 1]; - if (!get_dB_range(tlv + pos + 2, rangemin, rangemax, - &dbmin, &dbmax) && - db_gain >= dbmin && db_gain <= dbmax) - return convert_from_dB(tlv + pos + 2, - rangemin, rangemax, - db_gain, value, xdir); - pos += int_index(tlv[pos + 3]) + 4; - } - return -EINVAL; - } - case SND_CTL_TLVT_DB_SCALE: { - int min, step, max; - min = tlv[2]; - step = (tlv[3] & 0xffff); - max = min + (int)(step * (rangemax - rangemin)); - if (db_gain <= min) - *value = rangemin; - else if (db_gain >= max) - *value = rangemax; - else { - long v = (db_gain - min) * (rangemax - rangemin); - if (xdir > 0) - v += (max - min) - 1; - v = v / (max - min) + rangemin; - *value = v; - } - return 0; - } - default: - break; - } - return -EINVAL; -} - int _snd_selem_vol_set_dB(snd_selem_vol_item_t *item, snd_mixer_selem_channel_id_t channel, long db_gain, int xdir) @@ -1269,8 +1134,9 @@ int _snd_selem_vol_set_dB(snd_selem_vol_item_t *item, return -EINVAL; if (channel >= item->head.channels) channel = 0; - err = convert_from_dB(item->db_info, item->raw_min, item->raw_max, - db_gain, &value, xdir); + err = snd_tlv_convert_from_dB(item->db_info, + item->raw_min, item->raw_max, + db_gain, &value, xdir); if (err < 0) return err; item->vol[USR_IDX(channel)] = convert_to_user(item, value); |