diff options
author | Max Kellermann <max@duempel.org> | 2013-04-09 01:24:52 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-04-09 01:24:52 +0200 |
commit | c654c7630aad220a4935c34b076e107b6b0561a5 (patch) | |
tree | 7ca6e4e30bee7153ed54f302467140180d77490d /src/pcm/PcmFormat.cxx | |
parent | 3f3b26fb0ee090bfc1321572904aa94deca42a84 (diff) |
pcm_*: move to src/pcm/
Diffstat (limited to 'src/pcm/PcmFormat.cxx')
-rw-r--r-- | src/pcm/PcmFormat.cxx | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/src/pcm/PcmFormat.cxx b/src/pcm/PcmFormat.cxx new file mode 100644 index 000000000..1385d161b --- /dev/null +++ b/src/pcm/PcmFormat.cxx @@ -0,0 +1,500 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "PcmFormat.hxx" +#include "PcmDither.hxx" +#include "pcm_buffer.h" +#include "pcm_pack.h" +#include "PcmUtils.hxx" + +#include <type_traits> + +template<typename S> +struct DefaultSampleBits { + typedef decltype(*S()) T; + typedef typename std::remove_reference<T>::type U; + + static constexpr auto value = sizeof(U) * 8; +}; + +static void +pcm_convert_8_to_16(int16_t *out, const int8_t *in, const int8_t *in_end) +{ + while (in < in_end) { + *out++ = *in++ << 8; + } +} + +static void +pcm_convert_24_to_16(PcmDither &dither, + int16_t *out, const int32_t *in, const int32_t *in_end) +{ + dither.Dither24To16(out, in, in_end); +} + +static void +pcm_convert_32_to_16(PcmDither &dither, + int16_t *out, const int32_t *in, const int32_t *in_end) +{ + dither.Dither32To16(out, in, in_end); +} + +template<typename S, unsigned bits=DefaultSampleBits<S>::value> +static void +ConvertFromFloat(S dest, const float *src, const float *end) +{ + typedef decltype(*S()) T; + typedef typename std::remove_reference<T>::type U; + + const float factor = 1 << (bits - 1); + + while (src != end) { + int sample(*src++ * factor); + *dest++ = PcmClamp<U, int, bits>(sample); + } +} + +template<typename S, unsigned bits=DefaultSampleBits<S>::value> +static void +ConvertFromFloat(S dest, const float *src, size_t size) +{ + ConvertFromFloat<S, bits>(dest, src, pcm_end_pointer(src, size)); +} + +template<typename S, unsigned bits=sizeof(S)*8> +static S * +AllocateFromFloat(pcm_buffer &buffer, const float *src, size_t src_size, + size_t *dest_size_r) +{ + constexpr size_t src_sample_size = sizeof(*src); + assert(src_size % src_sample_size == 0); + + const size_t num_samples = src_size / src_sample_size; + *dest_size_r = num_samples * sizeof(S); + S *dest = (S *)pcm_buffer_get(&buffer, *dest_size_r); + ConvertFromFloat<S *, bits>(dest, src, src_size); + return dest; +} + +static int16_t * +pcm_allocate_8_to_16(struct pcm_buffer *buffer, + const int8_t *src, size_t src_size, size_t *dest_size_r) +{ + int16_t *dest; + *dest_size_r = src_size / sizeof(*src) * sizeof(*dest); + dest = (int16_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_8_to_16(dest, src, pcm_end_pointer(src, src_size)); + return dest; +} + +static int16_t * +pcm_allocate_24p32_to_16(struct pcm_buffer *buffer, PcmDither &dither, + const int32_t *src, size_t src_size, + size_t *dest_size_r) +{ + int16_t *dest; + *dest_size_r = src_size / 2; + assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); + dest = (int16_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_24_to_16(dither, dest, src, + pcm_end_pointer(src, src_size)); + return dest; +} + +static int16_t * +pcm_allocate_32_to_16(struct pcm_buffer *buffer, PcmDither &dither, + const int32_t *src, size_t src_size, + size_t *dest_size_r) +{ + int16_t *dest; + *dest_size_r = src_size / 2; + assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); + dest = (int16_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_32_to_16(dither, dest, src, + pcm_end_pointer(src, src_size)); + return dest; +} + +static int16_t * +pcm_allocate_float_to_16(struct pcm_buffer *buffer, + const float *src, size_t src_size, + size_t *dest_size_r) +{ + return AllocateFromFloat<int16_t>(*buffer, src, src_size, dest_size_r); +} + +const int16_t * +pcm_convert_to_16(struct pcm_buffer *buffer, PcmDither &dither, + enum sample_format src_format, const void *src, + size_t src_size, size_t *dest_size_r) +{ + assert(src_size % sample_format_size(src_format) == 0); + + switch (src_format) { + case SAMPLE_FORMAT_UNDEFINED: + case SAMPLE_FORMAT_DSD: + break; + + case SAMPLE_FORMAT_S8: + return pcm_allocate_8_to_16(buffer, + (const int8_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S16: + *dest_size_r = src_size; + return (const int16_t *)src; + + case SAMPLE_FORMAT_S24_P32: + return pcm_allocate_24p32_to_16(buffer, dither, + (const int32_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S32: + return pcm_allocate_32_to_16(buffer, dither, + (const int32_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_FLOAT: + return pcm_allocate_float_to_16(buffer, + (const float *)src, src_size, + dest_size_r); + } + + return NULL; +} + +static void +pcm_convert_8_to_24(int32_t *out, const int8_t *in, const int8_t *in_end) +{ + while (in < in_end) + *out++ = *in++ << 16; +} + +static void +pcm_convert_16_to_24(int32_t *out, const int16_t *in, const int16_t *in_end) +{ + while (in < in_end) + *out++ = *in++ << 8; +} + +static void +pcm_convert_32_to_24(int32_t *restrict out, + const int32_t *restrict in, + const int32_t *restrict in_end) +{ + while (in < in_end) + *out++ = *in++ >> 8; +} + +static int32_t * +pcm_allocate_8_to_24(struct pcm_buffer *buffer, + const int8_t *src, size_t src_size, size_t *dest_size_r) +{ + int32_t *dest; + *dest_size_r = src_size / sizeof(*src) * sizeof(*dest); + dest = (int32_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_8_to_24(dest, src, pcm_end_pointer(src, src_size)); + return dest; +} + +static int32_t * +pcm_allocate_16_to_24(struct pcm_buffer *buffer, + const int16_t *src, size_t src_size, size_t *dest_size_r) +{ + int32_t *dest; + *dest_size_r = src_size * 2; + assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); + dest = (int32_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_16_to_24(dest, src, pcm_end_pointer(src, src_size)); + return dest; +} + +static int32_t * +pcm_allocate_32_to_24(struct pcm_buffer *buffer, + const int32_t *src, size_t src_size, size_t *dest_size_r) +{ + *dest_size_r = src_size; + int32_t *dest = (int32_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_32_to_24(dest, src, pcm_end_pointer(src, src_size)); + return dest; +} + +static int32_t * +pcm_allocate_float_to_24(struct pcm_buffer *buffer, + const float *src, size_t src_size, + size_t *dest_size_r) +{ + return AllocateFromFloat<int32_t, 24>(*buffer, src, src_size, + dest_size_r); +} + +const int32_t * +pcm_convert_to_24(struct pcm_buffer *buffer, + enum sample_format src_format, const void *src, + size_t src_size, size_t *dest_size_r) +{ + assert(src_size % sample_format_size(src_format) == 0); + + switch (src_format) { + case SAMPLE_FORMAT_UNDEFINED: + case SAMPLE_FORMAT_DSD: + break; + + case SAMPLE_FORMAT_S8: + return pcm_allocate_8_to_24(buffer, + (const int8_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S16: + return pcm_allocate_16_to_24(buffer, + (const int16_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S24_P32: + *dest_size_r = src_size; + return (const int32_t *)src; + + case SAMPLE_FORMAT_S32: + return pcm_allocate_32_to_24(buffer, + (const int32_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_FLOAT: + return pcm_allocate_float_to_24(buffer, + (const float *)src, src_size, + dest_size_r); + } + + return NULL; +} + +static void +pcm_convert_8_to_32(int32_t *out, const int8_t *in, const int8_t *in_end) +{ + while (in < in_end) + *out++ = *in++ << 24; +} + +static void +pcm_convert_16_to_32(int32_t *out, const int16_t *in, const int16_t *in_end) +{ + while (in < in_end) + *out++ = *in++ << 16; +} + +static void +pcm_convert_24_to_32(int32_t *restrict out, + const int32_t *restrict in, + const int32_t *restrict in_end) +{ + while (in < in_end) + *out++ = *in++ << 8; +} + +static int32_t * +pcm_allocate_8_to_32(struct pcm_buffer *buffer, + const int8_t *src, size_t src_size, size_t *dest_size_r) +{ + int32_t *dest; + *dest_size_r = src_size / sizeof(*src) * sizeof(*dest); + dest = (int32_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_8_to_32(dest, src, pcm_end_pointer(src, src_size)); + return dest; +} + +static int32_t * +pcm_allocate_16_to_32(struct pcm_buffer *buffer, + const int16_t *src, size_t src_size, size_t *dest_size_r) +{ + int32_t *dest; + *dest_size_r = src_size * 2; + assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); + dest = (int32_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_16_to_32(dest, src, pcm_end_pointer(src, src_size)); + return dest; +} + +static int32_t * +pcm_allocate_24p32_to_32(struct pcm_buffer *buffer, + const int32_t *src, size_t src_size, + size_t *dest_size_r) +{ + *dest_size_r = src_size; + int32_t *dest = (int32_t *)pcm_buffer_get(buffer, *dest_size_r); + pcm_convert_24_to_32(dest, src, pcm_end_pointer(src, src_size)); + return dest; +} + +static int32_t * +pcm_allocate_float_to_32(struct pcm_buffer *buffer, + const float *src, size_t src_size, + size_t *dest_size_r) +{ + /* convert to S24_P32 first */ + int32_t *dest = pcm_allocate_float_to_24(buffer, src, src_size, + dest_size_r); + + /* convert to 32 bit in-place */ + pcm_convert_24_to_32(dest, dest, pcm_end_pointer(dest, *dest_size_r)); + return dest; +} + +const int32_t * +pcm_convert_to_32(struct pcm_buffer *buffer, + enum sample_format src_format, const void *src, + size_t src_size, size_t *dest_size_r) +{ + assert(src_size % sample_format_size(src_format) == 0); + + switch (src_format) { + case SAMPLE_FORMAT_UNDEFINED: + case SAMPLE_FORMAT_DSD: + break; + + case SAMPLE_FORMAT_S8: + return pcm_allocate_8_to_32(buffer, + (const int8_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S16: + return pcm_allocate_16_to_32(buffer, + (const int16_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S24_P32: + return pcm_allocate_24p32_to_32(buffer, + (const int32_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S32: + *dest_size_r = src_size; + return (const int32_t *)src; + + case SAMPLE_FORMAT_FLOAT: + return pcm_allocate_float_to_32(buffer, + (const float *)src, src_size, + dest_size_r); + } + + return NULL; +} + +template<typename S, unsigned bits=DefaultSampleBits<S>::value> +static void +ConvertToFloat(float *dest, S src, S end) +{ + constexpr float factor = 0.5 / (1 << (bits - 2)); + while (src != end) + *dest++ = float(*src++) * factor; + +} + +template<typename S, unsigned bits=DefaultSampleBits<S>::value> +static void +ConvertToFloat(float *dest, S src, size_t size) +{ + ConvertToFloat<S, bits>(dest, src, pcm_end_pointer(src, size)); +} + +template<typename S, unsigned bits=DefaultSampleBits<S>::value> +static float * +AllocateToFloat(pcm_buffer &buffer, S src, size_t src_size, + size_t *dest_size_r) +{ + constexpr size_t src_sample_size = sizeof(*S()); + assert(src_size % src_sample_size == 0); + + const size_t num_samples = src_size / src_sample_size; + *dest_size_r = num_samples * sizeof(float); + float *dest = (float *)pcm_buffer_get(&buffer, *dest_size_r); + ConvertToFloat<S, bits>(dest, src, src_size); + return dest; +} + +static float * +pcm_allocate_8_to_float(struct pcm_buffer *buffer, + const int8_t *src, size_t src_size, + size_t *dest_size_r) +{ + return AllocateToFloat(*buffer, src, src_size, dest_size_r); +} + +static float * +pcm_allocate_16_to_float(struct pcm_buffer *buffer, + const int16_t *src, size_t src_size, + size_t *dest_size_r) +{ + return AllocateToFloat(*buffer, src, src_size, dest_size_r); +} + +static float * +pcm_allocate_24p32_to_float(struct pcm_buffer *buffer, + const int32_t *src, size_t src_size, + size_t *dest_size_r) +{ + return AllocateToFloat<decltype(src), 24> + (*buffer, src, src_size, dest_size_r); +} + +static float * +pcm_allocate_32_to_float(struct pcm_buffer *buffer, + const int32_t *src, size_t src_size, + size_t *dest_size_r) +{ + return AllocateToFloat(*buffer, src, src_size, dest_size_r); +} + +const float * +pcm_convert_to_float(struct pcm_buffer *buffer, + enum sample_format src_format, const void *src, + size_t src_size, size_t *dest_size_r) +{ + switch (src_format) { + case SAMPLE_FORMAT_UNDEFINED: + case SAMPLE_FORMAT_DSD: + break; + + case SAMPLE_FORMAT_S8: + return pcm_allocate_8_to_float(buffer, + (const int8_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S16: + return pcm_allocate_16_to_float(buffer, + (const int16_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S24_P32: + return pcm_allocate_24p32_to_float(buffer, + (const int32_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_S32: + return pcm_allocate_32_to_float(buffer, + (const int32_t *)src, src_size, + dest_size_r); + + case SAMPLE_FORMAT_FLOAT: + *dest_size_r = src_size; + return (const float *)src; + } + + return NULL; +} |