diff options
Diffstat (limited to '')
-rw-r--r-- | src/pcm_utils.h | 14 | ||||
-rw-r--r-- | src/pcm_volume.c | 28 |
2 files changed, 42 insertions, 0 deletions
diff --git a/src/pcm_utils.h b/src/pcm_utils.h index 93f414231..8b2259655 100644 --- a/src/pcm_utils.h +++ b/src/pcm_utils.h @@ -38,4 +38,18 @@ pcm_range(int32_t sample, unsigned bits) return sample; } +/** + * Check if the value is within the range of the provided bit size, + * and caps it if necessary. + */ +static inline int64_t +pcm_range_64(int64_t sample, unsigned bits) +{ + if (G_UNLIKELY(sample < ((int64_t)-1 << (bits - 1)))) + return (int64_t)-1 << (bits - 1); + if (G_UNLIKELY(sample >= ((int64_t)1 << (bits - 1)))) + return ((int64_t)1 << (bits - 1)) - 1; + return sample; +} + #endif diff --git a/src/pcm_volume.c b/src/pcm_volume.c index ca720a30e..90ad17d6d 100644 --- a/src/pcm_volume.c +++ b/src/pcm_volume.c @@ -114,6 +114,29 @@ pcm_volume_change_24(int32_t *buffer, unsigned num_samples, int volume) } } +static void +pcm_volume_change_32(int32_t *buffer, unsigned num_samples, int volume) +{ + while (num_samples > 0) { +#ifdef __i386__ + /* assembly version for i386 */ + int32_t sample = *buffer; + + *buffer++ = pcm_volume_sample_24(sample, volume, 0); +#else + /* portable version */ + int64_t sample = *buffer; + + sample = (sample * volume + pcm_volume_dither() + + PCM_VOLUME_1 / 2) + / PCM_VOLUME_1; + *buffer++ = pcm_range_64(sample, 32); +#endif + + --num_samples; + } +} + bool pcm_volume(void *buffer, int length, const struct audio_format *format, @@ -142,6 +165,11 @@ pcm_volume(void *buffer, int length, volume); return true; + case 32: + pcm_volume_change_32((int32_t*)buffer, length / 4, + volume); + return true; + default: return false; } |