RP2040: fix 8-bit WAV "audio buffer too small" bug

Also subtly fixed 8- to 16-bit scaling math
This commit is contained in:
Phillip Burgess 2023-09-26 16:44:19 -07:00
parent 1c0155c99b
commit 54322578d2

View File

@ -64,20 +64,23 @@ STATIC size_t audio_dma_convert_samples(audio_dma_t *dma, uint8_t *input, uint32
if (dma->sample_resolution <= 8 && dma->output_resolution > 8) {
// reading bytes, writing 16-bit words, so output buffer will be bigger.
output_length_used = output_length * 2;
if (output_length_used > output_length) {
mp_raise_RuntimeError(translate("Internal audio buffer too small"));
}
output_length_used *= 2;
size_t shift = dma->output_resolution - dma->sample_resolution;
// Correct "rail-to-rail" scaling of arbitrary-depth input to output
// requires more operations than this, but at least the vital 8- to
// 16-bit cases are correctly scaled now. Prior code was only
// considering 8-to-16 anyway, but had a slight DC offset in the
// result, so this is no worse off WRT supported resolutions.
uint16_t mul = ((1 << dma->output_resolution) - 1) / ((1 << dma->sample_resolution) - 1);
uint16_t offset = (1 << dma->output_resolution) / 2;
for (uint32_t i = 0; i < input_length; i += dma->sample_spacing) {
if (dma->signed_to_unsigned) {
((uint16_t *)output)[out_i] = ((uint16_t)((int8_t *)input)[i] + 0x80) << shift;
((uint16_t *)output)[out_i] = (uint16_t)((((int8_t *)input)[i] + 0x80) * mul);
} else if (dma->unsigned_to_signed) {
((int16_t *)output)[out_i] = ((int16_t)((uint8_t *)input)[i] - 0x80) << shift;
((int16_t *)output)[out_i] = (int16_t)(((uint8_t *)input)[i] * mul - offset);
} else {
((uint16_t *)output)[out_i] = ((uint16_t)((uint8_t *)input)[i]) << shift;
((uint16_t *)output)[out_i] = (uint16_t)(((uint8_t *)input)[i] * mul);
}
out_i += 1;
}