2 * Copyright (c) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
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/avassert.h"
22 #include "libavutil/channel_layout.h"
23 #include "libavutil/opt.h"
29 enum PulsatorModes
{ SINE
, TRIANGLE
, SQUARE
, SAWUP
, SAWDOWN
, NB_MODES
};
30 enum PulsatorTimings
{ UNIT_BPM
, UNIT_MS
, UNIT_HZ
, NB_TIMINGS
};
32 typedef struct SimpleLFO
{
42 typedef struct AudioPulsatorContext
{
57 } AudioPulsatorContext
;
59 #define OFFSET(x) offsetof(AudioPulsatorContext, x)
60 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
62 static const AVOption apulsator_options
[] = {
63 { "level_in", "set input gain", OFFSET(level_in
), AV_OPT_TYPE_DOUBLE
, {.dbl
=1}, 0.015625, 64, FLAGS
, },
64 { "level_out", "set output gain", OFFSET(level_out
), AV_OPT_TYPE_DOUBLE
, {.dbl
=1}, 0.015625, 64, FLAGS
, },
65 { "mode", "set mode", OFFSET(mode
), AV_OPT_TYPE_INT
, {.i64
=SINE
}, SINE
, NB_MODES
-1, FLAGS
, .unit
= "mode" },
66 { "sine", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=SINE
}, 0, 0, FLAGS
, .unit
= "mode" },
67 { "triangle", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=TRIANGLE
},0, 0, FLAGS
, .unit
= "mode" },
68 { "square", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=SQUARE
}, 0, 0, FLAGS
, .unit
= "mode" },
69 { "sawup", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=SAWUP
}, 0, 0, FLAGS
, .unit
= "mode" },
70 { "sawdown", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=SAWDOWN
}, 0, 0, FLAGS
, .unit
= "mode" },
71 { "amount", "set modulation", OFFSET(amount
), AV_OPT_TYPE_DOUBLE
, {.dbl
=1}, 0, 1, FLAGS
},
72 { "offset_l", "set offset L", OFFSET(offset_l
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0}, 0, 1, FLAGS
},
73 { "offset_r", "set offset R", OFFSET(offset_r
), AV_OPT_TYPE_DOUBLE
, {.dbl
=.5}, 0, 1, FLAGS
},
74 { "width", "set pulse width", OFFSET(pwidth
), AV_OPT_TYPE_DOUBLE
, {.dbl
=1}, 0, 2, FLAGS
},
75 { "timing", "set timing", OFFSET(timing
), AV_OPT_TYPE_INT
, {.i64
=2}, 0, NB_TIMINGS
-1, FLAGS
, .unit
= "timing" },
76 { "bpm", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=UNIT_BPM
}, 0, 0, FLAGS
, .unit
= "timing" },
77 { "ms", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=UNIT_MS
}, 0, 0, FLAGS
, .unit
= "timing" },
78 { "hz", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=UNIT_HZ
}, 0, 0, FLAGS
, .unit
= "timing" },
79 { "bpm", "set BPM", OFFSET(bpm
), AV_OPT_TYPE_DOUBLE
, {.dbl
=120}, 30, 300, FLAGS
},
80 { "ms", "set ms", OFFSET(ms
), AV_OPT_TYPE_INT
, {.i64
=500}, 10, 2000, FLAGS
},
81 { "hz", "set frequency", OFFSET(hertz
), AV_OPT_TYPE_DOUBLE
, {.dbl
=2}, 0.01, 100, FLAGS
},
85 AVFILTER_DEFINE_CLASS(apulsator
);
87 static void lfo_advance(SimpleLFO
*lfo
, unsigned count
)
89 lfo
->phase
= fabs(lfo
->phase
+ count
* lfo
->freq
/ lfo
->srate
);
91 lfo
->phase
= fmod(lfo
->phase
, 1);
94 static double lfo_get_value(SimpleLFO
*lfo
)
96 double phs
= FFMIN(100, lfo
->phase
/ FFMIN(1.99, FFMAX(0.01, lfo
->pwidth
)) + lfo
->offset
);
104 val
= sin(phs
* 2 * M_PI
);
108 val
= (phs
- 0.75) * 4 - 1;
115 val
= phs
< 0.5 ? -1 : +1;
123 default: av_assert0(0);
126 return val
* lfo
->amount
;
129 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
131 AVFilterContext
*ctx
= inlink
->dst
;
132 AVFilterLink
*outlink
= ctx
->outputs
[0];
133 AudioPulsatorContext
*s
= ctx
->priv
;
134 const double *src
= (const double *)in
->data
[0];
135 const int nb_samples
= in
->nb_samples
;
136 const double level_out
= s
->level_out
;
137 const double level_in
= s
->level_in
;
138 const double amount
= s
->amount
;
143 if (av_frame_is_writable(in
)) {
146 out
= ff_get_audio_buffer(inlink
, in
->nb_samples
);
149 return AVERROR(ENOMEM
);
151 av_frame_copy_props(out
, in
);
153 dst
= (double *)out
->data
[0];
155 for (n
= 0; n
< nb_samples
; n
++) {
158 double inL
= src
[0] * level_in
;
159 double inR
= src
[1] * level_in
;
163 procL
*= lfo_get_value(&s
->lfoL
) * 0.5 + amount
/ 2;
164 procR
*= lfo_get_value(&s
->lfoR
) * 0.5 + amount
/ 2;
166 outL
= procL
+ inL
* (1 - amount
);
167 outR
= procR
+ inR
* (1 - amount
);
175 lfo_advance(&s
->lfoL
, 1);
176 lfo_advance(&s
->lfoR
, 1);
185 return ff_filter_frame(outlink
, out
);
188 static int query_formats(const AVFilterContext
*ctx
,
189 AVFilterFormatsConfig
**cfg_in
,
190 AVFilterFormatsConfig
**cfg_out
)
192 static const enum AVSampleFormat formats
[] = {
196 static const AVChannelLayout layouts
[] = {
197 AV_CHANNEL_LAYOUT_STEREO
,
198 { .nb_channels
= 0 },
203 ret
= ff_set_common_formats_from_list2(ctx
, cfg_in
, cfg_out
, formats
);
207 ret
= ff_set_common_channel_layouts_from_list2(ctx
, cfg_in
, cfg_out
, layouts
);
214 static int config_input(AVFilterLink
*inlink
)
216 AVFilterContext
*ctx
= inlink
->dst
;
217 AudioPulsatorContext
*s
= ctx
->priv
;
221 case UNIT_BPM
: freq
= s
->bpm
/ 60; break;
222 case UNIT_MS
: freq
= 1 / (s
->ms
/ 1000.); break;
223 case UNIT_HZ
: freq
= s
->hertz
; break;
224 default: av_assert0(0);
229 s
->lfoL
.mode
= s
->mode
;
230 s
->lfoR
.mode
= s
->mode
;
231 s
->lfoL
.offset
= s
->offset_l
;
232 s
->lfoR
.offset
= s
->offset_r
;
233 s
->lfoL
.srate
= inlink
->sample_rate
;
234 s
->lfoR
.srate
= inlink
->sample_rate
;
235 s
->lfoL
.amount
= s
->amount
;
236 s
->lfoR
.amount
= s
->amount
;
237 s
->lfoL
.pwidth
= s
->pwidth
;
238 s
->lfoR
.pwidth
= s
->pwidth
;
243 static const AVFilterPad inputs
[] = {
246 .type
= AVMEDIA_TYPE_AUDIO
,
247 .config_props
= config_input
,
248 .filter_frame
= filter_frame
,
252 const FFFilter ff_af_apulsator
= {
253 .p
.name
= "apulsator",
254 .p
.description
= NULL_IF_CONFIG_SMALL("Audio pulsator."),
255 .p
.priv_class
= &apulsator_class
,
256 .priv_size
= sizeof(AudioPulsatorContext
),
257 FILTER_INPUTS(inputs
),
258 FILTER_OUTPUTS(ff_audio_default_filterpad
),
259 FILTER_QUERY_FUNC2(query_formats
),