-
Notifications
You must be signed in to change notification settings - Fork 209
Open
Labels
Description
In EasyRPG, there's clipping when total_volume is greater than 1.0.
In RPG_RT, sound is limited to 0 dB.
.Flow has a lot of clipping, but you can notice it in Yume Nikki too, and Test Game 2000 (in Music Playing).
I only tested those, but in theory, it should affect all games.
Reproducing it is very easy.
This is caused by Decode in audio_generic.cpp:
It applies compression with a soft knee at -2 dB while converting to 16 bit, which causes distortion as if it's clipping.
RPG_RT limits to 0 dB by scaling samples uniformly.
Basically, replace this:
if (total_volume > 1.0) {
float threshold = 0.8f;
for (unsigned i = 0; i < (unsigned)(samples_per_frame * 2); i++) {
float sample = mixer_buffer[i];
float sign = (sample < 0) ? -1.0 : 1.0;
sample /= sign;
//dynamic range compression
if (sample > threshold) {
sample_buffer[i] = sign * 32768.0 * (threshold + (1.0 - threshold) * (sample - threshold) / (total_volume - threshold));
} else {
sample_buffer[i] = sign * sample * 32768.0;
}
}
} else {
//No dynamic range compression necessary
for (unsigned i = 0; i < (unsigned)(samples_per_frame * 2); i++) {
sample_buffer[i] = mixer_buffer[i] * 32768.0;
}
}
With this:
float max_sample = 0.0f;
unsigned num_samples = samples_per_frame * 2;
for (unsigned i = 0; i < num_samples; i++) {
float abs_sample = std::abs(mixer_buffer[i]);
if (abs_sample > max_sample) max_sample = abs_sample;
}
float scale = (max_sample > 1.0f) ? (1.0f / max_sample) : 1.0f;
for (unsigned i = 0; i < num_samples; i++) {
float sample = mixer_buffer[i] * scale;
sample_buffer[i] = static_cast<int16_t>(sample * 32768.0f);
}
Which also makes total_volume unnecessary
fdelapena