diff options
author | Max Kellermann <max@duempel.org> | 2013-12-28 17:42:03 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-12-28 18:30:27 +0100 |
commit | da29298d4dbe8dddade7cf241dd1af267470f2a8 (patch) | |
tree | 4cbb96c50418ce5d1dad66db9a946b1ba0a259aa | |
parent | afcf0795c44260f54e74ec854297de439e7562c3 (diff) | |
download | mpd-da29298d4dbe8dddade7cf241dd1af267470f2a8.tar.gz mpd-da29298d4dbe8dddade7cf241dd1af267470f2a8.tar.xz mpd-da29298d4dbe8dddade7cf241dd1af267470f2a8.zip |
pcm/PcmMix: improved dithering
Use the existing PcmDither library.
-rw-r--r-- | src/OutputInternal.hxx | 6 | ||||
-rw-r--r-- | src/OutputThread.cxx | 2 | ||||
-rw-r--r-- | src/pcm/PcmMix.cxx | 45 | ||||
-rw-r--r-- | src/pcm/PcmMix.hxx | 4 | ||||
-rw-r--r-- | test/test_pcm_mix.cxx | 16 |
5 files changed, 48 insertions, 25 deletions
diff --git a/src/OutputInternal.hxx b/src/OutputInternal.hxx index f05073bd7..ab1c1242e 100644 --- a/src/OutputInternal.hxx +++ b/src/OutputInternal.hxx @@ -22,6 +22,7 @@ #include "AudioFormat.hxx" #include "pcm/PcmBuffer.hxx" +#include "pcm/PcmDither.hxx" #include "thread/Mutex.hxx" #include "thread/Cond.hxx" #include "thread/Thread.hxx" @@ -172,6 +173,11 @@ struct audio_output { PcmBuffer cross_fade_buffer; /** + * The dithering state for cross-fading two streams. + */ + PcmDither cross_fade_dither; + + /** * The filter object of this audio output. This is an * instance of chain_filter_plugin. */ diff --git a/src/OutputThread.cxx b/src/OutputThread.cxx index 1a8c70196..62833e360 100644 --- a/src/OutputThread.cxx +++ b/src/OutputThread.cxx @@ -392,7 +392,7 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk, void *dest = ao->cross_fade_buffer.Get(other_length); memcpy(dest, other_data, other_length); - if (!pcm_mix(dest, data, length, + if (!pcm_mix(ao->cross_fade_dither, dest, data, length, ao->in_audio_format.format, 1.0 - chunk->mix_ratio)) { FormatError(output_domain, diff --git a/src/pcm/PcmMix.cxx b/src/pcm/PcmMix.cxx index caf7fe516..c1ffd8633 100644 --- a/src/pcm/PcmMix.cxx +++ b/src/pcm/PcmMix.cxx @@ -25,41 +25,47 @@ #include "Traits.hxx" #include "util/Clamp.hxx" +#include "PcmDither.cxx" // including the .cxx file to get inlined templates + #include <assert.h> #include <math.h> template<SampleFormat F, class Traits=SampleTraits<F>> static typename Traits::value_type -PcmAddVolume(typename Traits::value_type _a, typename Traits::value_type _b, +PcmAddVolume(PcmDither &dither, + typename Traits::value_type _a, typename Traits::value_type _b, int volume1, int volume2) { typename Traits::long_type a(_a), b(_b); + typename Traits::long_type c(a * volume1 + b * volume2); - typename Traits::value_type c = ((a * volume1 + b * volume2) + - pcm_volume_dither() + PCM_VOLUME_1S / 2) - / PCM_VOLUME_1S; - - return PcmClamp<F, Traits>(c); + return dither.DitherShift<typename Traits::long_type, + Traits::BITS + PCM_VOLUME_BITS, + Traits::BITS>(c); } template<SampleFormat F, class Traits=SampleTraits<F>> static void -PcmAddVolume(typename Traits::pointer_type a, +PcmAddVolume(PcmDither &dither, + typename Traits::pointer_type a, typename Traits::const_pointer_type b, size_t n, int volume1, int volume2) { for (size_t i = 0; i != n; ++i) - a[i] = PcmAddVolume<F, Traits>(a[i], b[i], volume1, volume2); + a[i] = PcmAddVolume<F, Traits>(dither, a[i], b[i], + volume1, volume2); } template<SampleFormat F, class Traits=SampleTraits<F>> static void -PcmAddVolumeVoid(void *a, const void *b, size_t size, int volume1, int volume2) +PcmAddVolumeVoid(PcmDither &dither, + void *a, const void *b, size_t size, int volume1, int volume2) { constexpr size_t sample_size = Traits::SAMPLE_SIZE; assert(size % sample_size == 0); - PcmAddVolume<F, Traits>(typename Traits::pointer_type(a), + PcmAddVolume<F, Traits>(dither, + typename Traits::pointer_type(a), typename Traits::const_pointer_type(b), size / sample_size, volume1, volume2); @@ -80,7 +86,7 @@ pcm_add_vol_float(float *buffer1, const float *buffer2, } static bool -pcm_add_vol(void *buffer1, const void *buffer2, size_t size, +pcm_add_vol(PcmDither &dither, void *buffer1, const void *buffer2, size_t size, int vol1, int vol2, SampleFormat format) { @@ -91,22 +97,26 @@ pcm_add_vol(void *buffer1, const void *buffer2, size_t size, return false; case SampleFormat::S8: - PcmAddVolumeVoid<SampleFormat::S8>(buffer1, buffer2, size, + PcmAddVolumeVoid<SampleFormat::S8>(dither, + buffer1, buffer2, size, vol1, vol2); return true; case SampleFormat::S16: - PcmAddVolumeVoid<SampleFormat::S16>(buffer1, buffer2, size, + PcmAddVolumeVoid<SampleFormat::S16>(dither, + buffer1, buffer2, size, vol1, vol2); return true; case SampleFormat::S24_P32: - PcmAddVolumeVoid<SampleFormat::S24_P32>(buffer1, buffer2, size, + PcmAddVolumeVoid<SampleFormat::S24_P32>(dither, + buffer1, buffer2, size, vol1, vol2); return true; case SampleFormat::S32: - PcmAddVolumeVoid<SampleFormat::S32>(buffer1, buffer2, size, + PcmAddVolumeVoid<SampleFormat::S32>(dither, + buffer1, buffer2, size, vol1, vol2); return true; @@ -201,7 +211,7 @@ pcm_add(void *buffer1, const void *buffer2, size_t size, } bool -pcm_mix(void *buffer1, const void *buffer2, size_t size, +pcm_mix(PcmDither &dither, void *buffer1, const void *buffer2, size_t size, SampleFormat format, float portion1) { float s; @@ -217,5 +227,6 @@ pcm_mix(void *buffer1, const void *buffer2, size_t size, int vol1 = s * PCM_VOLUME_1S + 0.5; vol1 = Clamp<int>(vol1, 0, PCM_VOLUME_1S); - return pcm_add_vol(buffer1, buffer2, size, vol1, PCM_VOLUME_1S - vol1, format); + return pcm_add_vol(dither, buffer1, buffer2, size, + vol1, PCM_VOLUME_1S - vol1, format); } diff --git a/src/pcm/PcmMix.hxx b/src/pcm/PcmMix.hxx index 637c88f8a..a6657a979 100644 --- a/src/pcm/PcmMix.hxx +++ b/src/pcm/PcmMix.hxx @@ -25,6 +25,8 @@ #include <stddef.h> +class PcmDither; + /* * Linearly mixes two PCM buffers. Both must have the same length and * the same audio format. The formula is: @@ -44,7 +46,7 @@ */ gcc_warn_unused_result bool -pcm_mix(void *buffer1, const void *buffer2, size_t size, +pcm_mix(PcmDither &dither, void *buffer1, const void *buffer2, size_t size, SampleFormat format, float portion1); #endif diff --git a/test/test_pcm_mix.cxx b/test/test_pcm_mix.cxx index 2a8a11388..542c4de80 100644 --- a/test/test_pcm_mix.cxx +++ b/test/test_pcm_mix.cxx @@ -21,6 +21,7 @@ #include "test_pcm_all.hxx" #include "test_pcm_util.hxx" #include "pcm/PcmMix.hxx" +#include "pcm/PcmDither.hxx" template<typename T, SampleFormat format, typename G=RandomInt<T>> static void @@ -30,23 +31,26 @@ TestPcmMix(G g=G()) const auto src1 = TestDataBuffer<T, N>(g); const auto src2 = TestDataBuffer<T, N>(g); + PcmDither dither; + /* portion1=1.0: result must be equal to src1 */ auto result = src1; - bool success = pcm_mix(result.begin(), src2.begin(), sizeof(result), + bool success = pcm_mix(dither, + result.begin(), src2.begin(), sizeof(result), format, 1.0); CPPUNIT_ASSERT(success); - AssertEqualWithTolerance(result, src1, 1); + AssertEqualWithTolerance(result, src1, 3); /* portion1=0.0: result must be equal to src2 */ result = src1; - success = pcm_mix(result.begin(), src2.begin(), sizeof(result), + success = pcm_mix(dither, result.begin(), src2.begin(), sizeof(result), format, 0.0); CPPUNIT_ASSERT(success); - AssertEqualWithTolerance(result, src2, 1); + AssertEqualWithTolerance(result, src2, 3); /* portion1=0.5 */ result = src1; - success = pcm_mix(result.begin(), src2.begin(), sizeof(result), + success = pcm_mix(dither, result.begin(), src2.begin(), sizeof(result), format, 0.5); CPPUNIT_ASSERT(success); @@ -54,7 +58,7 @@ TestPcmMix(G g=G()) for (unsigned i = 0; i < N; ++i) expected[i] = (int64_t(src1[i]) + int64_t(src2[i])) / 2; - AssertEqualWithTolerance(result, expected, 1); + AssertEqualWithTolerance(result, expected, 3); } void |