diff options
Diffstat (limited to 'src/pcm_mix.c')
-rw-r--r-- | src/pcm_mix.c | 159 |
1 files changed, 137 insertions, 22 deletions
diff --git a/src/pcm_mix.c b/src/pcm_mix.c index d1e716731..33815dac2 100644 --- a/src/pcm_mix.c +++ b/src/pcm_mix.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2009 The Music Player Daemon Project + * Copyright (C) 2003-2010 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" #include "pcm_mix.h" #include "pcm_volume.h" #include "pcm_utils.h" @@ -30,8 +31,8 @@ #define G_LOG_DOMAIN "pcm" static void -pcm_add_8(int8_t *buffer1, const int8_t *buffer2, - unsigned num_samples, int volume1, int volume2) +pcm_add_vol_8(int8_t *buffer1, const int8_t *buffer2, + unsigned num_samples, int volume1, int volume2) { while (num_samples > 0) { int32_t sample1 = *buffer1; @@ -47,8 +48,8 @@ pcm_add_8(int8_t *buffer1, const int8_t *buffer2, } static void -pcm_add_16(int16_t *buffer1, const int16_t *buffer2, - unsigned num_samples, int volume1, int volume2) +pcm_add_vol_16(int16_t *buffer1, const int16_t *buffer2, + unsigned num_samples, int volume1, int volume2) { while (num_samples > 0) { int32_t sample1 = *buffer1; @@ -64,8 +65,8 @@ pcm_add_16(int16_t *buffer1, const int16_t *buffer2, } static void -pcm_add_24(int32_t *buffer1, const int32_t *buffer2, - unsigned num_samples, unsigned volume1, unsigned volume2) +pcm_add_vol_24(int32_t *buffer1, const int32_t *buffer2, + unsigned num_samples, unsigned volume1, unsigned volume2) { while (num_samples > 0) { int64_t sample1 = *buffer1; @@ -81,29 +82,134 @@ pcm_add_24(int32_t *buffer1, const int32_t *buffer2, } static void +pcm_add_vol_32(int32_t *buffer1, const int32_t *buffer2, + unsigned num_samples, unsigned volume1, unsigned volume2) +{ + while (num_samples > 0) { + int64_t sample1 = *buffer1; + int64_t sample2 = *buffer2++; + + sample1 = ((sample1 * volume1 + sample2 * volume2) + + pcm_volume_dither() + PCM_VOLUME_1 / 2) + / PCM_VOLUME_1; + + *buffer1++ = pcm_range_64(sample1, 32); + --num_samples; + } +} + +static void +pcm_add_vol(void *buffer1, const void *buffer2, size_t size, + int vol1, int vol2, + const struct audio_format *format) +{ + switch (format->format) { + case SAMPLE_FORMAT_S8: + pcm_add_vol_8((int8_t *)buffer1, (const int8_t *)buffer2, + size, vol1, vol2); + break; + + case SAMPLE_FORMAT_S16: + pcm_add_vol_16((int16_t *)buffer1, (const int16_t *)buffer2, + size / 2, vol1, vol2); + break; + + case SAMPLE_FORMAT_S24_P32: + pcm_add_vol_24((int32_t *)buffer1, (const int32_t *)buffer2, + size / 4, vol1, vol2); + break; + + case SAMPLE_FORMAT_S32: + pcm_add_vol_32((int32_t *)buffer1, (const int32_t *)buffer2, + size / 4, vol1, vol2); + break; + + default: + g_error("format %s not supported by pcm_add_vol", + sample_format_to_string(format->format)); + } +} + +static void +pcm_add_8(int8_t *buffer1, const int8_t *buffer2, unsigned num_samples) +{ + while (num_samples > 0) { + int32_t sample1 = *buffer1; + int32_t sample2 = *buffer2++; + + sample1 += sample2; + + *buffer1++ = pcm_range(sample1, 8); + --num_samples; + } +} + +static void +pcm_add_16(int16_t *buffer1, const int16_t *buffer2, unsigned num_samples) +{ + while (num_samples > 0) { + int32_t sample1 = *buffer1; + int32_t sample2 = *buffer2++; + + sample1 += sample2; + + *buffer1++ = pcm_range(sample1, 16); + --num_samples; + } +} + +static void +pcm_add_24(int32_t *buffer1, const int32_t *buffer2, unsigned num_samples) +{ + while (num_samples > 0) { + int64_t sample1 = *buffer1; + int64_t sample2 = *buffer2++; + + sample1 += sample2; + + *buffer1++ = pcm_range(sample1, 24); + --num_samples; + } +} + +static void +pcm_add_32(int32_t *buffer1, const int32_t *buffer2, unsigned num_samples) +{ + while (num_samples > 0) { + int64_t sample1 = *buffer1; + int64_t sample2 = *buffer2++; + + sample1 += sample2; + + *buffer1++ = pcm_range_64(sample1, 32); + --num_samples; + } +} + +static void pcm_add(void *buffer1, const void *buffer2, size_t size, - int vol1, int vol2, const struct audio_format *format) { - switch (format->bits) { - case 8: - pcm_add_8((int8_t *)buffer1, (const int8_t *)buffer2, - size, vol1, vol2); + switch (format->format) { + case SAMPLE_FORMAT_S8: + pcm_add_8((int8_t *)buffer1, (const int8_t *)buffer2, size); break; - case 16: - pcm_add_16((int16_t *)buffer1, (const int16_t *)buffer2, - size / 2, vol1, vol2); + case SAMPLE_FORMAT_S16: + pcm_add_16((int16_t *)buffer1, (const int16_t *)buffer2, size / 2); break; - case 24: - pcm_add_24((int32_t*)buffer1, - (const int32_t*)buffer2, - size / 4, vol1, vol2); + case SAMPLE_FORMAT_S24_P32: + pcm_add_24((int32_t *)buffer1, (const int32_t *)buffer2, size / 4); + break; + + case SAMPLE_FORMAT_S32: + pcm_add_32((int32_t *)buffer1, (const int32_t *)buffer2, size / 4); break; default: - g_error("%u bits not supported by pcm_add!\n", format->bits); + g_error("format %s not supported by pcm_add", + sample_format_to_string(format->format)); } } @@ -112,11 +218,20 @@ pcm_mix(void *buffer1, const void *buffer2, size_t size, const struct audio_format *format, float portion1) { int vol1; - float s = sin(M_PI_2 * portion1); + float s; + + /* portion1 is between 0.0 and 1.0 for crossfading, MixRamp uses NaN + * to signal mixing rather than fading */ + if (isnan(portion1)) { + pcm_add(buffer1, buffer2, size, format); + return; + } + + s = sin(M_PI_2 * portion1); s *= s; vol1 = s * PCM_VOLUME_1 + 0.5; vol1 = vol1 > PCM_VOLUME_1 ? PCM_VOLUME_1 : (vol1 < 0 ? 0 : vol1); - pcm_add(buffer1, buffer2, size, vol1, PCM_VOLUME_1 - vol1, format); + pcm_add_vol(buffer1, buffer2, size, vol1, PCM_VOLUME_1 - vol1, format); } |