Commit 86a0f9cf authored by Max Kellermann's avatar Max Kellermann

PcmFormat: merge duplicate code with a template

parent e6a91d29
...@@ -24,6 +24,16 @@ ...@@ -24,6 +24,16 @@
#include "pcm_pack.h" #include "pcm_pack.h"
#include "PcmUtils.hxx" #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 static void
pcm_convert_8_to_16(int16_t *out, const int8_t *in, const int8_t *in_end) pcm_convert_8_to_16(int16_t *out, const int8_t *in, const int8_t *in_end)
{ {
...@@ -46,18 +56,43 @@ pcm_convert_32_to_16(PcmDither &dither, ...@@ -46,18 +56,43 @@ pcm_convert_32_to_16(PcmDither &dither,
dither.Dither32To16(out, in, in_end); dither.Dither32To16(out, in, in_end);
} }
template<typename S, unsigned bits=DefaultSampleBits<S>::value>
static void static void
pcm_convert_float_to_16(int16_t *out, const float *in, const float *in_end) ConvertFromFloat(S dest, const float *src, const float *end)
{ {
const unsigned OUT_BITS = 16; typedef decltype(*S()) T;
const float factor = 1 << (OUT_BITS - 1); typedef typename std::remove_reference<T>::type U;
while (in < in_end) { const float factor = 1 << (bits - 1);
int sample = *in++ * factor;
*out++ = pcm_clamp_16(sample); 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 * static int16_t *
pcm_allocate_8_to_16(struct pcm_buffer *buffer, pcm_allocate_8_to_16(struct pcm_buffer *buffer,
const int8_t *src, size_t src_size, size_t *dest_size_r) const int8_t *src, size_t src_size, size_t *dest_size_r)
...@@ -102,13 +137,7 @@ pcm_allocate_float_to_16(struct pcm_buffer *buffer, ...@@ -102,13 +137,7 @@ pcm_allocate_float_to_16(struct pcm_buffer *buffer,
const float *src, size_t src_size, const float *src, size_t src_size,
size_t *dest_size_r) size_t *dest_size_r)
{ {
int16_t *dest; return AllocateFromFloat<int16_t>(*buffer, src, src_size, dest_size_r);
*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_float_to_16(dest, src,
pcm_end_pointer(src, src_size));
return dest;
} }
const int16_t * const int16_t *
...@@ -174,18 +203,6 @@ pcm_convert_32_to_24(int32_t *restrict out, ...@@ -174,18 +203,6 @@ pcm_convert_32_to_24(int32_t *restrict out,
*out++ = *in++ >> 8; *out++ = *in++ >> 8;
} }
static void
pcm_convert_float_to_24(int32_t *out, const float *in, const float *in_end)
{
const unsigned OUT_BITS = 24;
const float factor = 1 << (OUT_BITS - 1);
while (in < in_end) {
int sample = *in++ * factor;
*out++ = pcm_clamp_24(sample);
}
}
static int32_t * static int32_t *
pcm_allocate_8_to_24(struct pcm_buffer *buffer, pcm_allocate_8_to_24(struct pcm_buffer *buffer,
const int8_t *src, size_t src_size, size_t *dest_size_r) const int8_t *src, size_t src_size, size_t *dest_size_r)
...@@ -224,10 +241,8 @@ pcm_allocate_float_to_24(struct pcm_buffer *buffer, ...@@ -224,10 +241,8 @@ pcm_allocate_float_to_24(struct pcm_buffer *buffer,
const float *src, size_t src_size, const float *src, size_t src_size,
size_t *dest_size_r) size_t *dest_size_r)
{ {
*dest_size_r = src_size; return AllocateFromFloat<int32_t, 24>(*buffer, src, src_size,
int32_t *dest = (int32_t *)pcm_buffer_get(buffer, *dest_size_r); dest_size_r);
pcm_convert_float_to_24(dest, src, pcm_end_pointer(src, src_size));
return dest;
} }
const int32_t * const int32_t *
...@@ -381,40 +396,36 @@ pcm_convert_to_32(struct pcm_buffer *buffer, ...@@ -381,40 +396,36 @@ pcm_convert_to_32(struct pcm_buffer *buffer,
return NULL; return NULL;
} }
template<typename S, unsigned bits=DefaultSampleBits<S>::value>
static void static void
pcm_convert_8_to_float(float *out, const int8_t *in, const int8_t *in_end) ConvertToFloat(float *dest, S src, S end)
{ {
enum { in_bits = sizeof(*in) * 8 }; constexpr float factor = 0.5 / (1 << (bits - 2));
static const float factor = 2.0f / (1 << in_bits); while (src != end)
while (in < in_end) *dest++ = float(*src++) * factor;
*out++ = (float)*in++ * factor;
}
static void
pcm_convert_16_to_float(float *out, const int16_t *in, const int16_t *in_end)
{
enum { in_bits = sizeof(*in) * 8 };
static const float factor = 2.0f / (1 << in_bits);
while (in < in_end)
*out++ = (float)*in++ * factor;
} }
template<typename S, unsigned bits=DefaultSampleBits<S>::value>
static void static void
pcm_convert_24_to_float(float *out, const int32_t *in, const int32_t *in_end) ConvertToFloat(float *dest, S src, size_t size)
{ {
enum { in_bits = 24 }; ConvertToFloat<S, bits>(dest, src, pcm_end_pointer(src, size));
static const float factor = 2.0f / (1 << in_bits);
while (in < in_end)
*out++ = (float)*in++ * factor;
} }
static void template<typename S, unsigned bits=DefaultSampleBits<S>::value>
pcm_convert_32_to_float(float *out, const int32_t *in, const int32_t *in_end) static float *
AllocateToFloat(pcm_buffer &buffer, S src, size_t src_size,
size_t *dest_size_r)
{ {
enum { in_bits = sizeof(*in) * 8 }; constexpr size_t src_sample_size = sizeof(*S());
static const float factor = 0.5f / (1 << (in_bits - 2)); assert(src_size % src_sample_size == 0);
while (in < in_end)
*out++ = (float)*in++ * factor; 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 * static float *
...@@ -422,11 +433,7 @@ pcm_allocate_8_to_float(struct pcm_buffer *buffer, ...@@ -422,11 +433,7 @@ pcm_allocate_8_to_float(struct pcm_buffer *buffer,
const int8_t *src, size_t src_size, const int8_t *src, size_t src_size,
size_t *dest_size_r) size_t *dest_size_r)
{ {
float *dest; return AllocateToFloat(*buffer, src, src_size, dest_size_r);
*dest_size_r = src_size / sizeof(*src) * sizeof(*dest);
dest = (float *)pcm_buffer_get(buffer, *dest_size_r);
pcm_convert_8_to_float(dest, src, pcm_end_pointer(src, src_size));
return dest;
} }
static float * static float *
...@@ -434,23 +441,16 @@ pcm_allocate_16_to_float(struct pcm_buffer *buffer, ...@@ -434,23 +441,16 @@ pcm_allocate_16_to_float(struct pcm_buffer *buffer,
const int16_t *src, size_t src_size, const int16_t *src, size_t src_size,
size_t *dest_size_r) size_t *dest_size_r)
{ {
float *dest; return AllocateToFloat(*buffer, src, src_size, dest_size_r);
*dest_size_r = src_size * 2;
assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest));
dest = (float *)pcm_buffer_get(buffer, *dest_size_r);
pcm_convert_16_to_float(dest, src, pcm_end_pointer(src, src_size));
return dest;
} }
static float * static float *
pcm_allocate_24p32_to_float(struct pcm_buffer *buffer, pcm_allocate_24p32_to_float(struct pcm_buffer *buffer,
const int32_t *src, size_t src_size, const int32_t *src, size_t src_size,
size_t *dest_size_r) size_t *dest_size_r)
{ {
*dest_size_r = src_size; return AllocateToFloat<decltype(src), 24>
float *dest = (float *)pcm_buffer_get(buffer, *dest_size_r); (*buffer, src, src_size, dest_size_r);
pcm_convert_24_to_float(dest, src, pcm_end_pointer(src, src_size));
return dest;
} }
static float * static float *
...@@ -458,10 +458,7 @@ pcm_allocate_32_to_float(struct pcm_buffer *buffer, ...@@ -458,10 +458,7 @@ pcm_allocate_32_to_float(struct pcm_buffer *buffer,
const int32_t *src, size_t src_size, const int32_t *src, size_t src_size,
size_t *dest_size_r) size_t *dest_size_r)
{ {
*dest_size_r = src_size; return AllocateToFloat(*buffer, src, src_size, dest_size_r);
float *dest = (float *)pcm_buffer_get(buffer, *dest_size_r);
pcm_convert_32_to_float(dest, src, pcm_end_pointer(src, src_size));
return dest;
} }
const float * const float *
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include "gcc.h" #include "gcc.h"
#include <limits>
#include <stdint.h> #include <stdint.h>
/** /**
...@@ -64,32 +66,39 @@ pcm_range_64(int64_t sample, unsigned bits) ...@@ -64,32 +66,39 @@ pcm_range_64(int64_t sample, unsigned bits)
return sample; return sample;
} }
template<typename T, typename U, unsigned bits>
gcc_const gcc_const
static inline int16_t static inline T
pcm_clamp_16(int x) PcmClamp(U x)
{ {
static const int32_t MIN_VALUE = -(1 << 15); constexpr U MIN_VALUE = -(1 << (bits - 1));
static const int32_t MAX_VALUE = (1 << 15) - 1; constexpr U MAX_VALUE = (1 << (bits - 1)) - 1;
typedef std::numeric_limits<T> limits;
static_assert(MIN_VALUE >= limits::min(), "out of range");
static_assert(MAX_VALUE <= limits::max(), "out of range");
if (gcc_unlikely(x < MIN_VALUE)) if (gcc_unlikely(x < MIN_VALUE))
return MIN_VALUE; return T(MIN_VALUE);
if (gcc_unlikely(x > MAX_VALUE)) if (gcc_unlikely(x > MAX_VALUE))
return MAX_VALUE; return T(MAX_VALUE);
return x;
return T(x);
}
gcc_const
static inline int16_t
pcm_clamp_16(int x)
{
return PcmClamp<int16_t, int, 16>(x);
} }
gcc_const gcc_const
static inline int32_t static inline int32_t
pcm_clamp_24(int x) pcm_clamp_24(int x)
{ {
static const int32_t MIN_VALUE = -(1 << 23); return PcmClamp<int32_t, int, 24>(x);
static const int32_t MAX_VALUE = (1 << 23) - 1;
if (gcc_unlikely(x < MIN_VALUE))
return MIN_VALUE;
if (gcc_unlikely(x > MAX_VALUE))
return MAX_VALUE;
return x;
} }
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment