summaryrefslogtreecommitdiff
path: root/libavfilter/af_sofalizer.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2016-03-28 18:07:45 +0200
committerPaul B Mahol <onemda@gmail.com>2016-03-28 21:27:59 +0200
commita55c953ef00cb89dabb49af6b3296d60da764c85 (patch)
tree206c18ce6c50c88abf5321b58d0de7fc46c62859 /libavfilter/af_sofalizer.c
parentf3ec8ac0f42242ff9a5c94cf143058ee772caa61 (diff)
avfilter/af_sofalizer: allow user to setup custom virtual speakers positions
Signed-off-by: Paul B Mahol <onemda@gmail.com>
Diffstat (limited to 'libavfilter/af_sofalizer.c')
-rw-r--r--libavfilter/af_sofalizer.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c
index e2553b6800..7558f57eb9 100644
--- a/libavfilter/af_sofalizer.c
+++ b/libavfilter/af_sofalizer.c
@@ -29,6 +29,8 @@
#include <netcdf.h>
#include "libavcodec/avfft.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
#include "libavutil/float_dsp.h"
#include "libavutil/intmath.h"
#include "libavutil/opt.h"
@@ -52,6 +54,12 @@ typedef struct NCSofa { /* contains data of one SOFA file */
float *data_ir; /* IRs (time-domain) */
} NCSofa;
+typedef struct VirtualSpeaker {
+ uint8_t set;
+ float azim;
+ float elev;
+} VirtualSpeaker;
+
typedef struct SOFAlizerContext {
const AVClass *class;
@@ -61,6 +69,7 @@ typedef struct SOFAlizerContext {
int sample_rate; /* sample rate from SOFA file */
float *speaker_azim; /* azimuth of the virtual loudspeakers */
float *speaker_elev; /* elevation of the virtual loudspeakers */
+ char *speakers_pos; /* custom positions of the virtual loudspeakers */
float gain_lfe; /* gain applied to LFE channel */
int lfe_channel; /* LFE channel position in channel layout */
@@ -89,6 +98,8 @@ typedef struct SOFAlizerContext {
float radius; /* distance virtual loudspeakers to listener (in metres) */
int type; /* processing type */
+ VirtualSpeaker vspkrpos[64];
+
FFTContext *fft[2], *ifft[2];
FFTComplex *data_hrtf[2];
@@ -362,6 +373,62 @@ error:
return ret;
}
+static int parse_channel_name(char **arg, int *rchannel)
+{
+ char buf[8];
+ int len, i, channel_id = 0;
+ int64_t layout, layout0;
+
+ /* try to parse a channel name, e.g. "FL" */
+ if (sscanf(*arg, "%7[A-Z]%n", buf, &len)) {
+ layout0 = layout = av_get_channel_layout(buf);
+ /* channel_id <- first set bit in layout */
+ for (i = 32; i > 0; i >>= 1) {
+ if (layout >= (int64_t)1 << i) {
+ channel_id += i;
+ layout >>= i;
+ }
+ }
+ /* reject layouts that are not a single channel */
+ if (channel_id >= 64 || layout0 != (int64_t)1 << channel_id)
+ return AVERROR(EINVAL);
+ *rchannel = channel_id;
+ *arg += len;
+ return 0;
+ }
+ return AVERROR(EINVAL);
+}
+
+static void parse_speaker_pos(AVFilterContext *ctx, int64_t in_channel_layout)
+{
+ SOFAlizerContext *s = ctx->priv;
+ char *arg, *tokenizer, *p, *args = av_strdup(s->speakers_pos);
+
+ if (!args)
+ return;
+ p = args;
+
+ while ((arg = av_strtok(p, "|", &tokenizer))) {
+ float azim, elev;
+ int out_ch_id;
+
+ p = NULL;
+ if (parse_channel_name(&arg, &out_ch_id))
+ continue;
+ if (sscanf(arg, "%f %f", &azim, &elev) == 2) {
+ s->vspkrpos[out_ch_id].set = 1;
+ s->vspkrpos[out_ch_id].azim = azim;
+ s->vspkrpos[out_ch_id].elev = elev;
+ } else if (sscanf(arg, "%f", &azim) == 1) {
+ s->vspkrpos[out_ch_id].set = 1;
+ s->vspkrpos[out_ch_id].azim = azim;
+ s->vspkrpos[out_ch_id].elev = 0;
+ }
+ }
+
+ av_free(args);
+}
+
static int get_speaker_pos(AVFilterContext *ctx,
float *speaker_azim, float *speaker_elev)
{
@@ -376,6 +443,9 @@ static int get_speaker_pos(AVFilterContext *ctx,
s->lfe_channel = -1;
+ if (s->speakers_pos)
+ parse_speaker_pos(ctx, channels_layout);
+
/* set speaker positions according to input channel configuration: */
for (m = 0, ch = 0; ch < n_conv && m < 64; m++) {
uint64_t mask = channels_layout & (1 << m);
@@ -417,6 +487,12 @@ static int get_speaker_pos(AVFilterContext *ctx,
default:
return AVERROR(EINVAL);
}
+
+ if (s->vspkrpos[m].set) {
+ azim[ch] = s->vspkrpos[m].azim;
+ elev[ch] = s->vspkrpos[m].elev;
+ }
+
if (mask)
ch++;
}
@@ -1114,6 +1190,7 @@ static const AVOption sofalizer_options[] = {
{ "type", "set processing", OFFSET(type), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags = FLAGS, "type" },
{ "time", "time domain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, .flags = FLAGS, "type" },
{ "freq", "frequency domain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, .flags = FLAGS, "type" },
+ { "speakers", "set speaker custom positions", OFFSET(speakers_pos), AV_OPT_TYPE_STRING, {.str=0}, 0, 0, .flags = FLAGS },
{ NULL }
};