You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-10 06:10:52 +02:00
avfilter/af_sofalizer: stop using easy API
Easy API is not flexible enough for our needs.
This commit is contained in:
@@ -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 }
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user