diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -973,9 +973,13 @@ #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 --- a/sys/dev/sound/pcm/feeder_chain.c +++ b/sys/dev/sound/pcm/feeder_chain.c @@ -102,6 +102,7 @@ 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 @@ 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_mixer.c b/sys/dev/sound/pcm/feeder_mixer.c --- a/sys/dev/sound/pcm/feeder_mixer.c +++ b/sys/dev/sound/pcm/feeder_mixer.c @@ -70,10 +70,12 @@ #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) FEEDMIXER_DECLARE(S, 16, LE) FEEDMIXER_DECLARE(S, 32, LE) +FEEDMIXER_DECLARE(F, 32, LE) #endif #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) FEEDMIXER_DECLARE(S, 16, BE) FEEDMIXER_DECLARE(S, 32, BE) +FEEDMIXER_DECLARE(F, 32, BE) #endif #ifdef SND_FEEDER_MULTIFORMAT FEEDMIXER_DECLARE(S, 8, NE) @@ -105,10 +107,12 @@ #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) FEEDMIXER_ENTRY(S, 16, LE), FEEDMIXER_ENTRY(S, 32, LE), + FEEDMIXER_ENTRY(F, 32, LE), #endif #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) FEEDMIXER_ENTRY(S, 16, BE), FEEDMIXER_ENTRY(S, 32, BE), + FEEDMIXER_ENTRY(F, 32, BE), #endif #ifdef SND_FEEDER_MULTIFORMAT FEEDMIXER_ENTRY(S, 24, LE), diff --git a/sys/dev/sound/pcm/feeder_rate.c b/sys/dev/sound/pcm/feeder_rate.c --- a/sys/dev/sound/pcm/feeder_rate.c +++ b/sys/dev/sound/pcm/feeder_rate.c @@ -643,6 +643,8 @@ 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 { @@ -691,6 +693,8 @@ 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 --- a/sys/dev/sound/pcm/feeder_volume.c +++ b/sys/dev/sound/pcm/feeder_volume.c @@ -92,6 +92,8 @@ 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 --- a/sys/dev/sound/pcm/pcm.h +++ b/sys/dev/sound/pcm/pcm.h @@ -124,6 +124,7 @@ #define PCM_CLAMP_U16(val) PCM_CLAMP_S16(val) #define PCM_CLAMP_U24(val) PCM_CLAMP_S24(val) #define PCM_CLAMP_U32(val) PCM_CLAMP_S32(val) +#define PCM_CLAMP_F32(val) PCM_CLAMP_S32(val) static const struct { const uint8_t ulaw_to_u8[G711_TABLE_SIZE]; @@ -146,9 +147,16 @@ static __always_inline __unused intpcm_t pcm_sample_read(uint8_t *src, uint32_t fmt) { + uint8_t *tmp; + float fv; intpcm_t v; fmt = AFMT_ENCODING(fmt); +#ifdef _KERNEL + if (fmt & (AFMT_F32_LE | AFMT_F32_BE)) + fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); +#endif /* _KERNEL */ + switch (fmt) { case AFMT_AC3: v = 0; @@ -207,11 +215,33 @@ 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: + fv = *(float *)src; + memcpy(&v, &fv, sizeof(v)); + tmp = (uint8_t *)&v; + if (fmt == AFMT_F32_LE) { + v = INTPCM_T(tmp[0] | tmp[1] << 8 | tmp[2] << 16 | + (int8_t)tmp[3] << 24); + } else { + v = INTPCM_T(tmp[3] | tmp[2] << 8 | tmp[1] << 16 | + (int8_t)tmp[0] << 24); + } + memcpy(&fv, &v, sizeof(fv)); + v = INTPCM_T(fv * (float)PCM_S32_MAX); + break; default: printf("%s(): unknown format: 0x%08x\n", __func__, fmt); v = 0; break; } + +#ifdef _KERNEL + if (fmt & (AFMT_F32_LE | AFMT_F32_BE)) + fpu_kern_leave(curthread, NULL); +#endif /* _KERNEL */ + +#ifndef SND_PCM_64 /* * Dynamic range for humans: ~140db. * @@ -224,7 +254,6 @@ * down to 24bit (see below for the reason), unless SND_PCM_64 is * defined. */ -#ifndef SND_PCM_64 if (fmt & AFMT_32BIT) v >>= PCM_FXSHIFT; #endif @@ -242,6 +271,8 @@ static __always_inline __unused void pcm_sample_write(uint8_t *dst, intpcm_t v, uint32_t fmt) { + float fv; + fmt = AFMT_ENCODING(fmt); #ifndef SND_PCM_64 @@ -249,6 +280,14 @@ v <<= PCM_FXSHIFT; #endif + if (fmt & (AFMT_F32_LE | AFMT_F32_BE)) { +#ifdef _KERNEL + fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); +#endif /* _KERNEL */ + fv = (float)v / (float)PCM_S32_MAX; + memcpy(&v, &fv, sizeof(v)); + } + switch (fmt) { case AFMT_AC3: *(int16_t *)dst = 0; @@ -301,13 +340,15 @@ 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; @@ -329,6 +370,11 @@ printf("%s(): unknown format: 0x%08x\n", __func__, fmt); break; } + +#ifdef _KERNEL + if (fmt & (AFMT_F32_LE | AFMT_F32_BE)) + fpu_kern_leave(curthread, NULL); +#endif /* _KERNEL */ } /* Write sample and shift down original magnitude. */ diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -444,15 +444,17 @@ #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) @@ -502,9 +504,11 @@ #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) + #endif /* _OS_H_ */ diff --git a/sys/sys/soundcard.h b/sys/sys/soundcard.h --- a/sys/sys/soundcard.h +++ b/sys/sys/soundcard.h @@ -184,6 +184,8 @@ #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 @@ #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 @@ #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 */ /*