feat(audio): use VHQ settings for SoXR resampling

This commit is contained in:
zarzet
2026-07-25 15:58:42 +07:00
parent 19787ed461
commit 1cfda41ef2
3 changed files with 29 additions and 1 deletions
+1 -1
View File
@@ -595,7 +595,7 @@ class FFmpegService {
if (!hasSampleRate && !hasSampleFormat && !processing.hasDither) return;
final options = <String>[
'resampler=${processing.normalizedResampler}',
...losslessResamplerFilterOptions(processing),
if (hasSampleRate) 'osr=$targetSampleRate',
if (hasSampleFormat) 'osf=${outputSampleFormat.trim()}',
if (processing.hasDither) 'dither_method=${processing.normalizedDither}',
+16
View File
@@ -27,6 +27,9 @@ const List<String> losslessDitherOptions = [
const List<String> losslessResamplerOptions = ['swr', 'soxr'];
const int soxrVhqPrecisionBits = 28;
const double soxrPassbandEndRatio = 0.95;
class LosslessConversionProcessing {
final String dither;
final String resampler;
@@ -49,6 +52,19 @@ class LosslessConversionProcessing {
bool get hasDither => normalizedDither != 'none';
}
List<String> losslessResamplerFilterOptions(
LosslessConversionProcessing processing,
) {
final resampler = processing.normalizedResampler;
return [
'resampler=$resampler',
if (resampler == 'soxr') ...[
'precision=$soxrVhqPrecisionBits',
'cutoff=$soxrPassbandEndRatio',
],
];
}
List<int> availableLosslessBitDepthOptions(int? sourceBitDepth) {
if (sourceBitDepth == null || sourceBitDepth <= 0) {
return losslessConversionBitDepthOptions;
+12
View File
@@ -44,6 +44,18 @@ void main() {
expect(swrHighPass.normalizedDither, 'triangular_hp');
expect(swrHighPass.hasDither, isTrue);
});
test('uses VHQ and a 95 percent passband only for SoXR', () {
const soxr = LosslessConversionProcessing(resampler: 'soxr');
const swr = LosslessConversionProcessing(resampler: 'swr');
expect(losslessResamplerFilterOptions(soxr), [
'resampler=soxr',
'precision=28',
'cutoff=0.95',
]);
expect(losslessResamplerFilterOptions(swr), ['resampler=swr']);
});
});
group('kept conversion output identity', () {