2 * Copyright (c) 2015 Kyle Swanson <k@ylo.ph>.
4 * This file is part of FFmpeg.
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.
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.
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
21 #include "libavutil/mem.h"
22 #include "libavutil/opt.h"
27 typedef struct TremoloContext
{
36 #define OFFSET(x) offsetof(TremoloContext, x)
37 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
39 static const AVOption tremolo_options
[] = {
40 { "f", "set frequency in hertz", OFFSET(freq
), AV_OPT_TYPE_DOUBLE
, {.dbl
= 5.0}, 0.1, 20000.0, FLAGS
},
41 { "d", "set depth as percentage", OFFSET(depth
), AV_OPT_TYPE_DOUBLE
, {.dbl
= 0.5}, 0.0, 1.0, FLAGS
},
45 AVFILTER_DEFINE_CLASS(tremolo
);
47 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
49 AVFilterContext
*ctx
= inlink
->dst
;
50 AVFilterLink
*outlink
= ctx
->outputs
[0];
51 TremoloContext
*s
= ctx
->priv
;
52 const double *src
= (const double *)in
->data
[0];
53 const int channels
= inlink
->ch_layout
.nb_channels
;
54 const int nb_samples
= in
->nb_samples
;
59 if (av_frame_is_writable(in
)) {
62 out
= ff_get_audio_buffer(outlink
, in
->nb_samples
);
65 return AVERROR(ENOMEM
);
67 av_frame_copy_props(out
, in
);
69 dst
= (double *)out
->data
[0];
71 for (n
= 0; n
< nb_samples
; n
++) {
72 for (c
= 0; c
< channels
; c
++)
73 dst
[c
] = src
[c
] * s
->table
[s
->index
];
77 if (s
->index
>= s
->table_size
)
84 return ff_filter_frame(outlink
, out
);
87 static av_cold
void uninit(AVFilterContext
*ctx
)
89 TremoloContext
*s
= ctx
->priv
;
93 static int config_input(AVFilterLink
*inlink
)
95 AVFilterContext
*ctx
= inlink
->dst
;
96 TremoloContext
*s
= ctx
->priv
;
97 const double offset
= 1. - s
->depth
/ 2.;
100 s
->table_size
= lrint(inlink
->sample_rate
/ s
->freq
+ 0.5);
101 s
->table
= av_malloc_array(s
->table_size
, sizeof(*s
->table
));
103 return AVERROR(ENOMEM
);
105 for (i
= 0; i
< s
->table_size
; i
++) {
106 double env
= s
->freq
* i
/ inlink
->sample_rate
;
107 env
= sin(2 * M_PI
* fmod(env
+ 0.25, 1.0));
108 s
->table
[i
] = env
* (1 - fabs(offset
)) + offset
;
116 static const AVFilterPad avfilter_af_tremolo_inputs
[] = {
119 .type
= AVMEDIA_TYPE_AUDIO
,
120 .config_props
= config_input
,
121 .filter_frame
= filter_frame
,
125 const FFFilter ff_af_tremolo
= {
127 .p
.description
= NULL_IF_CONFIG_SMALL("Apply tremolo effect."),
128 .p
.priv_class
= &tremolo_class
,
129 .p
.flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
,
130 .priv_size
= sizeof(TremoloContext
),
132 FILTER_INPUTS(avfilter_af_tremolo_inputs
),
133 FILTER_OUTPUTS(ff_audio_default_filterpad
),
134 FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL
),