NetBSD Problem Report #56552
From www@netbsd.org Wed Dec 15 21:36:24 2021
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id BF1AA1A9239
for <gnats-bugs@gnats.NetBSD.org>; Wed, 15 Dec 2021 21:36:23 +0000 (UTC)
Message-Id: <20211215213622.514A21A923A@mollari.NetBSD.org>
Date: Wed, 15 Dec 2021 21:36:22 +0000 (UTC)
From: rvp@SDF.ORG
Reply-To: rvp@SDF.ORG
To: gnats-bugs@NetBSD.org
Subject: mixerctl(1) does not increment volume with ++ or +=1
X-Send-Pr-Version: www-1.0
>Number: 56552
>Category: bin
>Synopsis: mixerctl(1) does not increment volume with ++ or +=1
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Dec 15 21:40:00 +0000 2021
>Last-Modified: Thu Dec 16 07:40:01 +0000 2021
>Originator: RVP
>Release: NetBSD/amd64 9.99.92
>Organization:
>Environment:
NetBSD x202e.localdomain 9.99.92 NetBSD 9.99.92 (MYKERNEL) #0: Mon Dec 13 03:43:43 UTC 2021 bld@x202e.localdomain:/usr/obj/usr/s
rc/sys/arch/amd64/compile/MYKERNEL amd64
>Description:
On my HW (VIA product 8446) the volume increment delta (5) seems to be
an open interval rather than a closed one, so I see this:
$ mixerctl -w outputs.master++
outputs.master: 162,162 -> 162,162
$ mixerctl -w outputs.master+=1
outputs.master: 162,162 -> 162,162
$
I have to use `+=2' to increment the volume by one "step". Decrementing
works OK however:
$ mixerctl -w outputs.master--
outputs.master: 162,162 -> 156,156
$ mixerctl -w outputs.master-=1
outputs.master: 156,156 -> 150,150
$
>How-To-Repeat:
As above.
>Fix:
Add one to ford interval:
diff -urN a/mixerctl.c b/mixerctl.c
--- a/mixerctl.c 2017-02-23 14:09:11.000000000 +0000
+++ b/mixerctl.c 2021-01-10 08:03:34.758061616 +0000
@@ -230,7 +230,7 @@
return 0;
case AUDIO_MIXER_VALUE:
if (p->infp->un.v.delta)
- inc *= p->infp->un.v.delta;
+ inc *= p->infp->un.v.delta + 1;
for (i = 0; i < m->un.value.num_channels; i++) {
v = m->un.value.level[i];
v += inc;
>Audit-Trail:
From: mlelstv@serpens.de (Michael van Elst)
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: bin/56552: mixerctl(1) does not increment volume with ++ or +=1
Date: Wed, 15 Dec 2021 23:24:22 -0000 (UTC)
rvp@SDF.ORG writes:
>On my HW (VIA product 8446) the volume increment delta (5) seems to be
>an open interval rather than a closed one, so I see this:
>
>$ mixerctl -w outputs.master++
>outputs.master: 162,162 -> 162,162
>$ mixerctl -w outputs.master+=1
>outputs.master: 162,162 -> 162,162
>$
>
>I have to use `+=2' to increment the volume by one "step". Decrementing
>works OK however:
>
>$ mixerctl -w outputs.master--
>outputs.master: 162,162 -> 156,156
>$ mixerctl -w outputs.master-=1
>outputs.master: 156,156 -> 150,150
>$
mixerctl just does what the driver tells it. If the driver says that
a 'step' is 5. Then it increments from 162 to 167 and decrements
from 162 to 157. Then it reads back the value from the driver.
HD-Audio computes the delta value as:
mx[index].mx_di.un.v.delta = 256 / (masterctl->ctl_step + 1);
where ctl_step is a value 0..127, denoting 1..128 volume settings.
So, with 43 to 51 settings (ctl_step=42..50), you get a delta value of 5.
When changing a value it computes the values like:
if (ctl->ctl_step == 0)
divisor = 128; /* ??? - just avoid div by 0 */
else
divisor = 255 / ctl->ctl_step;
hdafg_control_amp_set(ctl, HDAUDIO_AMP_MUTE_NONE,
mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] / divisor,
mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] / divisor);
But with 43 settings (ctl_step is then 42), the divisor is 6.
Reading back the value is done like:
if (ctl->ctl_step == 0)
factor = 128; /* ??? - just avoid div by 0 */
else
factor = 255 / ctl->ctl_step;
mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ctl->ctl_left * factor;
mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = ctl->ctl_right * factor;
So, with 43 settings:
delta = 5
incrementing 162 to 167
writing a hardware value of 167/6 = 27
reading back 27 and computing 27 *6 = 162
decrementing 162 to 157
writing a hardware value of 157/6 = 26
reading back 26 and computing 26 * 6 = 156
decrementing 156 to 151
writing a hardware value of 151/6 = 25
reading back 26 and computing 25 * 6 = 150
From: RVP <rvp@SDF.ORG>
To: gnats-bugs@netbsd.org
Cc: Michael van Elst <mlelstv@serpens.de>
Subject: Re: bin/56552: mixerctl(1) does not increment volume with ++ or
+=1
Date: Thu, 16 Dec 2021 07:38:17 +0000 (UTC)
On Wed, 15 Dec 2021, Michael van Elst wrote:
> HD-Audio computes the delta value as:
>
> mx[index].mx_di.un.v.delta = 256 / (masterctl->ctl_step + 1);
>
> [...]
>
> When changing a value it computes the values like:
>
> if (ctl->ctl_step == 0)
> divisor = 128; /* ??? - just avoid div by 0 */
> else
> divisor = 255 / ctl->ctl_step;
>
> hdafg_control_amp_set(ctl, HDAUDIO_AMP_MUTE_NONE,
> mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] / divisor,
> mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] / divisor);
>
> [...]
>
> Reading back the value is done like:
>
> if (ctl->ctl_step == 0)
> factor = 128; /* ??? - just avoid div by 0 */
> else
> factor = 255 / ctl->ctl_step;
>
> mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ctl->ctl_left * factor;
> mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = ctl->ctl_right * factor;
>
After that concise explanation it was pretty clear what had to be done:
---START---
--- sys/dev/hdaudio/hdafg.c.orig 2020-06-11 02:39:30.000000000 +0000
+++ sys/dev/hdaudio/hdafg.c 2021-12-16 07:04:54.341631494 +0000
@@ -2887,7 +2887,7 @@
mx[index].mx_di.prev = mx[index].mx_di.next = AUDIO_MIXER_LAST;
mx[index].mx_di.un.v.num_channels = 2; /* XXX */
mx[index].mx_di.mixer_class = HDAUDIO_MIXER_CLASS_OUTPUTS;
- mx[index].mx_di.un.v.delta = 256 / (masterctl->ctl_step + 1);
+ mx[index].mx_di.un.v.delta = 256 / (masterctl->ctl_step ? masterctl->ctl_step : 1);
strcpy(mx[index].mx_di.label.name, AudioNmaster);
strcpy(mx[index].mx_di.un.v.units.name, AudioNvolume);
hda_trace(sc, " adding outputs.%s\n",
@@ -2922,7 +2922,7 @@
mx[index].mx_di.type = AUDIO_MIXER_VALUE;
mx[index].mx_di.prev = mx[index].mx_di.next = AUDIO_MIXER_LAST;
mx[index].mx_di.un.v.num_channels = 2; /* XXX */
- mx[index].mx_di.un.v.delta = 256 / (ctl->ctl_step + 1);
+ mx[index].mx_di.un.v.delta = 256 / (ctl->ctl_step ? ctl->ctl_step : 1);
if (ctrlcnt[audiodev] > 0)
snprintf(mx[index].mx_di.label.name,
sizeof(mx[index].mx_di.label.name),
---END---
Now the mixerctl.c patch becomes:
---START---
diff -urN a/mixerctl.c b/mixerctl.c
--- a/mixerctl.c 2017-02-23 14:09:11.000000000 +0000
+++ b/mixerctl.c 2021-12-16 07:20:30.533031095 +0000
@@ -139,6 +139,16 @@
}
static int
+clamp(int vol)
+{
+ if (vol < AUDIO_MIN_GAIN)
+ vol = AUDIO_MIN_GAIN;
+ if (vol > AUDIO_MAX_GAIN)
+ vol = AUDIO_MAX_GAIN;
+ return vol;
+}
+
+static int
rdfield(struct field *p, char *q)
{
mixer_ctrl_t *m;
@@ -181,17 +191,17 @@
case AUDIO_MIXER_VALUE:
if (m->un.value.num_channels == 1) {
if (sscanf(q, "%d", &v) == 1) {
- m->un.value.level[0] = v;
+ m->un.value.level[0] = clamp(v);
} else {
warnx("Bad number %s", q);
return 0;
}
} else {
if (sscanf(q, "%d,%d", &v0, &v1) == 2) {
- m->un.value.level[0] = v0;
- m->un.value.level[1] = v1;
+ m->un.value.level[0] = clamp(v0);
+ m->un.value.level[1] = clamp(v1);
} else if (sscanf(q, "%d", &v) == 1) {
- m->un.value.level[0] = m->un.value.level[1] = v;
+ m->un.value.level[0] = m->un.value.level[1] = clamp(v);
} else {
warnx("Bad numbers %s", q);
return 0;
@@ -234,11 +244,7 @@
for (i = 0; i < m->un.value.num_channels; i++) {
v = m->un.value.level[i];
v += inc;
- if (v < AUDIO_MIN_GAIN)
- v = AUDIO_MIN_GAIN;
- if (v > AUDIO_MAX_GAIN)
- v = AUDIO_MAX_GAIN;
- m->un.value.level[i] = v;
+ m->un.value.level[i] = clamp(v);
}
break;
default:
---END---
I'm clamping the volume everywhere so there's no unwanted wraparound now:
$ ./mixerctl.new -w outputs.master++
outputs.master: 168,168 -> 174,174
$ ./mixerctl.new -w outputs.master+=1
outputs.master: 174,174 -> 180,180
$ ./mixerctl.new -w outputs.master=11111111
outputs.master: 180,180 -> 252,252
$ ./mixerctl.new -w outputs.master=-11111111
outputs.master: 252,252 -> 0,0
$
Thanks!
-RVP
(Contact us)
$NetBSD: query-full-pr,v 1.46 2020/01/03 16:35:01 leot Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2020
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.