mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
avfilter/af_sofalizer: make it possible to configure speaker elevation
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
parent
93d336fb07
commit
e6258677ee
@ -55,7 +55,8 @@ typedef struct SOFAlizerContext {
|
|||||||
|
|
||||||
const int8_t *reorder; /* reorder in SOFA channel order */
|
const int8_t *reorder; /* reorder in SOFA channel order */
|
||||||
int sample_rate; /* sample rate from SOFA file */
|
int sample_rate; /* sample rate from SOFA file */
|
||||||
float *speaker_pos; /* positions of the virtual loudspekaers */
|
float *speaker_azim; /* azimuth of the virtual loudspeakers */
|
||||||
|
float *speaker_elev; /* elevation of the virtual loudspeakers */
|
||||||
float gain_lfe; /* gain applied to LFE channel */
|
float gain_lfe; /* gain applied to LFE channel */
|
||||||
|
|
||||||
int n_conv; /* number of channels to convolute */
|
int n_conv; /* number of channels to convolute */
|
||||||
@ -373,11 +374,13 @@ static const int8_t reorder[18][9] = {
|
|||||||
{ 0, 1, 4, 5, 2, 6, 3, -1, -1 },
|
{ 0, 1, 4, 5, 2, 6, 3, -1, -1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int get_speaker_pos(AVFilterContext *ctx, float *speaker_pos)
|
static int get_speaker_pos(AVFilterContext *ctx,
|
||||||
|
float *speaker_azim, float *speaker_elev)
|
||||||
{
|
{
|
||||||
struct SOFAlizerContext *s = ctx->priv;
|
struct SOFAlizerContext *s = ctx->priv;
|
||||||
uint64_t channels_layout = ctx->inputs[0]->channel_layout;
|
uint64_t channels_layout = ctx->inputs[0]->channel_layout;
|
||||||
float pos_temp[9];
|
float azim[9] = { 0 };
|
||||||
|
float elev[9] = { 0 };
|
||||||
int nb_input_channels = ctx->inputs[0]->channels; /* get no. input channels */
|
int nb_input_channels = ctx->inputs[0]->channels; /* get no. input channels */
|
||||||
int n_conv = nb_input_channels;
|
int n_conv = nb_input_channels;
|
||||||
|
|
||||||
@ -389,103 +392,103 @@ static int get_speaker_pos(AVFilterContext *ctx, float *speaker_pos)
|
|||||||
/* set speaker positions according to input channel configuration: */
|
/* set speaker positions according to input channel configuration: */
|
||||||
switch (channels_layout) {
|
switch (channels_layout) {
|
||||||
case AV_CH_LAYOUT_MONO:
|
case AV_CH_LAYOUT_MONO:
|
||||||
pos_temp[0] = 0;
|
azim[0] = 0;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_STEREO:
|
case AV_CH_LAYOUT_STEREO:
|
||||||
case AV_CH_LAYOUT_2POINT1:
|
case AV_CH_LAYOUT_2POINT1:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_SURROUND:
|
case AV_CH_LAYOUT_SURROUND:
|
||||||
case AV_CH_LAYOUT_3POINT1:
|
case AV_CH_LAYOUT_3POINT1:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 0;
|
azim[2] = 0;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_2_1:
|
case AV_CH_LAYOUT_2_1:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 180;
|
azim[2] = 180;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_2_2:
|
case AV_CH_LAYOUT_2_2:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 90;
|
azim[2] = 90;
|
||||||
pos_temp[3] = 270;
|
azim[3] = 270;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_QUAD:
|
case AV_CH_LAYOUT_QUAD:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 120;
|
azim[2] = 120;
|
||||||
pos_temp[3] = 240;
|
azim[3] = 240;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_4POINT0:
|
case AV_CH_LAYOUT_4POINT0:
|
||||||
case AV_CH_LAYOUT_4POINT1:
|
case AV_CH_LAYOUT_4POINT1:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 0;
|
azim[2] = 0;
|
||||||
pos_temp[3] = 180;
|
azim[3] = 180;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_5POINT0:
|
case AV_CH_LAYOUT_5POINT0:
|
||||||
case AV_CH_LAYOUT_5POINT1:
|
case AV_CH_LAYOUT_5POINT1:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 90;
|
azim[2] = 90;
|
||||||
pos_temp[3] = 270;
|
azim[3] = 270;
|
||||||
pos_temp[4] = 0;
|
azim[4] = 0;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_5POINT0_BACK:
|
case AV_CH_LAYOUT_5POINT0_BACK:
|
||||||
case AV_CH_LAYOUT_5POINT1_BACK:
|
case AV_CH_LAYOUT_5POINT1_BACK:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 120;
|
azim[2] = 120;
|
||||||
pos_temp[3] = 240;
|
azim[3] = 240;
|
||||||
pos_temp[4] = 0;
|
azim[4] = 0;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_6POINT0:
|
case AV_CH_LAYOUT_6POINT0:
|
||||||
case AV_CH_LAYOUT_6POINT1:
|
case AV_CH_LAYOUT_6POINT1:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 90;
|
azim[2] = 90;
|
||||||
pos_temp[3] = 270;
|
azim[3] = 270;
|
||||||
pos_temp[4] = 0;
|
azim[4] = 0;
|
||||||
pos_temp[5] = 180;
|
azim[5] = 180;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_6POINT1_BACK:
|
case AV_CH_LAYOUT_6POINT1_BACK:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 120;
|
azim[2] = 120;
|
||||||
pos_temp[3] = 240;
|
azim[3] = 240;
|
||||||
pos_temp[4] = 0;
|
azim[4] = 0;
|
||||||
pos_temp[4] = 180;
|
azim[4] = 180;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_HEXAGONAL:
|
case AV_CH_LAYOUT_HEXAGONAL:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 120;
|
azim[2] = 120;
|
||||||
pos_temp[3] = 240;
|
azim[3] = 240;
|
||||||
pos_temp[4] = 0;
|
azim[4] = 0;
|
||||||
pos_temp[5] = 180;
|
azim[5] = 180;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_7POINT0:
|
case AV_CH_LAYOUT_7POINT0:
|
||||||
case AV_CH_LAYOUT_7POINT1:
|
case AV_CH_LAYOUT_7POINT1:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 90;
|
azim[2] = 90;
|
||||||
pos_temp[3] = 270;
|
azim[3] = 270;
|
||||||
pos_temp[4] = 150;
|
azim[4] = 150;
|
||||||
pos_temp[5] = 210;
|
azim[5] = 210;
|
||||||
pos_temp[6] = 0;
|
azim[6] = 0;
|
||||||
break;
|
break;
|
||||||
case AV_CH_LAYOUT_OCTAGONAL:
|
case AV_CH_LAYOUT_OCTAGONAL:
|
||||||
pos_temp[0] = 30;
|
azim[0] = 30;
|
||||||
pos_temp[1] = 330;
|
azim[1] = 330;
|
||||||
pos_temp[2] = 0;
|
azim[2] = 0;
|
||||||
pos_temp[3] = 150;
|
azim[3] = 150;
|
||||||
pos_temp[4] = 210;
|
azim[4] = 210;
|
||||||
pos_temp[5] = 180;
|
azim[5] = 180;
|
||||||
pos_temp[6] = 90;
|
azim[6] = 90;
|
||||||
pos_temp[7] = 270;
|
azim[7] = 270;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
@ -551,7 +554,8 @@ static int get_speaker_pos(AVFilterContext *ctx, float *speaker_pos)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(speaker_pos, pos_temp, n_conv * sizeof(float));
|
memcpy(speaker_azim, azim, n_conv * sizeof(float));
|
||||||
|
memcpy(speaker_elev, elev, n_conv * sizeof(float));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -818,7 +822,7 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius)
|
|||||||
float *data_ir_r = NULL;
|
float *data_ir_r = NULL;
|
||||||
int offset = 0; /* used for faster pointer arithmetics in for-loop */
|
int offset = 0; /* used for faster pointer arithmetics in for-loop */
|
||||||
int m[s->n_conv]; /* measurement index m of IR closest to required source positions */
|
int m[s->n_conv]; /* measurement index m of IR closest to required source positions */
|
||||||
int i, j, azim_orig = azim;
|
int i, j, azim_orig = azim, elev_orig = elev;
|
||||||
|
|
||||||
if (!s->sofa.ncid) { /* if an invalid SOFA file has been selected */
|
if (!s->sofa.ncid) { /* 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");
|
av_log(ctx, AV_LOG_ERROR, "Selected SOFA file is invalid. Please select valid SOFA file.\n");
|
||||||
@ -836,7 +840,8 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius)
|
|||||||
|
|
||||||
for (i = 0; i < s->n_conv; i++) {
|
for (i = 0; i < s->n_conv; i++) {
|
||||||
/* load and store IRs and corresponding delays */
|
/* load and store IRs and corresponding delays */
|
||||||
azim = (int)(s->speaker_pos[i] + azim_orig) % 360;
|
azim = (int)(s->speaker_azim[i] + azim_orig) % 360;
|
||||||
|
elev = (int)(s->speaker_elev[i] + elev_orig) % 90;
|
||||||
/* get id of IR closest to desired position */
|
/* get id of IR closest to desired position */
|
||||||
m[i] = find_m(s, azim, elev, radius);
|
m[i] = find_m(s, azim, elev, radius);
|
||||||
|
|
||||||
@ -956,18 +961,19 @@ static int config_input(AVFilterLink *inlink)
|
|||||||
s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
|
s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
|
||||||
s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
|
s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
|
||||||
/* length: number of channels to convolute */
|
/* length: number of channels to convolute */
|
||||||
s->speaker_pos = av_malloc_array(s->n_conv, sizeof(*s->speaker_pos));
|
s->speaker_azim = av_calloc(s->n_conv, sizeof(*s->speaker_azim));
|
||||||
|
s->speaker_elev = av_calloc(s->n_conv, sizeof(*s->speaker_elev));
|
||||||
|
|
||||||
/* memory allocation failed: */
|
/* memory allocation failed: */
|
||||||
if (!s->data_ir[0] || !s->data_ir[1] || !s->delay[1] ||
|
if (!s->data_ir[0] || !s->data_ir[1] || !s->delay[1] ||
|
||||||
!s->delay[0] || !s->ringbuffer[0] || !s->ringbuffer[1] ||
|
!s->delay[0] || !s->ringbuffer[0] || !s->ringbuffer[1] ||
|
||||||
!s->speaker_pos)
|
!s->speaker_azim || !s->speaker_elev)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
compensate_volume(ctx);
|
compensate_volume(ctx);
|
||||||
|
|
||||||
/* get speaker positions */
|
/* get speaker positions */
|
||||||
if ((ret = get_speaker_pos(ctx, s->speaker_pos)) < 0) {
|
if ((ret = get_speaker_pos(ctx, s->speaker_azim, s->speaker_elev)) < 0) {
|
||||||
av_log(ctx, AV_LOG_ERROR, "Couldn't get speaker positions. Input channel configuration not supported.\n");
|
av_log(ctx, AV_LOG_ERROR, "Couldn't get speaker positions. Input channel configuration not supported.\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -999,7 +1005,8 @@ static av_cold void uninit(AVFilterContext *ctx)
|
|||||||
av_freep(&s->data_ir[1]);
|
av_freep(&s->data_ir[1]);
|
||||||
av_freep(&s->ringbuffer[0]);
|
av_freep(&s->ringbuffer[0]);
|
||||||
av_freep(&s->ringbuffer[1]);
|
av_freep(&s->ringbuffer[1]);
|
||||||
av_freep(&s->speaker_pos);
|
av_freep(&s->speaker_azim);
|
||||||
|
av_freep(&s->speaker_elev);
|
||||||
av_freep(&s->temp_src[0]);
|
av_freep(&s->temp_src[0]);
|
||||||
av_freep(&s->temp_src[1]);
|
av_freep(&s->temp_src[1]);
|
||||||
av_freep(&s->fdsp);
|
av_freep(&s->fdsp);
|
||||||
|
Loading…
Reference in New Issue
Block a user