Browse Source

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 <clca@bang-olufsen.dk>
Co-authored-by: Claudio Cabral <cl@udio.co>
tags/v1.9.20
Claudio Cabral falkTX <falktx@falktx.com> 3 years ago
parent
commit
719fa1d545
3 changed files with 171 additions and 4 deletions
  1. +97
    -4
      common/memops.c
  2. +4
    -0
      common/memops.h
  3. +70
    -0
      linux/alsa/alsa_driver.c

+ 97
- 4
common/memops.c View File

@@ -73,6 +73,7 @@
So, for now (October 2008) we use 2^(N-1)-1 as the scaling factor. 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_24BIT_SCALING 8388607.0f
#define SAMPLE_16BIT_SCALING 32767.0f #define SAMPLE_16BIT_SCALING 32767.0f


@@ -81,6 +82,11 @@
advice from Fons Adriaensen: make the limits symmetrical 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_MAX 8388607
#define SAMPLE_24BIT_MIN -8388607 #define SAMPLE_24BIT_MIN -8388607
#define SAMPLE_24BIT_MAX_F 8388607.0f #define SAMPLE_24BIT_MAX_F 8388607.0f
@@ -106,6 +112,7 @@
*/ */


#define f_round(f) lrintf(f) #define f_round(f) lrintf(f)
#define d_round(f) lrint(f)


#define float_16(s, d)\ #define float_16(s, d)\
if ((s) <= NORMALIZED_FLOAT_MIN) {\ if ((s) <= NORMALIZED_FLOAT_MIN) {\
@@ -146,6 +153,15 @@
(d) = f_round ((s) * SAMPLE_24BIT_SCALING); \ (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) /* 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)); 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) static inline __m128i float_24_sse(__m128 s)
{ {
const __m128 upper_bound = gen_one(); /* NORMALIZED_FLOAT_MAX */ 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 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 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 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 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 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 16s - like 16 but reverse endian from the host CPU


For obvious reasons, the reverse endian versions only show as source types. 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 */ /* 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) 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) #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 #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) 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) #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) 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__) #if defined (__SSE2__) && !defined (__sun__)


+ 4
- 0
common/memops.h View File

@@ -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); 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 */ /* 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_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_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); 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_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_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_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_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); void sample_move_dS_s32l24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);


+ 70
- 0
linux/alsa/alsa_driver.c View File

@@ -314,10 +314,45 @@ alsa_driver_setup_io_function_pointers (alsa_driver_t *driver)
break; break;


case 4: /* NO DITHER */ case 4: /* NO DITHER */
switch (driver->playback_sample_format)
{
case SND_PCM_FORMAT_S24_LE:
case SND_PCM_FORMAT_S24_BE:
driver->write_via_copy = driver->quirk_bswap? driver->write_via_copy = driver->quirk_bswap?
sample_move_d32l24_sSs: sample_move_d32l24_sSs:
sample_move_d32l24_sS; sample_move_d32l24_sS;
break; break;
case SND_PCM_FORMAT_S32_LE:
case SND_PCM_FORMAT_S32_BE:
{
int bits = snd_pcm_hw_params_get_sbits(driver->playback_hw_params);
if (bits == 32)
{
driver->write_via_copy = driver->quirk_bswap?
sample_move_d32_sSs:
sample_move_d32_sS;
}
else if (bits == 24)
{
jack_log("sample format is SND_PCM_FORMAT_S32 but only 24 bits available");
driver->write_via_copy = driver->quirk_bswap?
sample_move_d32u24_sSs:
sample_move_d32u24_sS;
}
else
{
jack_error("unsupported sample format for playback: "
"SND_PCM_FORMAT_S32 with %d bits",
bits);
exit (1);
}
break;
}
default:
jack_error("unsupported 4 byte sample_format");
exit (1);
}
break;


default: default:
jack_error ("impossible sample width (%d) discovered!", jack_error ("impossible sample width (%d) discovered!",
@@ -343,10 +378,45 @@ alsa_driver_setup_io_function_pointers (alsa_driver_t *driver)
sample_move_dS_s24; sample_move_dS_s24;
break; break;
case 4: case 4:
switch (driver->capture_sample_format)
{
case SND_PCM_FORMAT_S24_LE:
case SND_PCM_FORMAT_S24_BE:
driver->read_via_copy = driver->quirk_bswap? driver->read_via_copy = driver->quirk_bswap?
sample_move_dS_s32l24s: sample_move_dS_s32l24s:
sample_move_dS_s32l24; sample_move_dS_s32l24;
break; break;
case SND_PCM_FORMAT_S32_LE:
case SND_PCM_FORMAT_S32_BE:
{
int bits = snd_pcm_hw_params_get_sbits(driver->capture_hw_params);
if (bits == 32)
{
driver->read_via_copy = driver->quirk_bswap?
sample_move_dS_s32s:
sample_move_dS_s32;
}
else if(bits == 24)
{
jack_log("sample format is SND_PCM_FORMAT_S32 but only 24 bits available");
driver->read_via_copy = driver->quirk_bswap?
sample_move_dS_s32u24s:
sample_move_dS_s32u24;
}
else
{
jack_error("unsupported sample format for capture: "
"SND_PCM_FORMAT_S32 with %d bits",
bits);
exit (1);
}
break;
}
default:
jack_error("unsupported 4 byte sample_format");
exit (1);
}
break;
} }
} }
} }


Loading…
Cancel
Save