Module Name: src Committed By: mlelstv Date: Sun Apr 23 08:05:37 UTC 2023
Modified Files: src/sys/dev/audio: audio.c Log Message: Add 24bit/32bit hardware support. To generate a diff of this commit: cvs rdiff -u -r1.139 -r1.140 src/sys/dev/audio/audio.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/audio/audio.c diff -u src/sys/dev/audio/audio.c:1.139 src/sys/dev/audio/audio.c:1.140 --- src/sys/dev/audio/audio.c:1.139 Sun Apr 23 06:30:58 2023 +++ src/sys/dev/audio/audio.c Sun Apr 23 08:05:36 2023 @@ -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) { - h = auring_tailptr_aint(&mixer->codecbuf); - } else { - h = auring_tailptr_aint(&mixer->hwbuf); - } + TRACE(4, "codec count=%d", frame_count); - 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++) { + h = auring_tailptr_aint(&mixer->codecbuf); + 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,25 +6057,61 @@ 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) { audio_track_t *track = f->rtrack; @@ -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)