From bf3eb50b55f61140d4614b16d70bcc57755b9d64 Mon Sep 17 00:00:00 2001 From: veclavtalica Date: Sun, 26 Jan 2025 11:08:13 +0300 Subject: [PATCH] twn_audio.c: only apply volume scaling on mixing of different streams --- src/twn_audio.c | 56 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/src/twn_audio.c b/src/twn_audio.c index 7288f5f..f4dd69f 100644 --- a/src/twn_audio.c +++ b/src/twn_audio.c @@ -356,7 +356,8 @@ TWN_API void audio_parameter(const char *channel, const char *param, float value static void audio_mixin_streams(const AudioChannel *channel, uint8_t *restrict a, uint8_t *restrict b, - size_t frames) + size_t frames, + bool last) { float *const sa = (float *)(void *)a; float *const sb = (float *)(void *)b; @@ -364,14 +365,22 @@ static void audio_mixin_streams(const AudioChannel *channel, const float left_panning = fminf(fabsf(channel->panning - 1.0f), 1.0f); const float right_panning = fminf(fabsf(channel->panning + 1.0f), 1.0f); - for (size_t s = 0; s < frames; ++s) { - /* left channel */ - sa[s * 2 + 0] += (float)(sb[s * 2 + 0] * channel->volume * left_panning); - sa[s * 2 + 0] *= 1 / (float)M_2_SQRTPI; - - /* right channel */ - sa[s * 2 + 1] += (float)(sb[s * 2 + 1] * channel->volume * right_panning); - sa[s * 2 + 1] *= 1 / (float)M_2_SQRTPI; + if (last) { + for (size_t s = 0; s < frames; ++s) { + /* left channel */ + sa[s * 2 + 0] += (float)(sb[s * 2 + 0] * channel->volume * left_panning); + /* right channel */ + sa[s * 2 + 1] += (float)(sb[s * 2 + 1] * channel->volume * right_panning); + } + } else { + for (size_t s = 0; s < frames; ++s) { + /* left channel */ + sa[s * 2 + 0] += (float)(sb[s * 2 + 0] * channel->volume * left_panning); + sa[s * 2 + 0] *= 1 / (float)M_2_SQRTPI; + /* right channel */ + sa[s * 2 + 1] += (float)(sb[s * 2 + 1] * channel->volume * right_panning); + sa[s * 2 + 1] *= 1 / (float)M_2_SQRTPI; + } } } @@ -379,7 +388,7 @@ static void audio_mixin_streams(const AudioChannel *channel, /* remember: frame consists of sample * channel_count */ static void audio_sample_and_mixin_channel(AudioChannel *channel, uint8_t *stream, - int len) + int len, bool last) { static uint8_t buffer[16384]; /* TODO: better make it a growable scratch instead, which will simplify things */ const size_t float_buffer_frames = sizeof (buffer) / sizeof (float) / 2; @@ -414,7 +423,8 @@ static void audio_sample_and_mixin_channel(AudioChannel *channel, /* panning and mixing */ audio_mixin_streams(channel, &stream[i * sizeof(float) * 2], buffer, - samples_per_channel); + samples_per_channel, + last); i += samples_per_channel; } @@ -431,7 +441,8 @@ static void audio_sample_and_mixin_channel(AudioChannel *channel, audio_mixin_streams(channel, &stream[i * sizeof(float) * 2], &((uint8_t *)channel->context.wav.samples)[channel->context.wav.position * sizeof (float) * 2], - limit); + limit, + last); channel->context.wav.position += limit; @@ -477,7 +488,8 @@ static void audio_sample_and_mixin_channel(AudioChannel *channel, audio_mixin_streams(channel, &stream[i * sizeof(float) * 2], buffer, - samples_per_channel); + samples_per_channel, + last); i += samples_per_channel; } @@ -509,19 +521,25 @@ void audio_callback(void *userdata, uint8_t *stream, int len) { /* prepare for mixing */ SDL_memset(stream, 0, len); - for (int i = 0; i < shlen(ctx.audio_channels); ++i) { + size_t const audio_channels_len = shlen(ctx.audio_channels); + for (size_t i = 0; i < audio_channels_len; ++i) { sanity_check_channel(&ctx.audio_channels[i].value); - audio_sample_and_mixin_channel(&ctx.audio_channels[i].value, stream, len); + audio_sample_and_mixin_channel(&ctx.audio_channels[i].value, + stream, len, + i == audio_channels_len - 1); } - for (int i = 0; i < arrlen(ctx.unnamed_audio_channels); ++i) { + size_t const unnamed_audio_channels_len = shlen(ctx.unnamed_audio_channels); + for (size_t i = 0; i < unnamed_audio_channels_len; ++i) { sanity_check_channel(&ctx.unnamed_audio_channels[i]); - audio_sample_and_mixin_channel(&ctx.unnamed_audio_channels[i], stream, len); + audio_sample_and_mixin_channel(&ctx.unnamed_audio_channels[i], + stream, len, + i == unnamed_audio_channels_len - 1); } /* ditch finished unnamed */ - int i = 0; - while (i < arrlen(ctx.unnamed_audio_channels)) { + size_t i = 0; + while (i < unnamed_audio_channels_len) { if (ctx.unnamed_audio_channels[i].finished) { free_audio_channel(ctx.unnamed_audio_channels[i]); arrdelswap(ctx.unnamed_audio_channels, i);