40#define MAX_BANDS MAX_SPLITS + 1
84#define OFFSET(x) offsetof(AudioCrossoverContext, x)
85#define AF AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
98 {
"18th",
"18th order (108 dB/8ve)",0,
AV_OPT_TYPE_CONST, {.i64=8}, 0, 0,
AF, .unit =
"m" },
99 {
"20th",
"20th order (120 dB/8ve)",0,
AV_OPT_TYPE_CONST, {.i64=9}, 0, 0,
AF, .unit =
"m" },
102 {
"precision",
"set processing precision",
OFFSET(precision),
AV_OPT_TYPE_INT, {.i64=0}, 0, 2,
AF, .unit =
"precision" },
103 {
"auto",
"set auto processing precision", 0,
AV_OPT_TYPE_CONST, {.i64=0}, 0, 0,
AF, .unit =
"precision" },
104 {
"float",
"set single-floating point processing precision", 0,
AV_OPT_TYPE_CONST, {.i64=1}, 0, 0,
AF, .unit =
"precision" },
105 {
"double",
"set double-floating point processing precision", 0,
AV_OPT_TYPE_CONST, {.i64=2}, 0, 0,
AF, .unit =
"precision" },
128 switch (
s->precision) {
130 sample_fmts_list = auto_sample_fmts;
151 char *p, *
arg, *saveptr =
NULL;
171 if (
c[0] ==
'd' &&
c[1] ==
'B')
186 char *p, *
arg, *saveptr =
NULL;
211 if (
i > 0 && freq <= s->splits[
i-1]) {
225 for (
i = 0;
i <=
s->nb_splits;
i++) {
244 double omega = 2. *
M_PI *
fc / sr;
245 double cosine = cos(omega);
246 double alpha = sin(omega) / (2. * q);
270 double omega = 2. *
M_PI *
fc / sr;
271 double cosine = cos(omega);
272 double alpha = sin(omega) / (2. * q);
296 double omega = 2. *
M_PI *
fc / sr;
297 double cosine = cos(omega);
298 double alpha = sin(omega) / (2. * q);
322 double omega = 2. *
M_PI *
fc / sr;
339 double n = order / 2.;
341 for (
int i = 0;
i < n / 2;
i++)
342 q[
i] = 1. / (-2. * cos(
M_PI * (2. * (
i + 1) + n - 1.) / (2. * n)));
345#define BIQUAD_PROCESS(name, type) \
346static void biquad_process_## name(const type *const c, \
348 type *dst, const type *src, \
351 const type b0 = c[B0]; \
352 const type b1 = c[B1]; \
353 const type b2 = c[B2]; \
354 const type a1 = c[A1]; \
355 const type a2 = c[A2]; \
359 for (int n = 0; n + 1 < nb_samples; n++) { \
363 out = in * b0 + z1; \
364 z1 = b1 * in + z2 + a1 * out; \
365 z2 = b2 * in + a2 * out; \
370 out = in * b0 + z1; \
371 z1 = b1 * in + z2 + a1 * out; \
372 z2 = b2 * in + a2 * out; \
376 if (nb_samples & 1) { \
377 const int n = nb_samples - 1; \
378 const type in = src[n]; \
381 out = in * b0 + z1; \
382 z1 = b1 * in + z2 + a1 * out; \
383 z2 = b2 * in + a2 * out; \
394#define XOVER_PROCESS(name, type, one, ff) \
395static int filter_channels_## name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
397 AudioCrossoverContext *s = ctx->priv; \
399 AVFrame **frames = s->frames; \
400 const int start = ff_slice_pos(in->ch_layout.nb_channels, jobnr, nb_jobs); \
401 const int end = ff_slice_pos(in->ch_layout.nb_channels, jobnr + 1, nb_jobs); \
402 const int nb_samples = in->nb_samples; \
403 const int nb_outs = ctx->nb_outputs; \
404 const int first_order = s->first_order; \
406 for (int ch = start; ch < end; ch++) { \
407 const type *src = (const type *)in->extended_data[ch]; \
408 type *xover = (type *)s->xover->extended_data[ch]; \
410 s->fdsp->vector_## ff ##mul_scalar((type *)frames[0]->extended_data[ch], src, \
411 s->level_in, FFALIGN(nb_samples, sizeof(type))); \
413 for (int band = 0; band < nb_outs; band++) { \
414 for (int f = 0; band + 1 < nb_outs && f < s->filter_count; f++) { \
415 const type *prv = (const type *)frames[band]->extended_data[ch]; \
416 type *dst = (type *)frames[band + 1]->extended_data[ch]; \
417 const type *hsrc = f == 0 ? prv : dst; \
418 type *hp = xover + nb_outs * 20 + band * 20 + f * 2; \
419 const type *const hpc = (type *)&s->hp[band][f].c ## ff; \
421 biquad_process_## name(hpc, hp, dst, hsrc, nb_samples); \
424 for (int f = 0; band + 1 < nb_outs && f < s->filter_count; f++) { \
425 type *dst = (type *)frames[band]->extended_data[ch]; \
426 const type *lsrc = dst; \
427 type *lp = xover + band * 20 + f * 2; \
428 const type *const lpc = (type *)&s->lp[band][f].c ## ff; \
430 biquad_process_## name(lpc, lp, dst, lsrc, nb_samples); \
433 for (int aband = band + 1; aband + 1 < nb_outs; aband++) { \
435 const type *asrc = (const type *)frames[band]->extended_data[ch]; \
436 type *dst = (type *)frames[band]->extended_data[ch]; \
437 type *ap = xover + nb_outs * 40 + (aband * nb_outs + band) * 20; \
438 const type *const apc = (type *)&s->ap[aband][0].c ## ff; \
440 biquad_process_## name(apc, ap, dst, asrc, nb_samples); \
443 for (int f = first_order; f < s->ap_filter_count; f++) { \
444 const type *asrc = (const type *)frames[band]->extended_data[ch]; \
445 type *dst = (type *)frames[band]->extended_data[ch]; \
446 type *ap = xover + nb_outs * 40 + (aband * nb_outs + band) * 20 + f * 2;\
447 const type *const apc = (type *)&s->ap[aband][f].c ## ff; \
449 biquad_process_## name(apc, ap, dst, asrc, nb_samples); \
454 for (int band = 0; band < nb_outs; band++) { \
455 const type gain = s->gains[band] * ((band & 1 && first_order) ? -one : one); \
456 type *dst = (type *)frames[band]->extended_data[ch]; \
458 s->fdsp->vector_## ff ##mul_scalar(dst, dst, gain, \
459 FFALIGN(nb_samples, sizeof(type))); \
473 int sample_rate = inlink->sample_rate;
476 s->order = (
s->order_opt + 1) * 2;
477 s->filter_count =
s->order / 2;
478 s->first_order =
s->filter_count & 1;
479 s->ap_filter_count =
s->filter_count / 2 +
s->first_order;
482 for (
int band = 0; band <=
s->nb_splits; band++) {
483 if (
s->first_order) {
484 set_lp(&
s->lp[band][0],
s->splits[band], 0.5, sample_rate);
485 set_hp(&
s->hp[band][0],
s->splits[band], 0.5, sample_rate);
488 for (
int n =
s->first_order; n < s->filter_count; n++) {
489 const int idx =
s->filter_count / 2 - ((n +
s->first_order) / 2 -
s->first_order) - 1;
491 set_lp(&
s->lp[band][n],
s->splits[band], q[idx], sample_rate);
492 set_hp(&
s->hp[band][n],
s->splits[band], q[idx], sample_rate);
496 set_ap1(&
s->ap[band][0],
s->splits[band], sample_rate);
498 for (
int n =
s->first_order; n < s->ap_filter_count; n++) {
499 const int idx = (
s->filter_count / 2 - ((n * 2 +
s->first_order) / 2 -
s->first_order) - 1);
501 set_ap(&
s->ap[band][n],
s->splits[band], q[idx], sample_rate);
505 switch (inlink->format) {
512 ctx->nb_outputs *
ctx->nb_outputs * 10));
526 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
542 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
555 for (
int i = 0;
i <
ctx->nb_outputs;
i++)
568 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
583 for (
int i = 0;
i <
ctx->nb_outputs;
i++) {
613 .p.name =
"acrossover",
615 .p.priv_class = &acrossover_class,
static enum AVSampleFormat sample_fmts[]
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static const AVFilterPad inputs[]
static int config_input(AVFilterLink *inlink)
static void set_hp(BiquadCoeffs *b, double fc, double q, double sr)
static void set_lp(BiquadCoeffs *b, double fc, double q, double sr)
static void set_ap(BiquadCoeffs *b, double fc, double q, double sr)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static const AVOption acrossover_options[]
static void set_ap1(BiquadCoeffs *b, double fc, double sr)
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static int activate(AVFilterContext *ctx)
static av_cold void uninit(AVFilterContext *ctx)
const FFFilter ff_af_acrossover
#define XOVER_PROCESS(name, type, one, ff)
#define BIQUAD_PROCESS(name, type)
static void calc_q_factors(int order, double *q)
static int parse_gains(AVFilterContext *ctx)
static AVFormatContext * ctx
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
int ff_outlink_get_status(AVFilterLink *link)
Get the status on an output link.
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
int ff_append_outpad_free_name(AVFilterContext *f, AVFilterPad *p)
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
Main libavfilter public API header.
int av_sscanf(const char *string, const char *format,...)
char * av_asprintf(const char *fmt,...)
#define i(width, name, range_min, range_max)
Public libavutil channel layout APIs header.
static const uint16_t fc[]
int(* init)(AVBSFContext *ctx)
static av_unused double cosine(double x, const double *params)
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
#define AVFILTER_FLAG_DYNAMIC_OUTPUTS
The number of the filter outputs is not determined just by AVFilter.outputs.
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
AVSampleFormat
Audio sample formats.
@ AV_SAMPLE_FMT_FLTP
float, planar
@ AV_SAMPLE_FMT_DBLP
double, planar
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
static const int16_t alpha[]
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
#define FF_FILTER_FORWARD_WANTED_ANY(filter, inlink)
Forward the frame_wanted_out flag from any of the output links to an input link.
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
#define FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, filter)
Forward the status on an output link to all input links.
#define AVFILTER_DEFINE_CLASS(fname)
#define FILTER_QUERY_FUNC2(func)
Macro definitions for various function/variable attributes.
av_cold AVFloatDSPContext * avpriv_float_dsp_alloc(int bit_exact)
Allocate a float DSP context.
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Memory handling functions.
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
A link between two filters.
AVChannelLayout ch_layout
channel layout of current buffer (see libavutil/channel_layout.h)
AVFilterContext * dst
dest filter
A filter pad used for either input or output.
enum AVMediaType type
AVFilterPad type.
const char * name
Pad name.
This structure describes decoded (raw) audio or video data.
int nb_samples
number of audio samples (per channel) described by this frame
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
BiquadCoeffs lp[MAX_BANDS][20]
BiquadCoeffs hp[MAX_BANDS][20]
int(* filter_channels)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
BiquadCoeffs ap[MAX_BANDS][20]
AVFrame * frames[MAX_BANDS]
static double b1(void *priv, double x, double y)
static double a0(void *priv, double x, double y)
static double b2(void *priv, double x, double y)
static double b0(void *priv, double x, double y)
static double a2(void *priv, double x, double y)
static double a1(void *priv, double x, double y)
#define MAX_BANDS
max number of scale factor bands