From 07b6d8e63aaf85b3dbab703600d1dc6619c1c119 Mon Sep 17 00:00:00 2001 From: Claudio Cabral Date: Sat, 15 Jan 2022 16:02:31 +0100 Subject: [PATCH] Add 32 bit support for ALSA driver (#811) * apply changes without whitespace * remove neon intrinsics and fix indentation * update float_32 macro and fix misspellings * check msbits to determine number of bits in alsa driver * add better error messages and support for SND_PCM_FORMAT_S32_BE * log when sample format is not equal to bits Co-authored-by: Claudio Cabral Co-authored-by: Claudio Cabral --- common/memops.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++-- common/memops.h | 4 ++ 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/common/memops.c b/common/memops.c index 725c49e..b00af0b 100644 --- a/common/memops.c +++ b/common/memops.c @@ -73,6 +73,7 @@ So, for now (October 2008) we use 2^(N-1)-1 as the scaling factor. */ +#define SAMPLE_32BIT_SCALING 2147483647.0 #define SAMPLE_24BIT_SCALING 8388607.0f #define SAMPLE_16BIT_SCALING 32767.0f @@ -81,6 +82,11 @@ advice from Fons Adriaensen: make the limits symmetrical */ +#define SAMPLE_32BIT_MAX 2147483647 +#define SAMPLE_32BIT_MIN -2147483647 +#define SAMPLE_32BIT_MAX_D 2147483647.0 +#define SAMPLE_32BIT_MIN_D -2147483647.0 + #define SAMPLE_24BIT_MAX 8388607 #define SAMPLE_24BIT_MIN -8388607 #define SAMPLE_24BIT_MAX_F 8388607.0f @@ -106,6 +112,7 @@ */ #define f_round(f) lrintf(f) +#define d_round(f) lrint(f) #define float_16(s, d)\ if ((s) <= NORMALIZED_FLOAT_MIN) {\ @@ -146,6 +153,15 @@ (d) = f_round ((s) * SAMPLE_24BIT_SCALING); \ } +#define float_32(s, d) \ + do { \ + double clipped = fmin(NORMALIZED_FLOAT_MAX, \ + fmax((double)(s), NORMALIZED_FLOAT_MIN)); \ + double scaled = clipped * SAMPLE_32BIT_MAX_D; \ + (d) = d_round(scaled); \ + } \ + while (0) + /* call this when "s" has already been scaled (e.g. when dithering) */ @@ -195,6 +211,11 @@ static inline __m128 clip(__m128 s, __m128 min, __m128 max) return _mm_min_ps(max, _mm_max_ps(s, min)); } +static inline __m128d clip_double(__m128d s, __m128d min, __m128d max) +{ + return _mm_min_pd(max, _mm_max_pd(s, min)); +} + static inline __m128i float_24_sse(__m128 s) { const __m128 upper_bound = gen_one(); /* NORMALIZED_FLOAT_MAX */ @@ -274,13 +295,14 @@ void sample_move_dS_floatLE (char *dst, jack_default_audio_sample_t *src, unsign S - sample is a jack_default_audio_sample_t, currently (October 2008) a 32 bit floating point value Ss - like S but reverse endian from the host CPU - 32u24 - sample is an signed 32 bit integer value, but data is in upper 24 bits only + 32 - sample is a signed 32 bit integer value + 32u24 - sample is a signed 32 bit integer value, but data is in upper 24 bits only 32u24s - like 32u24 but reverse endian from the host CPU - 32l24 - sample is an signed 32 bit integer value, but data is in lower 24 bits only + 32l24 - sample is a signed 32 bit integer value, but data is in lower 24 bits only 32l24s - like 32l24 but reverse endian from the host CPU - 24 - sample is an signed 24 bit integer value + 24 - sample is a signed 24 bit integer value 24s - like 24 but reverse endian from the host CPU - 16 - sample is an signed 16 bit integer value + 16 - sample is a signed 16 bit integer value 16s - like 16 but reverse endian from the host CPU For obvious reasons, the reverse endian versions only show as source types. @@ -290,6 +312,36 @@ void sample_move_dS_floatLE (char *dst, jack_default_audio_sample_t *src, unsign /* functions for native integer sample data */ +void sample_move_d32_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) +{ + while (nsamples--) { + int32_t z; + float_32(*src, z); +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>24); + dst[1]=(char)(z>>16); + dst[2]=(char)(z>>8); + dst[3]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); + dst[3]=(char)(z>>24); +#endif + dst += dst_skip; + src++; + } +} + +void sample_move_d32_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) +{ + while (nsamples--) { + float_32(*src, *(int32_t *)dst); + dst += dst_skip; + src++; + } +} + void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) @@ -689,6 +741,35 @@ void sample_move_d32l24_sS (char *dst, jack_default_audio_sample_t *src, unsigne #endif } +void sample_move_dS_s32s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) +{ + const jack_default_audio_sample_t scaling = 1.0/SAMPLE_32BIT_SCALING; + while (nsamples--) { + int32_t x; +#if __BYTE_ORDER == __LITTLE_ENDIAN + x = (unsigned char)(src[0]); + x <<= 8; + x |= (unsigned char)(src[1]); + x <<= 8; + x |= (unsigned char)(src[2]); + x <<= 8; + x |= (unsigned char)(src[3]); +#elif __BYTE_ORDER == __BIG_ENDIAN + x = (unsigned char)(src[3]); + x <<= 8; + x |= (unsigned char)(src[2]); + x <<= 8; + x |= (unsigned char)(src[1]); + x <<= 8; + x |= (unsigned char)(src[0]); +#endif + double extended = x * scaling; + *dst = (float)extended; + dst++; + src += src_skip; + } +} + void sample_move_dS_s32l24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { #if defined (__ARM_NEON__) || defined (__ARM_NEON) @@ -753,6 +834,18 @@ void sample_move_dS_s32l24s (jack_default_audio_sample_t *dst, char *src, unsign } } +void sample_move_dS_s32 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) +{ + const double scaling = 1.0 / SAMPLE_32BIT_SCALING; + while (nsamples--) { + int32_t val=(*((int32_t*)src)); + double extended = val * scaling; + *dst = (float)extended; + dst++; + src += src_skip; + } +} + void sample_move_dS_s32l24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { #if defined (__SSE2__) && !defined (__sun__) diff --git a/common/memops.h b/common/memops.h index 40e6abf..b4f6db9 100644 --- a/common/memops.h +++ b/common/memops.h @@ -53,6 +53,8 @@ void sample_move_floatLE_sSs (jack_default_audio_sample_t *dst, char *src, unsig void sample_move_dS_floatLE (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); /* integer functions */ +void sample_move_d32_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d32_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_d32l24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); @@ -81,6 +83,8 @@ void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_ void sample_move_dither_shaped_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dS_s32s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); +void sample_move_dS_s32 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32u24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s32l24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);