2 * Copyright (c) 2006 Rob Sykes <robs@users.sourceforge.net>
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/avstring.h"
22 #include "libavutil/opt.h"
23 #include "libavutil/samplefmt.h"
27 #include "generate_wave_table.h"
29 #define INTERPOLATION_LINEAR 0
30 #define INTERPOLATION_QUADRATIC 1
32 typedef struct FlangerContext
{
44 uint8_t **delay_buffer
;
52 #define OFFSET(x) offsetof(FlangerContext, x)
53 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
55 static const AVOption flanger_options
[] = {
56 { "delay", "base delay in milliseconds", OFFSET(delay_min
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0}, 0, 30, A
},
57 { "depth", "added swept delay in milliseconds", OFFSET(delay_depth
), AV_OPT_TYPE_DOUBLE
, {.dbl
=2}, 0, 10, A
},
58 { "regen", "percentage regeneration (delayed signal feedback)", OFFSET(feedback_gain
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0}, -95, 95, A
},
59 { "width", "percentage of delayed signal mixed with original", OFFSET(delay_gain
), AV_OPT_TYPE_DOUBLE
, {.dbl
=71}, 0, 100, A
},
60 { "speed", "sweeps per second (Hz)", OFFSET(speed
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0.5}, 0.1, 10, A
},
61 { "shape", "swept wave shape", OFFSET(wave_shape
), AV_OPT_TYPE_INT
, {.i64
=WAVE_SIN
}, WAVE_SIN
, WAVE_NB
-1, A
, "type" },
62 { "triangular", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=WAVE_TRI
}, 0, 0, A
, "type" },
63 { "t", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=WAVE_TRI
}, 0, 0, A
, "type" },
64 { "sinusoidal", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=WAVE_SIN
}, 0, 0, A
, "type" },
65 { "s", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=WAVE_SIN
}, 0, 0, A
, "type" },
66 { "phase", "swept wave percentage phase-shift for multi-channel", OFFSET(channel_phase
), AV_OPT_TYPE_DOUBLE
, {.dbl
=25}, 0, 100, A
},
67 { "interp", "delay-line interpolation", OFFSET(interpolation
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, A
, "itype" },
68 { "linear", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=INTERPOLATION_LINEAR
}, 0, 0, A
, "itype" },
69 { "quadratic", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=INTERPOLATION_QUADRATIC
}, 0, 0, A
, "itype" },
73 AVFILTER_DEFINE_CLASS(flanger
);
75 static int init(AVFilterContext
*ctx
)
77 FlangerContext
*s
= ctx
->priv
;
79 s
->feedback_gain
/= 100;
81 s
->channel_phase
/= 100;
83 s
->delay_depth
/= 1000;
84 s
->in_gain
= 1 / (1 + s
->delay_gain
);
85 s
->delay_gain
/= 1 + s
->delay_gain
;
86 s
->delay_gain
*= 1 - fabs(s
->feedback_gain
);
91 static int query_formats(AVFilterContext
*ctx
)
93 AVFilterChannelLayouts
*layouts
;
94 AVFilterFormats
*formats
;
95 static const enum AVSampleFormat sample_fmts
[] = {
96 AV_SAMPLE_FMT_DBLP
, AV_SAMPLE_FMT_NONE
99 layouts
= ff_all_channel_layouts();
101 return AVERROR(ENOMEM
);
102 ff_set_common_channel_layouts(ctx
, layouts
);
104 formats
= ff_make_format_list(sample_fmts
);
106 return AVERROR(ENOMEM
);
107 ff_set_common_formats(ctx
, formats
);
109 formats
= ff_all_samplerates();
111 return AVERROR(ENOMEM
);
112 ff_set_common_samplerates(ctx
, formats
);
117 static int config_input(AVFilterLink
*inlink
)
119 AVFilterContext
*ctx
= inlink
->dst
;
120 FlangerContext
*s
= ctx
->priv
;
122 s
->max_samples
= (s
->delay_min
+ s
->delay_depth
) * inlink
->sample_rate
+ 2.5;
123 s
->lfo_length
= inlink
->sample_rate
/ s
->speed
;
124 s
->delay_last
= av_calloc(inlink
->channels
, sizeof(*s
->delay_last
));
125 s
->lfo
= av_calloc(s
->lfo_length
, sizeof(*s
->lfo
));
126 if (!s
->lfo
|| !s
->delay_last
)
127 return AVERROR(ENOMEM
);
129 ff_generate_wave_table(s
->wave_shape
, AV_SAMPLE_FMT_FLT
, s
->lfo
, s
->lfo_length
,
130 floor(s
->delay_min
* inlink
->sample_rate
+ 0.5),
131 s
->max_samples
- 2., 3 * M_PI_2
);
133 return av_samples_alloc_array_and_samples(&s
->delay_buffer
, NULL
,
134 inlink
->channels
, s
->max_samples
,
138 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*frame
)
140 AVFilterContext
*ctx
= inlink
->dst
;
141 FlangerContext
*s
= ctx
->priv
;
145 if (av_frame_is_writable(frame
)) {
148 out_frame
= ff_get_audio_buffer(inlink
, frame
->nb_samples
);
150 return AVERROR(ENOMEM
);
151 av_frame_copy_props(out_frame
, frame
);
154 for (i
= 0; i
< frame
->nb_samples
; i
++) {
156 s
->delay_buf_pos
= (s
->delay_buf_pos
+ s
->max_samples
- 1) % s
->max_samples
;
158 for (chan
= 0; chan
< inlink
->channels
; chan
++) {
159 double *src
= (double *)frame
->extended_data
[chan
];
160 double *dst
= (double *)out_frame
->extended_data
[chan
];
161 double delayed_0
, delayed_1
;
164 int channel_phase
= chan
* s
->lfo_length
* s
->channel_phase
+ .5;
165 double delay
= s
->lfo
[(s
->lfo_pos
+ channel_phase
) % s
->lfo_length
];
166 int int_delay
= (int)delay
;
167 double frac_delay
= modf(delay
, &delay
);
168 double *delay_buffer
= (double *)s
->delay_buffer
[chan
];
171 delay_buffer
[s
->delay_buf_pos
] = in
+ s
->delay_last
[chan
] *
173 delayed_0
= delay_buffer
[(s
->delay_buf_pos
+ int_delay
++) % s
->max_samples
];
174 delayed_1
= delay_buffer
[(s
->delay_buf_pos
+ int_delay
++) % s
->max_samples
];
176 if (s
->interpolation
== INTERPOLATION_LINEAR
) {
177 delayed
= delayed_0
+ (delayed_1
- delayed_0
) * frac_delay
;
180 double delayed_2
= delay_buffer
[(s
->delay_buf_pos
+ int_delay
++) % s
->max_samples
];
181 delayed_2
-= delayed_0
;
182 delayed_1
-= delayed_0
;
183 a
= delayed_2
* .5 - delayed_1
;
184 b
= delayed_1
* 2 - delayed_2
*.5;
185 delayed
= delayed_0
+ (a
* frac_delay
+ b
) * frac_delay
;
188 s
->delay_last
[chan
] = delayed
;
189 out
= in
* s
->in_gain
+ delayed
* s
->delay_gain
;
192 s
->lfo_pos
= (s
->lfo_pos
+ 1) % s
->lfo_length
;
195 if (frame
!= out_frame
)
196 av_frame_free(&frame
);
198 return ff_filter_frame(ctx
->outputs
[0], out_frame
);
201 static av_cold
void uninit(AVFilterContext
*ctx
)
203 FlangerContext
*s
= ctx
->priv
;
206 av_freep(&s
->delay_last
);
209 av_freep(&s
->delay_buffer
[0]);
210 av_freep(&s
->delay_buffer
);
213 static const AVFilterPad flanger_inputs
[] = {
216 .type
= AVMEDIA_TYPE_AUDIO
,
217 .config_props
= config_input
,
218 .filter_frame
= filter_frame
,
223 static const AVFilterPad flanger_outputs
[] = {
226 .type
= AVMEDIA_TYPE_AUDIO
,
231 AVFilter ff_af_flanger
= {
233 .description
= NULL_IF_CONFIG_SMALL("Apply a flanging effect to the audio."),
234 .query_formats
= query_formats
,
235 .priv_size
= sizeof(FlangerContext
),
236 .priv_class
= &flanger_class
,
239 .inputs
= flanger_inputs
,
240 .outputs
= flanger_outputs
,