Alby's blog

世上没有巧合,只有巧合的假象。

0%

FFmpeg filters 使用:af_sidechaincompress(acompressor)

一、概述

本文简述 FFmpeg af_sidechaincompress(acompressor) 的使用。

效果图

二、Ccompressor 的作用及基本原理

压缩器主要用于减小信号的动态范围。尤其是现代音乐大多采用高比例压缩以提高整体响度。这样做是为了引起听众的最高关注,“丰富”声音并为曲目带来更多“力量”。如果信号被压缩太多,之后听起来可能会沉闷或“死气沉沉”,或者可能会开始“泵动(pump)”(这可能是一个强大的效果,但也可能完全破坏轨道)。正确的压缩是获得专业声音的关键,也是混音和母带处理的高雅艺术。由于其复杂的设置,可能需要很长时间才能获得这种效果的正确感觉。

搞不懂后期制作的COMPRESSOR压缩效果器?看这篇就对了!》这篇文章进行了比较细致的描述。

除了 FFmpeg,Adobe AudtionWavesRenaissance Vox Vocal Compressor Plugin ($79)等 VST 插件也能很好地实现。

四、在调用 ffmpeg 程序时使用 acompressor

1
ffmpeg -i input.mp3 -af "acompressor=threshold=-18dB:ratio=8:attack=1:release=100:makeup=1" output.mp3 -y

备注:makeup 单位不是 dB。

五、配合 dynaudnorm 标准化

1
ffmpeg -i input.mp3 -af "acompressor=threshold=-18dB:ratio=8:attack=1:release=100:makeup=1,dynaudnorm=framelen=20:gausssize=13:peak=0.98:threshold=-40dB" output.mp3 -y

dynaudnorm 不是本文的重点,在此暂时不用深入了解。详情可见官方文档:https://ffmpeg.org/ffmpeg-filters.html#dynaudnorm

六、在 C# 使用 acompressor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public static class CompressUtils
{
public static async Task<bool> Compress(Stream inputStream,
Stream outputStream,
int inputSampleRate = 44100,
int inputChannels = 2,
int inputBitsPreSample = 16,
int outputSampleRate = 44100,
int ouputChannels = 2,
int outputBitsPreSample = 16)
{
var filters = $"-filter_complex \"acompressor=threshold=-18dB:ratio=8:attack=1:release=100:makeup=1,dynaudnorm=framelen=20:gausssize=13:peak=0.98:threshold=-40dB\"";
var fFMpegArguments = FFMpegArguments
.FromPipeInput(new StreamPipeSource(inputStream), args => {
args.WithCustomArgument("-f s16be -ac 2 -ar 44100 -acodec pcm_s16le");
});
var processor = fFMpegArguments
.WithGlobalOptions(options =>
{
options.WithVerbosityLevel(VerbosityLevel.Warning);
})
.OutputToPipe(new StreamPipeSink(outputStream), args => {
args.WithCustomArgument(filters);
if (outputBitsPreSample == 16)
{
args.WithCustomArgument("-acodec pcm_s16le -f s16le");
}
else if (outputBitsPreSample == 32)
{
args.WithCustomArgument("-acodec pcm_f32le -f f32le");
}
else
{
throw new NotSupportedException("只支持转换为 s16le 和 f32le 。");
}
args.WithAudioSamplingRate(outputSampleRate)
.WithCustomArgument($"-ac {ouputChannels}");
});

var arguments = processor.Arguments;

return await processor.ProcessAsynchronously(true, Contracts.DefaultFFOptions)
.ConfigureAwait(false);
}
}

主要使用了 FFMpegCore,因为它将命名管道进行了封装以支持 Stream 到 Stream 的输入和输出。

参考资料