From 4096c670abefdd361fcfd427e163088979871c6c Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sun, 23 Dec 2018 17:56:59 +0100 Subject: avfilter/af_sofalizer: stop using easy API Easy API is not flexible enough for our needs. --- libavfilter/af_sofalizer.c | 117 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 17 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c index 94e5b73131..7812e25557 100644 --- a/libavfilter/af_sofalizer.c +++ b/libavfilter/af_sofalizer.c @@ -42,10 +42,13 @@ #define FREQUENCY_DOMAIN 1 typedef struct MySofa { /* contains data of one SOFA file */ - struct MYSOFA_EASY *easy; + struct MYSOFA_HRTF *hrtf; + struct MYSOFA_LOOKUP *lookup; + struct MYSOFA_NEIGHBORHOOD *neighborhood; int ir_samples; /* length of one impulse response (IR) */ int n_samples; /* ir_samples to next power of 2 */ float *lir, *rir; /* IRs (time-domain) */ + float *fir; int max_delay; } MySofa; @@ -94,6 +97,11 @@ typedef struct SOFAlizerContext { float radius; /* distance virtual loudspeakers to listener (in metres) */ int type; /* processing type */ int framesize; /* size of buffer */ + int normalize; /* should all IRs be normalized upon import ? */ + int interpolate; /* should wanted IRs be interpolated from neighbors ? */ + int minphase; /* should all IRs be minphased upon import ? */ + float anglestep; /* neighbor search angle step, in agles */ + float radstep; /* neighbor search radius step, in meters */ VirtualSpeaker vspkrpos[64]; @@ -105,24 +113,62 @@ typedef struct SOFAlizerContext { static int close_sofa(struct MySofa *sofa) { - mysofa_close(sofa->easy); - sofa->easy = NULL; + if (sofa->neighborhood) + mysofa_neighborhood_free(sofa->neighborhood); + sofa->neighborhood = NULL; + if (sofa->lookup) + mysofa_lookup_free(sofa->lookup); + sofa->lookup = NULL; + if (sofa->hrtf) + mysofa_free(sofa->hrtf); + sofa->hrtf = NULL; + av_freep(&sofa->fir); return 0; } static int preload_sofa(AVFilterContext *ctx, char *filename, int *samplingrate) { + struct SOFAlizerContext *s = ctx->priv; struct MYSOFA_HRTF *mysofa; char *license; int ret; mysofa = mysofa_load(filename, &ret); + s->sofa.hrtf = mysofa; if (ret || !mysofa) { av_log(ctx, AV_LOG_ERROR, "Can't find SOFA-file '%s'\n", filename); return AVERROR(EINVAL); } + ret = mysofa_check(mysofa); + if (ret != MYSOFA_OK) { + av_log(ctx, AV_LOG_ERROR, "Selected SOFA file is invalid. Please select valid SOFA file.\n"); + return ret; + } + + if (s->normalize) + mysofa_loudness(s->sofa.hrtf); + + if (s->minphase) + mysofa_minphase(s->sofa.hrtf, 0.01); + + mysofa_tocartesian(s->sofa.hrtf); + + s->sofa.lookup = mysofa_lookup_init(s->sofa.hrtf); + if (s->sofa.lookup == NULL) + return AVERROR(EINVAL); + + if (s->interpolate) + s->sofa.neighborhood = mysofa_neighborhood_init_withstepdefine(s->sofa.hrtf, + s->sofa.lookup, + s->anglestep, + s->radstep); + + s->sofa.fir = av_calloc(s->sofa.hrtf->N * s->sofa.hrtf->R, sizeof(*s->sofa.fir)); + if (!s->sofa.fir) + return AVERROR(ENOMEM); + if (mysofa->DataSamplingRate.elements != 1) return AVERROR(EINVAL); av_log(ctx, AV_LOG_DEBUG, "Original IR length: %d.\n", mysofa->N); @@ -130,7 +176,6 @@ static int preload_sofa(AVFilterContext *ctx, char *filename, int *samplingrate) license = mysofa_getAttribute(mysofa->attributes, (char *)"License"); if (license) av_log(ctx, AV_LOG_INFO, "SOFA license: %s\n", license); - mysofa_free(mysofa); return 0; } @@ -560,6 +605,43 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_samplerates(ctx, formats); } +static int getfilter_float(AVFilterContext *ctx, float x, float y, float z, + float *left, float *right, + float *delay_left, float *delay_right) +{ + struct SOFAlizerContext *s = ctx->priv; + float c[3], delays[2]; + float *fl, *fr; + int nearest; + int *neighbors; + float *res; + + c[0] = x, c[1] = y, c[2] = z; + nearest = mysofa_lookup(s->sofa.lookup, c); + if (nearest < 0) + return AVERROR(EINVAL); + + if (s->interpolate) { + neighbors = mysofa_neighborhood(s->sofa.neighborhood, nearest); + res = mysofa_interpolate(s->sofa.hrtf, c, + nearest, neighbors, + s->sofa.fir, delays); + } else { + res = s->sofa.hrtf->DataIR.values + nearest * s->sofa.hrtf->N * s->sofa.hrtf->R; + } + + *delay_left = delays[0]; + *delay_right = delays[1]; + + fl = res; + fr = res + s->sofa.hrtf->N; + + memcpy(left, fl, sizeof(float) * s->sofa.hrtf->N); + memcpy(right, fr, sizeof(float) * s->sofa.hrtf->N); + + return 0; +} + static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int sample_rate) { struct SOFAlizerContext *s = ctx->priv; @@ -579,18 +661,12 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int float *data_ir_r = NULL; int offset = 0; /* used for faster pointer arithmetics in for-loop */ int i, j, azim_orig = azim, elev_orig = elev; - int filter_length, ret = 0; + int ret = 0; int n_current; int n_max = 0; - s->sofa.easy = mysofa_open(s->filename, sample_rate, &filter_length, &ret); - if (!s->sofa.easy || ret) { /* if an invalid SOFA file has been selected */ - av_log(ctx, AV_LOG_ERROR, "Selected SOFA file is invalid. Please select valid SOFA file.\n"); - return AVERROR_INVALIDDATA; - } - - av_log(ctx, AV_LOG_DEBUG, "IR length: %d.\n", s->sofa.easy->hrtf->N); - s->sofa.ir_samples = s->sofa.easy->hrtf->N; + av_log(ctx, AV_LOG_DEBUG, "IR length: %d.\n", s->sofa.hrtf->N); + s->sofa.ir_samples = s->sofa.hrtf->N; s->sofa.n_samples = 1 << (32 - ff_clz(s->sofa.ir_samples)); n_samples = s->sofa.n_samples; @@ -650,10 +726,12 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int mysofa_s2c(coordinates); /* get id of IR closest to desired position */ - mysofa_getfilter_float(s->sofa.easy, coordinates[0], coordinates[1], coordinates[2], - data_ir_l + n_samples * i, - data_ir_r + n_samples * i, - &delay_l, &delay_r); + ret = getfilter_float(ctx, coordinates[0], coordinates[1], coordinates[2], + data_ir_l + n_samples * i, + data_ir_r + n_samples * i, + &delay_l, &delay_r); + if (ret < 0) + return ret; s->delay[0][i] = delay_l * sample_rate; s->delay[1][i] = delay_r * sample_rate; @@ -894,6 +972,11 @@ static const AVOption sofalizer_options[] = { { "speakers", "set speaker custom positions", OFFSET(speakers_pos), AV_OPT_TYPE_STRING, {.str=0}, 0, 0, .flags = FLAGS }, { "lfegain", "set lfe gain", OFFSET(lfe_gain), AV_OPT_TYPE_FLOAT, {.dbl=0}, -20,40, .flags = FLAGS }, { "framesize", "set frame size", OFFSET(framesize), AV_OPT_TYPE_INT, {.i64=1024},1024,96000, .flags = FLAGS }, + { "normalize", "normalize IRs", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, .flags = FLAGS }, + { "interpolate","interpolate IRs from neighbors", OFFSET(interpolate),AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, + { "minphase", "minphase IRs", OFFSET(minphase), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, + { "anglestep", "set neighbor search angle step", OFFSET(anglestep), AV_OPT_TYPE_FLOAT, {.dbl=.5}, 0.01, 10, .flags = FLAGS }, + { "radstep", "set neighbor search radius step", OFFSET(radstep), AV_OPT_TYPE_FLOAT, {.dbl=.01}, 0.01, 1, .flags = FLAGS }, { NULL } }; -- cgit v1.2.3