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 @@ -966,9 +966,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_format.c b/sys/dev/sound/pcm/feeder_format.c --- a/sys/dev/sound/pcm/feeder_format.c +++ b/sys/dev/sound/pcm/feeder_format.c @@ -63,9 +63,13 @@ __always_inline intpcm_t pcm_sample_read(uint8_t *src, uint32_t fmt, bool shift) { + float fv; intpcm_t v; fmt = AFMT_ENCODING(fmt); + if (fmt == AFMT_F32_LE || fmt == AFMT_F32_BE) + fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); + switch (fmt) { #if BYTE_ORDER == LITTLE_ENDIAN case AFMT_S16_LE: @@ -94,6 +98,16 @@ v = INTPCM_T(src[3] | src[2] << 8 | src[1] << 16 | ((int8_t)src[0] ^ 0x80) << 24); break; + case AFMT_F32_LE: + v = INTPCM_T(*(float *)src * (float)PCM_S32_MAX); + break; + case AFMT_F32_BE: + fv = *(float *)src; + memcpy(&v, &fv, sizeof(v)); + v = __bswap32(v); + memcpy(&fv, &v, sizeof(fv)); + v = INTPCM_T(fv * (float)PCM_S32_MAX); + break; #else /* BYTE_ORDER != LITTLE_ENDIAN */ case AFMT_S16_LE: v = INTPCM_T(src[0] | (int8_t)src[1] << 8); @@ -121,6 +135,16 @@ case AFMT_U32_BE: v = INTPCM_T((int32_t)(*(uint32_t *)src) ^ 0x80000000); break; + case AFMT_F32_LE: + fv = *(float *)src; + memcpy(&v, &fv, sizeof(v)); + v = __bswap32(v); + memcpy(&fv, &v, sizeof(fv)); + v = INTPCM_T(fv * (float)PCM_S32_MAX); + break; + case AFMT_F32_BE: + v = INTPCM_T(*(float *)src * (float)PCM_S32_MAX); + break; #endif /* BYTE_ORDER == LITTLE_ENDIAN */ case AFMT_S8: v = INTPCM_T(*(int8_t *)src); @@ -157,6 +181,9 @@ break; } + if (fmt == AFMT_F32_LE || fmt == AFMT_F32_BE) + fpu_kern_leave(curthread, NULL); + #ifndef SND_PCM_64 v >>= PCM_FXSHIFT; #endif @@ -170,6 +197,9 @@ __always_inline void pcm_sample_write(uint8_t *dst, intpcm_t v, uint32_t fmt, bool shift) { + uint8_t *tmp; + float fv; + fmt = AFMT_ENCODING(fmt); if (shift) @@ -179,6 +209,9 @@ v <<= PCM_FXSHIFT; #endif + if (fmt == AFMT_F32_LE || fmt == AFMT_F32_BE) + fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX); + switch (fmt) { #if BYTE_ORDER == LITTLE_ENDIAN case AFMT_S16_LE: @@ -213,6 +246,17 @@ dst[1] = v >> 16; dst[0] = (v >> 24) ^ 0x80; break; + case AFMT_F32_LE: + *(float *)dst = (float)v / (float)PCM_S32_MAX; + break; + case AFMT_F32_BE: + fv = (float)v / (float)PCM_S32_MAX; + tmp = (uint8_t *)&fv; + dst[0] = tmp[3]; + dst[1] = tmp[2]; + dst[2] = tmp[1]; + dst[3] = tmp[0]; + break; #else /* BYTE_ORDER != LITTLE_ENDIAN */ case AFMT_S16_LE: dst[0] = v; @@ -246,6 +290,17 @@ case AFMT_U32_BE: *(uint32_t *)dst = v ^ 0x80000000; break; + case AFMT_F32_LE: + fv = (float)v / (float)PCM_S32_MAX; + tmp = (uint8_t *)&fv; + dst[0] = tmp[3]; + dst[1] = tmp[2]; + dst[2] = tmp[1]; + dst[3] = tmp[0]; + break; + case AFMT_F32_BE: + *(float *)dst = (float)v / (float)PCM_S32_MAX; + break; #endif /* BYTE_ORDER == LITTLE_ENDIAN */ case AFMT_S8: *(int8_t *)dst = v; @@ -286,6 +341,9 @@ printf("%s(): unknown format: 0x%08x\n", __func__, fmt); break; } + + if (fmt == AFMT_F32_LE || fmt == AFMT_F32_BE) + fpu_kern_leave(curthread, NULL); } static int 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 @@ -67,10 +67,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) @@ -102,10 +104,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/pcm.h b/sys/dev/sound/pcm/pcm.h --- a/sys/dev/sound/pcm/pcm.h +++ b/sys/dev/sound/pcm/pcm.h @@ -120,6 +120,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) extern __always_inline intpcm_t pcm_sample_read(uint8_t *, uint32_t, bool); extern __always_inline void pcm_sample_write(uint8_t *, intpcm_t, uint32_t, bool); 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 @@ -161,13 +161,15 @@ (((var)<(low))? (low) : ((var)>(high))? (high) : (var)) /* 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 | \ - AFMT_S16_LE | AFMT_S16_BE | AFMT_S8) + AFMT_S16_LE | AFMT_S16_BE | AFMT_S8 | AFMT_F32_LE | \ + AFMT_F32_BE) #define AFMT_BIGENDIAN (AFMT_S32_BE | AFMT_U32_BE | AFMT_S24_BE | AFMT_U24_BE | \ AFMT_S16_BE | AFMT_U16_BE) 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,7 @@ #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 #else #define AFMT_S16_OE AFMT_S16_LE #define AFMT_S24_OE AFMT_S24_LE @@ -212,8 +215,11 @@ #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 #endif +#define AFMT_FLOAT AFMT_F32_NE /* compatibility alias */ + #define AFMT_STEREO 0x10000000 /* can do/want stereo */ /*