]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_asoftclip.c
Merge commit '9485cce6d55baf547e92ef1f54cad117f2a38287'
[ffmpeg] / libavfilter / af_asoftclip.c
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/channel_layout.h"
22 #include "libavutil/opt.h"
23 #include "avfilter.h"
24 #include "audio.h"
25 #include "formats.h"
26
27 enum ASoftClipTypes {
28     ASC_TANH,
29     ASC_ATAN,
30     ASC_CUBIC,
31     ASC_EXP,
32     ASC_ALG,
33     ASC_QUINTIC,
34     ASC_SIN,
35     NB_TYPES,
36 };
37
38 typedef struct ASoftClipContext {
39     const AVClass *class;
40
41     int type;
42     double param;
43
44     void (*filter)(struct ASoftClipContext *s, void **dst, const void **src,
45                    int nb_samples, int channels);
46 } ASoftClipContext;
47
48 #define OFFSET(x) offsetof(ASoftClipContext, x)
49 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
50
51 static const AVOption asoftclip_options[] = {
52     { "type", "set softclip type", OFFSET(type), AV_OPT_TYPE_INT,    {.i64=0},          0, NB_TYPES-1, A, "types" },
53     { "tanh",                NULL,            0, AV_OPT_TYPE_CONST,  {.i64=ASC_TANH},   0,          0, A, "types" },
54     { "atan",                NULL,            0, AV_OPT_TYPE_CONST,  {.i64=ASC_ATAN},   0,          0, A, "types" },
55     { "cubic",               NULL,            0, AV_OPT_TYPE_CONST,  {.i64=ASC_CUBIC},  0,          0, A, "types" },
56     { "exp",                 NULL,            0, AV_OPT_TYPE_CONST,  {.i64=ASC_EXP},    0,          0, A, "types" },
57     { "alg",                 NULL,            0, AV_OPT_TYPE_CONST,  {.i64=ASC_ALG},    0,          0, A, "types" },
58     { "quintic",             NULL,            0, AV_OPT_TYPE_CONST,  {.i64=ASC_QUINTIC},0,          0, A, "types" },
59     { "sin",                 NULL,            0, AV_OPT_TYPE_CONST,  {.i64=ASC_SIN},    0,          0, A, "types" },
60     { "param", "set softclip parameter", OFFSET(param), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01,        3, A },
61     { NULL }
62 };
63
64 AVFILTER_DEFINE_CLASS(asoftclip);
65
66 static int query_formats(AVFilterContext *ctx)
67 {
68     AVFilterFormats *formats = NULL;
69     AVFilterChannelLayouts *layouts = NULL;
70     static const enum AVSampleFormat sample_fmts[] = {
71         AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
72         AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
73         AV_SAMPLE_FMT_NONE
74     };
75     int ret;
76
77     formats = ff_make_format_list(sample_fmts);
78     if (!formats)
79         return AVERROR(ENOMEM);
80     ret = ff_set_common_formats(ctx, formats);
81     if (ret < 0)
82         return ret;
83
84     layouts = ff_all_channel_counts();
85     if (!layouts)
86         return AVERROR(ENOMEM);
87
88     ret = ff_set_common_channel_layouts(ctx, layouts);
89     if (ret < 0)
90         return ret;
91
92     formats = ff_all_samplerates();
93     return ff_set_common_samplerates(ctx, formats);
94 }
95
96 #define SQR(x) ((x) * (x))
97
98 static void filter_flt(ASoftClipContext *s,
99                        void **dptr, const void **sptr,
100                        int nb_samples, int channels)
101 {
102     float param = s->param;
103
104     for (int c = 0; c < channels; c++) {
105         const float *src = sptr[c];
106         float *dst = dptr[c];
107
108         switch (s->type) {
109         case ASC_TANH:
110             for (int n = 0; n < nb_samples; n++) {
111                 dst[n] = tanhf(src[n] * param);
112             }
113             break;
114         case ASC_ATAN:
115             for (int n = 0; n < nb_samples; n++)
116                 dst[n] = 2.f / M_PI * atanf(src[n] * param);
117             break;
118         case ASC_CUBIC:
119             for (int n = 0; n < nb_samples; n++) {
120                 if (FFABS(src[n]) >= 1.5f)
121                     dst[n] = FFSIGN(src[n]);
122                 else
123                     dst[n] = src[n] - 0.1481f * powf(src[n], 3.f);
124             }
125             break;
126         case ASC_EXP:
127             for (int n = 0; n < nb_samples; n++)
128                 dst[n] = 2.f / (1.f + expf(-2.f * src[n])) - 1.;
129             break;
130         case ASC_ALG:
131             for (int n = 0; n < nb_samples; n++)
132                 dst[n] = src[n] / (sqrtf(param + src[n] * src[n]));
133             break;
134         case ASC_QUINTIC:
135             for (int n = 0; n < nb_samples; n++) {
136                 if (FFABS(src[n]) >= 1.25)
137                     dst[n] = FFSIGN(src[n]);
138                 else
139                     dst[n] = src[n] - 0.08192f * powf(src[n], 5.f);
140             }
141             break;
142         case ASC_SIN:
143             for (int n = 0; n < nb_samples; n++) {
144                 if (FFABS(src[n]) >= M_PI_2)
145                     dst[n] = FFSIGN(src[n]);
146                 else
147                     dst[n] = sinf(src[n]);
148             }
149             break;
150         }
151     }
152 }
153
154 static void filter_dbl(ASoftClipContext *s,
155                        void **dptr, const void **sptr,
156                        int nb_samples, int channels)
157 {
158     double param = s->param;
159
160     for (int c = 0; c < channels; c++) {
161         const double *src = sptr[c];
162         double *dst = dptr[c];
163
164         switch (s->type) {
165         case ASC_TANH:
166             for (int n = 0; n < nb_samples; n++) {
167                 dst[n] = tanh(src[n] * param);
168             }
169             break;
170         case ASC_ATAN:
171             for (int n = 0; n < nb_samples; n++)
172                 dst[n] = 2. / M_PI * atan(src[n] * param);
173             break;
174         case ASC_CUBIC:
175             for (int n = 0; n < nb_samples; n++) {
176                 if (FFABS(src[n]) >= 1.5)
177                     dst[n] = FFSIGN(src[n]);
178                 else
179                     dst[n] = src[n] - 0.1481 * pow(src[n], 3.);
180             }
181             break;
182         case ASC_EXP:
183             for (int n = 0; n < nb_samples; n++)
184                 dst[n] = 2. / (1. + exp(-2. * src[n])) - 1.;
185             break;
186         case ASC_ALG:
187             for (int n = 0; n < nb_samples; n++)
188                 dst[n] = src[n] / (sqrt(param + src[n] * src[n]));
189             break;
190         case ASC_QUINTIC:
191             for (int n = 0; n < nb_samples; n++) {
192                 if (FFABS(src[n]) >= 1.25)
193                     dst[n] = FFSIGN(src[n]);
194                 else
195                     dst[n] = src[n] - 0.08192 * pow(src[n], 5.);
196             }
197             break;
198         case ASC_SIN:
199             for (int n = 0; n < nb_samples; n++) {
200                 if (FFABS(src[n]) >= M_PI_2)
201                     dst[n] = FFSIGN(src[n]);
202                 else
203                     dst[n] = sin(src[n]);
204             }
205             break;
206         }
207     }
208 }
209
210 static int config_input(AVFilterLink *inlink)
211 {
212     AVFilterContext *ctx = inlink->dst;
213     ASoftClipContext *s = ctx->priv;
214
215     switch (inlink->format) {
216     case AV_SAMPLE_FMT_FLT:
217     case AV_SAMPLE_FMT_FLTP: s->filter = filter_flt; break;
218     case AV_SAMPLE_FMT_DBL:
219     case AV_SAMPLE_FMT_DBLP: s->filter = filter_dbl; break;
220     }
221
222     return 0;
223 }
224
225 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
226 {
227     AVFilterContext *ctx = inlink->dst;
228     AVFilterLink *outlink = ctx->outputs[0];
229     ASoftClipContext *s = ctx->priv;
230     int nb_samples, channels;
231     AVFrame *out;
232
233     if (av_frame_is_writable(in)) {
234         out = in;
235     } else {
236         out = ff_get_audio_buffer(outlink, in->nb_samples);
237         if (!out) {
238             av_frame_free(&in);
239             return AVERROR(ENOMEM);
240         }
241         av_frame_copy_props(out, in);
242     }
243
244     if (av_sample_fmt_is_planar(in->format)) {
245         nb_samples = in->nb_samples;
246         channels = in->channels;
247     } else {
248         nb_samples = in->channels * in->nb_samples;
249         channels = 1;
250     }
251
252     s->filter(s, (void **)out->extended_data, (const void **)in->extended_data,
253               nb_samples, channels);
254
255     if (out != in)
256         av_frame_free(&in);
257
258     return ff_filter_frame(outlink, out);
259 }
260
261 static const AVFilterPad inputs[] = {
262     {
263         .name         = "default",
264         .type         = AVMEDIA_TYPE_AUDIO,
265         .filter_frame = filter_frame,
266         .config_props = config_input,
267     },
268     { NULL }
269 };
270
271 static const AVFilterPad outputs[] = {
272     {
273         .name = "default",
274         .type = AVMEDIA_TYPE_AUDIO,
275     },
276     { NULL }
277 };
278
279 AVFilter ff_af_asoftclip = {
280     .name           = "asoftclip",
281     .description    = NULL_IF_CONFIG_SMALL("Audio Soft Clipper."),
282     .query_formats  = query_formats,
283     .priv_size      = sizeof(ASoftClipContext),
284     .priv_class     = &asoftclip_class,
285     .inputs         = inputs,
286     .outputs        = outputs,
287     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
288 };