summaryrefslogtreecommitdiff
path: root/libavfilter
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2018-12-23 17:56:59 +0100
committerPaul B Mahol <onemda@gmail.com>2018-12-23 18:29:53 +0100
commit4096c670abefdd361fcfd427e163088979871c6c (patch)
treef166670a538437aee3628f3c8d029f72d4ef986e /libavfilter
parentf52dd8a55a98418b6301cce4a56d2b73d08b7eea (diff)
avfilter/af_sofalizer: stop using easy API
Easy API is not flexible enough for our needs.
Diffstat (limited to 'libavfilter')
-rw-r--r--libavfilter/af_sofalizer.c117
1 files changed, 100 insertions, 17 deletions
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 }
};