aboutsummaryrefslogtreecommitdiffstats
path: root/src/pcm/PcmDither.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/pcm/PcmDither.cxx')
-rw-r--r--src/pcm/PcmDither.cxx76
1 files changed, 52 insertions, 24 deletions
diff --git a/src/pcm/PcmDither.cxx b/src/pcm/PcmDither.cxx
index 98d0d443e..7b2a9e900 100644
--- a/src/pcm/PcmDither.cxx
+++ b/src/pcm/PcmDither.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,18 +20,14 @@
#include "config.h"
#include "PcmDither.hxx"
#include "PcmPrng.hxx"
+#include "Traits.hxx"
-inline int16_t
-PcmDither::Dither24To16(int_fast32_t sample)
+template<typename T, T MIN, T MAX, unsigned scale_bits>
+inline T
+PcmDither::Dither(T sample)
{
- constexpr unsigned from_bits = 24;
- constexpr unsigned to_bits = 16;
- constexpr unsigned scale_bits = from_bits - to_bits;
- constexpr int_fast32_t round = 1 << (scale_bits - 1);
- constexpr int_fast32_t mask = (1 << scale_bits) - 1;
- constexpr int_fast32_t ONE = 1 << (from_bits - 1);
- constexpr int_fast32_t MIN = -ONE;
- constexpr int_fast32_t MAX = ONE - 1;
+ constexpr T round = 1 << (scale_bits - 1);
+ constexpr T mask = (1 << scale_bits) - 1;
sample += error[0] - error[1] + error[2];
@@ -39,9 +35,9 @@ PcmDither::Dither24To16(int_fast32_t sample)
error[1] = error[0] / 2;
/* round */
- int_fast32_t output = sample + round;
+ T output = sample + round;
- int_fast32_t rnd = pcm_prng(random);
+ const T rnd = pcm_prng(random);
output += (rnd & mask) - (random & mask);
random = rnd;
@@ -63,27 +59,59 @@ PcmDither::Dither24To16(int_fast32_t sample)
error[0] = sample - output;
- return (int16_t)(output >> scale_bits);
+ return output >> scale_bits;
}
-void
-PcmDither::Dither24To16(int16_t *dest, const int32_t *src,
- const int32_t *src_end)
+template<typename ST, unsigned SBITS, unsigned DBITS>
+inline ST
+PcmDither::DitherShift(ST sample)
+{
+ static_assert(sizeof(ST) * 8 > SBITS, "Source type too small");
+ static_assert(SBITS > DBITS, "Non-positive scale_bits");
+
+ static constexpr ST MIN = -(ST(1) << (SBITS - 1));
+ static constexpr ST MAX = (ST(1) << (SBITS - 1)) - 1;
+
+ return Dither<ST, MIN, MAX, SBITS - DBITS>(sample);
+}
+
+template<typename ST, typename DT>
+inline typename DT::value_type
+PcmDither::DitherConvert(typename ST::value_type sample)
+{
+ static_assert(ST::BITS > DT::BITS,
+ "Sample formats cannot be dithered");
+
+ constexpr unsigned scale_bits = ST::BITS - DT::BITS;
+
+ return Dither<typename ST::sum_type, ST::MIN, ST::MAX,
+ scale_bits>(sample);
+}
+
+template<typename ST, typename DT>
+inline void
+PcmDither::DitherConvert(typename DT::pointer_type dest,
+ typename ST::const_pointer_type src,
+ typename ST::const_pointer_type src_end)
{
while (src < src_end)
- *dest++ = Dither24To16(*src++);
+ *dest++ = DitherConvert<ST, DT>(*src++);
}
-inline int16_t
-PcmDither::Dither32To16(int_fast32_t sample)
+inline void
+PcmDither::Dither24To16(int16_t *dest, const int32_t *src,
+ const int32_t *src_end)
{
- return Dither24To16(sample >> 8);
+ typedef SampleTraits<SampleFormat::S24_P32> ST;
+ typedef SampleTraits<SampleFormat::S16> DT;
+ DitherConvert<ST, DT>(dest, src, src_end);
}
-void
+inline void
PcmDither::Dither32To16(int16_t *dest, const int32_t *src,
const int32_t *src_end)
{
- while (src < src_end)
- *dest++ = Dither32To16(*src++);
+ typedef SampleTraits<SampleFormat::S32> ST;
+ typedef SampleTraits<SampleFormat::S16> DT;
+ DitherConvert<ST, DT>(dest, src, src_end);
}