FFmpeg
Loading...
Searching...
No Matches
af_virtualbass.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Paul B Mahol
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 License
8 * 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
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
22#include "libavutil/opt.h"
23#include "audio.h"
24#include "avfilter.h"
25#include "filters.h"
26#include "formats.h"
27
28#include <float.h>
29
31 const AVClass *class;
32
33 double cutoff;
34 double strength;
35
36 double a[3], m[3], cf[2];
38
39#define OFFSET(x) offsetof(AudioVirtualBassContext, x)
40#define TFLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM
41#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
42
43static const AVOption virtualbass_options[] = {
44 { "cutoff", "set virtual bass cutoff", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, {.dbl=250},100,500, FLAGS },
45 { "strength", "set virtual bass strength", OFFSET(strength), AV_OPT_TYPE_DOUBLE, {.dbl=3}, 0.5, 3, TFLAGS },
46 {NULL}
47};
48
50
52 AVFilterFormatsConfig **cfg_in,
53 AVFilterFormatsConfig **cfg_out)
54{
55 static const enum AVSampleFormat formats[] = {
58 };
59
60 AVFilterChannelLayouts *in_layout = NULL, *out_layout = NULL;
61 int ret;
62
63 ret = ff_set_sample_formats_from_list2(ctx, cfg_in, cfg_out, formats);
64 if (ret < 0)
65 return ret;
66
67 if ((ret = ff_add_channel_layout (&in_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 ||
68 (ret = ff_channel_layouts_ref(in_layout, &cfg_in[0]->channel_layouts)) < 0 ||
70 (ret = ff_channel_layouts_ref(out_layout, &cfg_out[0]->channel_layouts)) < 0)
71 return ret;
72
73 return 0;
74}
75
76static int config_input(AVFilterLink *inlink)
77{
78 AVFilterContext *ctx = inlink->dst;
80 const double Q = 0.707;
81 double g, k;
82
83 g = tan(M_PI * s->cutoff / inlink->sample_rate);
84 k = 1. / Q;
85 s->a[0] = 1. / (1. + g * (g + k));
86 s->a[1] = g * s->a[0];
87 s->a[2] = g * s->a[1];
88 s->m[0] = 0.;
89 s->m[1] = 0.;
90 s->m[2] = 1.;
91
92 return 0;
93}
94
95#define SQR(x) ((x) * (x))
96
97static double vb_fun(double x)
98{
99 double y = 2.5 * atan(0.9 * x) + 2.5 * sqrt(1. - SQR(0.9 * x)) - 2.5;
100
101 return y < 0. ? sin(y) : y;
102}
103
105{
107 const double *lsrc = (const double *)in->extended_data[0];
108 const double *rsrc = (const double *)in->extended_data[1];
109 double *ldst = (double *)out->extended_data[0];
110 double *rdst = (double *)out->extended_data[1];
111 double *lfe = (double *)out->extended_data[2];
112 const double st = M_PI / s->strength;
113 const double a0 = s->a[0];
114 const double a1 = s->a[1];
115 const double a2 = s->a[2];
116 const double m0 = s->m[0];
117 const double m1 = s->m[1];
118 const double m2 = s->m[2];
119 double b0 = s->cf[0];
120 double b1 = s->cf[1];
121
122 memcpy(ldst, lsrc, in->nb_samples * sizeof(double));
123 memcpy(rdst, rsrc, in->nb_samples * sizeof(double));
124
125 for (int n = 0; n < in->nb_samples; n++) {
126 const double center = (lsrc[n] + rsrc[n]) * 0.5;
127 const double v0 = center;
128 const double v3 = v0 - b1;
129 const double v1 = a0 * b0 + a1 * v3;
130 const double v2 = b1 + a1 * b0 + a2 * v3;
131 double b, vb;
132
133 b0 = 2. * v1 - b0;
134 b1 = 2. * v2 - b1;
135
136 b = m0 * v0 + m1 * v1 + m2 * v2;
137 vb = sin(vb_fun(b) * st);
138
139 lfe[n] = vb;
140 }
141
142 s->cf[0] = b0;
143 s->cf[1] = b1;
144}
145
146static int filter_frame(AVFilterLink *inlink, AVFrame *in)
147{
148 AVFilterContext *ctx = inlink->dst;
149 AVFilterLink *outlink = ctx->outputs[0];
150 AVFrame *out;
151
152 out = ff_get_audio_buffer(outlink, in->nb_samples);
153 if (!out) {
154 av_frame_free(&in);
155 return AVERROR(ENOMEM);
156 }
158
159 vb_stereo(ctx, out, in);
160
161 av_frame_free(&in);
162 return ff_filter_frame(outlink, out);
163}
164
165static const AVFilterPad inputs[] = {
166 {
167 .name = "default",
168 .type = AVMEDIA_TYPE_AUDIO,
169 .filter_frame = filter_frame,
170 .config_props = config_input,
171 },
172};
173
175 .p.name = "virtualbass",
176 .p.description = NULL_IF_CONFIG_SMALL("Audio Virtual Bass."),
177 .p.priv_class = &virtualbass_class,
179 .priv_size = sizeof(AudioVirtualBassContext),
183 .process_command = ff_filter_process_command,
184};
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition aeval.c:246
static const AVFilterPad inputs[]
Definition af_aap.c:299
static int config_input(AVFilterLink *inlink)
#define TFLAGS
Definition af_afade.c:66
static void vb_stereo(AVFilterContext *ctx, AVFrame *out, AVFrame *in)
const FFFilter ff_af_virtualbass
static int config_input(AVFilterLink *inlink)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
#define SQR(x)
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static double vb_fun(double x)
#define OFFSET(x)
static const AVOption virtualbass_options[]
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 s(width, name)
Definition cbs_vp9.c:198
Public libavutil channel layout APIs header.
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
static const uint16_t channel_layouts[7]
Definition dca_lbr.c:112
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int ff_add_channel_layout(AVFilterChannelLayouts **l, const AVChannelLayout *channel_layout)
Definition formats.c:588
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition formats.c:751
int ff_set_sample_formats_from_list2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, const enum AVSampleFormat *fmts)
Definition formats.c:1154
@ AV_OPT_TYPE_DOUBLE
Underlying C type is double.
Definition opt.h:266
#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 AV_CHANNEL_LAYOUT_STEREO
#define AV_CHANNEL_LAYOUT_2POINT1
#define AVERROR(e)
Definition error.h:45
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
AVSampleFormat
Audio sample formats.
Definition samplefmt.h:55
@ AV_SAMPLE_FMT_NONE
Definition samplefmt.h:56
@ AV_SAMPLE_FMT_DBLP
double, planar
Definition samplefmt.h:67
#define Q(q)
#define b
Definition input.c:43
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define FILTER_QUERY_FUNC2(func)
Definition filters.h:241
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
#define M_PI
Definition mathematics.h:67
AVOptions.
formats
Definition signature.h:47
An AVChannelLayout holds information about the channel layout of audio data.
Describe the class of an AVClass context structure.
Definition log.h:76
A list of supported channel layouts.
Definition formats.h:85
An instance of a filter.
Definition avfilter.h:273
Lists of formats / etc.
Definition avfilter.h:120
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 ** extended_data
pointers to the data planes/channels.
Definition frame.h:533
AVOption.
Definition opt.h:428
static FILE * out
Definition movenc.c:55
static AVFormatContext * ctx
Definition movenc.c:49
const char * g
Definition vf_curves.c:128
static double b1(void *priv, double x, double y)
Definition vf_xfade.c:2034
static double a0(void *priv, double x, double y)
Definition vf_xfade.c:2028
static double b0(void *priv, double x, double y)
Definition vf_xfade.c:2033
static double a2(void *priv, double x, double y)
Definition vf_xfade.c:2030
static double a1(void *priv, double x, double y)
Definition vf_xfade.c:2029