From 6dc76d11583979ba73dbe4bbf54f52fc1af901e2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 16 Jan 2009 03:15:39 +0100 Subject: add support for 24bit packed samples --- src/modules/alsa/alsa-util.c | 8 +++ src/modules/oss/oss-util.c | 2 + src/pulse/sample.c | 16 +++++- src/pulse/sample.h | 26 +++++++-- src/pulse/stream.c | 1 + src/pulsecore/endianmacros.h | 38 +++++++++++++ src/pulsecore/envelope.c | 1 - src/pulsecore/protocol-native.c | 7 +++ src/pulsecore/resampler.c | 4 +- src/pulsecore/sample-util.c | 123 ++++++++++++++++++++++++++++++++++++++++ src/pulsecore/sconv-s16be.c | 16 +++++- src/pulsecore/sconv-s16be.h | 20 +++---- src/pulsecore/sconv-s16le.c | 112 +++++++++++++++++++++++++++++++++++- src/pulsecore/sconv-s16le.h | 20 +++---- src/pulsecore/sconv.c | 8 +++ 15 files changed, 370 insertions(+), 32 deletions(-) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 871471f1..7616ad1d 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -232,6 +232,8 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE, [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE, + [PA_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE, + [PA_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE, }; static const pa_sample_format_t try_order[] = { @@ -239,6 +241,8 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s PA_SAMPLE_FLOAT32RE, PA_SAMPLE_S32NE, PA_SAMPLE_S32RE, + PA_SAMPLE_S24NE, + PA_SAMPLE_S24RE, PA_SAMPLE_S16NE, PA_SAMPLE_S16RE, PA_SAMPLE_ALAW, @@ -259,6 +263,10 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s *f = PA_SAMPLE_FLOAT32LE; else if (*f == PA_SAMPLE_FLOAT32LE) *f = PA_SAMPLE_FLOAT32BE; + else if (*f == PA_SAMPLE_S24BE) + *f = PA_SAMPLE_S24LE; + else if (*f == PA_SAMPLE_S24LE) + *f = PA_SAMPLE_S24BE; else if (*f == PA_SAMPLE_S16BE) *f = PA_SAMPLE_S16LE; else if (*f == PA_SAMPLE_S16LE) diff --git a/src/modules/oss/oss-util.c b/src/modules/oss/oss-util.c index f766030d..fbe930cd 100644 --- a/src/modules/oss/oss-util.c +++ b/src/modules/oss/oss-util.c @@ -164,6 +164,8 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss) { [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */ [PA_SAMPLE_S32LE] = AFMT_QUERY, /* not supported */ [PA_SAMPLE_S32BE] = AFMT_QUERY, /* not supported */ + [PA_SAMPLE_S24LE] = AFMT_QUERY, /* not supported */ + [PA_SAMPLE_S24BE] = AFMT_QUERY, /* not supported */ }; pa_assert(fd >= 0); diff --git a/src/pulse/sample.c b/src/pulse/sample.c index 29501595..8228a9bb 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -48,6 +48,8 @@ size_t pa_sample_size(const pa_sample_spec *spec) { [PA_SAMPLE_FLOAT32BE] = 4, [PA_SAMPLE_S32LE] = 4, [PA_SAMPLE_S32BE] = 4, + [PA_SAMPLE_S24LE] = 3, + [PA_SAMPLE_S24BE] = 3 }; pa_assert(spec); @@ -125,6 +127,8 @@ const char *pa_sample_format_to_string(pa_sample_format_t f) { [PA_SAMPLE_FLOAT32BE] = "float32be", [PA_SAMPLE_S32LE] = "s32le", [PA_SAMPLE_S32BE] = "s32be", + [PA_SAMPLE_S24LE] = "s24le", + [PA_SAMPLE_S24BE] = "s24be", }; if (f < 0 || f >= PA_SAMPLE_MAX) @@ -194,8 +198,16 @@ pa_sample_format_t pa_parse_sample_format(const char *format) { return PA_SAMPLE_S32BE; else if (strcasecmp(format, "s32ne") == 0 || strcasecmp(format, "s32") == 0 || strcasecmp(format, "32") == 0) return PA_SAMPLE_S32NE; - else if (strcasecmp(format, "s32re") == 0) - return PA_SAMPLE_S32RE; + else if (strcasecmp(format, "s24re") == 0) + return PA_SAMPLE_S24RE; + else if (strcasecmp(format, "s24le") == 0) + return PA_SAMPLE_S24LE; + else if (strcasecmp(format, "s24be") == 0) + return PA_SAMPLE_S24BE; + else if (strcasecmp(format, "s24ne") == 0 || strcasecmp(format, "s24") == 0 || strcasecmp(format, "24") == 0) + return PA_SAMPLE_S24NE; + else if (strcasecmp(format, "s24re") == 0) + return PA_SAMPLE_S24RE; return -1; } diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 3c7dd0e7..8d09d32e 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -51,6 +51,8 @@ * \li PA_SAMPLE_ULAW - 8 bit mu-Law. * \li PA_SAMPLE_S32LE - Signed 32 bit integer PCM, little endian. * \li PA_SAMPLE_S32BE - Signed 32 bit integer PCM, big endian. + * \li PA_SAMPLE_242LE - Signed 24 bit integer PCM packed, little endian. + * \li PA_SAMPLE_242BE - Signed 24 bit integer PCM packed, big endian. * * The floating point sample formats have the range from -1.0 to 1.0. * @@ -145,7 +147,13 @@ typedef enum pa_sample_format { /**< Signed 32 Bit PCM, little endian (PC) */ PA_SAMPLE_S32BE, - /**< Signed 32 Bit PCM, big endian (PC) */ + /**< Signed 32 Bit PCM, big endian */ + + PA_SAMPLE_S24LE, + /**< Signed 24 Bit PCM packed, little endian (PC) */ + + PA_SAMPLE_S24BE, + /**< Signed 24 Bit PCM packed, big endian */ PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ @@ -161,12 +169,16 @@ typedef enum pa_sample_format { #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE /** Signed 32 Bit PCM, native endian */ #define PA_SAMPLE_S32NE PA_SAMPLE_S32BE +/** Signed 24 Bit PCM packed, native endian */ +#define PA_SAMPLE_S24NE PA_SAMPLE_S24BE /** Signed 16 Bit PCM reverse endian */ #define PA_SAMPLE_S16RE PA_SAMPLE_S16LE /** 32 Bit IEEE floating point, reverse endian */ #define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE -/** Signed 32 Bit PCM reverse endian */ +/** Signed 32 Bit PCM, reverse endian */ #define PA_SAMPLE_S32RE PA_SAMPLE_S32LE +/** Signed 24 Bit PCM, packed reverse endian */ +#define PA_SAMPLE_S24RE PA_SAMPLE_242LE #else /** Signed 16 Bit PCM, native endian */ #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE @@ -174,12 +186,16 @@ typedef enum pa_sample_format { #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE /** Signed 32 Bit PCM, native endian */ #define PA_SAMPLE_S32NE PA_SAMPLE_S32LE -/** Signed 16 Bit PCM reverse endian */ +/** Signed 24 Bit PCM packed, native endian */ +#define PA_SAMPLE_S24NE PA_SAMPLE_S24LE +/** Signed 16 Bit PCM, reverse endian */ #define PA_SAMPLE_S16RE PA_SAMPLE_S16BE /** 32 Bit IEEE floating point, reverse endian */ #define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE -/** Signed 32 Bit PCM reverse endian */ +/** Signed 32 Bit PCM, reverse endian */ #define PA_SAMPLE_S32RE PA_SAMPLE_S32BE +/** Signed 24 Bit PCM packed, reverse endian */ +#define PA_SAMPLE_S24RE PA_SAMPLE_S24BE #endif /** A Shortcut for PA_SAMPLE_FLOAT32NE */ @@ -196,6 +212,8 @@ typedef enum pa_sample_format { #define PA_SAMPLE_FLOAT32BE PA_SAMPLE_FLOAT32BE #define PA_SAMPLE_S32LE PA_SAMPLE_S32LE #define PA_SAMPLE_S32BE PA_SAMPLE_S32BE +#define PA_SAMPLE_S24LE PA_SAMPLE_S24LE +#define PA_SAMPLE_S24BE PA_SAMPLE_S24BE /** \endcond */ /** A sample format and attribute specification */ diff --git a/src/pulse/stream.c b/src/pulse/stream.c index c0ae4ac2..2a958e04 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -87,6 +87,7 @@ pa_stream *pa_stream_new_with_proplist( PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 12 || (ss->format != PA_SAMPLE_S32LE && ss->format != PA_SAMPLE_S32BE), PA_ERR_NOTSUPPORTED); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 15 || (ss->format != PA_SAMPLE_S24LE && ss->format != PA_SAMPLE_S24BE), PA_ERR_NOTSUPPORTED); PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, name || (p && pa_proplist_contains(p, PA_PROP_MEDIA_NAME)), PA_ERR_INVALID); diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h index 85bebd68..eea1c743 100644 --- a/src/pulsecore/endianmacros.h +++ b/src/pulsecore/endianmacros.h @@ -45,6 +45,32 @@ #define PA_UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) (x) >> 24) | ((uint32_t) (x) << 24) | (((uint32_t) (x) & 0xFF00) << 8) | ((((uint32_t) (x)) >> 8) & 0xFF00) ) ) #endif +static inline uint32_t PA_READ24LE(const uint8_t *p) { + return + ((uint32_t) p[0] << 16) | + ((uint32_t) p[1] << 8) | + ((uint32_t) p[2]); +} + +static inline uint32_t PA_READ24BE(const uint8_t *p) { + return + ((uint32_t) p[2] << 16) | + ((uint32_t) p[1] << 8) | + ((uint32_t) p[0]); +} + +static inline void PA_WRITE24LE(uint8_t *p, uint32_t u) { + p[0] = (uint8_t) (u >> 16); + p[1] = (uint8_t) (u >> 8); + p[2] = (uint8_t) u; +} + +static inline void PA_WRITE24BE(uint8_t *p, uint32_t u) { + p[2] = (uint8_t) (u >> 16); + p[1] = (uint8_t) (u >> 8); + p[0] = (uint8_t) u; +} + static inline float PA_FLOAT32_SWAP(float x) { union { float f; @@ -91,6 +117,12 @@ static inline float PA_FLOAT32_SWAP(float x) { #define PA_FLOAT32_TO_LE(x) PA_FLOAT32_SWAP(x) #define PA_FLOAT32_TO_BE(x) ((float) (x)) + + #define PA_READ24NE(x) PA_READ24BE(x) + #define PA_WRITE24NE(x,y) PA_WRITE24BE((x),(y)) + + #define PA_READ24RE(x) PA_READ24LE(x) + #define PA_WRITE24RE(x,y) PA_WRITE24LE((x),(y)) #else #define PA_INT16_FROM_LE(x) ((int16_t)(x)) #define PA_INT16_FROM_BE(x) PA_INT16_SWAP(x) @@ -118,6 +150,12 @@ static inline float PA_FLOAT32_SWAP(float x) { #define PA_FLOAT32_TO_LE(x) ((float) (x)) #define PA_FLOAT32_TO_BE(x) PA_FLOAT32_SWAP(x) + + #define PA_READ24NE(x) PA_READ24LE(x) + #define PA_WRITE24NE(x,y) PA_WRITE24LE((x),(y)) + + #define PA_READ24RE(x) PA_READ24BE(x) + #define PA_WRITE24RE(x,y) PA_WRITE24BE((x),(y)) #endif #endif diff --git a/src/pulsecore/envelope.c b/src/pulsecore/envelope.c index 7f2252e9..f872d347 100644 --- a/src/pulsecore/envelope.c +++ b/src/pulsecore/envelope.c @@ -600,7 +600,6 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { switch (e->sample_spec.format) { - case PA_SAMPLE_U8: { uint8_t *t; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index af013da3..b1ef64f2 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2640,6 +2640,13 @@ static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, co if (fixed->format == PA_SAMPLE_S32BE) fixed->format = PA_SAMPLE_FLOAT32BE; } + + if (c->version < 15) { + if (fixed->format == PA_SAMPLE_S24LE) + fixed->format = PA_SAMPLE_FLOAT32LE; + if (fixed->format == PA_SAMPLE_S24BE) + fixed->format = PA_SAMPLE_FLOAT32BE; + } } static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) { diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index f0515ebe..67c37581 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -257,8 +257,10 @@ pa_resampler* pa_resampler_new( if (a->format == PA_SAMPLE_S32NE || a->format == PA_SAMPLE_S32RE || a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE || + a->format == PA_SAMPLE_S24NE || a->format == PA_SAMPLE_S24RE || b->format == PA_SAMPLE_S32NE || b->format == PA_SAMPLE_S32RE || - b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE) + b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE || + b->format == PA_SAMPLE_S24NE || b->format == PA_SAMPLE_S24RE) r->work_format = PA_SAMPLE_FLOAT32NE; else r->work_format = PA_SAMPLE_S16NE; diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 3be08efd..533181b8 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -83,6 +83,8 @@ static uint8_t silence_byte(pa_sample_format_t format) { case PA_SAMPLE_S32BE: case PA_SAMPLE_FLOAT32LE: case PA_SAMPLE_FLOAT32BE: + case PA_SAMPLE_S24LE: + case PA_SAMPLE_S24BE: return 0; case PA_SAMPLE_ALAW: return 0xd5; @@ -340,6 +342,78 @@ size_t pa_mix( break; } + case PA_SAMPLE_S24NE: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int64_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t cv = m->linear[channel].i; + int64_t v; + + if (PA_UNLIKELY(cv <= 0)) + continue; + + v = (int32_t) (PA_READ24NE(m->ptr) << 8); + v = (v * cv) / 0x10000; + sum += v; + + m->ptr = (uint8_t*) m->ptr + 3; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(data, ((uint32_t) sum) >> 8); + + data = (uint8_t*) data + 3; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + + case PA_SAMPLE_S24RE: { + unsigned channel = 0; + + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); + + while (data < end) { + int64_t sum = 0; + unsigned i; + + for (i = 0; i < nstreams; i++) { + pa_mix_info *m = streams + i; + int32_t cv = m->linear[channel].i; + int64_t v; + + if (PA_UNLIKELY(cv <= 0)) + continue; + + v = (int32_t) (PA_READ24RE(m->ptr) << 8); + v = (v * cv) / 0x10000; + sum += v; + + m->ptr = (uint8_t*) m->ptr + 3; + } + + sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(data, ((uint32_t) sum) >> 8); + + data = (uint8_t*) data + 3; + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + + break; + } + case PA_SAMPLE_U8: { unsigned channel = 0; @@ -642,7 +716,52 @@ void pa_volume_memchunk( if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; } + break; + } + + case PA_SAMPLE_S24NE: { + uint8_t *d, *e; + unsigned channel; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_volume(linear, volume); + + e = (uint8_t*) ptr + c->length/3; + + for (channel = 0, d = ptr; d < e; d++) { + int64_t t; + t = (int64_t)((int32_t) (PA_READ24NE(d) << 8)); + t = (t * linear[channel]) / 0x10000; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(d, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } + break; + } + + case PA_SAMPLE_S24RE: { + uint8_t *d, *e; + unsigned channel; + int32_t linear[PA_CHANNELS_MAX]; + + calc_linear_integer_volume(linear, volume); + + e = (uint8_t*) ptr + c->length/3; + + for (channel = 0, d = ptr; d < e; d++) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24RE(d) << 8)); + t = (t * linear[channel]) / 0x10000; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(d, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= spec->channels)) + channel = 0; + } break; } @@ -900,12 +1019,16 @@ pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool, case PA_SAMPLE_S16BE: case PA_SAMPLE_S32LE: case PA_SAMPLE_S32BE: + case PA_SAMPLE_S24LE: + case PA_SAMPLE_S24BE: case PA_SAMPLE_FLOAT32LE: case PA_SAMPLE_FLOAT32BE: cache->blocks[PA_SAMPLE_S16LE] = b = silence_memblock_new(pool, 0); cache->blocks[PA_SAMPLE_S16BE] = pa_memblock_ref(b); cache->blocks[PA_SAMPLE_S32LE] = pa_memblock_ref(b); cache->blocks[PA_SAMPLE_S32BE] = pa_memblock_ref(b); + cache->blocks[PA_SAMPLE_S24LE] = pa_memblock_ref(b); + cache->blocks[PA_SAMPLE_S24BE] = pa_memblock_ref(b); cache->blocks[PA_SAMPLE_FLOAT32LE] = pa_memblock_ref(b); cache->blocks[PA_SAMPLE_FLOAT32BE] = pa_memblock_ref(b); break; diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c index e7e1449a..d6137d39 100644 --- a/src/pulsecore/sconv-s16be.c +++ b/src/pulsecore/sconv-s16be.c @@ -31,24 +31,34 @@ #define INT32_FROM PA_INT32_FROM_BE #define INT32_TO PA_INT32_TO_BE +#define READ24 PA_READ24BE +#define WRITE24 PA_WRITE24BE + #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne #define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne - #define pa_sconv_s16le_to_float32re pa_sconv_s16be_to_float32re #define pa_sconv_s16le_from_float32re pa_sconv_s16be_from_float32re #define pa_sconv_s32le_to_float32ne pa_sconv_s32be_to_float32ne #define pa_sconv_s32le_from_float32ne pa_sconv_s32be_from_float32ne - #define pa_sconv_s32le_to_float32re pa_sconv_s32be_to_float32re #define pa_sconv_s32le_from_float32re pa_sconv_s32be_from_float32re +#define pa_sconv_s24le_to_float32ne pa_sconv_s24be_to_float32ne +#define pa_sconv_s24le_from_float32ne pa_sconv_s24be_from_float32ne +#define pa_sconv_s24le_to_float32re pa_sconv_s24be_to_float32re +#define pa_sconv_s24le_from_float32re pa_sconv_s24be_from_float32re + #define pa_sconv_s32le_to_s16ne pa_sconv_s32be_to_s16ne #define pa_sconv_s32le_from_s16ne pa_sconv_s32be_from_s16ne - #define pa_sconv_s32le_to_s16re pa_sconv_s32be_to_s16re #define pa_sconv_s32le_from_s16re pa_sconv_s32be_from_s16re +#define pa_sconv_s24le_to_s16ne pa_sconv_s24be_to_s16ne +#define pa_sconv_s24le_from_s16ne pa_sconv_s24be_from_s16ne +#define pa_sconv_s24le_to_s16re pa_sconv_s24be_to_s16re +#define pa_sconv_s24le_from_s16re pa_sconv_s24be_from_s16re + #ifdef WORDS_BIGENDIAN #define SWAP_WORDS 0 #else diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h index 60580815..1b88fd45 100644 --- a/src/pulsecore/sconv-s16be.h +++ b/src/pulsecore/sconv-s16be.h @@ -34,26 +34,26 @@ void pa_sconv_s32be_from_float32ne(unsigned n, const float *a, int32_t *b); void pa_sconv_s32be_to_float32re(unsigned n, const int32_t *a, float *b); void pa_sconv_s32be_from_float32re(unsigned n, const float *a, int32_t *b); +void pa_sconv_s24be_to_float32ne(unsigned n, const uint8_t *a, float *b); +void pa_sconv_s24be_from_float32ne(unsigned n, const float *a, uint8_t *b); +void pa_sconv_s24be_to_float32re(unsigned n, const uint8_t *a, float *b); +void pa_sconv_s24be_from_float32re(unsigned n, const float *a, uint8_t *b); + void pa_sconv_s32be_to_s16ne(unsigned n, const int32_t *a, int16_t *b); void pa_sconv_s32be_from_s16ne(unsigned n, const int16_t *a, int32_t *b); void pa_sconv_s32be_to_s16re(unsigned n, const int32_t *a, int16_t *b); void pa_sconv_s32be_from_s16re(unsigned n, const int16_t *a, int32_t *b); +void pa_sconv_s24be_to_s16ne(unsigned n, const uint8_t *a, int16_t *b); +void pa_sconv_s24be_from_s16ne(unsigned n, const int16_t *a, uint8_t *b); +void pa_sconv_s24be_to_s16re(unsigned n, const uint8_t *a, int16_t *b); +void pa_sconv_s24be_from_s16re(unsigned n, const int16_t *a, uint8_t *b); + #ifdef WORDS_BIGENDIAN #define pa_sconv_float32be_to_s16ne pa_sconv_s16be_from_float32ne #define pa_sconv_float32be_from_s16ne pa_sconv_s16be_to_float32ne #define pa_sconv_float32le_to_s16ne pa_sconv_s16be_from_float32re #define pa_sconv_float32le_from_s16ne pa_sconv_s16be_to_float32re - -#define pa_sconv_float32be_to_s32ne pa_sconv_s32be_from_float32ne -#define pa_sconv_float32be_from_s32ne pa_sconv_s32be_to_float32ne -#define pa_sconv_float32le_to_s32ne pa_sconv_s32be_from_float32re -#define pa_sconv_float32le_from_s32ne pa_sconv_s32be_to_float32re - -#define pa_sconv_s16be_to_s32ne pa_sconv_s32be_from_s16ne -#define pa_sconv_s16be_from_s32ne pa_sconv_s32be_to_s16ne -#define pa_sconv_s16le_to_s32ne pa_sconv_s32be_from_s16re -#define pa_sconv_s16le_from_s32ne pa_sconv_s32be_to_s16re #endif #endif diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index 159c4655..37ebc983 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -23,7 +23,7 @@ #include #endif -/* Despite the name of this file we implement S32 handling here, too. */ +/* Despite the name of this file we implement S32 and S24 handling here, too. */ #include #include @@ -54,6 +54,14 @@ #define INT32_TO PA_INT32_TO_LE #endif +#ifndef READ24 +#define READ24 PA_READ24LE +#endif + +#ifndef WRITE24 +#define WRITE24 PA_WRITE24LE +#endif + #ifndef SWAP_WORDS #ifdef WORDS_BIGENDIAN #define SWAP_WORDS 1 @@ -243,3 +251,105 @@ void pa_sconv_s32le_from_s16re(unsigned n, const int16_t *a, int32_t *b) { b++; } } + +void pa_sconv_s24le_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + *b = (int16_t) (READ24(a) >> 8); + a += 3; + b++; + } +} + +void pa_sconv_s24le_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + WRITE24(b, ((uint32_t) *a) << 8); + a++; + b += 3; + } +} + +void pa_sconv_s24le_to_s16re(unsigned n, const uint8_t *a, int16_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int16_t s = (int16_t) (READ24(a) >> 8); + *b = PA_INT16_SWAP(s); + a += 3; + b++; + } +} + +void pa_sconv_s24le_from_s16re(unsigned n, const int16_t *a, uint8_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + uint32_t s = ((uint32_t) PA_INT16_SWAP(*a)) << 8; + WRITE24(b, s); + a++; + b += 3; + } +} + +void pa_sconv_s24le_to_float32ne(unsigned n, const uint8_t *a, float *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int32_t s = READ24(a) << 8; + *b = ((float) s) / 0x7FFFFFFF; + a += 3; + b ++; + } +} + +void pa_sconv_s24le_from_float32ne(unsigned n, const float *a, uint8_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int32_t s; + float v = *a; + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.0f); + s = (int32_t) lrint((double) v * (double) 0x7FFFFFFF); + WRITE24(b, ((uint32_t) s) >> 8); + a++; + b+=3; + } +} + +void pa_sconv_s24le_to_float32re(unsigned n, const uint8_t *a, float *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int32_t s = READ24(a) << 8; + float k = ((float) s) / 0x7FFFFFFF; + *b = PA_FLOAT32_SWAP(k); + a += 3; + b ++; + } +} + +void pa_sconv_s24le_from_float32re(unsigned n, const float *a, uint8_t *b) { + pa_assert(a); + pa_assert(b); + + for (; n > 0; n--) { + int32_t s; + float v = *a; + v = PA_FLOAT32_SWAP(v); + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.0f); + s = (int32_t) lrint((double) v * (double) 0x7FFFFFFF); + WRITE24(b, ((uint32_t) s) >> 8); + a++; + b+=3; + } +} diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h index 8d4c87c3..b853515c 100644 --- a/src/pulsecore/sconv-s16le.h +++ b/src/pulsecore/sconv-s16le.h @@ -34,26 +34,26 @@ void pa_sconv_s32le_from_float32ne(unsigned n, const float *a, int32_t *b); void pa_sconv_s32le_to_float32re(unsigned n, const int32_t *a, float *b); void pa_sconv_s32le_from_float32re(unsigned n, const float *a, int32_t *b); +void pa_sconv_s24le_to_float32ne(unsigned n, const uint8_t *a, float *b); +void pa_sconv_s24le_from_float32ne(unsigned n, const float *a, uint8_t *b); +void pa_sconv_s24le_to_float32re(unsigned n, const uint8_t *a, float *b); +void pa_sconv_s24le_from_float32re(unsigned n, const float *a, uint8_t *b); + void pa_sconv_s32le_to_s16ne(unsigned n, const int32_t *a, int16_t *b); void pa_sconv_s32le_from_s16ne(unsigned n, const int16_t *a, int32_t *b); void pa_sconv_s32le_to_s16re(unsigned n, const int32_t *a, int16_t *b); void pa_sconv_s32le_from_s16re(unsigned n, const int16_t *a, int32_t *b); +void pa_sconv_s24le_to_s16ne(unsigned n, const uint8_t *a, int16_t *b); +void pa_sconv_s24le_from_s16ne(unsigned n, const int16_t *a, uint8_t *b); +void pa_sconv_s24le_to_s16re(unsigned n, const uint8_t *a, int16_t *b); +void pa_sconv_s24le_from_s16re(unsigned n, const int16_t *a, uint8_t *b); + #ifndef WORDS_BIGENDIAN #define pa_sconv_float32be_to_s16ne pa_sconv_s16le_from_float32re #define pa_sconv_float32be_from_s16ne pa_sconv_s16le_to_float32re #define pa_sconv_float32le_to_s16ne pa_sconv_s16le_from_float32ne #define pa_sconv_float32le_from_s16ne pa_sconv_s16le_to_float32ne - -#define pa_sconv_float32be_to_s32ne pa_sconv_s32le_from_float32re -#define pa_sconv_float32be_from_s32ne pa_sconv_s32le_to_float32re -#define pa_sconv_float32le_to_s32ne pa_sconv_s32le_from_float32ne -#define pa_sconv_float32le_from_s32ne pa_sconv_s32le_to_float32ne - -#define pa_sconv_s16be_to_s32ne pa_sconv_s32le_from_s16re -#define pa_sconv_s16be_from_s32ne pa_sconv_s32le_to_s16re -#define pa_sconv_s16le_to_s32ne pa_sconv_s32le_from_s16ne -#define pa_sconv_s16le_from_s32ne pa_sconv_s32le_to_s16ne #endif #endif diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index 6c4d420e..13700c12 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -198,6 +198,8 @@ pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_to_float32ne, [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_to_float32ne, [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_to_float32ne, + [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_to_float32ne, + [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_to_float32ne, [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, }; @@ -216,6 +218,8 @@ pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_from_float32ne, [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_from_float32ne, [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_from_float32ne, + [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_from_float32ne, + [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_from_float32ne, [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_float32ne, @@ -238,6 +242,8 @@ pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) { [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_to_s16ne, [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_to_s16ne, [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_to_s16ne, + [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_to_s16ne, + [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_to_s16ne, [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_to_s16ne, [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_s16ne }; @@ -258,6 +264,8 @@ pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) { [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_from_s16ne, [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_from_s16ne, [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_from_s16ne, + [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_from_s16ne, + [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_from_s16ne, [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_s16ne, [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_from_s16ne, }; -- cgit