FFmpeg
Loading...
Searching...
No Matches
af_asoftclip.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 The FFmpeg Project
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/avassert.h"
23#include "libavutil/opt.h"
24#include "avfilter.h"
25#include "audio.h"
26#include "filters.h"
27
28#define MAX_OVERSAMPLE 64
29
42
43typedef struct Lowpass {
44 float fb0, fb1, fb2;
45 float fa0, fa1, fa2;
46
47 double db0, db1, db2;
48 double da0, da1, da2;
49} Lowpass;
50
51typedef struct ASoftClipContext {
52 const AVClass *class;
53
54 int type;
57 double threshold;
58 double output;
59 double param;
60
63
64 void (*filter)(struct ASoftClipContext *s, void **dst, const void **src,
65 int nb_samples, int channels, int start, int end);
67
68#define OFFSET(x) offsetof(ASoftClipContext, x)
69#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
70
71static const AVOption asoftclip_options[] = {
72 { "type", "set softclip type", OFFSET(type), AV_OPT_TYPE_INT, {.i64=0}, -1, NB_TYPES-1, A, .unit = "types" },
73 { "hard", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_HARD}, 0, 0, A, .unit = "types" },
74 { "tanh", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_TANH}, 0, 0, A, .unit = "types" },
75 { "atan", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_ATAN}, 0, 0, A, .unit = "types" },
76 { "cubic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_CUBIC}, 0, 0, A, .unit = "types" },
77 { "exp", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_EXP}, 0, 0, A, .unit = "types" },
78 { "alg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_ALG}, 0, 0, A, .unit = "types" },
79 { "quintic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_QUINTIC},0, 0, A, .unit = "types" },
80 { "sin", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_SIN}, 0, 0, A, .unit = "types" },
81 { "erf", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_ERF}, 0, 0, A, .unit = "types" },
82 { "threshold", "set softclip threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.000001, 1, A },
83 { "output", "set softclip output gain", OFFSET(output), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.000001, 16, A },
84 { "param", "set softclip parameter", OFFSET(param), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 3, A },
85 { "oversample", "set oversample factor", OFFSET(oversample), AV_OPT_TYPE_INT, {.i64=1}, 1, MAX_OVERSAMPLE, A },
86 { NULL }
87};
88
90
91static void get_lowpass(Lowpass *s,
92 double frequency,
93 double sample_rate)
94{
95 double w0 = 2 * M_PI * frequency / sample_rate;
96 double alpha = sin(w0) / (2 * 0.8);
97 double factor;
98
99 s->da0 = 1 + alpha;
100 s->da1 = -2 * cos(w0);
101 s->da2 = 1 - alpha;
102 s->db0 = (1 - cos(w0)) / 2;
103 s->db1 = 1 - cos(w0);
104 s->db2 = (1 - cos(w0)) / 2;
105
106 s->da1 /= s->da0;
107 s->da2 /= s->da0;
108 s->db0 /= s->da0;
109 s->db1 /= s->da0;
110 s->db2 /= s->da0;
111 s->da0 /= s->da0;
112
113 factor = (s->da0 + s->da1 + s->da2) / (s->db0 + s->db1 + s->db2);
114 s->db0 *= factor;
115 s->db1 *= factor;
116 s->db2 *= factor;
117
118 s->fa0 = s->da0;
119 s->fa1 = s->da1;
120 s->fa2 = s->da2;
121 s->fb0 = s->db0;
122 s->fb1 = s->db1;
123 s->fb2 = s->db2;
124}
125
126static inline float run_lowpassf(const Lowpass *const s,
127 float src, float *w)
128{
129 float dst;
130
131 dst = src * s->fb0 + w[0];
132 w[0] = s->fb1 * src + w[1] - s->fa1 * dst;
133 w[1] = s->fb2 * src - s->fa2 * dst;
134
135 return dst;
136}
137
139 void **dptr, const void **sptr,
140 int nb_samples, int channels,
141 int start, int end)
142{
143 const int oversample = s->oversample;
144 const int nb_osamples = nb_samples * oversample;
145 const float scale = oversample > 1 ? oversample * 0.5f : 1.f;
146 float threshold = s->threshold;
147 float gain = s->output * threshold;
148 float factor = 1.f / threshold;
149 float param = s->param;
150
151 for (int c = start; c < end; c++) {
152 float *w = (float *)(s->frame[0]->extended_data[c]) + 2 * (oversample - 1);
153 const float *src = sptr[c];
154 float *dst = dptr[c];
155
156 for (int n = 0; n < nb_samples; n++) {
157 dst[oversample * n] = src[n];
158
159 for (int m = 1; m < oversample; m++)
160 dst[oversample * n + m] = 0.f;
161 }
162
163 for (int n = 0; n < nb_osamples && oversample > 1; n++)
164 dst[n] = run_lowpassf(&s->lowpass[oversample - 1], dst[n], w);
165
166 switch (s->type) {
167 case ASC_HARD:
168 for (int n = 0; n < nb_osamples; n++) {
169 dst[n] = av_clipf(dst[n] * factor, -1.f, 1.f);
170 dst[n] *= gain;
171 }
172 break;
173 case ASC_TANH:
174 for (int n = 0; n < nb_osamples; n++) {
175 dst[n] = tanhf(dst[n] * factor * param);
176 dst[n] *= gain;
177 }
178 break;
179 case ASC_ATAN:
180 for (int n = 0; n < nb_osamples; n++) {
181 dst[n] = 2.f / M_PI * atanf(dst[n] * factor * param);
182 dst[n] *= gain;
183 }
184 break;
185 case ASC_CUBIC:
186 for (int n = 0; n < nb_osamples; n++) {
187 float sample = dst[n] * factor;
188
189 if (FFABS(sample) >= 1.5f)
190 dst[n] = FFSIGN(sample);
191 else
192 dst[n] = sample - 0.1481f * powf(sample, 3.f);
193 dst[n] *= gain;
194 }
195 break;
196 case ASC_EXP:
197 for (int n = 0; n < nb_osamples; n++) {
198 dst[n] = 2.f / (1.f + expf(-2.f * dst[n] * factor)) - 1.;
199 dst[n] *= gain;
200 }
201 break;
202 case ASC_ALG:
203 for (int n = 0; n < nb_osamples; n++) {
204 float sample = dst[n] * factor;
205
206 dst[n] = sample / (sqrtf(param + sample * sample));
207 dst[n] *= gain;
208 }
209 break;
210 case ASC_QUINTIC:
211 for (int n = 0; n < nb_osamples; n++) {
212 float sample = dst[n] * factor;
213
214 if (FFABS(sample) >= 1.25)
215 dst[n] = FFSIGN(sample);
216 else
217 dst[n] = sample - 0.08192f * powf(sample, 5.f);
218 dst[n] *= gain;
219 }
220 break;
221 case ASC_SIN:
222 for (int n = 0; n < nb_osamples; n++) {
223 float sample = dst[n] * factor;
224
225 if (FFABS(sample) >= M_PI_2)
226 dst[n] = FFSIGN(sample);
227 else
228 dst[n] = sinf(sample);
229 dst[n] *= gain;
230 }
231 break;
232 case ASC_ERF:
233 for (int n = 0; n < nb_osamples; n++) {
234 dst[n] = erff(dst[n] * factor);
235 dst[n] *= gain;
236 }
237 break;
238 default:
239 av_assert0(0);
240 }
241
242 w = (float *)(s->frame[1]->extended_data[c]) + 2 * (oversample - 1);
243 for (int n = 0; n < nb_osamples && oversample > 1; n++)
244 dst[n] = run_lowpassf(&s->lowpass[oversample - 1], dst[n], w);
245
246 for (int n = 0; n < nb_samples; n++)
247 dst[n] = dst[n * oversample] * scale;
248 }
249}
250
251static inline double run_lowpassd(const Lowpass *const s,
252 double src, double *w)
253{
254 double dst;
255
256 dst = src * s->db0 + w[0];
257 w[0] = s->db1 * src + w[1] - s->da1 * dst;
258 w[1] = s->db2 * src - s->da2 * dst;
259
260 return dst;
261}
262
264 void **dptr, const void **sptr,
265 int nb_samples, int channels,
266 int start, int end)
267{
268 const int oversample = s->oversample;
269 const int nb_osamples = nb_samples * oversample;
270 const double scale = oversample > 1 ? oversample * 0.5 : 1.;
271 double threshold = s->threshold;
272 double gain = s->output * threshold;
273 double factor = 1. / threshold;
274 double param = s->param;
275
276 for (int c = start; c < end; c++) {
277 double *w = (double *)(s->frame[0]->extended_data[c]) + 2 * (oversample - 1);
278 const double *src = sptr[c];
279 double *dst = dptr[c];
280
281 for (int n = 0; n < nb_samples; n++) {
282 dst[oversample * n] = src[n];
283
284 for (int m = 1; m < oversample; m++)
285 dst[oversample * n + m] = 0.f;
286 }
287
288 for (int n = 0; n < nb_osamples && oversample > 1; n++)
289 dst[n] = run_lowpassd(&s->lowpass[oversample - 1], dst[n], w);
290
291 switch (s->type) {
292 case ASC_HARD:
293 for (int n = 0; n < nb_osamples; n++) {
294 dst[n] = av_clipd(dst[n] * factor, -1., 1.);
295 dst[n] *= gain;
296 }
297 break;
298 case ASC_TANH:
299 for (int n = 0; n < nb_osamples; n++) {
300 dst[n] = tanh(dst[n] * factor * param);
301 dst[n] *= gain;
302 }
303 break;
304 case ASC_ATAN:
305 for (int n = 0; n < nb_osamples; n++) {
306 dst[n] = 2. / M_PI * atan(dst[n] * factor * param);
307 dst[n] *= gain;
308 }
309 break;
310 case ASC_CUBIC:
311 for (int n = 0; n < nb_osamples; n++) {
312 double sample = dst[n] * factor;
313
314 if (FFABS(sample) >= 1.5)
315 dst[n] = FFSIGN(sample);
316 else
317 dst[n] = sample - 0.1481 * pow(sample, 3.);
318 dst[n] *= gain;
319 }
320 break;
321 case ASC_EXP:
322 for (int n = 0; n < nb_osamples; n++) {
323 dst[n] = 2. / (1. + exp(-2. * dst[n] * factor)) - 1.;
324 dst[n] *= gain;
325 }
326 break;
327 case ASC_ALG:
328 for (int n = 0; n < nb_osamples; n++) {
329 double sample = dst[n] * factor;
330
331 dst[n] = sample / (sqrt(param + sample * sample));
332 dst[n] *= gain;
333 }
334 break;
335 case ASC_QUINTIC:
336 for (int n = 0; n < nb_osamples; n++) {
337 double sample = dst[n] * factor;
338
339 if (FFABS(sample) >= 1.25)
340 dst[n] = FFSIGN(sample);
341 else
342 dst[n] = sample - 0.08192 * pow(sample, 5.);
343 dst[n] *= gain;
344 }
345 break;
346 case ASC_SIN:
347 for (int n = 0; n < nb_osamples; n++) {
348 double sample = dst[n] * factor;
349
350 if (FFABS(sample) >= M_PI_2)
351 dst[n] = FFSIGN(sample);
352 else
353 dst[n] = sin(sample);
354 dst[n] *= gain;
355 }
356 break;
357 case ASC_ERF:
358 for (int n = 0; n < nb_osamples; n++) {
359 dst[n] = erf(dst[n] * factor);
360 dst[n] *= gain;
361 }
362 break;
363 default:
364 av_assert0(0);
365 }
366
367 w = (double *)(s->frame[1]->extended_data[c]) + 2 * (oversample - 1);
368 for (int n = 0; n < nb_osamples && oversample > 1; n++)
369 dst[n] = run_lowpassd(&s->lowpass[oversample - 1], dst[n], w);
370
371 for (int n = 0; n < nb_samples; n++)
372 dst[n] = dst[n * oversample] * scale;
373 }
374}
375
376static int config_input(AVFilterLink *inlink)
377{
378 AVFilterContext *ctx = inlink->dst;
379 ASoftClipContext *s = ctx->priv;
380
381 switch (inlink->format) {
382 case AV_SAMPLE_FMT_FLTP: s->filter = filter_flt; break;
383 case AV_SAMPLE_FMT_DBLP: s->filter = filter_dbl; break;
384 default: av_assert0(0);
385 }
386
387 s->frame[0] = ff_get_audio_buffer(inlink, 2 * MAX_OVERSAMPLE);
388 s->frame[1] = ff_get_audio_buffer(inlink, 2 * MAX_OVERSAMPLE);
389 if (!s->frame[0] || !s->frame[1])
390 return AVERROR(ENOMEM);
391
392 for (int i = 0; i < MAX_OVERSAMPLE; i++) {
393 get_lowpass(&s->lowpass[i], inlink->sample_rate / 2, inlink->sample_rate * (i + 1));
394 }
395
396 return 0;
397}
398
399typedef struct ThreadData {
400 AVFrame *in, *out;
403} ThreadData;
404
405static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
406{
407 ASoftClipContext *s = ctx->priv;
408 ThreadData *td = arg;
409 AVFrame *out = td->out;
410 AVFrame *in = td->in;
411 const int channels = td->channels;
412 const int nb_samples = td->nb_samples;
413 const int start = ff_slice_pos(channels, jobnr, nb_jobs);
414 const int end = ff_slice_pos(channels, jobnr + 1, nb_jobs);
415
416 s->filter(s, (void **)out->extended_data, (const void **)in->extended_data,
417 nb_samples, channels, start, end);
418
419 return 0;
420}
421
422static int filter_frame(AVFilterLink *inlink, AVFrame *in)
423{
424 AVFilterContext *ctx = inlink->dst;
425 ASoftClipContext *s = ctx->priv;
426 AVFilterLink *outlink = ctx->outputs[0];
427 int nb_samples, channels;
428 ThreadData td;
429 AVFrame *out;
430
431 if (av_frame_is_writable(in) && s->oversample == 1) {
432 out = in;
433 } else {
434 out = ff_get_audio_buffer(outlink, in->nb_samples * s->oversample);
435 if (!out) {
436 av_frame_free(&in);
437 return AVERROR(ENOMEM);
438 }
440 }
441
442 nb_samples = in->nb_samples;
444
445 td.in = in;
446 td.out = out;
447 td.nb_samples = nb_samples;
448 td.channels = channels;
451
452 if (out != in)
453 av_frame_free(&in);
454
455 out->nb_samples /= s->oversample;
456 return ff_filter_frame(outlink, out);
457}
458
460{
461 ASoftClipContext *s = ctx->priv;
462
463 av_frame_free(&s->frame[0]);
464 av_frame_free(&s->frame[1]);
465}
466
467static const AVFilterPad inputs[] = {
468 {
469 .name = "default",
470 .type = AVMEDIA_TYPE_AUDIO,
471 .filter_frame = filter_frame,
472 .config_props = config_input,
473 },
474};
475
477 .p.name = "asoftclip",
478 .p.description = NULL_IF_CONFIG_SMALL("Audio Soft Clipper."),
479 .p.priv_class = &asoftclip_class,
482 .priv_size = sizeof(ASoftClipContext),
486 .uninit = uninit,
487 .process_command = ff_filter_process_command,
488};
static int fn filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static const AVFilterPad inputs[]
Definition af_aap.c:299
static int config_input(AVFilterLink *inlink)
static void filter_dbl(void **d, const void **s, int nb_samples, int channels, float contrast)
static void filter_flt(void **d, const void **s, int nb_samples, int channels, float contrast)
@ NB_TYPES
Definition af_adenorm.c:31
#define MAX_OVERSAMPLE
static double run_lowpassd(const Lowpass *const s, double src, double *w)
static const AVOption asoftclip_options[]
const FFFilter ff_af_asoftclip
static void filter_dbl(ASoftClipContext *s, void **dptr, const void **sptr, int nb_samples, int channels, int start, int end)
static void get_lowpass(Lowpass *s, double frequency, double sample_rate)
static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static int config_input(AVFilterLink *inlink)
ASoftClipTypes
@ ASC_HARD
@ ASC_ALG
@ ASC_SIN
@ ASC_TANH
@ ASC_ATAN
@ ASC_ERF
@ ASC_CUBIC
@ ASC_EXP
@ ASC_QUINTIC
static void filter_flt(ASoftClipContext *s, void **dptr, const void **sptr, int nb_samples, int channels, int start, int end)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static av_cold void uninit(AVFilterContext *ctx)
#define OFFSET(x)
static float run_lowpassf(const Lowpass *const s, float src, float *w)
static FILE * out
static AVFormatContext * ctx
channels
Definition aptx.h:31
#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
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
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
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition avfilter.c:1696
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition avfilter.c:846
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
Public libavutil channel layout APIs header.
#define av_clipd
Definition common.h:148
#define av_clipf
Definition common.h:145
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition common.h:74
#define FFSIGN(a)
Definition common.h:75
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static __device__ float sqrtf(float a)
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int8_t exp
Definition eval.c:76
#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
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition avfilter.h:196
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition avfilter.h:166
#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_FLTP
float, planar
Definition samplefmt.h:66
@ AV_SAMPLE_FMT_DBLP
double, planar
Definition samplefmt.h:67
cl_device_type type
static const int16_t alpha[]
Definition ilbcdata.h:55
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition intra.c:278
static av_cold void uninit(AVBitStreamFilterContext *ctx)
const char * arg
Definition jacosubdec.c:65
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FILTER_SAMPLEFMTS(...)
Definition filters.h:252
static int ff_slice_pos(int total, int jobnr, int nb_jobs)
Compute the boundary index for a slice when work of size total is split into nb_jobs slices.
Definition filters.h:763
#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 double erf(double z)
erf function Algorithm taken from the Boost project, source: http://www.boost.org/doc/libs/1_46_1/boo...
Definition libm.h:123
#define atanf(x)
Definition libm.h:42
#define sinf(x)
Definition libm.h:421
#define expf(x)
Definition libm.h:285
#define powf(x, y)
Definition libm.h:52
uint8_t w
Definition llvidencdsp.c:39
#define FFMIN(a, b)
Definition macros.h:49
#define M_PI_2
Definition mathematics.h:73
#define M_PI
Definition mathematics.h:67
AVOptions.
Lowpass lowpass[MAX_OVERSAMPLE]
void(* filter)(struct ASoftClipContext *s, void **dst, const void **src, int nb_samples, int channels, int start, int end)
AVFrame * frame[2]
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
AVChannelLayout ch_layout
Channel layout of the audio data.
Definition frame.h:815
uint8_t ** extended_data
pointers to the data planes/channels.
Definition frame.h:533
AVOption.
Definition opt.h:428
float fb1
double da0
float fa1
double da1
double db0
float fb0
float fa2
float fa0
double da2
float fb2
double db1
double db2
Used for passing data between threads.
Definition dsddec.c:71
AVFrame * out
#define src
Definition vp8dsp.c:248
static double c[64]