Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/audio Implement auto recovery of the mixing volume.
details: https://anonhg.NetBSD.org/src/rev/f8a8f40355fb
branches: trunk
changeset: 962229:f8a8f40355fb
user: isaki <isaki%NetBSD.org@localhost>
date: Sat Jul 06 12:58:58 2019 +0000
description:
Implement auto recovery of the mixing volume.
diffstat:
sys/dev/audio/audio.c | 135 ++++++++++++++++++++++++++++------------------
sys/dev/audio/audiodef.h | 7 ++-
2 files changed, 89 insertions(+), 53 deletions(-)
diffs (202 lines):
diff -r a5c8ab10b450 -r f8a8f40355fb sys/dev/audio/audio.c
--- a/sys/dev/audio/audio.c Sat Jul 06 12:30:36 2019 +0000
+++ b/sys/dev/audio/audio.c Sat Jul 06 12:58:58 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: audio.c,v 1.22 2019/06/26 07:47:25 isaki Exp $ */
+/* $NetBSD: audio.c,v 1.23 2019/07/06 12:58:58 isaki Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -142,7 +142,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.22 2019/06/26 07:47:25 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.23 2019/07/06 12:58:58 isaki Exp $");
#ifdef _KERNEL_OPT
#include "audio.h"
@@ -593,6 +593,7 @@
static void audio_mixer_destroy(struct audio_softc *, audio_trackmixer_t *);
static void audio_pmixer_start(struct audio_softc *, bool);
static void audio_pmixer_process(struct audio_softc *);
+static void audio_pmixer_agc(audio_trackmixer_t *, int);
static int audio_pmixer_mix_track(audio_trackmixer_t *, audio_track_t *, int);
static void audio_pmixer_output(struct audio_softc *);
static int audio_pmixer_halt(struct audio_softc *);
@@ -2155,6 +2156,7 @@
if (sc->sc_popens == 0) {
mutex_enter(sc->sc_intr_lock);
sc->sc_pmixer->volume = 256;
+ sc->sc_pmixer->voltimer = 0;
mutex_exit(sc->sc_intr_lock);
}
}
@@ -4972,60 +4974,33 @@
memset(mixer->mixsample, 0,
frametobyte(&mixer->mixfmt, frame_count));
} else {
- aint2_t ovf_plus;
- aint2_t ovf_minus;
- int vol;
-
- /* Overflow detection */
- ovf_plus = AINT_T_MAX;
- ovf_minus = AINT_T_MIN;
- m = mixer->mixsample;
- for (i = 0; i < sample_count; i++) {
- aint2_t val;
-
- val = *m++;
- if (val > ovf_plus)
- ovf_plus = val;
- else if (val < ovf_minus)
- ovf_minus = val;
- }
-
- /* Master Volume Auto Adjust */
- vol = mixer->volume;
- if (ovf_plus > (aint2_t)AINT_T_MAX
- || ovf_minus < (aint2_t)AINT_T_MIN) {
- aint2_t ovf;
- int vol2;
-
- /* XXX TODO: Check AINT2_T_MIN ? */
- ovf = ovf_plus;
- if (ovf < -ovf_minus)
- ovf = -ovf_minus;
-
- /* Turn down the volume if overflow occured. */
- vol2 = (int)((aint2_t)AINT_T_MAX * 256 / ovf);
- if (vol2 < vol)
- vol = vol2;
-
- if (vol < mixer->volume) {
- /* Turn down gradually to 128. */
- if (mixer->volume > 128) {
- mixer->volume =
- (mixer->volume * 95) / 100;
- TRACE(2,
- "auto volume adjust: volume %d",
- mixer->volume);
- }
- }
- }
-
- /* Apply Master Volume. */
- if (vol != 256) {
+ if (mixed > 1) {
+ /* If there are multiple tracks, do auto gain control */
+ audio_pmixer_agc(mixer, sample_count);
+ }
+
+ /* Apply master volume */
+ if (mixer->volume < 256) {
m = mixer->mixsample;
for (i = 0; i < sample_count; i++) {
- *m = AUDIO_SCALEDOWN(*m * vol, 8);
+ *m = AUDIO_SCALEDOWN(*m * mixer->volume, 8);
m++;
}
+
+ /*
+ * Recover the volume gradually at the pace of
+ * several times per second. If it's too fast, you
+ * can recognize that the volume changes up and down
+ * quickly and it's not so comfortable.
+ */
+ mixer->voltimer += mixer->blktime_n;
+ if (mixer->voltimer * 4 >= mixer->blktime_d) {
+ mixer->volume++;
+ mixer->voltimer = 0;
+#if defined(AUDIO_DEBUG_AGC)
+ TRACE(1, "volume recover: %d", mixer->volume);
+#endif
+ }
}
}
@@ -5069,6 +5044,62 @@
}
/*
+ * Do auto gain control.
+ * Must be called sc_intr_lock held.
+ */
+static void
+audio_pmixer_agc(audio_trackmixer_t *mixer, int sample_count)
+{
+ struct audio_softc *sc __unused;
+ aint2_t val;
+ aint2_t maxval;
+ aint2_t minval;
+ aint2_t over_plus;
+ aint2_t over_minus;
+ aint2_t *m;
+ int newvol;
+ int i;
+
+ sc = mixer->sc;
+
+ /* Overflow detection */
+ maxval = AINT_T_MAX;
+ minval = AINT_T_MIN;
+ m = mixer->mixsample;
+ for (i = 0; i < sample_count; i++) {
+ val = *m++;
+ if (val > maxval)
+ maxval = val;
+ else if (val < minval)
+ minval = val;
+ }
+
+ /* Absolute value of overflowed amount */
+ over_plus = maxval - AINT_T_MAX;
+ over_minus = AINT_T_MIN - minval;
+
+ if (over_plus > 0 || over_minus > 0) {
+ if (over_plus > over_minus) {
+ newvol = (int)((aint2_t)AINT_T_MAX * 256 / maxval);
+ } else {
+ newvol = (int)((aint2_t)AINT_T_MIN * 256 / minval);
+ }
+
+ /*
+ * Change the volume only if new one is smaller.
+ * Reset the timer even if the volume isn't changed.
+ */
+ if (newvol <= mixer->volume) {
+ mixer->volume = newvol;
+ mixer->voltimer = 0;
+#if defined(AUDIO_DEBUG_AGC)
+ TRACE(1, "auto volume adjust: %d", mixer->volume);
+#endif
+ }
+ }
+}
+
+/*
* Mix one track.
* 'mixed' specifies the number of tracks mixed so far.
* It returns the number of tracks mixed. In other words, it returns
diff -r a5c8ab10b450 -r f8a8f40355fb sys/dev/audio/audiodef.h
--- a/sys/dev/audio/audiodef.h Sat Jul 06 12:30:36 2019 +0000
+++ b/sys/dev/audio/audiodef.h Sat Jul 06 12:58:58 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: audiodef.h,v 1.6 2019/06/26 06:57:45 isaki Exp $ */
+/* $NetBSD: audiodef.h,v 1.7 2019/07/06 12:58:58 isaki Exp $ */
/*
* Copyright (C) 2017 Tetsuya Isaki. All rights reserved.
@@ -214,6 +214,11 @@
* Must be protected by sc_intr_lock.
*/
u_int volume;
+ /*
+ * Volume recovery timer in auto gain control.
+ * Must be protected by sc_intr_lock.
+ */
+ int voltimer;
audio_format2_t mixfmt;
void *mixsample; /* mixing buf in double-sized int */
Home |
Main Index |
Thread Index |
Old Index