FFmpeg
Loading...
Searching...
No Matches
af_acrusher.c
Go to the documentation of this file.
1/*
2 * Copyright (c) Markus Schmidt and Christian Holschuh
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "libavutil/mem.h"
22#include "libavutil/opt.h"
23#include "avfilter.h"
24#include "filters.h"
25#include "audio.h"
26
27typedef struct LFOContext {
28 double freq;
29 double offset;
30 int srate;
31 double amount;
32 double pwidth;
33 double phase;
35
36typedef struct SRContext {
37 double target;
38 double real;
39 double samples;
40 double last;
41} SRContext;
42
43typedef struct ACrusherContext {
44 const AVClass *class;
45
46 double level_in;
47 double level_out;
48 double bits;
49 double mix;
50 int mode;
51 double dc;
52 double idc;
53 double aa;
54 double samples;
55 int is_lfo;
56 double lforange;
57 double lforate;
58
59 double sqr;
60 double aa1;
61 double coeff;
62 int round;
63 double sov;
64 double smin;
65 double sdiff;
66
70
71#define OFFSET(x) offsetof(ACrusherContext, x)
72#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
73
74static const AVOption acrusher_options[] = {
75 { "level_in", "set level in", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A },
76 { "level_out","set level out", OFFSET(level_out), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A },
77 { "bits", "set bit reduction", OFFSET(bits), AV_OPT_TYPE_DOUBLE, {.dbl=8}, 1, 64, A },
78 { "mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=.5}, 0, 1, A },
79 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A, .unit = "mode" },
80 { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A, .unit = "mode" },
81 { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A, .unit = "mode" },
82 { "dc", "set DC", OFFSET(dc), AV_OPT_TYPE_DOUBLE, {.dbl=1}, .25, 4, A },
83 { "aa", "set anti-aliasing", OFFSET(aa), AV_OPT_TYPE_DOUBLE, {.dbl=.5}, 0, 1, A },
84 { "samples", "set sample reduction", OFFSET(samples), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 1, 250, A },
85 { "lfo", "enable LFO", OFFSET(is_lfo), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, A },
86 { "lforange", "set LFO depth", OFFSET(lforange), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 1, 250, A },
87 { "lforate", "set LFO rate", OFFSET(lforate), AV_OPT_TYPE_DOUBLE, {.dbl=.3}, .01, 200, A },
88 { NULL }
89};
90
92
93static double samplereduction(ACrusherContext *s, SRContext *sr, double in)
94{
95 sr->samples++;
96 if (sr->samples >= s->round) {
97 sr->target += s->samples;
98 sr->real += s->round;
99 if (sr->target + s->samples >= sr->real + 1) {
100 sr->last = in;
101 sr->target = 0;
102 sr->real = 0;
103 }
104 sr->samples = 0;
105 }
106 return sr->last;
107}
108
109static double add_dc(double s, double dc, double idc)
110{
111 return s > 0 ? s * dc : s * idc;
112}
113
114static double remove_dc(double s, double dc, double idc)
115{
116 return s > 0 ? s * idc : s * dc;
117}
118
119static inline double factor(double y, double k, double aa1, double aa)
120{
121 return 0.5 * (sin(M_PI * (fabs(y - k) - aa1) / aa - M_PI_2) + 1);
122}
123
124static double bitreduction(ACrusherContext *s, double in)
125{
126 const double sqr = s->sqr;
127 const double coeff = s->coeff;
128 const double aa = s->aa;
129 const double aa1 = s->aa1;
130 double y, k;
131
132 // add dc
133 in = add_dc(in, s->dc, s->idc);
134
135 // main rounding calculation depending on mode
136
137 // the idea for anti-aliasing:
138 // you need a function f which brings you to the scale, where
139 // you want to round and the function f_b (with f(f_b)=id) which
140 // brings you back to your original scale.
141 //
142 // then you can use the logic below in the following way:
143 // y = f(in) and k = roundf(y)
144 // if (y > k + aa1)
145 // k = f_b(k) + ( f_b(k+1) - f_b(k) ) * 0.5 * (sin(x - PI/2) + 1)
146 // if (y < k + aa1)
147 // k = f_b(k) - ( f_b(k+1) - f_b(k) ) * 0.5 * (sin(x - PI/2) + 1)
148 //
149 // whereas x = (fabs(f(in) - k) - aa1) * PI / aa
150 // for both cases.
151
152 switch (s->mode) {
153 case 0:
154 default:
155 // linear
156 y = in * coeff;
157 k = roundf(y);
158 if (k - aa1 <= y && y <= k + aa1) {
159 k /= coeff;
160 } else if (y > k + aa1) {
161 k = k / coeff + ((k + 1) / coeff - k / coeff) *
162 factor(y, k, aa1, aa);
163 } else {
164 k = k / coeff - (k / coeff - (k - 1) / coeff) *
165 factor(y, k, aa1, aa);
166 }
167 break;
168 case 1:
169 // logarithmic
170 y = sqr * log(fabs(in)) + sqr * sqr;
171 k = roundf(y);
172 if(!in) {
173 k = 0;
174 } else if (k - aa1 <= y && y <= k + aa1) {
175 k = in / fabs(in) * exp(k / sqr - sqr);
176 } else if (y > k + aa1) {
177 double x = exp(k / sqr - sqr);
178 k = FFSIGN(in) * (x + (exp((k + 1) / sqr - sqr) - x) *
179 factor(y, k, aa1, aa));
180 } else {
181 double x = exp(k / sqr - sqr);
182 k = in / fabs(in) * (x - (x - exp((k - 1) / sqr - sqr)) *
183 factor(y, k, aa1, aa));
184 }
185 break;
186 }
187
188 // mix between dry and wet signal
189 k += (in - k) * s->mix;
190
191 // remove dc
192 k = remove_dc(k, s->dc, s->idc);
193
194 return k;
195}
196
197static double lfo_get(LFOContext *lfo)
198{
199 double phs = FFMIN(100., lfo->phase / FFMIN(1.99, FFMAX(0.01, lfo->pwidth)) + lfo->offset);
200 double val;
201
202 if (phs > 1)
203 phs = fmod(phs, 1.);
204
205 val = sin((phs * 360.) * M_PI / 180);
206
207 return val * lfo->amount;
208}
209
210static void lfo_advance(LFOContext *lfo, unsigned count)
211{
212 lfo->phase = fabs(lfo->phase + count * lfo->freq * (1. / lfo->srate));
213 if (lfo->phase >= 1.)
214 lfo->phase = fmod(lfo->phase, 1.);
215}
216
217static int filter_frame(AVFilterLink *inlink, AVFrame *in)
218{
219 AVFilterContext *ctx = inlink->dst;
220 ACrusherContext *s = ctx->priv;
221 AVFilterLink *outlink = ctx->outputs[0];
222 AVFrame *out;
223 const double *src = (const double *)in->data[0];
224 double *dst;
225 const double level_in = s->level_in;
226 const double level_out = s->level_out;
227 const double mix = s->mix;
228 int n, c;
229
230 if (av_frame_is_writable(in)) {
231 out = in;
232 } else {
233 out = ff_get_audio_buffer(inlink, in->nb_samples);
234 if (!out) {
235 av_frame_free(&in);
236 return AVERROR(ENOMEM);
237 }
239 }
240
241 dst = (double *)out->data[0];
242 for (n = 0; n < in->nb_samples; n++) {
243 if (s->is_lfo) {
244 s->samples = s->smin + s->sdiff * (lfo_get(&s->lfo) + 0.5);
245 s->round = round(s->samples);
246 }
247
248 for (c = 0; c < inlink->ch_layout.nb_channels; c++) {
249 double sample = src[c] * level_in;
250
251 sample = mix * samplereduction(s, &s->sr[c], sample) + src[c] * (1. - mix) * level_in;
252 dst[c] = ctx->is_disabled ? src[c] : bitreduction(s, sample) * level_out;
253 }
254 src += c;
255 dst += c;
256
257 if (s->is_lfo)
258 lfo_advance(&s->lfo, 1);
259 }
260
261 if (in != out)
262 av_frame_free(&in);
263
264 return ff_filter_frame(outlink, out);
265}
266
268{
269 ACrusherContext *s = ctx->priv;
270
271 av_freep(&s->sr);
272}
273
274static int config_input(AVFilterLink *inlink)
275{
276 AVFilterContext *ctx = inlink->dst;
277 ACrusherContext *s = ctx->priv;
278 double rad, sunder, smax, sover;
279
280 s->idc = 1. / s->dc;
281 s->coeff = exp2(s->bits) - 1;
282 s->sqr = sqrt(s->coeff / 2);
283 s->aa1 = (1. - s->aa) / 2.;
284 s->round = round(s->samples);
285 rad = s->lforange / 2.;
286 s->smin = FFMAX(s->samples - rad, 1.);
287 sunder = s->samples - rad - s->smin;
288 smax = FFMIN(s->samples + rad, 250.);
289 sover = s->samples + rad - smax;
290 smax -= sunder;
291 s->smin -= sover;
292 s->sdiff = smax - s->smin;
293
294 s->lfo.freq = s->lforate;
295 s->lfo.pwidth = 1.;
296 s->lfo.srate = inlink->sample_rate;
297 s->lfo.amount = .5;
298
299 if (!s->sr)
300 s->sr = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->sr));
301 if (!s->sr)
302 return AVERROR(ENOMEM);
303
304 return 0;
305}
306
307static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
308 char *res, int res_len, int flags)
309{
310 AVFilterLink *inlink = ctx->inputs[0];
311 int ret;
312
313 ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
314 if (ret < 0)
315 return ret;
316
317 return config_input(inlink);
318}
319
321 {
322 .name = "default",
323 .type = AVMEDIA_TYPE_AUDIO,
324 .config_props = config_input,
325 .filter_frame = filter_frame,
326 },
327};
328
330 .p.name = "acrusher",
331 .p.description = NULL_IF_CONFIG_SMALL("Reduce audio bit resolution."),
332 .p.priv_class = &acrusher_class,
334 .priv_size = sizeof(ACrusherContext),
335 .uninit = uninit,
339 .process_command = process_command,
340};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static double val(void *priv, double ch)
Definition aeval.c:77
static int config_input(AVFilterLink *inlink)
static double lfo_get(LFOContext *lfo)
static int config_input(AVFilterLink *inlink)
static double remove_dc(double s, double dc, double idc)
const FFFilter ff_af_acrusher
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static void lfo_advance(LFOContext *lfo, unsigned count)
static double add_dc(double s, double dc, double idc)
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
static av_cold void uninit(AVFilterContext *ctx)
#define OFFSET(x)
Definition af_acrusher.c:71
static const AVFilterPad avfilter_af_acrusher_inputs[]
static double samplereduction(ACrusherContext *s, SRContext *sr, double in)
Definition af_acrusher.c:93
static const AVOption acrusher_options[]
Definition af_acrusher.c:74
static double bitreduction(ACrusherContext *s, double in)
static double sqr(double in)
Definition af_afwtdn.c:872
#define A(x)
Definition vpx_arith.h:28
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
Definition audio.c:34
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition audio.c:74
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition avfilter.c:906
Main libavfilter public API header.
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define s(width, name)
Definition cbs_vp9.c:198
#define FFSIGN(a)
Definition common.h:75
#define NULL
Definition coverity.c:32
static __device__ float fabs(float a)
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int8_t exp
Definition eval.c:76
static const uint8_t bits[8]
Definition fastaudio.c:100
#define sample
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_DOUBLE
Underlying C type is double.
Definition opt.h:266
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition avfilter.h:204
#define AVERROR(e)
Definition error.h:45
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition frame.c:535
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AV_SAMPLE_FMT_DBL
double
Definition samplefmt.h:61
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int mix(int c0, int c1)
Definition 4xm.c:717
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_)
Definition filters.h:257
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
static const int factor[16]
Definition vf_pp7.c:98
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static av_always_inline av_const double round(double x)
Definition libm.h:446
static av_always_inline av_const float roundf(float x)
Definition libm.h:453
#define exp2(x)
Definition libm.h:290
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
#define M_PI_2
Definition mathematics.h:73
#define M_PI
Definition mathematics.h:67
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
AVOptions.
SRContext * sr
Definition af_acrusher.c:68
LFOContext lfo
Definition af_acrusher.c:67
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
int nb_samples
number of audio samples (per channel) described by this frame
Definition frame.h:552
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
AVOption.
Definition opt.h:428
double pwidth
Definition af_acrusher.c:32
double amount
Definition af_acrusher.c:31
double freq
Definition af_acrusher.c:28
double phase
Definition af_acrusher.c:33
double offset
Definition af_acrusher.c:29
double real
Definition af_acrusher.c:38
double target
Definition af_acrusher.c:37
double samples
Definition af_acrusher.c:39
double last
Definition af_acrusher.c:40
Definition swscale.c:71
#define av_freep(p)
#define src
Definition vp8dsp.c:248
static FILE * out
Definition movenc.c:55
static AVFormatContext * ctx
Definition movenc.c:49
static const double coeff[2][5]
static double c[64]