From 54322578d2277bdd9116103835b645505daabfec Mon Sep 17 00:00:00 2001 From: Phillip Burgess Date: Tue, 26 Sep 2023 16:44:19 -0700 Subject: [PATCH 1/2] RP2040: fix 8-bit WAV "audio buffer too small" bug Also subtly fixed 8- to 16-bit scaling math --- ports/raspberrypi/audio_dma.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index b5bd8c069c83f..ad5aebbef1d46 100644 --- a/ports/raspberrypi/audio_dma.c +++ b/ports/raspberrypi/audio_dma.c @@ -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; } From 2fe0fa5b5cf077085435ab7d324afc5986be45d0 Mon Sep 17 00:00:00 2001 From: Phillip Burgess Date: Fri, 29 Sep 2023 14:25:54 -0700 Subject: [PATCH 2/2] Add output_length_used check as requested --- ports/raspberrypi/audio_dma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index ad5aebbef1d46..940a383cbef39 100644 --- a/ports/raspberrypi/audio_dma.c +++ b/ports/raspberrypi/audio_dma.c @@ -65,6 +65,9 @@ STATIC size_t audio_dma_convert_samples(audio_dma_t *dma, uint8_t *input, uint32 // reading bytes, writing 16-bit words, so output buffer will be bigger. output_length_used *= 2; + if (output_length_used > output_length) { + mp_raise_RuntimeError(translate("Internal audio buffer too small")); + } // Correct "rail-to-rail" scaling of arbitrary-depth input to output // requires more operations than this, but at least the vital 8- to