diff options
Diffstat (limited to 'src')
-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 |
4 files changed, 38 insertions, 19 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 |