67#define OFFSET(x) offsetof(AudioPsyClipContext, x)
68#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM
85 for (
int i = 0;
i <
size;
i++) {
95 const int (*points)[2],
int num_points,
int sample_rate)
99 s->margin_curve[0] = points[0][1];
101 for (
int i = 0;
i < num_points - 1;
i++) {
102 while (j < s->fft_size / 2 + 1 && j * sample_rate /
s->fft_size < points[
i + 1][0]) {
104 int binHz = j * sample_rate /
s->fft_size;
105 s->margin_curve[j] = points[
i][1] + (binHz - points[
i][0]) * (points[
i + 1][1] - points[
i][1]) / (points[
i + 1][0] - points[
i][0]);
110 while (j < s->fft_size / 2 + 1) {
111 s->margin_curve[j] = points[num_points - 1][1];
116 for (j = 0; j <
s->fft_size / 2 + 1; j++)
117 s->margin_curve[j] =
powf(10.f,
s->margin_curve[j] / 20.f);
135 while (bin < s->num_psy_bins) {
137 int base_idx = table_index *
s->num_psy_bins;
138 int start_bin = bin * 3 / 4;
139 int end_bin =
FFMIN(
s->num_psy_bins, ((bin + 1) * 4 + 2) / 3);
142 for (
int j = start_bin; j < end_bin; j++) {
144 float rel_idx_log =
FFABS(logf((j + 0.5f) / (bin + 0.5f)));
155 s->spread_table[base_idx +
s->num_psy_bins / 2 + j - bin] =
value;
158 for (
int j = start_bin; j < end_bin; j++) {
159 s->spread_table[base_idx +
s->num_psy_bins / 2 + j - bin] /= sum;
162 s->spread_table_range[table_index][0] = start_bin - bin;
163 s->spread_table_range[table_index][1] = end_bin - bin;
168 if ((bin & (bin - 1)) == 0) {
177 for (
int i = bin;
i < next_bin;
i++)
178 s->spread_table_index[
i] = table_index;
189 static const int points[][2] = { {0,14}, {125,14}, {250,16}, {500,18}, {1000,20}, {2000,20}, {4000,20}, {8000,17}, {16000,14}, {20000,-10} };
190 static const int num_points = 10;
195 s->overlap =
s->fft_size / 4;
200 s->num_psy_bins =
s->fft_size / 2;
202 s->num_psy_bins =
s->fft_size / 4;
204 s->num_psy_bins =
s->fft_size / 8;
208 s->inv_window =
av_calloc(
s->fft_size,
sizeof(*
s->inv_window));
209 if (!
s->window || !
s->inv_window)
219 if (!
s->in_buffer || !
s->in_frame ||
220 !
s->out_dist_frame || !
s->windowed_frame ||
221 !
s->clipping_delta || !
s->spectrum_buf || !
s->mask_curve)
226 s->margin_curve =
av_calloc(
s->fft_size / 2 + 1,
sizeof(*
s->margin_curve));
227 if (!
s->margin_curve)
230 s->spread_table_rows =
av_log2(
s->num_psy_bins) * 2;
231 s->spread_table =
av_calloc(
s->spread_table_rows *
s->num_psy_bins,
sizeof(*
s->spread_table));
232 if (!
s->spread_table)
235 s->spread_table_range =
av_calloc(
s->spread_table_rows * 2,
sizeof(*
s->spread_table_range));
236 if (!
s->spread_table_range)
239 s->spread_table_index =
av_calloc(
s->num_psy_bins,
sizeof(*
s->spread_table_index));
240 if (!
s->spread_table_index)
250 s->itx_ctx =
av_calloc(
s->channels,
sizeof(*
s->itx_ctx));
251 if (!
s->tx_ctx || !
s->itx_ctx)
254 for (
int ch = 0; ch <
s->channels; ch++) {
268 const float *in_frame,
float *out_frame,
const int add_to_out_frame)
270 const float *
window =
s->window;
272 for (
int i = 0;
i <
s->fft_size;
i++) {
273 if (add_to_out_frame) {
282 const float *spectrum,
float *mask_curve)
284 for (
int i = 0;
i <
s->fft_size / 2 + 1;
i++)
287 for (
int i = 0;
i <
s->num_psy_bins;
i++) {
288 int base_idx, start_bin, end_bin, table_idx;
293 magnitude =
FFABS(spectrum[0]);
294 }
else if (
i ==
s->fft_size / 2) {
295 magnitude =
FFABS(spectrum[
s->fft_size]);
299 magnitude = hypotf(spectrum[2 *
i], spectrum[2 *
i + 1]) * 2;
302 table_idx =
s->spread_table_index[
i];
303 range[0] =
s->spread_table_range[table_idx][0];
304 range[1] =
s->spread_table_range[table_idx][1];
305 base_idx = table_idx *
s->num_psy_bins;
309 for (
int j = start_bin; j < end_bin; j++)
310 mask_curve[j] +=
s->spread_table[base_idx +
s->num_psy_bins / 2 + j -
i] * magnitude;
314 for (
int i =
s->num_psy_bins;
i < s->fft_size / 2 + 1;
i++) {
316 if (
i ==
s->fft_size / 2) {
317 magnitude =
FFABS(spectrum[
s->fft_size]);
321 magnitude = hypotf(spectrum[2 *
i], spectrum[2 *
i + 1]) * 2;
324 mask_curve[
i] = magnitude;
327 for (
int i = 0;
i <
s->fft_size / 2 + 1;
i++)
328 mask_curve[
i] = mask_curve[
i] /
s->margin_curve[
i];
332 const float *windowed_frame,
float *clipping_delta,
float delta_boost)
334 const float *
window =
s->window;
336 for (
int i = 0;
i <
s->fft_size;
i++) {
338 const float effective_value = windowed_frame[
i] + clipping_delta[
i];
340 if (effective_value >
limit) {
341 clipping_delta[
i] += (
limit - effective_value) * delta_boost;
342 }
else if (effective_value < -
limit) {
343 clipping_delta[
i] += (-
limit - effective_value) * delta_boost;
349 float *clip_spectrum,
const float *mask_curve)
352 float relative_distortion_level =
FFABS(clip_spectrum[0]) / mask_curve[0];
354 if (relative_distortion_level > 1.f)
355 clip_spectrum[0] /= relative_distortion_level;
358 for (
int i = 1;
i <
s->fft_size / 2;
i++) {
359 float real = clip_spectrum[
i * 2];
360 float imag = clip_spectrum[
i * 2 + 1];
363 relative_distortion_level = hypotf(real, imag) * 2 / mask_curve[
i];
364 if (relative_distortion_level > 1.0) {
365 clip_spectrum[
i * 2] /= relative_distortion_level;
366 clip_spectrum[
i * 2 + 1] /= relative_distortion_level;
367 clip_spectrum[
s->fft_size * 2 -
i * 2] /= relative_distortion_level;
368 clip_spectrum[
s->fft_size * 2 -
i * 2 + 1] /= relative_distortion_level;
372 relative_distortion_level =
FFABS(clip_spectrum[
s->fft_size]) / mask_curve[
s->fft_size / 2];
373 if (relative_distortion_level > 1.f)
374 clip_spectrum[
s->fft_size] /= relative_distortion_level;
379 for (
int i =
size - 1;
i >= 0;
i--)
382 for (
int i =
size - 1;
i >= 0;
i--)
396 const float *in_samples,
float *out_samples,
int diff_only,
397 float *in_frame,
float *out_dist_frame,
398 float *windowed_frame,
float *clipping_delta,
399 float *spectrum_buf,
float *mask_curve)
402 const float clip_level_inv = 1.f /
s->clip_level;
403 const float level_out =
s->level_out;
408 for (
int i = 0;
i <
s->fft_size -
s->overlap;
i++) {
409 in_frame[
i] = in_frame[
i +
s->overlap];
410 out_dist_frame[
i] = out_dist_frame[
i +
s->overlap];
413 for (
int i = 0;
i <
s->overlap;
i++) {
414 in_frame[
i +
s->fft_size -
s->overlap] = in_samples[
i];
415 out_dist_frame[
i +
s->fft_size -
s->overlap] = 0.f;
419 r2c(windowed_frame,
s->fft_size);
420 s->tx_fn(
s->tx_ctx[ch], spectrum_buf, windowed_frame,
sizeof(
AVComplexFloat));
421 c2r(windowed_frame,
s->fft_size);
427 for (
int i = 0;
i <
s->fft_size;
i++)
428 orig_peak =
FFMAX(orig_peak,
FFABS(windowed_frame[
i] *
s->inv_window[
i]));
429 orig_peak *= clip_level_inv;
433 for (
int i = 0;
i <
s->fft_size * 2;
i++)
434 clipping_delta[
i] = 0.f;
437 for (
int i = 0;
i <
s->iterations;
i++) {
438 float mask_curve_shift = 1.122f;
440 float delta_boost = 1.f;
441 if (
i >=
s->iterations -
s->iterations / 3) {
449 r2c(clipping_delta,
s->fft_size);
450 s->tx_fn(
s->tx_ctx[ch], spectrum_buf, clipping_delta,
sizeof(
AVComplexFloat));
454 s->itx_fn(
s->itx_ctx[ch], clipping_delta, spectrum_buf,
sizeof(
AVComplexFloat));
455 c2r(clipping_delta,
s->fft_size);
457 for (
int j = 0; j <
s->fft_size; j++)
458 clipping_delta[j] /=
s->fft_size;
461 for (
int j = 0; j <
s->fft_size; j++)
462 peak =
FFMAX(peak,
FFABS((windowed_frame[j] + clipping_delta[j]) *
s->inv_window[j]));
463 peak *= clip_level_inv;
466 if (orig_peak > 1.f && peak > 1.f) {
467 float diff_achieved = orig_peak - peak;
468 if (
i + 1 <
s->iterations -
s->iterations / 3 && diff_achieved > 0) {
469 float diff_needed = orig_peak - 1.f;
470 float diff_ratio = diff_needed / diff_achieved;
475 diff_ratio =
FFMIN(diff_ratio, peak);
476 mask_curve_shift =
FFMAX(mask_curve_shift, diff_ratio);
480 mask_curve_shift =
FFMAX(mask_curve_shift, peak);
484 mask_curve_shift = 1.f + (mask_curve_shift - 1.f) *
s->adaptive;
488 for (
int j = 0; j <
s->fft_size / 2 + 1; j++)
489 mask_curve[j] *= mask_curve_shift;
495 for (
int i = 0;
i <
s->overlap;
i++) {
497 if (!
ctx->is_disabled) {
498 out_samples[
i] = out_dist_frame[
i] / 1.5f;
500 out_samples[
i] += in_frame[
i];
502 out_samples[
i] *= clip_level_inv;
503 out_samples[
i] *= level_out;
505 out_samples[
i] = in_frame[
i];
514 float *in_buffer = (
float *)
s->in_buffer->extended_data[ch];
515 float *
dst = (
float *)
out->extended_data[ch];
517 for (
int n = 0; n <
s->overlap; n++)
518 in_buffer[n] =
src[n] *
s->level_in;
521 (
float *)(
s->in_frame->extended_data[ch]),
522 (
float *)(
s->out_dist_frame->extended_data[ch]),
523 (
float *)(
s->windowed_frame->extended_data[ch]),
524 (
float *)(
s->clipping_delta->extended_data[ch]),
525 (
float *)(
s->spectrum_buf->extended_data[ch]),
526 (
float *)(
s->mask_curve->extended_data[ch]));
535 const int start =
ff_slice_pos(
out->ch_layout.nb_channels, jobnr, nb_jobs);
536 const int end =
ff_slice_pos(
out->ch_layout.nb_channels, jobnr + 1, nb_jobs);
538 for (
int ch = start; ch < end; ch++)
569 return ret < 0 ? ret : 0;
621 for (
int ch = 0; ch <
s->channels; ch++) {
641 .p.name =
"apsyclip",
643 .p.priv_class = &apsyclip_class,
static void(*const apply_window[4])(AVFloatDSPContext *fdsp, SingleChannelElement *sce, const float *audio)
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
static const AVFilterPad inputs[]
static int config_input(AVFilterLink *inlink)
static int psy_channel(AVFilterContext *ctx, AVFrame *in, AVFrame *out, int ch)
static const AVOption apsyclip_options[]
static void generate_hann_window(float *window, float *inv_window, int size)
static void set_margin_curve(AudioPsyClipContext *s, const int(*points)[2], int num_points, int sample_rate)
static void feed(AVFilterContext *ctx, int ch, const float *in_samples, float *out_samples, int diff_only, float *in_frame, float *out_dist_frame, float *windowed_frame, float *clipping_delta, float *spectrum_buf, float *mask_curve)
static int config_input(AVFilterLink *inlink)
static void generate_spread_table(AudioPsyClipContext *s)
static int psy_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
const FFFilter ff_af_apsyclip
static void c2r(float *buffer, int size)
static void limit_clip_spectrum(AudioPsyClipContext *s, float *clip_spectrum, const float *mask_curve)
static void clip_to_window(AudioPsyClipContext *s, const float *windowed_frame, float *clipping_delta, float delta_boost)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static void calculate_mask_curve(AudioPsyClipContext *s, const float *spectrum, float *mask_curve)
static int activate(AVFilterContext *ctx)
static av_cold void uninit(AVFilterContext *ctx)
static void r2c(float *buffer, int size)
static AVFormatContext * ctx
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
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_outlink_frame_wanted(AVFilterLink *link)
Test if a frame is wanted on an output link.
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.
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, AVFrame **rframe)
Take samples from the link's FIFO and update the link's stats.
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
int ff_inlink_queued_samples(AVFilterLink *link)
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
#define increment(name, min, max)
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
static SDL_Window * window
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_DOUBLE
Underlying C type is double.
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
@ AV_SAMPLE_FMT_FLTP
float, planar
static void scale(int *out, const int *in, const int w, const int h, const int shift)
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
static int ff_slice_pos(int total, int jobnr, int nb_jobs)
Compute the boundary index for a slice when work of size total is split into nb_jobs slices.
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 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_)
#define AVFILTER_DEFINE_CLASS(fname)
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
void * av_calloc(size_t nmemb, size_t size)
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.
int sample_rate
samples per second
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.
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).
uint8_t ** extended_data
pointers to the data planes/channels.
int(* spread_table_range)[2]
av_cold void av_tx_uninit(AVTXContext **ctx)
Frees a context and sets *ctx to NULL, does nothing when *ctx == NULL.
av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, int inv, int len, const void *scale, uint64_t flags)
Initialize a transform context with the given configuration (i)MDCTs with an odd length are currently...
@ AV_TX_FLOAT_FFT
Standard complex to complex FFT with sample data type of AVComplexFloat, AVComplexDouble or AVComplex...
void(* av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride)
Function pointer to a function to perform the transform.
static double limit(double x)