Commit 4096c670 authored by Paul B Mahol's avatar Paul B Mahol

avfilter/af_sofalizer: stop using easy API

Easy API is not flexible enough for our needs.
parent f52dd8a5
......@@ -4511,6 +4511,23 @@ Set custom gain for LFE channels. Value is in dB. Default is 0.
Set custom frame size in number of samples. Default is 1024.
Allowed range is from 1024 to 96000. Only used if option @samp{type}
is set to @var{freq}.
@item normalize
Should all IRs be normalized upon importing SOFA file.
By default is enabled.
@item interpolate
Should nearest IRs be interpolated with neighbor IRs if exact position
does not match. By default is disabled.
@item minphase
Minphase all IRs upon loading of SOFA file. By default is disabled.
@item anglestep
Set neighbor search angle step. Only used if option @var{interpolate} is enabled.
@item radstep
Set neighbor search radius step. Only used if option @var{interpolate} is enabled.
@end table
@subsection Examples
......
......@@ -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 }
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment