All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] TLV entry for linear volume
@ 2006-08-23 13:52 Takashi Iwai
  2006-08-23 15:07 ` James Courtier-Dutton
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2006-08-23 13:52 UTC (permalink / raw)
  To: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 305 bytes --]

Hi,

some codecs and dsp chips use linear volumes instead of logarithmic
one.  The patch below adds a new TLV type for such a volume type.
In alsa-lib, it's converted to dB on the fly.

If no one has objection, I'll push it together with AC97-TLV and
other similar patches after 1.0.12 release.


Takashi

[-- Attachment #2: tlv-linear-kernel.diff --]
[-- Type: application/octet-stream, Size: 733 bytes --]

diff -r d8d32c66f4f5 include/tlv.h
--- a/include/tlv.h	Wed Aug 23 13:07:19 2006 +0200
+++ b/include/tlv.h	Wed Aug 23 12:47:04 2006 +0200
@@ -33,6 +33,7 @@
 
 #define SNDRV_CTL_TLVT_CONTAINER 0	/* one level down - group of TLVs */
 #define SNDRV_CTL_TLVT_DB_SCALE	1       /* dB scale */
+#define SNDRV_CTL_TLVT_DB_LINEAR 2	/* linear volume */
 
 #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
 unsigned int name[] = { \
@@ -40,4 +41,10 @@ unsigned int name[] = { \
         (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0) \
 }
 
+#define DECLARE_TLV_DB_LINEAR(name, min, max) \
+unsigned int name[] = { \
+        SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \
+        (min), (max) \
+}
+
 #endif /* __SOUND_TLV_H */

[-- Attachment #3: tlv-linear-lib.diff --]
[-- Type: application/octet-stream, Size: 1915 bytes --]

diff -r 2728d2269be9 include/control.h
--- a/include/control.h	Wed Aug 23 15:44:09 2006 +0200
+++ b/include/control.h	Wed Aug 23 15:44:23 2006 +0200
@@ -170,6 +170,8 @@ typedef enum _snd_ctl_event_type {
 #define SND_CTL_TLVT_CONTAINER		0x0000
 /** TLV type - basic dB scale */
 #define SND_CTL_TLVT_DB_SCALE		0x0001
+/** TLV type - linear volume */
+#define SND_CTL_TLVT_DB_LINEAR		0x0002
 
 /** CTL type */
 typedef enum _snd_ctl_type {
diff -r 2728d2269be9 src/mixer/simple_none.c
--- a/src/mixer/simple_none.c	Wed Aug 23 15:44:09 2006 +0200
+++ b/src/mixer/simple_none.c	Wed Aug 23 15:53:02 2006 +0200
@@ -1014,6 +1014,9 @@ static int parse_db_range(struct selem_s
 		}
 		break;
 	case SND_CTL_TLVT_DB_SCALE:
+#ifndef HAVE_SOFT_FLOAT
+	case SND_CTL_TLVT_DB_LINEAR:
+#endif
 		rec->db_info = malloc(size + sizeof(int) * 2);
 		if (! rec->db_info)
 			return -ENOMEM;
@@ -1027,20 +1030,38 @@ static int parse_db_range(struct selem_s
 
 /* convert the given raw volume value to a dB gain
  */
+
+#define MIN_DB_GAIN	-9999999	/* should be in the public header? */
+
 static int convert_db_range(struct selem_str *rec, long volume, long *db_gain)
 {
-	int min, step, mute;
-
 	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];
 		step = (rec->db_info[3] & 0xffff);
 		mute = (rec->db_info[3] >> 16) & 1;
 		if (mute && volume == rec->min)
-			*db_gain = -9999999;
+			*db_gain = MIN_DB_GAIN;
 		else
 			*db_gain = (volume - rec->min) * step + min;
 		return 0;
+	}
+#ifndef HAVE_SOFT_FLOAT
+	case SND_CTL_TLVT_DB_LINEAR: {
+		int min, max;
+		if (volume <= rec->min)
+			*db_gain = MIN_DB_GAIN;
+		else {
+			min = rec->db_info[2];
+			max = rec->db_info[3];
+			*db_gain = (long)(100.0 * 20.0 *
+					  log10((double)(volume - rec->min) /
+						(double)(max - min)));
+		}
+		return 0;
+	}
+#endif
 	}
 	return -EINVAL;
 }

[-- Attachment #4: Type: text/plain, Size: 373 bytes --]

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

[-- Attachment #5: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-23 13:52 [RFC] TLV entry for linear volume Takashi Iwai
@ 2006-08-23 15:07 ` James Courtier-Dutton
  2006-08-23 15:31   ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: James Courtier-Dutton @ 2006-08-23 15:07 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

Takashi Iwai wrote:
> Hi,
>
> some codecs and dsp chips use linear volumes instead of logarithmic
> one.  The patch below adds a new TLV type for such a volume type.
> In alsa-lib, it's converted to dB on the fly.
>
> If no one has objection, I'll push it together with AC97-TLV and
> other similar patches after 1.0.12 release.
>
>
> Takashi
>   
I have not had time to look at the AC97-TLV, but if it works, I can't 
see why I would object.

I have never come across a sound card with linear volumes.
Could you identify a few of them, and also better explain the formula 
you are using for the conversion to dB gain.
*db_gain = (long)(100.0 * 20.0 *
                      log10((double)(volume - rec->min) /
                        (double)(max - min)));

So, 0 dB is when (volume - rec->min) / (max - min) == 1
So, for +6 dB gain, the volume will need to be higher than max?
Does this sound right? In that case, maybe "max" is not a good name for 
it because volume can be greater than max.

James




-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-23 15:07 ` James Courtier-Dutton
@ 2006-08-23 15:31   ` Takashi Iwai
  2006-08-23 17:09     ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2006-08-23 15:31 UTC (permalink / raw)
  To: James Courtier-Dutton; +Cc: alsa-devel

At Wed, 23 Aug 2006 16:07:02 +0100,
James Courtier-Dutton wrote:
> 
> Takashi Iwai wrote:
> > Hi,
> >
> > some codecs and dsp chips use linear volumes instead of logarithmic
> > one.  The patch below adds a new TLV type for such a volume type.
> > In alsa-lib, it's converted to dB on the fly.
> >
> > If no one has objection, I'll push it together with AC97-TLV and
> > other similar patches after 1.0.12 release.
> >
> >
> > Takashi
> >   
> I have not had time to look at the AC97-TLV, but if it works, I can't 
> see why I would object.

OK.

> I have never come across a sound card with linear volumes.

Some AK codecs use linear volumes.  Also, YMFPCI DSP use for its
native volume controls.

> Could you identify a few of them, and also better explain the formula 
> you are using for the conversion to dB gain.
> *db_gain = (long)(100.0 * 20.0 *
>                       log10((double)(volume - rec->min) /
>                         (double)(max - min)));

A standard definition of dB (and x100 for alsa-lib unit).

> So, 0 dB is when (volume - rec->min) / (max - min) == 1
> So, for +6 dB gain, the volume will need to be higher than max?
> Does this sound right? In that case, maybe "max" is not a good name for 
> it because volume can be greater than max.

Hm, right, I didn't think of overload case with a linear volume
codec.  By min and max, I thought of a "segment" between mute and
0dB (although not implemented rightly in alsa-lib).

Maybe min and max should be in (0.01) dB expressions since the min and
max "values" are known from snd_ctl_elem_info.  The only problem is
that we have no standard definition of "mute" in dB expression.
In alsa-lib, -9999999 indicates mute.  But it should be defined as a
constant in a public header.


Takashi

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-23 15:31   ` Takashi Iwai
@ 2006-08-23 17:09     ` Takashi Iwai
  2006-08-23 18:22       ` James Courtier-Dutton
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2006-08-23 17:09 UTC (permalink / raw)
  To: James Courtier-Dutton; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1015 bytes --]

At Wed, 23 Aug 2006 17:31:10 +0200,
I wrote:
> 
> > So, 0 dB is when (volume - rec->min) / (max - min) == 1
> > So, for +6 dB gain, the volume will need to be higher than max?
> > Does this sound right? In that case, maybe "max" is not a good name for 
> > it because volume can be greater than max.
> 
> Hm, right, I didn't think of overload case with a linear volume
> codec.  By min and max, I thought of a "segment" between mute and
> 0dB (although not implemented rightly in alsa-lib).
> 
> Maybe min and max should be in (0.01) dB expressions since the min and
> max "values" are known from snd_ctl_elem_info.  The only problem is
> that we have no standard definition of "mute" in dB expression.
> In alsa-lib, -9999999 indicates mute.  But it should be defined as a
> constant in a public header.

It turned out that minimal dB makes the computation too complicated,
and chips are very likely from mute to a certain dB.  So, I decided to
drop the min dB there.

The below are the revised patches.


Takashi

[-- Attachment #2: tlv-linear-kernel2.diff --]
[-- Type: application/octet-stream, Size: 774 bytes --]

diff -r 2df0d1a21cc9 include/tlv.h
--- a/include/tlv.h	Wed Aug 23 18:35:35 2006 +0200
+++ b/include/tlv.h	Wed Aug 23 18:56:49 2006 +0200
@@ -33,6 +33,7 @@
 
 #define SNDRV_CTL_TLVT_CONTAINER 0	/* one level down - group of TLVs */
 #define SNDRV_CTL_TLVT_DB_SCALE	1       /* dB scale */
+#define SNDRV_CTL_TLVT_DB_LINEAR 2	/* linear volume */
 
 #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
 unsigned int name[] = { \
@@ -40,4 +41,11 @@ unsigned int name[] = { \
         (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0) \
 }
 
+/* linear volume between mute - max_dB (.01dB) */
+#define DECLARE_TLV_DB_LINEAR(name, max_dB) \
+unsigned int name[] = { \
+        SNDRV_CTL_TLVT_DB_LINEAR, sizeof(unsigned int), \
+        (max_dB) \
+}
+
 #endif /* __SOUND_TLV_H */

[-- Attachment #3: tlv-linear-lib2.diff --]
[-- Type: application/octet-stream, Size: 1966 bytes --]

diff -r 2728d2269be9 include/control.h
--- a/include/control.h	Wed Aug 23 15:44:09 2006 +0200
+++ b/include/control.h	Wed Aug 23 15:44:23 2006 +0200
@@ -170,6 +170,8 @@ typedef enum _snd_ctl_event_type {
 #define SND_CTL_TLVT_CONTAINER		0x0000
 /** TLV type - basic dB scale */
 #define SND_CTL_TLVT_DB_SCALE		0x0001
+/** TLV type - linear volume */
+#define SND_CTL_TLVT_DB_LINEAR		0x0002
 
 /** CTL type */
 typedef enum _snd_ctl_type {
diff -r 2728d2269be9 src/mixer/simple_none.c
--- a/src/mixer/simple_none.c	Wed Aug 23 15:44:09 2006 +0200
+++ b/src/mixer/simple_none.c	Wed Aug 23 18:59:43 2006 +0200
@@ -1014,6 +1014,9 @@ static int parse_db_range(struct selem_s
 		}
 		break;
 	case SND_CTL_TLVT_DB_SCALE:
+#ifndef HAVE_SOFT_FLOAT
+	case SND_CTL_TLVT_DB_LINEAR:
+#endif
 		rec->db_info = malloc(size + sizeof(int) * 2);
 		if (! rec->db_info)
 			return -ENOMEM;
@@ -1027,20 +1030,39 @@ static int parse_db_range(struct selem_s
 
 /* convert the given raw volume value to a dB gain
  */
+
+#define MIN_DB_GAIN	-9999999	/* should be in the public header? */
+
 static int convert_db_range(struct selem_str *rec, long volume, long *db_gain)
 {
-	int min, step, mute;
-
 	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];
 		step = (rec->db_info[3] & 0xffff);
 		mute = (rec->db_info[3] >> 16) & 1;
 		if (mute && volume == rec->min)
-			*db_gain = -9999999;
+			*db_gain = MIN_DB_GAIN;
 		else
 			*db_gain = (volume - rec->min) * step + min;
 		return 0;
+	}
+#ifndef HAVE_SOFT_FLOAT
+	case SND_CTL_TLVT_DB_LINEAR: {
+		int maxdb = rec->db_info[2];
+		if (volume <= rec->min)
+			*db_gain = MIN_DB_GAIN;
+		else if (rec->max <= rec->min)
+			*db_gain = maxdb;
+		else {
+			*db_gain = (long)(100.0 * 20.0 * 
+					  log10((double)(volume - rec->min) /
+						(double)(rec->max - rec->min)));
+			*db_gain += maxdb;
+		}
+		return 0;
+	}
+#endif
 	}
 	return -EINVAL;
 }

[-- Attachment #4: Type: text/plain, Size: 373 bytes --]

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

[-- Attachment #5: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-23 17:09     ` Takashi Iwai
@ 2006-08-23 18:22       ` James Courtier-Dutton
  2006-08-23 18:34         ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: James Courtier-Dutton @ 2006-08-23 18:22 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

Takashi Iwai wrote:
> At Wed, 23 Aug 2006 17:31:10 +0200,
> I wrote:
>   
>>> So, 0 dB is when (volume - rec->min) / (max - min) == 1
>>> So, for +6 dB gain, the volume will need to be higher than max?
>>> Does this sound right? In that case, maybe "max" is not a good name for 
>>> it because volume can be greater than max.
>>>       
>> Hm, right, I didn't think of overload case with a linear volume
>> codec.  By min and max, I thought of a "segment" between mute and
>> 0dB (although not implemented rightly in alsa-lib).
>>
>> Maybe min and max should be in (0.01) dB expressions since the min and
>> max "values" are known from snd_ctl_elem_info.  The only problem is
>> that we have no standard definition of "mute" in dB expression.
>> In alsa-lib, -9999999 indicates mute.  But it should be defined as a
>> constant in a public header.
>>     
>
> It turned out that minimal dB makes the computation too complicated,
> and chips are very likely from mute to a certain dB.  So, I decided to
> drop the min dB there.
>
> The below are the revised patches.
>
>
> Takashi
>   
I think you will find that your second approach is still wrong.
You need to first identify the 0dB point, and then the scale factor and 
offset value for the linear component before the log10 conversion.
So, linear to log should be something like:
20log10 ((linear / scale) - offset)
I.e. the offset taken before the log10 operation, not afterwards as is 
shown in your code:
*db_gain = (long)(100.0 * 20.0 *
                      log10((double)(volume - rec->min) /
                        (double)(rec->max - rec->min)));
*db_gain += maxdb;

Then check the equation by finding the linear value that equates to:
0dB, so that ((linear / scale) - offset) == 1 * original signal voltage
6dB, so that ((linear / scale) - offset) == 2 * original signal voltage
-6dB, so that ((linear / scale) - offset) == 0.5 * original signal voltage

This is assuming that the linear values affect the voltage, and not the 
power.

So, you need to pass from driver to userspace the value of "scale" and 
"offset", together with maybe one bit to identify if the minimum value 
of the "linear" is mute or not.

James


-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-23 18:22       ` James Courtier-Dutton
@ 2006-08-23 18:34         ` Takashi Iwai
  2006-08-23 23:48           ` James Courtier-Dutton
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2006-08-23 18:34 UTC (permalink / raw)
  To: James Courtier-Dutton; +Cc: alsa-devel

At Wed, 23 Aug 2006 19:22:37 +0100,
James Courtier-Dutton wrote:
> 
> Takashi Iwai wrote:
> > At Wed, 23 Aug 2006 17:31:10 +0200,
> > I wrote:
> >   
> >>> So, 0 dB is when (volume - rec->min) / (max - min) == 1
> >>> So, for +6 dB gain, the volume will need to be higher than max?
> >>> Does this sound right? In that case, maybe "max" is not a good name for 
> >>> it because volume can be greater than max.
> >>>       
> >> Hm, right, I didn't think of overload case with a linear volume
> >> codec.  By min and max, I thought of a "segment" between mute and
> >> 0dB (although not implemented rightly in alsa-lib).
> >>
> >> Maybe min and max should be in (0.01) dB expressions since the min and
> >> max "values" are known from snd_ctl_elem_info.  The only problem is
> >> that we have no standard definition of "mute" in dB expression.
> >> In alsa-lib, -9999999 indicates mute.  But it should be defined as a
> >> constant in a public header.
> >>     
> >
> > It turned out that minimal dB makes the computation too complicated,
> > and chips are very likely from mute to a certain dB.  So, I decided to
> > drop the min dB there.
> >
> > The below are the revised patches.
> >
> >
> > Takashi
> >   
> I think you will find that your second approach is still wrong.
> You need to first identify the 0dB point, and then the scale factor and 
> offset value for the linear component before the log10 conversion.
> So, linear to log should be something like:
> 20log10 ((linear / scale) - offset)

What is linear and scale here?

In my case, the calculation is so simple as below.

The value y at x [0,max] is

   y = (x / max) * maxVal

where maxVal = 10^(maxdB/20)

so, in dB expression,

  Y = 20 * log10(y) = 20 * log10((x / max) * 10^(maxdB/20))
    = 20 * log10(x/max) + maxdB


Takashi

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-23 18:34         ` Takashi Iwai
@ 2006-08-23 23:48           ` James Courtier-Dutton
  2006-08-24  9:16             ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: James Courtier-Dutton @ 2006-08-23 23:48 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

Takashi Iwai wrote:
> At Wed, 23 Aug 2006 19:22:37 +0100,
> James Courtier-Dutton wrote:
>> Takashi Iwai wrote:
>>> At Wed, 23 Aug 2006 17:31:10 +0200,
>>> I wrote:
>>>   
>>>>> So, 0 dB is when (volume - rec->min) / (max - min) == 1
>>>>> So, for +6 dB gain, the volume will need to be higher than max?
>>>>> Does this sound right? In that case, maybe "max" is not a good name for 
>>>>> it because volume can be greater than max.
>>>>>       
>>>> Hm, right, I didn't think of overload case with a linear volume
>>>> codec.  By min and max, I thought of a "segment" between mute and
>>>> 0dB (although not implemented rightly in alsa-lib).
>>>>
>>>> Maybe min and max should be in (0.01) dB expressions since the min and
>>>> max "values" are known from snd_ctl_elem_info.  The only problem is
>>>> that we have no standard definition of "mute" in dB expression.
>>>> In alsa-lib, -9999999 indicates mute.  But it should be defined as a
>>>> constant in a public header.
>>>>     
>>> It turned out that minimal dB makes the computation too complicated,
>>> and chips are very likely from mute to a certain dB.  So, I decided to
>>> drop the min dB there.
>>>
>>> The below are the revised patches.
>>>
>>>
>>> Takashi
>>>   
>> I think you will find that your second approach is still wrong.
>> You need to first identify the 0dB point, and then the scale factor and 
>> offset value for the linear component before the log10 conversion.
>> So, linear to log should be something like:
>> 20log10 ((linear / scale) - offset)
> 
> What is linear and scale here?
I explain that in the rest of my email.
but I will repeat differently:
"linear" is your X value that the hardware requires, that you say is a
linear scale and not a log10 scale.
"scale" is some multiplier to convert the integer X value into some
floating point value. Together with an offset value to reach the correct
0db, +6dB and -6dB gain points.

> 
> In my case, the calculation is so simple as below.
> 
> The value y at x [0,max] is
> 
>    y = (x / max) * maxVal
> 
> where maxVal = 10^(maxdB/20)
> 
> so, in dB expression,
> 
>   Y = 20 * log10(y) = 20 * log10((x / max) * 10^(maxdB/20))
>     = 20 * log10(x/max) + maxdB
> 
> 
> Takashi

It is unclear from your equation where the 0dB point is.
>From your equation, when x = max( i.e. what I would expect to be the 0dB
point as a result of comments by you in previous emails), one reaches
the maxdB point, and not the 0dB point. Getting the 0dB point on the
log10 curve is very important, otherwise the conversion from linear to
dB occurs at the wrong point on the log10 curve, resulting in the dB
values all being wrong.
Remember, these dB values are dB GAIN, not absolute dB levels.

James



-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-23 23:48           ` James Courtier-Dutton
@ 2006-08-24  9:16             ` Takashi Iwai
  2006-08-25 10:23               ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2006-08-24  9:16 UTC (permalink / raw)
  To: James Courtier-Dutton; +Cc: alsa-devel

At Thu, 24 Aug 2006 00:48:25 +0100,
James Courtier-Dutton wrote:
> 
> Takashi Iwai wrote:
> > At Wed, 23 Aug 2006 19:22:37 +0100,
> > James Courtier-Dutton wrote:
> >> Takashi Iwai wrote:
> >>> At Wed, 23 Aug 2006 17:31:10 +0200,
> >>> I wrote:
> >>>   
> >>>>> So, 0 dB is when (volume - rec->min) / (max - min) == 1
> >>>>> So, for +6 dB gain, the volume will need to be higher than max?
> >>>>> Does this sound right? In that case, maybe "max" is not a good name for 
> >>>>> it because volume can be greater than max.
> >>>>>       
> >>>> Hm, right, I didn't think of overload case with a linear volume
> >>>> codec.  By min and max, I thought of a "segment" between mute and
> >>>> 0dB (although not implemented rightly in alsa-lib).
> >>>>
> >>>> Maybe min and max should be in (0.01) dB expressions since the min and
> >>>> max "values" are known from snd_ctl_elem_info.  The only problem is
> >>>> that we have no standard definition of "mute" in dB expression.
> >>>> In alsa-lib, -9999999 indicates mute.  But it should be defined as a
> >>>> constant in a public header.
> >>>>     
> >>> It turned out that minimal dB makes the computation too complicated,
> >>> and chips are very likely from mute to a certain dB.  So, I decided to
> >>> drop the min dB there.
> >>>
> >>> The below are the revised patches.
> >>>
> >>>
> >>> Takashi
> >>>   
> >> I think you will find that your second approach is still wrong.
> >> You need to first identify the 0dB point, and then the scale factor and 
> >> offset value for the linear component before the log10 conversion.
> >> So, linear to log should be something like:
> >> 20log10 ((linear / scale) - offset)
> > 
> > What is linear and scale here?
> I explain that in the rest of my email.
> but I will repeat differently:
> "linear" is your X value that the hardware requires, that you say is a
> linear scale and not a log10 scale.
> "scale" is some multiplier to convert the integer X value into some
> floating point value. Together with an offset value to reach the correct
> 0db, +6dB and -6dB gain points.

But scale cannot be accurately expressed if the value range is small.
I don't think this manual calculation would make the programer
happier.

Actually, my assumption that the minimum value is always mute is
wrong.  There are real cases starting from non-mute.  Hence, passing
min_dB and max_dB is the best solution from the driver side.
It results in a little bit more computation in alsa-lib side in the
case min_dB != mute.  (When min_dB = mute, it's easy as I showed.)
min_dB != mute is anyway a rare case, and can be easily optimized by
precalculating the coefficients if necessary.


> > In my case, the calculation is so simple as below.
> > 
> > The value y at x [0,max] is
> > 
> >    y = (x / max) * maxVal
> > 
> > where maxVal = 10^(maxdB/20)
> > 
> > so, in dB expression,
> > 
> >   Y = 20 * log10(y) = 20 * log10((x / max) * 10^(maxdB/20))
> >     = 20 * log10(x/max) + maxdB
> > 
> > 
> > Takashi
> 
> It is unclear from your equation where the 0dB point is.

0dB point doesn't have to be defined strictly.  See below.

> From your equation, when x = max( i.e. what I would expect to be the 0dB
> point as a result of comments by you in previous emails), one reaches
> the maxdB point, and not the 0dB point. Getting the 0dB point on the
> log10 curve is very important, otherwise the conversion from linear to
> dB occurs at the wrong point on the log10 curve, resulting in the dB
> values all being wrong.

Sorry but how bad?  Put values in the real word there.

As a counter example to your case, imagine a volume range from +1dB to
+15dB in [0, 255].  This is a preamp and routed only when a switch is
on, so no 0dB crossing.  How would you calculate the 0dB point and how
would you express it in integer?

The difference between us is just how to express and pass the
coefficeints.  My suggestion is to pass the values given in the
datasheet as they are, min and max dB.


Takashi

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-24  9:16             ` Takashi Iwai
@ 2006-08-25 10:23               ` Takashi Iwai
  2006-08-25 16:27                 ` James Courtier-Dutton
  0 siblings, 1 reply; 11+ messages in thread
From: Takashi Iwai @ 2006-08-25 10:23 UTC (permalink / raw)
  To: James Courtier-Dutton; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 309 bytes --]

At Thu, 24 Aug 2006 11:16:45 +0200,
I wrote:
> 
> The difference between us is just how to express and pass the
> coefficeints.  My suggestion is to pass the values given in the
> datasheet as they are, min and max dB.

The below is the latest version I have on my local tree.
It's against HG tree.


Takashi

[-- Attachment #2: kernel-tlv-fix.diff --]
[-- Type: application/octet-stream, Size: 1872 bytes --]

diff -r 758522076155 include/tlv.h
--- a/include/tlv.h	Thu Aug 24 12:36:36 2006 +0200
+++ b/include/tlv.h	Thu Aug 24 12:49:38 2006 +0200
@@ -33,6 +33,7 @@
 
 #define SNDRV_CTL_TLVT_CONTAINER 0	/* one level down - group of TLVs */
 #define SNDRV_CTL_TLVT_DB_SCALE	1       /* dB scale */
+#define SNDRV_CTL_TLVT_DB_LINEAR 2	/* linear volume */
 
 #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
 unsigned int name[] = { \
@@ -40,4 +41,13 @@ unsigned int name[] = { \
         (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0) \
 }
 
+/* linear volume between min_dB and max_dB (.01dB unit) */
+#define DECLARE_TLV_DB_LINEAR(name, min_dB, max_dB)	\
+unsigned int name[] = { \
+        SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \
+        (min_dB), (max_dB)				\
+}
+
+#define TLV_DB_GAIN_MUTE	-9999999
+
 #endif /* __SOUND_TLV_H */
diff -r 758522076155 pci/ymfpci/ymfpci_main.c
--- a/pci/ymfpci/ymfpci_main.c	Thu Aug 24 12:36:36 2006 +0200
+++ b/pci/ymfpci/ymfpci_main.c	Thu Aug 24 12:49:37 2006 +0200
@@ -36,6 +36,7 @@
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
+#include <sound/tlv.h>
 #include <sound/ymfpci.h>
 #include <sound/asoundef.h>
 #include <sound/mpu401.h>
@@ -1477,11 +1478,15 @@ static int snd_ymfpci_put_single(struct 
 	return change;
 }
 
+static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0);
+
 #define YMFPCI_DOUBLE(xname, xindex, reg) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
   .info = snd_ymfpci_info_double, \
   .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \
-  .private_value = reg }
+  .private_value = reg, \
+  .tlv = { .p = db_scale_native } }
 
 static int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {

[-- Attachment #3: linear-tlv.diff --]
[-- Type: application/octet-stream, Size: 3537 bytes --]

diff -r b64f7b87c52c include/control.h
--- a/include/control.h	Fri Aug 25 11:56:50 2006 +0200
+++ b/include/control.h	Fri Aug 25 12:02:57 2006 +0200
@@ -170,6 +170,11 @@ typedef enum _snd_ctl_event_type {
 #define SND_CTL_TLVT_CONTAINER		0x0000
 /** TLV type - basic dB scale */
 #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 */
 typedef enum _snd_ctl_type {
diff -r b64f7b87c52c src/mixer/simple_none.c
--- a/src/mixer/simple_none.c	Fri Aug 25 11:56:50 2006 +0200
+++ b/src/mixer/simple_none.c	Fri Aug 25 12:03:04 2006 +0200
@@ -1008,6 +1008,13 @@ static int parse_db_range(struct selem_s
 		}
 		break;
 	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);
 		if (! rec->db_info)
 			return -ENOMEM;
@@ -1025,21 +1032,46 @@ static int convert_to_dB(snd_hctl_elem_t
 static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
 			 long volume, long *db_gain)
 {
-	int min, step, mute;
-
 	if (init_db_range(ctl, rec) < 0)
 		return -EINVAL;
 
 	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];
 		step = (rec->db_info[3] & 0xffff);
 		mute = (rec->db_info[3] >> 16) & 1;
 		if (mute && volume == rec->min)
-			*db_gain = -9999999;
+			*db_gain = SND_CTL_TLV_DB_GAIN_MUTE;
 		else
 			*db_gain = (volume - rec->min) * step + min;
 		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;
 }
@@ -1114,6 +1146,10 @@ static int get_dB_range(snd_hctl_elem_t 
 		*min = (int)rec->db_info[2];
 		step = (rec->db_info[3] & 0xffff);
 		*max = *min + (long)(step * (rec->max - rec->min));
+		return 0;
+	case SND_CTL_TLVT_DB_LINEAR:
+		*min = (int)rec->db_info[2];
+		*max = (int)rec->db_info[3];
 		return 0;
 	}
 	return -EINVAL;
@@ -1160,6 +1196,30 @@ static int convert_from_dB(snd_hctl_elem
 		}
 		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:
 		break;
 	}

[-- Attachment #4: Type: text/plain, Size: 373 bytes --]

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

[-- Attachment #5: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-25 10:23               ` Takashi Iwai
@ 2006-08-25 16:27                 ` James Courtier-Dutton
  2006-08-28 10:00                   ` Takashi Iwai
  0 siblings, 1 reply; 11+ messages in thread
From: James Courtier-Dutton @ 2006-08-25 16:27 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

Takashi Iwai wrote:
> At Thu, 24 Aug 2006 11:16:45 +0200,
> I wrote:
>   
>> The difference between us is just how to express and pass the
>> coefficeints.  My suggestion is to pass the values given in the
>> datasheet as they are, min and max dB.
>>     
>
> The below is the latest version I have on my local tree.
> It's against HG tree.
>
>
> Takashi
>   
+#ifndef HAVE_SOFT_FLOAT
+    case SND_CTL_TLVT_DB_LINEAR: {
+        int mindb = rec->db_info[2];
+        int maxdb = rec->db_info[3];
Maybe I am unclear about what rec->min is, but I though that it was the 
lowest value the volume(old % scale) could be.
So, what exactly is this section trying to do? Just handling error cases?
+        if (volume <= rec->min || rec->max <= rec->min)
+            *db_gain = mindb;
+        else if (volume >= rec->max)
+            *db_gain = maxdb;
+        else {

This makes sense. (part A), when combined with (part B)
+            double val = (double)(volume - rec->min) /
+                (double)(rec->max - rec->min);

This special case is for when mindb = negative infinity.
+            if (mindb <= SND_CTL_TLV_DB_GAIN_MUTE)
+                *db_gain = (long)(100.0 * 20.0 * log10(val)) +
+                    maxdb;
+            else {

This makes sense. (Part B) when combined with (Part A)
It covers a good general case of mapping (linear_min...linear_max) onto 
(dB_min...dB_max)
+                /* 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


Summary, I am happy with this now.

James


-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] TLV entry for linear volume
  2006-08-25 16:27                 ` James Courtier-Dutton
@ 2006-08-28 10:00                   ` Takashi Iwai
  0 siblings, 0 replies; 11+ messages in thread
From: Takashi Iwai @ 2006-08-28 10:00 UTC (permalink / raw)
  To: James Courtier-Dutton; +Cc: alsa-devel

At Fri, 25 Aug 2006 17:27:12 +0100,
James Courtier-Dutton wrote:
> 
> Takashi Iwai wrote:
> > At Thu, 24 Aug 2006 11:16:45 +0200,
> > I wrote:
> >   
> >> The difference between us is just how to express and pass the
> >> coefficeints.  My suggestion is to pass the values given in the
> >> datasheet as they are, min and max dB.
> >>     
> >
> > The below is the latest version I have on my local tree.
> > It's against HG tree.
> >
> >
> > Takashi
> >   
> +#ifndef HAVE_SOFT_FLOAT
> +    case SND_CTL_TLVT_DB_LINEAR: {
> +        int mindb = rec->db_info[2];
> +        int maxdb = rec->db_info[3];
> Maybe I am unclear about what rec->min is, but I though that it was the 
> lowest value the volume(old % scale) could be.
> So, what exactly is this section trying to do? Just handling error cases?
> +        if (volume <= rec->min || rec->max <= rec->min)
> +            *db_gain = mindb;
> +        else if (volume >= rec->max)
> +            *db_gain = maxdb;
> +        else {

Yes.  The edge condition is also a special case that you can handle
easily.

> 
> This makes sense. (part A), when combined with (part B)
> +            double val = (double)(volume - rec->min) /
> +                (double)(rec->max - rec->min);
> 
> This special case is for when mindb = negative infinity.
> +            if (mindb <= SND_CTL_TLV_DB_GAIN_MUTE)
> +                *db_gain = (long)(100.0 * 20.0 * log10(val)) +
> +                    maxdb;
> +            else {
> 
> This makes sense. (Part B) when combined with (Part A)
> It covers a good general case of mapping (linear_min...linear_max) onto 
> (dB_min...dB_max)
> +                /* 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
> 
> 
> Summary, I am happy with this now.

Great :)

I'll commit the patch later, then.


Takashi

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2006-08-28 10:00 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-23 13:52 [RFC] TLV entry for linear volume Takashi Iwai
2006-08-23 15:07 ` James Courtier-Dutton
2006-08-23 15:31   ` Takashi Iwai
2006-08-23 17:09     ` Takashi Iwai
2006-08-23 18:22       ` James Courtier-Dutton
2006-08-23 18:34         ` Takashi Iwai
2006-08-23 23:48           ` James Courtier-Dutton
2006-08-24  9:16             ` Takashi Iwai
2006-08-25 10:23               ` Takashi Iwai
2006-08-25 16:27                 ` James Courtier-Dutton
2006-08-28 10:00                   ` Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.