summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2010-07-20 10:34:53 +0300
committerTakashi Iwai <tiwai@suse.de>2010-07-20 12:55:51 +0200
commitd81ce4ea7af917f992aa0529c29db590d566ae7a (patch)
tree936d6806be1489e4469073afdb218d3d0dcd92a4
parent16a2cad39b7ee29e34b92d39d72eebfc88f8dc22 (diff)
downloadalsa-lib-d81ce4ea7af917f992aa0529c29db590d566ae7a.tar.gz
tlv: Handle 'holes' in SND_CTL_TLVT_DB_RANGE array
When converting from dB to raw value, and DB_RANGE is used with non overlapping map, dB value in between the sub ranges will be not found. For example, if the control has the following: 0: -10dB 1: -5dB 2: 0dB 3: 2dB 4: 4dB static const unsigned int nonoverlapping_tlv[] = { TLV_DB_RANGE_HEAD(2), 0, 2, TLV_DB_SCALE_ITEM(-1000, 500, 0), 3, 4, TLV_DB_SCALE_ITEM(200, 200, 0), }; Range 1: -10 .. 0dB Range 2: 2 .. 4dB If user asks for 1dB the snd_tlv_convert_from_dB will not find the raw value, since the 1dB is not part of either range. To fix this, we will store the previous non maching range's maximum raw value. If the dB value is not found in the next range, we will check, if the requested dB value is in between the current and the previous range, and if it is than pick the apropriate raw value based on the xdir (up or down rounding). Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--src/control/tlv.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/src/control/tlv.c b/src/control/tlv.c
index 9f26f355..49f9afec 100644
--- a/src/control/tlv.c
+++ b/src/control/tlv.c
@@ -285,7 +285,7 @@ int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax,
{
switch (tlv[0]) {
case SND_CTL_TLVT_DB_RANGE: {
- long dbmin, dbmax;
+ long dbmin, dbmax, prev_rangemax;
unsigned int pos, len;
len = int_index(tlv[1]);
if (len > MAX_TLV_RANGE_SIZE)
@@ -301,6 +301,7 @@ int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax,
return 0;
}
pos = 2;
+ prev_rangemax = 0;
while (pos + 4 <= len) {
rangemin = (int)tlv[pos];
rangemax = (int)tlv[pos + 1];
@@ -311,6 +312,11 @@ int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax,
return snd_tlv_convert_from_dB(tlv + pos + 2,
rangemin, rangemax,
db_gain, value, xdir);
+ else if (db_gain < dbmin) {
+ *value = xdir ? rangemin : prev_rangemax;
+ return 0;
+ }
+ prev_rangemax = rangemax;
pos += int_index(tlv[pos + 3]) + 4;
}
return -EINVAL;