@@ -64,20 +64,26 @@ 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 ;
67+ output_length_used *= 2 ;
6868 if (output_length_used > output_length ) {
6969 mp_raise_RuntimeError (translate ("Internal audio buffer too small" ));
7070 }
7171
72- size_t shift = dma -> output_resolution - dma -> sample_resolution ;
72+ // Correct "rail-to-rail" scaling of arbitrary-depth input to output
73+ // requires more operations than this, but at least the vital 8- to
74+ // 16-bit cases are correctly scaled now. Prior code was only
75+ // considering 8-to-16 anyway, but had a slight DC offset in the
76+ // result, so this is no worse off WRT supported resolutions.
77+ uint16_t mul = ((1 << dma -> output_resolution ) - 1 ) / ((1 << dma -> sample_resolution ) - 1 );
78+ uint16_t offset = (1 << dma -> output_resolution ) / 2 ;
7379
7480 for (uint32_t i = 0 ; i < input_length ; i += dma -> sample_spacing ) {
7581 if (dma -> signed_to_unsigned ) {
76- ((uint16_t * )output )[out_i ] = (( uint16_t )((int8_t * )input )[i ] + 0x80 ) << shift ;
82+ ((uint16_t * )output )[out_i ] = (uint16_t )(((( int8_t * )input )[i ] + 0x80 ) * mul ) ;
7783 } else if (dma -> unsigned_to_signed ) {
78- ((int16_t * )output )[out_i ] = (( int16_t )((uint8_t * )input )[i ] - 0x80 ) << shift ;
84+ ((int16_t * )output )[out_i ] = (int16_t )((( uint8_t * )input )[i ] * mul - offset ) ;
7985 } else {
80- ((uint16_t * )output )[out_i ] = (( uint16_t )((uint8_t * )input )[i ]) << shift ;
86+ ((uint16_t * )output )[out_i ] = (uint16_t )((( uint8_t * )input )[i ] * mul ) ;
8187 }
8288 out_i += 1 ;
8389 }
0 commit comments