From nobody Sun Mar 30 17:48:25 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4ZQhZL1W3lz5rp4d; Sun, 30 Mar 2025 17:48:26 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4ZQhZK6fYPz3RNS; Sun, 30 Mar 2025 17:48:25 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1743356905; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=At9QrgFUJAOknBCne9KsDXJfBL2YvT6oJ41vgL9noro=; b=MHjllBHJ4AURGT9xaDi8NV4J0pkHw5CkdSt1C5y2/22Kogxut3ZzitA9x2LODjgLB7Qb0h OE4JS+ZwveT3gwPcZSse2EoFteAhU6Qvhhly4iOpHetcbFLndFcjMe/y7UVL7brRWtVcJP iXuu1IkS9zGj52J/rgmGLa83Lw8BpJgwCavua5NRzFM/E32UdopJocHAK/IKktpryY4+wl 60Gh1Bssw8TODNRG+jPKqn7zy9mTS+vUVCCtuTiFXIWtiS8q8x6ek6Xn+E7aRASt+WJXjv 0ShoAY3D6KKKK26sLjSX1xQRE6DrH3u18vWTJYLRZDAbBcXGyLUNIkFrTg6rFA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1743356905; a=rsa-sha256; cv=none; b=EvdamIiVmpxdd0uT58EU1wyiLQYBDpHB5ubHQABr2wU78iH7HuDKzgTBmdCRy4LvwAcsey 2MGM3uYLt6PeJP/gQj5XGoFPMhF3vSANtMI6ladPC2s+il+jsn/e1kQgIirnXOKplhFHHY XWK/br/COxuOHCxXa6M3BfFuxA6GmH9XjCUAKDf6xSQqmKUKsNxpHfaez8svaM0oUDEd/p 8tKHjU4YaHcGQUBgjse0ohsPU9l5O/ZScKGaiSB3c76gmDkbjXXn/l9FGQsTSXQ4r4Xidj Xmrm2ojNQEtjv8LD1wtIfnWDopvCPA2Bi6hNX3kY3tphzduaFe1kKuP4GKWl4A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1743356905; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=At9QrgFUJAOknBCne9KsDXJfBL2YvT6oJ41vgL9noro=; b=E+b2gKoMVvtFkr9dsCdJ+Cqw3GB0rH8pHQgmK4P3sASs7jssJEtYtAqk/keCx7A40k9Cdx lnwznSprf7PaHMFiW0905+qyvWlICMOxFCY9gLeOYjzjbJcyjHosTXIL5OcIWcavLo4JlX 8+seT8UGJkPo2ZXfSvWzTcj1QL8yaQnpX18LDU8BylPTQSCNT1dWeyzadmA4uS5yZ6DJFF c2dApdBGARlH9I7BgE4sIpY7kLR5v2z4yL9TbeVMyzLEi5G/bAxDU9A3XXCJSPqlQQ+97d HfqMhfnfjB3uITD6/maaOX8R7wx51bNdSHy83RP+nAXlDl3jR4gmZRCA5Kcu5A== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4ZQhZK6Dxjz1NMT; Sun, 30 Mar 2025 17:48:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 52UHmPmo060203; Sun, 30 Mar 2025 17:48:25 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 52UHmPRF060200; Sun, 30 Mar 2025 17:48:25 GMT (envelope-from git) Date: Sun, 30 Mar 2025 17:48:25 GMT Message-Id: <202503301748.52UHmPRF060200@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Christos Margiolis Subject: git: e1bbaa71d62c - main - sound: Implement AFMT_FLOAT support List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: christos X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e1bbaa71d62c8681a576f9f5bedf475c7541bd35 Auto-Submitted: auto-generated The branch main has been updated by christos: URL: https://cgit.FreeBSD.org/src/commit/?id=e1bbaa71d62c8681a576f9f5bedf475c7541bd35 commit e1bbaa71d62c8681a576f9f5bedf475c7541bd35 Author: Christos Margiolis AuthorDate: 2025-03-30 17:45:38 +0000 Commit: Christos Margiolis CommitDate: 2025-03-30 17:45:38 +0000 sound: Implement AFMT_FLOAT support Even though the OSS manual [1] advises against using AFMT_FLOAT, there are applications that expect the sound driver to support it, and might not work properly without it. This patch adds AFMT_F32_LE|BE (as well as AFMT_FLOAT for OSS compatibility) in sys/soundcard.h and implements AFMT_F32_LE|BE <-> AFMT_S32_LE|BE conversion functions. As a result, applications can write/read floats to/from sound(4), but internally, because sound(4) works with integers, we convert floating point samples to integer ones, before doing any processing. The reason for encoding/decoding IEEE754s manually, instead of using fpu_kern(9), is that fpu_kern(9) is not supported by all architectures, and also introduces significant overhead. The IEEE754 encoding/decoding implementation has been written by Ariff Abdullah [2]. [1] http://manuals.opensound.com/developer/AFMT_FLOAT.html [2] https://people.freebsd.org/~ariff/utils/ieee754.c PR: 157050, 184380, 264973, 280612, 281390 Sponsored by: The FreeBSD Foundation MFC after: 1 week Reviewed by: emaste Differential Revision: https://reviews.freebsd.org/D47638 --- sys/dev/sound/pcm/channel.c | 4 +++ sys/dev/sound/pcm/feeder_chain.c | 2 ++ sys/dev/sound/pcm/feeder_rate.c | 4 +++ sys/dev/sound/pcm/feeder_volume.c | 2 ++ sys/dev/sound/pcm/pcm.h | 67 +++++++++++++++++++++++++++++++++++++-- sys/dev/sound/pcm/sound.h | 13 +++++--- sys/sys/soundcard.h | 8 +++++ tests/sys/sound/pcm_read_write.c | 6 ++++ 8 files changed, 98 insertions(+), 8 deletions(-) diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index 4a96505ada66..3aa7cf219d81 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -977,9 +977,13 @@ static const struct { #if BYTE_ORDER == LITTLE_ENDIAN { "s32le", "s32", "32", AFMT_S32_LE }, { "s32be", NULL, NULL, AFMT_S32_BE }, + { "f32le", "f32", NULL, AFMT_F32_LE }, + { "f32be", NULL, NULL, AFMT_F32_BE }, #else { "s32le", NULL, NULL, AFMT_S32_LE }, { "s32be", "s32", "32", AFMT_S32_BE }, + { "f32le", NULL, NULL, AFMT_F32_LE }, + { "f32be", "f32", NULL, AFMT_F32_BE }, #endif { "u32le", NULL, NULL, AFMT_U32_LE }, { "u32be", NULL, NULL, AFMT_U32_BE }, diff --git a/sys/dev/sound/pcm/feeder_chain.c b/sys/dev/sound/pcm/feeder_chain.c index 1c4ddca6cdd5..56de32441de7 100644 --- a/sys/dev/sound/pcm/feeder_chain.c +++ b/sys/dev/sound/pcm/feeder_chain.c @@ -102,6 +102,7 @@ static uint32_t feeder_chain_formats_multi[] = { AFMT_S16_LE, AFMT_S16_BE, AFMT_U16_LE, AFMT_U16_BE, AFMT_S24_LE, AFMT_S24_BE, AFMT_U24_LE, AFMT_U24_BE, AFMT_S32_LE, AFMT_S32_BE, AFMT_U32_LE, AFMT_U32_BE, + AFMT_F32_LE, AFMT_F32_BE, 0 }; @@ -111,6 +112,7 @@ static uint32_t feeder_chain_formats_fullmulti[] = { AFMT_S16_LE, AFMT_S16_BE, AFMT_U16_LE, AFMT_U16_BE, AFMT_S24_LE, AFMT_S24_BE, AFMT_U24_LE, AFMT_U24_BE, AFMT_S32_LE, AFMT_S32_BE, AFMT_U32_LE, AFMT_U32_BE, + AFMT_F32_LE, AFMT_F32_BE, 0 }; diff --git a/sys/dev/sound/pcm/feeder_rate.c b/sys/dev/sound/pcm/feeder_rate.c index 1610211ff5f5..9ea454cdee1e 100644 --- a/sys/dev/sound/pcm/feeder_rate.c +++ b/sys/dev/sound/pcm/feeder_rate.c @@ -639,6 +639,8 @@ Z_DECLARE(U, 32, LE) Z_DECLARE(U, 16, BE) Z_DECLARE(U, 24, BE) Z_DECLARE(U, 32, BE) +Z_DECLARE(F, 32, LE) +Z_DECLARE(F, 32, BE) #endif enum { @@ -687,6 +689,8 @@ static const struct { Z_RESAMPLER_ENTRY(U, 16, BE), Z_RESAMPLER_ENTRY(U, 24, BE), Z_RESAMPLER_ENTRY(U, 32, BE), + Z_RESAMPLER_ENTRY(F, 32, LE), + Z_RESAMPLER_ENTRY(F, 32, BE), #endif }; diff --git a/sys/dev/sound/pcm/feeder_volume.c b/sys/dev/sound/pcm/feeder_volume.c index f72c6aa7ef4f..2d35bb56ef8f 100644 --- a/sys/dev/sound/pcm/feeder_volume.c +++ b/sys/dev/sound/pcm/feeder_volume.c @@ -93,6 +93,8 @@ FEEDVOLUME_DECLARE(U, 32, LE) FEEDVOLUME_DECLARE(U, 16, BE) FEEDVOLUME_DECLARE(U, 24, BE) FEEDVOLUME_DECLARE(U, 32, BE) +FEEDVOLUME_DECLARE(F, 32, LE) +FEEDVOLUME_DECLARE(F, 32, BE) #endif struct feed_volume_info { diff --git a/sys/dev/sound/pcm/pcm.h b/sys/dev/sound/pcm/pcm.h index 1de686b04097..7d0a8f0f431b 100644 --- a/sys/dev/sound/pcm/pcm.h +++ b/sys/dev/sound/pcm/pcm.h @@ -128,7 +128,8 @@ static const struct { static __always_inline __unused intpcm_t pcm_sample_read(const uint8_t *src, uint32_t fmt) { - intpcm_t v; + intpcm_t v, e, m; + bool s; fmt = AFMT_ENCODING(fmt); @@ -190,6 +191,34 @@ pcm_sample_read(const uint8_t *src, uint32_t fmt) v = INTPCM_T(src[3] | src[2] << 8 | src[1] << 16 | (int8_t)(src[0] ^ 0x80) << 24); break; + case AFMT_F32_LE: /* FALLTHROUGH */ + case AFMT_F32_BE: + if (fmt == AFMT_F32_LE) { + v = INTPCM_T(src[0] | src[1] << 8 | src[2] << 16 | + (int8_t)src[3] << 24); + } else { + v = INTPCM_T(src[3] | src[2] << 8 | src[1] << 16 | + (int8_t)src[0] << 24); + } + e = (v >> 23) & 0xff; + /* NaN, +/- Inf or too small */ + if (e == 0xff || e < 96) { + v = INTPCM_T(0); + break; + } + s = v & 0x80000000U; + if (e > 126) { + v = INTPCM_T((s == 0) ? PCM_S32_MAX : PCM_S32_MIN); + break; + } + m = 0x800000 | (v & 0x7fffff); + e += 8 - 127; + if (e < 0) + m >>= -e; + else + m <<= e; + v = INTPCM_T((s == 0) ? m : -m); + break; default: v = 0; printf("%s(): unknown format: 0x%08x\n", __func__, fmt); @@ -241,8 +270,38 @@ pcm_sample_read_calc(const uint8_t *src, uint32_t fmt) static __always_inline __unused void pcm_sample_write(uint8_t *dst, intpcm_t v, uint32_t fmt) { + intpcm_t r, e; + fmt = AFMT_ENCODING(fmt); + if (fmt & (AFMT_F32_LE | AFMT_F32_BE)) { + if (v == 0) + r = 0; + else if (v == PCM_S32_MAX) + r = 0x3f800000; + else if (v == PCM_S32_MIN) + r = 0x80000000U | 0x3f800000; + else { + r = 0; + if (v < 0) { + r |= 0x80000000U; + v = -v; + } + e = 127 - 8; + while ((v & 0x7f000000) != 0) { + v >>= 1; + e++; + } + while ((v & 0x7f800000) == 0) { + v <<= 1; + e--; + } + r |= (e & 0xff) << 23; + r |= v & 0x7fffff; + } + v = r; + } + switch (fmt) { case AFMT_AC3: *(int16_t *)dst = 0; @@ -295,13 +354,15 @@ pcm_sample_write(uint8_t *dst, intpcm_t v, uint32_t fmt) dst[1] = v >> 8; dst[0] = (v >> 16) ^ 0x80; break; - case AFMT_S32_LE: + case AFMT_S32_LE: /* FALLTHROUGH */ + case AFMT_F32_LE: dst[0] = v; dst[1] = v >> 8; dst[2] = v >> 16; dst[3] = v >> 24; break; - case AFMT_S32_BE: + case AFMT_S32_BE: /* FALLTHROUGH */ + case AFMT_F32_BE: dst[3] = v; dst[2] = v >> 8; dst[1] = v >> 16; diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index 637bcbbe1b00..a1370180f350 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -451,15 +451,17 @@ int sound_oss_card_info(oss_card_info *); #endif /* _KERNEL */ /* make figuring out what a format is easier. got AFMT_STEREO already */ -#define AFMT_32BIT (AFMT_S32_LE | AFMT_S32_BE | AFMT_U32_LE | AFMT_U32_BE) +#define AFMT_32BIT (AFMT_S32_LE | AFMT_S32_BE | AFMT_U32_LE | AFMT_U32_BE | \ + AFMT_F32_LE | AFMT_F32_BE) #define AFMT_24BIT (AFMT_S24_LE | AFMT_S24_BE | AFMT_U24_LE | AFMT_U24_BE) #define AFMT_16BIT (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE) #define AFMT_G711 (AFMT_MU_LAW | AFMT_A_LAW) #define AFMT_8BIT (AFMT_G711 | AFMT_U8 | AFMT_S8) -#define AFMT_SIGNED (AFMT_S32_LE | AFMT_S32_BE | AFMT_S24_LE | AFMT_S24_BE | \ +#define AFMT_SIGNED (AFMT_S32_LE | AFMT_S32_BE | AFMT_F32_LE | AFMT_F32_BE | \ + AFMT_S24_LE | AFMT_S24_BE | \ AFMT_S16_LE | AFMT_S16_BE | AFMT_S8) -#define AFMT_BIGENDIAN (AFMT_S32_BE | AFMT_U32_BE | AFMT_S24_BE | AFMT_U24_BE | \ - AFMT_S16_BE | AFMT_U16_BE) +#define AFMT_BIGENDIAN (AFMT_S32_BE | AFMT_U32_BE | AFMT_F32_BE | \ + AFMT_S24_BE | AFMT_U24_BE | AFMT_S16_BE | AFMT_U16_BE) #define AFMT_CONVERTIBLE (AFMT_8BIT | AFMT_16BIT | AFMT_24BIT | \ AFMT_32BIT) @@ -509,7 +511,8 @@ int sound_oss_card_info(oss_card_info *); #define AFMT_U8_NE AFMT_U8 #define AFMT_S8_NE AFMT_S8 -#define AFMT_SIGNED_NE (AFMT_S8_NE | AFMT_S16_NE | AFMT_S24_NE | AFMT_S32_NE) +#define AFMT_SIGNED_NE (AFMT_S8_NE | AFMT_S16_NE | AFMT_S24_NE | \ + AFMT_S32_NE | AFMT_F32_NE) #define AFMT_NE (AFMT_SIGNED_NE | AFMT_U8_NE | AFMT_U16_NE | \ AFMT_U24_NE | AFMT_U32_NE) diff --git a/sys/sys/soundcard.h b/sys/sys/soundcard.h index 304ae38c08d4..aab67532503e 100644 --- a/sys/sys/soundcard.h +++ b/sys/sys/soundcard.h @@ -184,6 +184,8 @@ struct snd_size { #define AFMT_S24_BE 0x00020000 /* Big endian signed 24-bit */ #define AFMT_U24_LE 0x00040000 /* Little endian unsigned 24-bit */ #define AFMT_U24_BE 0x00080000 /* Big endian unsigned 24-bit */ +#define AFMT_F32_LE 0x10000000 /* Little endian 32-bit floating point */ +#define AFMT_F32_BE 0x20000000 /* Big endian 32-bit floating point */ /* Machine dependent AFMT_* definitions. */ #if BYTE_ORDER == LITTLE_ENDIAN @@ -199,6 +201,8 @@ struct snd_size { #define AFMT_U16_OE AFMT_U16_BE #define AFMT_U24_OE AFMT_U24_BE #define AFMT_U32_OE AFMT_U32_BE +#define AFMT_F32_NE AFMT_F32_LE +#define AFMT_F32_OE AFMT_F32_BE #else #define AFMT_S16_OE AFMT_S16_LE #define AFMT_S24_OE AFMT_S24_LE @@ -212,8 +216,12 @@ struct snd_size { #define AFMT_U16_NE AFMT_U16_BE #define AFMT_U24_NE AFMT_U24_BE #define AFMT_U32_NE AFMT_U32_BE +#define AFMT_F32_NE AFMT_F32_BE +#define AFMT_F32_OE AFMT_F32_LE #endif +#define AFMT_FLOAT AFMT_F32_NE /* compatibility alias */ + #define AFMT_STEREO 0x10000000 /* can do/want stereo */ /* diff --git a/tests/sys/sound/pcm_read_write.c b/tests/sys/sound/pcm_read_write.c index 2aba19840735..a77b953a78a0 100644 --- a/tests/sys/sound/pcm_read_write.c +++ b/tests/sys/sound/pcm_read_write.c @@ -70,6 +70,12 @@ static struct afmt_test_data { {"u32be_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_U32_BE, 0x81020304}, {"u32be_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_U32_BE, 0x01828384}, + /* 32 bit floating point sample formats. */ + {"f32le_1", {0x00, 0x00, 0x00, 0x3f}, 4, AFMT_F32_LE, 0x40000000}, + {"f32le_2", {0x00, 0x00, 0x00, 0xbf}, 4, AFMT_F32_LE, 0xc0000000}, + {"f32be_1", {0x3f, 0x00, 0x00, 0x00}, 4, AFMT_F32_BE, 0x40000000}, + {"f32be_2", {0xbf, 0x00, 0x00, 0x00}, 4, AFMT_F32_BE, 0xc0000000}, + /* u-law and A-law sample formats. */ {"mulaw_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0xffffff87}, {"mulaw_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0x00000079},