twn_audio.c: only apply volume scaling on mixing of different streams

This commit is contained in:
veclavtalica 2025-01-26 11:08:13 +03:00
parent 6a029b7e79
commit bf3eb50b55

View File

@ -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,22 +365,30 @@ 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);
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;
}
}
}
/* 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);