@@ -64,20 +64,23 @@ STATIC size_t audio_dma_convert_samples(audio_dma_t *dma, uint8_t *input, uint32
6464 if (dma -> sample_resolution <= 8 && dma -> output_resolution > 8 ) {
6565 // reading bytes, writing 16-bit words, so output buffer will be bigger.
6666
67- output_length_used = output_length * 2 ;
68- if (output_length_used > output_length ) {
69- mp_raise_RuntimeError (translate ("Internal audio buffer too small" ));
70- }
67+ output_length_used *= 2 ;
7168
72- size_t shift = dma -> output_resolution - dma -> sample_resolution ;
69+ // Correct "rail-to-rail" scaling of arbitrary-depth input to output
70+ // requires more operations than this, but at least the vital 8- to
71+ // 16-bit cases are correctly scaled now. Prior code was only
72+ // considering 8-to-16 anyway, but had a slight DC offset in the
73+ // result, so this is no worse off WRT supported resolutions.
74+ uint16_t mul = ((1 << dma -> output_resolution ) - 1 ) / ((1 << dma -> sample_resolution ) - 1 );
75+ uint16_t offset = (1 << dma -> output_resolution ) / 2 ;
7376
7477 for (uint32_t i = 0 ; i < input_length ; i += dma -> sample_spacing ) {
7578 if (dma -> signed_to_unsigned ) {
76- ((uint16_t * )output )[out_i ] = (( uint16_t )((int8_t * )input )[i ] + 0x80 ) << shift ;
79+ ((uint16_t * )output )[out_i ] = (uint16_t )(((( int8_t * )input )[i ] + 0x80 ) * mul ) ;
7780 } else if (dma -> unsigned_to_signed ) {
78- ((int16_t * )output )[out_i ] = (( int16_t )((uint8_t * )input )[i ] - 0x80 ) << shift ;
81+ ((int16_t * )output )[out_i ] = (int16_t )((( uint8_t * )input )[i ] * mul - offset ) ;
7982 } else {
80- ((uint16_t * )output )[out_i ] = (( uint16_t )((uint8_t * )input )[i ]) << shift ;
83+ ((uint16_t * )output )[out_i ] = (uint16_t )((( uint8_t * )input )[i ] * mul ) ;
8184 }
8285 out_i += 1 ;
8386 }
0 commit comments