aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-01-24 18:03:38 +0100
committerTakashi Iwai <tiwai@suse.de>2008-01-24 18:03:38 +0100
commit6ce026d9cd06415f71a81bc69f43a9427fdf1eb2 (patch)
treef91a7cf84cecadd4b61515fba420f824edf976de
parente4fdf44119b4460eb3be0f762bd214032c882461 (diff)
downloadsalsa-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.c147
-rw-r--r--src/control.h24
-rw-r--r--src/ctl_macros.h49
-rw-r--r--src/mixer.c162
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);