Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/audio Add 24bit/32bit hardware support.



details:   https://anonhg.NetBSD.org/src/rev/5f2caee354db
branches:  trunk
changeset: 374447:5f2caee354db
user:      mlelstv <mlelstv%NetBSD.org@localhost>
date:      Sun Apr 23 08:05:36 2023 +0000

description:
Add 24bit/32bit hardware support.

diffstat:

 sys/dev/audio/audio.c |  178 ++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 144 insertions(+), 34 deletions(-)

diffs (252 lines):

diff -r c4279e2f5fa8 -r 5f2caee354db sys/dev/audio/audio.c
--- a/sys/dev/audio/audio.c     Sun Apr 23 07:03:30 2023 +0000
+++ b/sys/dev/audio/audio.c     Sun Apr 23 08:05:36 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: audio.c,v 1.139 2023/04/23 06:30:58 mlelstv Exp $      */
+/*     $NetBSD: audio.c,v 1.140 2023/04/23 08:05:36 mlelstv Exp $      */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -181,7 +181,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.139 2023/04/23 06:30:58 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.140 2023/04/23 08:05:36 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "audio.h"
@@ -697,6 +697,8 @@ static int au_get_monitor_gain(struct au
 static int audio_get_port(struct audio_softc *, mixer_ctrl_t *);
 static int audio_set_port(struct audio_softc *, mixer_ctrl_t *);
 
+void audio_mixsample_to_linear(audio_filter_arg_t *);
+
 static __inline struct audio_params
 format2_to_params(const audio_format2_t *f2)
 {
@@ -5377,8 +5379,15 @@ audio_mixer_init(struct audio_softc *sc,
                len = mixer->frames_per_block * mixer->mixfmt.channels *
                    mixer->mixfmt.stride / NBBY;
                mixer->mixsample = audio_realloc(mixer->mixsample, len);
-       } else {
-               /* No mixing buffer for recording */
+       } else if (reg->codec == NULL) {
+               /*
+                * Recording requires an input conversion buffer
+                * unless the hardware provides a codec itself
+                */
+               mixer->mixfmt = mixer->track_fmt;
+               len = mixer->frames_per_block * mixer->mixfmt.channels *
+                   mixer->mixfmt.stride / NBBY;
+               mixer->mixsample = audio_realloc(mixer->mixsample, len);
        }
 
        if (reg->codec) {
@@ -5647,31 +5656,32 @@ audio_pmixer_process(struct audio_softc 
         * The rest is the hardware part.
         */
 
+       m = mixer->mixsample;
+
        if (mixer->codec) {
+               TRACE(4, "codec count=%d", frame_count);
+
                h = auring_tailptr_aint(&mixer->codecbuf);
-       } else {
-               h = auring_tailptr_aint(&mixer->hwbuf);
-       }
-
-       m = mixer->mixsample;
-       if (!mixer->codec && mixer->swap_endian) {
-               for (i = 0; i < sample_count; i++) {
-                       *h++ = bswap16(*m++);
-               }
-       } else {
-               for (i = 0; i < sample_count; i++) {
+               for (i=0; i<sample_count; ++i)
                        *h++ = *m++;
-               }
-       }
-
-       /* Hardware driver's codec */
-       if (mixer->codec) {
+
+               /* Hardware driver's codec */
                auring_push(&mixer->codecbuf, frame_count);
                mixer->codecarg.src = auring_headptr(&mixer->codecbuf);
                mixer->codecarg.dst = auring_tailptr(&mixer->hwbuf);
                mixer->codecarg.count = frame_count;
                mixer->codec(&mixer->codecarg);
                auring_take(&mixer->codecbuf, mixer->codecarg.count);
+       } else {
+               TRACE(4, "direct count=%d", frame_count);
+
+               /* Direct conversion to linear output */
+               mixer->codecarg.src = m;
+               mixer->codecarg.dst = auring_tailptr(&mixer->hwbuf);
+               mixer->codecarg.count = frame_count;
+               mixer->codecarg.srcfmt = &mixer->mixfmt;
+               mixer->codecarg.dstfmt = &mixer->hwbuf.fmt;
+               audio_mixsample_to_linear(&mixer->codecarg);
        }
 
        auring_push(&mixer->hwbuf, frame_count);
@@ -6024,11 +6034,12 @@ audio_rmixer_process(struct audio_softc 
 {
        audio_trackmixer_t *mixer;
        audio_ring_t *mixersrc;
+       audio_ring_t tmpsrc;
+       audio_filter_t codec;
+       audio_filter_arg_t codecarg;
        audio_file_t *f;
-       aint_t *p;
        int count;
        int bytes;
-       int i;
 
        mixer = sc->sc_rmixer;
 
@@ -6046,24 +6057,60 @@ audio_rmixer_process(struct audio_softc 
 
        /* Hardware driver's codec */
        if (mixer->codec) {
+               TRACE(4, "codec count=%d", count);
                mixer->codecarg.src = auring_headptr(&mixer->hwbuf);
                mixer->codecarg.dst = auring_tailptr(&mixer->codecbuf);
                mixer->codecarg.count = count;
                mixer->codec(&mixer->codecarg);
-               auring_take(&mixer->hwbuf, mixer->codecarg.count);
-               auring_push(&mixer->codecbuf, mixer->codecarg.count);
                mixersrc = &mixer->codecbuf;
        } else {
-               mixersrc = &mixer->hwbuf;
-       }
-
-       if (!mixer->codec && mixer->swap_endian) {
-               /* inplace conversion */
-               p = auring_headptr_aint(mixersrc);
-               for (i = 0; i < count * mixer->track_fmt.channels; i++, p++) {
-                       *p = bswap16(*p);
-               }
-       }
+               TRACE(4, "direct count=%d", count);
+               /* temporary ring using mixsample buffer */
+               tmpsrc.fmt = mixer->mixfmt;
+               tmpsrc.capacity = mixer->frames_per_block;
+               tmpsrc.mem = mixer->mixsample;
+               tmpsrc.head = 0;
+               tmpsrc.used = 0;
+ 
+               /* ad-hoc codec */
+               codecarg.srcfmt = &mixer->hwbuf.fmt;
+               codecarg.dstfmt = &mixer->mixfmt;
+               codec = NULL;
+               if (audio_format2_is_linear(codecarg.srcfmt)) {
+                       switch (codecarg.srcfmt->stride) {
+                       case 8:
+                               codec = audio_linear8_to_internal;
+                               break;
+                       case 16:
+                               codec = audio_linear16_to_internal;
+                               break;
+#if defined(AUDIO_SUPPORT_LINEAR24)
+                       case 24:
+                               codec = audio_linear24_to_internal;
+                               break;
+#endif
+                       case 32:
+                               codec = audio_linear32_to_internal;
+                               break;
+                       }
+               }
+               if (codec == NULL) {
+                       TRACE(4, "unsupported hw format");
+                       return;
+               }
+ 
+               codecarg.src = auring_headptr(&mixer->hwbuf);
+               codecarg.dst = auring_tailptr(&tmpsrc);
+               codecarg.count = count;
+               codec(&codecarg);
+               mixersrc = &tmpsrc;
+       }
+
+       auring_take(&mixer->hwbuf, count);
+       auring_push(mixersrc, count);
+ 
+       TRACE(4, "distribute");
+ 
 
        /* Distribute to all tracks. */
        SLIST_FOREACH(f, &sc->sc_files, entry) {
@@ -9147,6 +9194,69 @@ audio_query_devinfo(struct audio_softc *
        return sc->hw_if->query_devinfo(sc->hw_hdl, di);
 }
 
+void
+audio_mixsample_to_linear(audio_filter_arg_t *arg)
+{
+       const audio_format2_t *fmt;
+       const aint2_t *m;
+       uint8_t *p;
+       u_int sample_count;
+       bool swap;
+       aint2_t v, xor;
+       u_int i, bps;
+       bool little;
+
+       DIAGNOSTIC_filter_arg(arg);
+       KASSERT(audio_format2_is_linear(arg->dstfmt));
+       KASSERT(arg->srcfmt->channels == arg->dstfmt->channels);
+
+       fmt = arg->dstfmt;
+       m = arg->src;
+       p = arg->dst;
+       sample_count = arg->count * fmt->channels;
+       swap = arg->dstfmt->encoding == AUDIO_ENCODING_SLINEAR_OE;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+       little = !swap;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+       little = swap;
+#endif
+
+       bps = fmt->stride / NBBY;
+
+       xor = audio_format2_is_signed(fmt)
+          ? 0 : 1 << (fmt->stride - 1);
+
+       for (i=0; i<sample_count; ++i) {
+               v = *m++;
+
+               /* scale up to 32bit and then down to target size */
+               v <<= 32 - AUDIO_INTERNAL_BITS;
+               v >>= (4 - bps) * NBBY;
+
+               /* signed -> unsigned */
+               v ^= xor;
+
+               if (little) {
+                       switch (bps) {
+                       case 4: *p++ = v; v >>= 8; /* FALLTHROUGH */
+                       case 3: *p++ = v; v >>= 8; /* FALLTHROUGH */
+                       case 2: *p++ = v; v >>= 8; /* FALLTHROUGH */
+                       case 1: *p++ = v; /* FALLTHROUGH */
+                       }
+               } else {
+                       switch (bps) {
+                       case 4: *p++ = v >> 24; v <<= 8; /* FALLTHROUGH */
+                       case 3: *p++ = v >> 24; v <<= 8; /* FALLTHROUGH */
+                       case 2: *p++ = v >> 24; v <<= 8; /* FALLTHROUGH */
+                       case 1: *p++ = v >> 24; /* FALLTHROUGH */
+                       }
+               }
+       }
+}
+
+
 #endif /* NAUDIO > 0 */
 
 #if NAUDIO == 0 && (NMIDI > 0 || NMIDIBUS > 0)



Home | Main Index | Thread Index | Old Index