@@ -64,20 +64,26 @@ STATIC size_t audio_dma_convert_samples(audio_dma_t *dma, uint8_t *input, uint32
64
64
if (dma -> sample_resolution <= 8 && dma -> output_resolution > 8 ) {
65
65
// reading bytes, writing 16-bit words, so output buffer will be bigger.
66
66
67
- output_length_used = output_length * 2 ;
67
+ output_length_used *= 2 ;
68
68
if (output_length_used > output_length ) {
69
69
mp_raise_RuntimeError (translate ("Internal audio buffer too small" ));
70
70
}
71
71
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 ;
73
79
74
80
for (uint32_t i = 0 ; i < input_length ; i += dma -> sample_spacing ) {
75
81
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 ) ;
77
83
} 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 ) ;
79
85
} 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 ) ;
81
87
}
82
88
out_i += 1 ;
83
89
}
0 commit comments