perex 37d715
From f78af4ab0412052aabb74c9122a8d8f3ab6d45e6 Mon Sep 17 00:00:00 2001
perex 37d715
From: Takashi Iwai <tiwai@suse.de>
perex 37d715
Date: Wed, 16 Jul 2008 12:37:51 +0200
perex 37d715
Subject: [PATCH] Add boolean (mute) functionality to softvol plugin
perex 37d715
perex 37d715
When the resolution is set to 2, a boolean control is created as a
perex 37d715
mute switch instead of a volume control.
perex 37d715
Also, fixed the possible zero-division error.
perex 37d715
perex 37d715
Signed-off-by: Takashi Iwai <tiwai@suse.de>
perex 37d715
---
perex 37d715
 src/pcm/pcm_softvol.c |   59 +++++++++++++++++++++++++++++++++++-------------
perex 37d715
 1 files changed, 43 insertions(+), 16 deletions(-)
perex 37d715
perex 37d715
diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c
perex 37d715
index 7af7f40..eee6424 100644
perex 37d715
--- a/src/pcm/pcm_softvol.c
perex 37d715
+++ b/src/pcm/pcm_softvol.c
perex 37d715
@@ -275,9 +275,15 @@ static void softvol_convert_stereo_vol(snd_pcm_softvol_t *svol,
perex 37d715
 		return;
perex 37d715
 	}
perex 37d715
 
perex 37d715
-	vol[0] = svol->dB_value[svol->cur_vol[0]];
perex 37d715
-	vol[1] = svol->dB_value[svol->cur_vol[1]];
perex 37d715
-	vol_c = svol->dB_value[(svol->cur_vol[0] + svol->cur_vol[1]) / 2];
perex 37d715
+	if (svol->max_val == 1) {
perex 37d715
+		vol[0] = svol->cur_vol[0] ? 0xffff : 0;
perex 37d715
+		vol[1] = svol->cur_vol[1] ? 0xffff : 0;
perex 37d715
+		vol_c = vol[0] | vol[1];
perex 37d715
+	} else {
perex 37d715
+		vol[0] = svol->dB_value[svol->cur_vol[0]];
perex 37d715
+		vol[1] = svol->dB_value[svol->cur_vol[1]];
perex 37d715
+		vol_c = svol->dB_value[(svol->cur_vol[0] + svol->cur_vol[1]) / 2];
perex 37d715
+	}
perex 37d715
 	switch (svol->sformat) {
perex 37d715
 	case SND_PCM_FORMAT_S16_LE:
perex 37d715
 	case SND_PCM_FORMAT_S16_BE:
perex 37d715
@@ -325,7 +331,10 @@ static void softvol_convert_mono_vol(snd_pcm_softvol_t *svol,
perex 37d715
 		return;
perex 37d715
 	}
perex 37d715
 
perex 37d715
-	vol_scale = svol->dB_value[svol->cur_vol[0]];
perex 37d715
+	if (svol->max_val == 1)
perex 37d715
+		vol_scale = svol->cur_vol[0] ? 0xffff : 0;
perex 37d715
+	else
perex 37d715
+		vol_scale = svol->dB_value[svol->cur_vol[0]];
perex 37d715
 	switch (svol->sformat) {
perex 37d715
 	case SND_PCM_FORMAT_S16_LE:
perex 37d715
 	case SND_PCM_FORMAT_S16_BE:
perex 37d715
@@ -569,9 +578,13 @@ static void snd_pcm_softvol_dump(snd_pcm_t *pcm, snd_output_t *out)
perex 37d715
 	snd_pcm_softvol_t *svol = pcm->private_data;
perex 37d715
 	snd_output_printf(out, "Soft volume PCM\n");
perex 37d715
 	snd_output_printf(out, "Control: %s\n", svol->elem.id.name);
perex 37d715
-	snd_output_printf(out, "min_dB: %g\n", svol->min_dB);
perex 37d715
-	snd_output_printf(out, "max_dB: %g\n", svol->max_dB);
perex 37d715
-	snd_output_printf(out, "resolution: %d\n", svol->max_val + 1);
perex 37d715
+	if (svol->max_val == 1)
perex 37d715
+		snd_output_printf(out, "boolean\n");
perex 37d715
+	else {
perex 37d715
+		snd_output_printf(out, "min_dB: %g\n", svol->min_dB);
perex 37d715
+		snd_output_printf(out, "max_dB: %g\n", svol->max_dB);
perex 37d715
+		snd_output_printf(out, "resolution: %d\n", svol->max_val + 1);
perex 37d715
+	}
perex 37d715
 	if (pcm->setup) {
perex 37d715
 		snd_output_printf(out, "Its setup is:\n");
perex 37d715
 		snd_pcm_dump_setup(pcm, out);
perex 37d715
@@ -596,13 +609,21 @@ static int add_user_ctl(snd_pcm_softvol_t *svol, snd_ctl_elem_info_t *cinfo, int
perex 37d715
 	int i;
perex 37d715
 	unsigned int def_val;
perex 37d715
 	
perex 37d715
-	err = snd_ctl_elem_add_integer(svol->ctl, &cinfo->id, count, 0, svol->max_val, 0);
perex 37d715
+	if (svol->max_val == 1)
perex 37d715
+		err = snd_ctl_elem_add_boolean(svol->ctl, &cinfo->id, count);
perex 37d715
+	else
perex 37d715
+		err = snd_ctl_elem_add_integer(svol->ctl, &cinfo->id, count,
perex 37d715
+					       0, svol->max_val, 0);
perex 37d715
 	if (err < 0)
perex 37d715
 		return err;
perex 37d715
-	add_tlv_info(svol, cinfo);
perex 37d715
-	/* set zero dB value as default, or max_val if
perex 37d715
-	   there is no 0 dB setting */
perex 37d715
-	def_val = svol->zero_dB_val ? svol->zero_dB_val : svol->max_val;
perex 37d715
+	if (svol->max_val == 1)
perex 37d715
+		def_val = 1;
perex 37d715
+	else {
perex 37d715
+		add_tlv_info(svol, cinfo);
perex 37d715
+		/* set zero dB value as default, or max_val if
perex 37d715
+		   there is no 0 dB setting */
perex 37d715
+		def_val = svol->zero_dB_val ? svol->zero_dB_val : svol->max_val;
perex 37d715
+	}
perex 37d715
 	for (i = 0; i < count; i++)
perex 37d715
 		svol->elem.value.integer.value[i] = def_val;
perex 37d715
 	return snd_ctl_elem_write(svol->ctl, &svol->elem);
perex 37d715
@@ -647,7 +668,7 @@ static int softvol_load_control(snd_pcm_t *pcm, snd_pcm_softvol_t *svol,
perex 37d715
 	svol->max_val = resolution - 1;
perex 37d715
 	svol->min_dB = min_dB;
perex 37d715
 	svol->max_dB = max_dB;
perex 37d715
-	if (svol->max_dB == ZERO_DB)
perex 37d715
+	if (svol->max_val == 1 || svol->max_dB == ZERO_DB)
perex 37d715
 		svol->zero_dB_val = svol->max_val;
perex 37d715
 	else if (svol->max_dB < 0)
perex 37d715
 		svol->zero_dB_val = 0; /* there is no 0 dB setting */
perex 37d715
@@ -671,7 +692,8 @@ static int softvol_load_control(snd_pcm_t *pcm, snd_pcm_softvol_t *svol,
perex 37d715
 			/* hardware control exists */
perex 37d715
 			return 1; /* notify */
perex 37d715
 
perex 37d715
-		} else if (cinfo->type != SND_CTL_ELEM_TYPE_INTEGER ||
perex 37d715
+		} else if ((cinfo->type != SND_CTL_ELEM_TYPE_INTEGER &&
perex 37d715
+			    cinfo->type != SND_CTL_ELEM_TYPE_BOOLEAN) ||
perex 37d715
 			   cinfo->count != (unsigned int)cchannels ||
perex 37d715
 			   cinfo->value.integer.min != 0 ||
perex 37d715
 			   cinfo->value.integer.max != resolution - 1) {
perex 37d715
@@ -684,7 +706,7 @@ static int softvol_load_control(snd_pcm_t *pcm, snd_pcm_softvol_t *svol,
perex 37d715
 				SNDERR("Cannot add a control");
perex 37d715
 				return err;
perex 37d715
 			}
perex 37d715
-		} else {
perex 37d715
+		} else if (svol->max_val > 1) {
perex 37d715
 			/* check TLV availability */
perex 37d715
 			unsigned int tlv[4];
perex 37d715
 			err = snd_ctl_elem_tlv_read(svol->ctl, &cinfo->id, tlv, sizeof(tlv));
perex 37d715
@@ -693,6 +715,10 @@ static int softvol_load_control(snd_pcm_t *pcm, snd_pcm_softvol_t *svol,
perex 37d715
 		}
perex 37d715
 	}
perex 37d715
 
perex 37d715
+	if (svol->max_val == 1)
perex 37d715
+		return 0;
perex 37d715
+
perex 37d715
+	/* set up dB table */
perex 37d715
 	if (min_dB == PRESET_MIN_DB && max_dB == ZERO_DB && resolution == PRESET_RESOLUTION)
perex 37d715
 		svol->dB_value = preset_dB_value;
perex 37d715
 	else {
perex 37d715
@@ -863,6 +889,7 @@ pcm.name {
perex 37d715
 	[min_dB REAL]           # minimal dB value (default: -51.0)
perex 37d715
 	[max_dB REAL]           # maximal dB value (default:   0.0)
perex 37d715
 	[resolution INT]        # resolution (default: 256)
perex 37d715
+				# resolution = 2 means a mute switch
perex 37d715
 }
perex 37d715
 \endcode
perex 37d715
 
perex 37d715
@@ -965,7 +992,7 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
perex 37d715
 		       MAX_DB_UPPER_LIMIT);
perex 37d715
 		return -EINVAL;
perex 37d715
 	}
perex 37d715
-	if (resolution < 0 || resolution > 1024) {
perex 37d715
+	if (resolution <= 1 || resolution > 1024) {
perex 37d715
 		SNDERR("Invalid resolution value %d", resolution);
perex 37d715
 		return -EINVAL;
perex 37d715
 	}
perex 37d715
-- 
perex 37d715
1.5.5.1
perex 37d715