FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
af_sofalizer.c
Go to the documentation of this file.
1 /*****************************************************************************
2  * sofalizer.c : SOFAlizer filter for virtual binaural acoustics
3  *****************************************************************************
4  * Copyright (C) 2013-2015 Andreas Fuchs, Wolfgang Hrauda,
5  * Acoustics Research Institute (ARI), Vienna, Austria
6  *
7  * Authors: Andreas Fuchs <andi.fuchs.mail@gmail.com>
8  * Wolfgang Hrauda <wolfgang.hrauda@gmx.at>
9  *
10  * SOFAlizer project coordinator at ARI, main developer of SOFA:
11  * Piotr Majdak <piotr@majdak.at>
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU Lesser General Public License as published by
15  * the Free Software Foundation; either version 2.1 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27 
28 #include <math.h>
29 #include <netcdf.h>
30 
31 #include "libavcodec/avfft.h"
32 #include "libavutil/float_dsp.h"
33 #include "libavutil/intmath.h"
34 #include "libavutil/opt.h"
35 #include "avfilter.h"
36 #include "internal.h"
37 #include "audio.h"
38 
39 #define TIME_DOMAIN 0
40 #define FREQUENCY_DOMAIN 1
41 
42 typedef struct NCSofa { /* contains data of one SOFA file */
43  int ncid; /* netCDF ID of the opened SOFA file */
44  int n_samples; /* length of one impulse response (IR) */
45  int m_dim; /* number of measurement positions */
46  int *data_delay; /* broadband delay of each IR */
47  /* all measurement positions for each receiver (i.e. ear): */
48  float *sp_a; /* azimuth angles */
49  float *sp_e; /* elevation angles */
50  float *sp_r; /* radii */
51  /* data at each measurement position for each receiver: */
52  float *data_ir; /* IRs (time-domain) */
53 } NCSofa;
54 
55 typedef struct SOFAlizerContext {
56  const AVClass *class;
57 
58  char *filename; /* name of SOFA file */
59  NCSofa sofa; /* contains data of the SOFA file */
60 
61  int sample_rate; /* sample rate from SOFA file */
62  float *speaker_azim; /* azimuth of the virtual loudspeakers */
63  float *speaker_elev; /* elevation of the virtual loudspeakers */
64  float gain_lfe; /* gain applied to LFE channel */
65  int lfe_channel; /* LFE channel position in channel layout */
66 
67  int n_conv; /* number of channels to convolute */
68 
69  /* buffer variables (for convolution) */
70  float *ringbuffer[2]; /* buffers input samples, length of one buffer: */
71  /* no. input ch. (incl. LFE) x buffer_length */
72  int write[2]; /* current write position to ringbuffer */
73  int buffer_length; /* is: longest IR plus max. delay in all SOFA files */
74  /* then choose next power of 2 */
75  int n_fft; /* number of samples in one FFT block */
76 
77  /* netCDF variables */
78  int *delay[2]; /* broadband delay for each channel/IR to be convolved */
79 
80  float *data_ir[2]; /* IRs for all channels to be convolved */
81  /* (this excludes the LFE) */
82  float *temp_src[2];
84 
85  /* control variables */
86  float gain; /* filter gain (in dB) */
87  float rotation; /* rotation of virtual loudspeakers (in degrees) */
88  float elevation; /* elevation of virtual loudspeakers (in deg.) */
89  float radius; /* distance virtual loudspeakers to listener (in metres) */
90  int type; /* processing type */
91 
92  FFTContext *fft[2], *ifft[2];
94 
97 
98 static int close_sofa(struct NCSofa *sofa)
99 {
100  av_freep(&sofa->data_delay);
101  av_freep(&sofa->sp_a);
102  av_freep(&sofa->sp_e);
103  av_freep(&sofa->sp_r);
104  av_freep(&sofa->data_ir);
105  nc_close(sofa->ncid);
106  sofa->ncid = 0;
107 
108  return 0;
109 }
110 
111 static int load_sofa(AVFilterContext *ctx, char *filename, int *samplingrate)
112 {
113  struct SOFAlizerContext *s = ctx->priv;
114  /* variables associated with content of SOFA file: */
115  int ncid, n_dims, n_vars, n_gatts, n_unlim_dim_id, status;
116  char data_delay_dim_name[NC_MAX_NAME];
117  float *sp_a, *sp_e, *sp_r, *data_ir;
118  char *sofa_conventions;
119  char dim_name[NC_MAX_NAME]; /* names of netCDF dimensions */
120  size_t *dim_length; /* lengths of netCDF dimensions */
121  char *text;
122  unsigned int sample_rate;
123  int data_delay_dim_id[2];
124  int samplingrate_id;
125  int data_delay_id;
126  int n_samples;
127  int m_dim_id = -1;
128  int n_dim_id = -1;
129  int data_ir_id;
130  size_t att_len;
131  int m_dim;
132  int *data_delay;
133  int sp_id;
134  int i, ret;
135 
136  s->sofa.ncid = 0;
137  status = nc_open(filename, NC_NOWRITE, &ncid); /* open SOFA file read-only */
138  if (status != NC_NOERR) {
139  av_log(ctx, AV_LOG_ERROR, "Can't find SOFA-file '%s'\n", filename);
140  return AVERROR(EINVAL);
141  }
142 
143  /* get number of dimensions, vars, global attributes and Id of unlimited dimensions: */
144  nc_inq(ncid, &n_dims, &n_vars, &n_gatts, &n_unlim_dim_id);
145 
146  /* -- get number of measurements ("M") and length of one IR ("N") -- */
147  dim_length = av_malloc_array(n_dims, sizeof(*dim_length));
148  if (!dim_length) {
149  nc_close(ncid);
150  return AVERROR(ENOMEM);
151  }
152 
153  for (i = 0; i < n_dims; i++) { /* go through all dimensions of file */
154  nc_inq_dim(ncid, i, (char *)&dim_name, &dim_length[i]); /* get dimensions */
155  if (!strncmp("M", (const char *)&dim_name, 1)) /* get ID of dimension "M" */
156  m_dim_id = i;
157  if (!strncmp("N", (const char *)&dim_name, 1)) /* get ID of dimension "N" */
158  n_dim_id = i;
159  }
160 
161  if ((m_dim_id == -1) || (n_dim_id == -1)) { /* dimension "M" or "N" couldn't be found */
162  av_log(ctx, AV_LOG_ERROR, "Can't find required dimensions in SOFA file.\n");
163  av_freep(&dim_length);
164  nc_close(ncid);
165  return AVERROR(EINVAL);
166  }
167 
168  n_samples = dim_length[n_dim_id]; /* get length of one IR */
169  m_dim = dim_length[m_dim_id]; /* get number of measurements */
170 
171  av_freep(&dim_length);
172 
173  /* -- check file type -- */
174  /* get length of attritube "Conventions" */
175  status = nc_inq_attlen(ncid, NC_GLOBAL, "Conventions", &att_len);
176  if (status != NC_NOERR) {
177  av_log(ctx, AV_LOG_ERROR, "Can't get length of attribute \"Conventions\".\n");
178  nc_close(ncid);
179  return AVERROR_INVALIDDATA;
180  }
181 
182  /* check whether file is SOFA file */
183  text = av_malloc(att_len + 1);
184  if (!text) {
185  nc_close(ncid);
186  return AVERROR(ENOMEM);
187  }
188 
189  nc_get_att_text(ncid, NC_GLOBAL, "Conventions", text);
190  *(text + att_len) = 0;
191  if (strncmp("SOFA", text, 4)) {
192  av_log(ctx, AV_LOG_ERROR, "Not a SOFA file!\n");
193  av_freep(&text);
194  nc_close(ncid);
195  return AVERROR(EINVAL);
196  }
197  av_freep(&text);
198 
199  status = nc_inq_attlen(ncid, NC_GLOBAL, "License", &att_len);
200  if (status == NC_NOERR) {
201  text = av_malloc(att_len + 1);
202  if (text) {
203  nc_get_att_text(ncid, NC_GLOBAL, "License", text);
204  *(text + att_len) = 0;
205  av_log(ctx, AV_LOG_INFO, "SOFA file License: %s\n", text);
206  av_freep(&text);
207  }
208  }
209 
210  status = nc_inq_attlen(ncid, NC_GLOBAL, "SourceDescription", &att_len);
211  if (status == NC_NOERR) {
212  text = av_malloc(att_len + 1);
213  if (text) {
214  nc_get_att_text(ncid, NC_GLOBAL, "SourceDescription", text);
215  *(text + att_len) = 0;
216  av_log(ctx, AV_LOG_INFO, "SOFA file SourceDescription: %s\n", text);
217  av_freep(&text);
218  }
219  }
220 
221  status = nc_inq_attlen(ncid, NC_GLOBAL, "Comment", &att_len);
222  if (status == NC_NOERR) {
223  text = av_malloc(att_len + 1);
224  if (text) {
225  nc_get_att_text(ncid, NC_GLOBAL, "Comment", text);
226  *(text + att_len) = 0;
227  av_log(ctx, AV_LOG_INFO, "SOFA file Comment: %s\n", text);
228  av_freep(&text);
229  }
230  }
231 
232  status = nc_inq_attlen(ncid, NC_GLOBAL, "SOFAConventions", &att_len);
233  if (status != NC_NOERR) {
234  av_log(ctx, AV_LOG_ERROR, "Can't get length of attribute \"SOFAConventions\".\n");
235  nc_close(ncid);
236  return AVERROR_INVALIDDATA;
237  }
238 
239  sofa_conventions = av_malloc(att_len + 1);
240  if (!sofa_conventions) {
241  nc_close(ncid);
242  return AVERROR(ENOMEM);
243  }
244 
245  nc_get_att_text(ncid, NC_GLOBAL, "SOFAConventions", sofa_conventions);
246  *(sofa_conventions + att_len) = 0;
247  if (strncmp("SimpleFreeFieldHRIR", sofa_conventions, att_len)) {
248  av_log(ctx, AV_LOG_ERROR, "Not a SimpleFreeFieldHRIR file!\n");
249  av_freep(&sofa_conventions);
250  nc_close(ncid);
251  return AVERROR(EINVAL);
252  }
253  av_freep(&sofa_conventions);
254 
255  /* -- get sampling rate of HRTFs -- */
256  /* read ID, then value */
257  status = nc_inq_varid(ncid, "Data.SamplingRate", &samplingrate_id);
258  status += nc_get_var_uint(ncid, samplingrate_id, &sample_rate);
259  if (status != NC_NOERR) {
260  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.SamplingRate.\n");
261  nc_close(ncid);
262  return AVERROR(EINVAL);
263  }
264  *samplingrate = sample_rate; /* remember sampling rate */
265 
266  /* -- allocate memory for one value for each measurement position: -- */
267  sp_a = s->sofa.sp_a = av_malloc_array(m_dim, sizeof(float));
268  sp_e = s->sofa.sp_e = av_malloc_array(m_dim, sizeof(float));
269  sp_r = s->sofa.sp_r = av_malloc_array(m_dim, sizeof(float));
270  /* delay and IR values required for each ear and measurement position: */
271  data_delay = s->sofa.data_delay = av_calloc(m_dim, 2 * sizeof(int));
272  data_ir = s->sofa.data_ir = av_malloc_array(m_dim * n_samples, sizeof(float) * 2);
273 
274  if (!data_delay || !sp_a || !sp_e || !sp_r || !data_ir) {
275  /* if memory could not be allocated */
276  close_sofa(&s->sofa);
277  return AVERROR(ENOMEM);
278  }
279 
280  /* get impulse responses (HRTFs): */
281  /* get corresponding ID */
282  status = nc_inq_varid(ncid, "Data.IR", &data_ir_id);
283  status += nc_get_var_float(ncid, data_ir_id, data_ir); /* read and store IRs */
284  if (status != NC_NOERR) {
285  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.IR!\n");
286  ret = AVERROR(EINVAL);
287  goto error;
288  }
289 
290  /* get source positions of the HRTFs in the SOFA file: */
291  status = nc_inq_varid(ncid, "SourcePosition", &sp_id); /* get corresponding ID */
292  status += nc_get_vara_float(ncid, sp_id, (size_t[2]){ 0, 0 } ,
293  (size_t[2]){ m_dim, 1}, sp_a); /* read & store azimuth angles */
294  status += nc_get_vara_float(ncid, sp_id, (size_t[2]){ 0, 1 } ,
295  (size_t[2]){ m_dim, 1}, sp_e); /* read & store elevation angles */
296  status += nc_get_vara_float(ncid, sp_id, (size_t[2]){ 0, 2 } ,
297  (size_t[2]){ m_dim, 1}, sp_r); /* read & store radii */
298  if (status != NC_NOERR) { /* if any source position variable coudn't be read */
299  av_log(ctx, AV_LOG_ERROR, "Couldn't read SourcePosition.\n");
300  ret = AVERROR(EINVAL);
301  goto error;
302  }
303 
304  /* read Data.Delay, check for errors and fit it to data_delay */
305  status = nc_inq_varid(ncid, "Data.Delay", &data_delay_id);
306  status += nc_inq_vardimid(ncid, data_delay_id, &data_delay_dim_id[0]);
307  status += nc_inq_dimname(ncid, data_delay_dim_id[0], data_delay_dim_name);
308  if (status != NC_NOERR) {
309  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.Delay.\n");
310  ret = AVERROR(EINVAL);
311  goto error;
312  }
313 
314  /* Data.Delay dimension check */
315  /* dimension of Data.Delay is [I R]: */
316  if (!strncmp(data_delay_dim_name, "I", 2)) {
317  /* check 2 characters to assure string is 0-terminated after "I" */
318  int delay[2]; /* delays get from SOFA file: */
319 
320  av_log(ctx, AV_LOG_DEBUG, "Data.Delay has dimension [I R]\n");
321  status = nc_get_var_int(ncid, data_delay_id, &delay[0]);
322  if (status != NC_NOERR) {
323  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.Delay\n");
324  ret = AVERROR(EINVAL);
325  goto error;
326  }
327  int *data_delay_r = data_delay + m_dim;
328  for (i = 0; i < m_dim; i++) { /* extend given dimension [I R] to [M R] */
329  /* assign constant delay value for all measurements to data_delay fields */
330  data_delay[i] = delay[0];
331  data_delay_r[i] = delay[1];
332  }
333  /* dimension of Data.Delay is [M R] */
334  } else if (!strncmp(data_delay_dim_name, "M", 2)) {
335  av_log(ctx, AV_LOG_ERROR, "Data.Delay in dimension [M R]\n");
336  /* get delays from SOFA file: */
337  status = nc_get_var_int(ncid, data_delay_id, data_delay);
338  if (status != NC_NOERR) {
339  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.Delay\n");
340  ret = AVERROR(EINVAL);
341  goto error;
342  }
343  } else { /* dimension of Data.Delay is neither [I R] nor [M R] */
344  av_log(ctx, AV_LOG_ERROR, "Data.Delay does not have the required dimensions [I R] or [M R].\n");
345  ret = AVERROR(EINVAL);
346  goto error;
347  }
348 
349  /* save information in SOFA struct: */
350  s->sofa.m_dim = m_dim; /* no. measurement positions */
351  s->sofa.n_samples = n_samples; /* length on one IR */
352  s->sofa.ncid = ncid; /* netCDF ID of SOFA file */
353  nc_close(ncid); /* close SOFA file */
354 
355  return 0;
356 
357 error:
358  close_sofa(&s->sofa);
359  return ret;
360 }
361 
363  float *speaker_azim, float *speaker_elev)
364 {
365  struct SOFAlizerContext *s = ctx->priv;
366  uint64_t channels_layout = ctx->inputs[0]->channel_layout;
367  float azim[16] = { 0 };
368  float elev[16] = { 0 };
369  int m, ch, n_conv = ctx->inputs[0]->channels; /* get no. input channels */
370 
371  if (n_conv > 16)
372  return AVERROR(EINVAL);
373 
374  s->lfe_channel = -1;
375 
376  /* set speaker positions according to input channel configuration: */
377  for (m = 0, ch = 0; ch < n_conv && m < 64; m++) {
378  uint64_t mask = channels_layout & (1 << m);
379 
380  switch (mask) {
381  case AV_CH_FRONT_LEFT: azim[ch] = 30; break;
382  case AV_CH_FRONT_RIGHT: azim[ch] = 330; break;
383  case AV_CH_FRONT_CENTER: azim[ch] = 0; break;
384  case AV_CH_LOW_FREQUENCY:
385  case AV_CH_LOW_FREQUENCY_2: s->lfe_channel = ch; break;
386  case AV_CH_BACK_LEFT: azim[ch] = 150; break;
387  case AV_CH_BACK_RIGHT: azim[ch] = 210; break;
388  case AV_CH_BACK_CENTER: azim[ch] = 180; break;
389  case AV_CH_SIDE_LEFT: azim[ch] = 90; break;
390  case AV_CH_SIDE_RIGHT: azim[ch] = 270; break;
391  case AV_CH_FRONT_LEFT_OF_CENTER: azim[ch] = 15; break;
392  case AV_CH_FRONT_RIGHT_OF_CENTER: azim[ch] = 345; break;
393  case AV_CH_TOP_CENTER: azim[ch] = 0;
394  elev[ch] = 90; break;
395  case AV_CH_TOP_FRONT_LEFT: azim[ch] = 30;
396  elev[ch] = 45; break;
397  case AV_CH_TOP_FRONT_CENTER: azim[ch] = 0;
398  elev[ch] = 45; break;
399  case AV_CH_TOP_FRONT_RIGHT: azim[ch] = 330;
400  elev[ch] = 45; break;
401  case AV_CH_TOP_BACK_LEFT: azim[ch] = 150;
402  elev[ch] = 45; break;
403  case AV_CH_TOP_BACK_RIGHT: azim[ch] = 210;
404  elev[ch] = 45; break;
405  case AV_CH_TOP_BACK_CENTER: azim[ch] = 180;
406  elev[ch] = 45; break;
407  case AV_CH_WIDE_LEFT: azim[ch] = 90; break;
408  case AV_CH_WIDE_RIGHT: azim[ch] = 270; break;
409  case AV_CH_SURROUND_DIRECT_LEFT: azim[ch] = 90; break;
410  case AV_CH_SURROUND_DIRECT_RIGHT: azim[ch] = 270; break;
411  case AV_CH_STEREO_LEFT: azim[ch] = 90; break;
412  case AV_CH_STEREO_RIGHT: azim[ch] = 270; break;
413  case 0: break;
414  default:
415  return AVERROR(EINVAL);
416  }
417  if (mask)
418  ch++;
419  }
420 
421  memcpy(speaker_azim, azim, n_conv * sizeof(float));
422  memcpy(speaker_elev, elev, n_conv * sizeof(float));
423 
424  return 0;
425 
426 }
427 
428 static int max_delay(struct NCSofa *sofa)
429 {
430  int i, max = 0;
431 
432  for (i = 0; i < sofa->m_dim * 2; i++) {
433  /* search maximum delay in given SOFA file */
434  max = FFMAX(max, sofa->data_delay[i]);
435  }
436 
437  return max;
438 }
439 
440 static int find_m(SOFAlizerContext *s, int azim, int elev, float radius)
441 {
442  /* get source positions and M of currently selected SOFA file */
443  float *sp_a = s->sofa.sp_a; /* azimuth angle */
444  float *sp_e = s->sofa.sp_e; /* elevation angle */
445  float *sp_r = s->sofa.sp_r; /* radius */
446  int m_dim = s->sofa.m_dim; /* no. measurements */
447  int best_id = 0; /* index m currently closest to desired source pos. */
448  float delta = 1000; /* offset between desired and currently best pos. */
449  float current;
450  int i;
451 
452  for (i = 0; i < m_dim; i++) {
453  /* search through all measurements in currently selected SOFA file */
454  /* distance of current to desired source position: */
455  current = fabs(sp_a[i] - azim) +
456  fabs(sp_e[i] - elev) +
457  fabs(sp_r[i] - radius);
458  if (current <= delta) {
459  /* if current distance is smaller than smallest distance so far */
460  delta = current;
461  best_id = i; /* remember index */
462  }
463  }
464 
465  return best_id;
466 }
467 
469 {
470  struct SOFAlizerContext *s = ctx->priv;
471  float compensate;
472  float energy = 0;
473  float *ir;
474  int m;
475 
476  if (s->sofa.ncid) {
477  /* find IR at front center position in the SOFA file (IR closest to 0°,0°,1m) */
478  struct NCSofa *sofa = &s->sofa;
479  m = find_m(s, 0, 0, 1);
480  /* get energy of that IR and compensate volume */
481  ir = sofa->data_ir + 2 * m * sofa->n_samples;
482  if (sofa->n_samples & 31) {
483  energy = avpriv_scalarproduct_float_c(ir, ir, sofa->n_samples);
484  } else {
485  energy = s->fdsp->scalarproduct_float(ir, ir, sofa->n_samples);
486  }
487  compensate = 256 / (sofa->n_samples * sqrt(energy));
488  av_log(ctx, AV_LOG_DEBUG, "Compensate-factor: %f\n", compensate);
489  ir = sofa->data_ir;
490  /* apply volume compensation to IRs */
491  s->fdsp->vector_fmul_scalar(ir, ir, compensate, sofa->n_samples * sofa->m_dim * 2);
492  emms_c();
493  }
494 
495  return 0;
496 }
497 
498 typedef struct ThreadData {
500  int *write;
501  int **delay;
502  float **ir;
504  float **ringbuffer;
505  float **temp_src;
507 } ThreadData;
508 
509 static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
510 {
511  SOFAlizerContext *s = ctx->priv;
512  ThreadData *td = arg;
513  AVFrame *in = td->in, *out = td->out;
514  int offset = jobnr;
515  int *write = &td->write[jobnr];
516  const int *const delay = td->delay[jobnr];
517  const float *const ir = td->ir[jobnr];
518  int *n_clippings = &td->n_clippings[jobnr];
519  float *ringbuffer = td->ringbuffer[jobnr];
520  float *temp_src = td->temp_src[jobnr];
521  const int n_samples = s->sofa.n_samples; /* length of one IR */
522  const float *src = (const float *)in->data[0]; /* get pointer to audio input buffer */
523  float *dst = (float *)out->data[0]; /* get pointer to audio output buffer */
524  const int in_channels = s->n_conv; /* number of input channels */
525  /* ring buffer length is: longest IR plus max. delay -> next power of 2 */
526  const int buffer_length = s->buffer_length;
527  /* -1 for AND instead of MODULO (applied to powers of 2): */
528  const uint32_t modulo = (uint32_t)buffer_length - 1;
529  float *buffer[16]; /* holds ringbuffer for each input channel */
530  int wr = *write;
531  int read;
532  int i, l;
533 
534  dst += offset;
535  for (l = 0; l < in_channels; l++) {
536  /* get starting address of ringbuffer for each input channel */
537  buffer[l] = ringbuffer + l * buffer_length;
538  }
539 
540  for (i = 0; i < in->nb_samples; i++) {
541  const float *temp_ir = ir; /* using same set of IRs for each sample */
542 
543  *dst = 0;
544  for (l = 0; l < in_channels; l++) {
545  /* write current input sample to ringbuffer (for each channel) */
546  *(buffer[l] + wr) = src[l];
547  }
548 
549  /* loop goes through all channels to be convolved */
550  for (l = 0; l < in_channels; l++) {
551  const float *const bptr = buffer[l];
552 
553  if (l == s->lfe_channel) {
554  /* LFE is an input channel but requires no convolution */
555  /* apply gain to LFE signal and add to output buffer */
556  *dst += *(buffer[s->lfe_channel] + wr) * s->gain_lfe;
557  temp_ir += n_samples;
558  continue;
559  }
560 
561  /* current read position in ringbuffer: input sample write position
562  * - delay for l-th ch. + diff. betw. IR length and buffer length
563  * (mod buffer length) */
564  read = (wr - *(delay + l) - (n_samples - 1) + buffer_length) & modulo;
565 
566  if (read + n_samples < buffer_length) {
567  memcpy(temp_src, bptr + read, n_samples * sizeof(*temp_src));
568  } else {
569  int len = FFMIN(n_samples - (read % n_samples), buffer_length - read);
570 
571  memcpy(temp_src, bptr + read, len * sizeof(*temp_src));
572  memcpy(temp_src + len, bptr, (n_samples - len) * sizeof(*temp_src));
573  }
574 
575  /* multiply signal and IR, and add up the results */
576  dst[0] += s->fdsp->scalarproduct_float(temp_ir, temp_src, n_samples);
577  temp_ir += n_samples;
578  }
579 
580  /* clippings counter */
581  if (fabs(*dst) > 1)
582  *n_clippings += 1;
583 
584  /* move output buffer pointer by +2 to get to next sample of processed channel: */
585  dst += 2;
586  src += in_channels;
587  wr = (wr + 1) & modulo; /* update ringbuffer write position */
588  }
589 
590  *write = wr; /* remember write position in ringbuffer for next call */
591 
592  return 0;
593 }
594 
595 static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
596 {
597  SOFAlizerContext *s = ctx->priv;
598  ThreadData *td = arg;
599  AVFrame *in = td->in, *out = td->out;
600  int offset = jobnr;
601  int *write = &td->write[jobnr];
602  FFTComplex *hrtf = s->data_hrtf[jobnr]; /* get pointers to current HRTF data */
603  int *n_clippings = &td->n_clippings[jobnr];
604  float *ringbuffer = td->ringbuffer[jobnr];
605  const int n_samples = s->sofa.n_samples; /* length of one IR */
606  const float *src = (const float *)in->data[0]; /* get pointer to audio input buffer */
607  float *dst = (float *)out->data[0]; /* get pointer to audio output buffer */
608  const int in_channels = s->n_conv; /* number of input channels */
609  /* ring buffer length is: longest IR plus max. delay -> next power of 2 */
610  const int buffer_length = s->buffer_length;
611  /* -1 for AND instead of MODULO (applied to powers of 2): */
612  const uint32_t modulo = (uint32_t)buffer_length - 1;
613  FFTComplex *fft_in = s->temp_fft[jobnr]; /* temporary array for FFT input/output data */
614  FFTContext *ifft = s->ifft[jobnr];
615  FFTContext *fft = s->fft[jobnr];
616  const int n_conv = s->n_conv;
617  const int n_fft = s->n_fft;
618  int wr = *write;
619  int n_read;
620  int i, j;
621 
622  dst += offset;
623 
624  /* find minimum between number of samples and output buffer length:
625  * (important, if one IR is longer than the output buffer) */
626  n_read = FFMIN(s->sofa.n_samples, in->nb_samples);
627  for (j = 0; j < n_read; j++) {
628  /* initialize output buf with saved signal from overflow buf */
629  dst[2 * j] = ringbuffer[wr];
630  ringbuffer[wr] = 0.0; /* re-set read samples to zero */
631  /* update ringbuffer read/write position */
632  wr = (wr + 1) & modulo;
633  }
634 
635  /* initialize rest of output buffer with 0 */
636  for (j = n_read; j < in->nb_samples; j++) {
637  dst[2 * j] = 0;
638  }
639 
640  for (i = 0; i < n_conv; i++) {
641  if (i == s->lfe_channel) { /* LFE */
642  for (j = 0; j < in->nb_samples; j++) {
643  /* apply gain to LFE signal and add to output buffer */
644  dst[2 * j] += src[i + j * in_channels] * s->gain_lfe;
645  }
646  continue;
647  }
648 
649  /* outer loop: go through all input channels to be convolved */
650  offset = i * n_fft; /* no. samples already processed */
651 
652  /* fill FFT input with 0 (we want to zero-pad) */
653  memset(fft_in, 0, sizeof(FFTComplex) * n_fft);
654 
655  for (j = 0; j < in->nb_samples; j++) {
656  /* prepare input for FFT */
657  /* write all samples of current input channel to FFT input array */
658  fft_in[j].re = src[j * in_channels + i];
659  }
660 
661  /* transform input signal of current channel to frequency domain */
662  av_fft_permute(fft, fft_in);
663  av_fft_calc(fft, fft_in);
664  for (j = 0; j < n_fft; j++) {
665  const float re = fft_in[j].re;
666  const float im = fft_in[j].im;
667 
668  /* complex multiplication of input signal and HRTFs */
669  /* output channel (real): */
670  fft_in[j].re = re * (hrtf + offset + j)->re - im * (hrtf + offset + j)->im;
671  /* output channel (imag): */
672  fft_in[j].im = re * (hrtf + offset + j)->im + im * (hrtf + offset + j)->re;
673  }
674 
675  /* transform output signal of current channel back to time domain */
676  av_fft_permute(ifft, fft_in);
677  av_fft_calc(ifft, fft_in);
678 
679  for (j = 0; j < in->nb_samples; j++) {
680  /* write output signal of current channel to output buffer */
681  dst[2 * j] += fft_in[j].re / (float)n_fft;
682  }
683 
684  for (j = 0; j < n_samples - 1; j++) { /* overflow length is IR length - 1 */
685  /* write the rest of output signal to overflow buffer */
686  int write_pos = (wr + j) & modulo;
687 
688  *(ringbuffer + write_pos) += fft_in[in->nb_samples + j].re / (float)n_fft;
689  }
690  }
691 
692  /* go through all samples of current output buffer: count clippings */
693  for (i = 0; i < out->nb_samples; i++) {
694  /* clippings counter */
695  if (fabs(*dst) > 1) { /* if current output sample > 1 */
696  *n_clippings = *n_clippings + 1;
697  }
698 
699  /* move output buffer pointer by +2 to get to next sample of processed channel: */
700  dst += 2;
701  }
702 
703  /* remember read/write position in ringbuffer for next call */
704  *write = wr;
705 
706  return 0;
707 }
708 
709 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
710 {
711  AVFilterContext *ctx = inlink->dst;
712  SOFAlizerContext *s = ctx->priv;
713  AVFilterLink *outlink = ctx->outputs[0];
714  int n_clippings[2] = { 0 };
715  ThreadData td;
716  AVFrame *out;
717 
718  out = ff_get_audio_buffer(outlink, in->nb_samples);
719  if (!out) {
720  av_frame_free(&in);
721  return AVERROR(ENOMEM);
722  }
723  av_frame_copy_props(out, in);
724 
725  td.in = in; td.out = out; td.write = s->write;
726  td.delay = s->delay; td.ir = s->data_ir; td.n_clippings = n_clippings;
727  td.ringbuffer = s->ringbuffer; td.temp_src = s->temp_src;
728  td.temp_fft = s->temp_fft;
729 
730  if (s->type == TIME_DOMAIN) {
731  ctx->internal->execute(ctx, sofalizer_convolute, &td, NULL, 2);
732  } else {
733  ctx->internal->execute(ctx, sofalizer_fast_convolute, &td, NULL, 2);
734  }
735  emms_c();
736 
737  /* display error message if clipping occurred */
738  if (n_clippings[0] + n_clippings[1] > 0) {
739  av_log(ctx, AV_LOG_WARNING, "%d of %d samples clipped. Please reduce gain.\n",
740  n_clippings[0] + n_clippings[1], out->nb_samples * 2);
741  }
742 
743  av_frame_free(&in);
744  return ff_filter_frame(outlink, out);
745 }
746 
748 {
749  struct SOFAlizerContext *s = ctx->priv;
752  int ret, sample_rates[] = { 48000, -1 };
753 
754  ret = ff_add_format(&formats, AV_SAMPLE_FMT_FLT);
755  if (ret)
756  return ret;
757  ret = ff_set_common_formats(ctx, formats);
758  if (ret)
759  return ret;
760 
761  layouts = ff_all_channel_layouts();
762  if (!layouts)
763  return AVERROR(ENOMEM);
764 
765  ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->out_channel_layouts);
766  if (ret)
767  return ret;
768 
769  layouts = NULL;
771  if (ret)
772  return ret;
773 
774  ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
775  if (ret)
776  return ret;
777 
778  sample_rates[0] = s->sample_rate;
779  formats = ff_make_format_list(sample_rates);
780  if (!formats)
781  return AVERROR(ENOMEM);
782  return ff_set_common_samplerates(ctx, formats);
783 }
784 
785 static int load_data(AVFilterContext *ctx, int azim, int elev, float radius)
786 {
787  struct SOFAlizerContext *s = ctx->priv;
788  const int n_samples = s->sofa.n_samples;
789  int n_conv = s->n_conv; /* no. channels to convolve */
790  int n_fft = s->n_fft;
791  int delay_l[16]; /* broadband delay for each IR */
792  int delay_r[16];
793  int nb_input_channels = ctx->inputs[0]->channels; /* no. input channels */
794  float gain_lin = expf((s->gain - 3 * nb_input_channels) / 20 * M_LN10); /* gain - 3dB/channel */
795  FFTComplex *data_hrtf_l = NULL;
796  FFTComplex *data_hrtf_r = NULL;
797  FFTComplex *fft_in_l = NULL;
798  FFTComplex *fft_in_r = NULL;
799  float *data_ir_l = NULL;
800  float *data_ir_r = NULL;
801  int offset = 0; /* used for faster pointer arithmetics in for-loop */
802  int m[16]; /* measurement index m of IR closest to required source positions */
803  int i, j, azim_orig = azim, elev_orig = elev;
804 
805  if (!s->sofa.ncid) { /* if an invalid SOFA file has been selected */
806  av_log(ctx, AV_LOG_ERROR, "Selected SOFA file is invalid. Please select valid SOFA file.\n");
807  return AVERROR_INVALIDDATA;
808  }
809 
810  if (s->type == TIME_DOMAIN) {
811  s->temp_src[0] = av_calloc(FFALIGN(n_samples, 16), sizeof(float));
812  s->temp_src[1] = av_calloc(FFALIGN(n_samples, 16), sizeof(float));
813 
814  /* get temporary IR for L and R channel */
815  data_ir_l = av_malloc_array(n_conv * n_samples, sizeof(*data_ir_l));
816  data_ir_r = av_malloc_array(n_conv * n_samples, sizeof(*data_ir_r));
817  if (!data_ir_r || !data_ir_l || !s->temp_src[0] || !s->temp_src[1]) {
818  av_free(data_ir_l);
819  av_free(data_ir_r);
820  return AVERROR(ENOMEM);
821  }
822  } else {
823  /* get temporary HRTF memory for L and R channel */
824  data_hrtf_l = av_malloc_array(n_fft, sizeof(*data_hrtf_l) * n_conv);
825  data_hrtf_r = av_malloc_array(n_fft, sizeof(*data_hrtf_r) * n_conv);
826  if (!data_hrtf_r || !data_hrtf_l) {
827  av_free(data_hrtf_l);
828  av_free(data_hrtf_r);
829  return AVERROR(ENOMEM);
830  }
831  }
832 
833  for (i = 0; i < s->n_conv; i++) {
834  /* load and store IRs and corresponding delays */
835  azim = (int)(s->speaker_azim[i] + azim_orig) % 360;
836  elev = (int)(s->speaker_elev[i] + elev_orig) % 90;
837  /* get id of IR closest to desired position */
838  m[i] = find_m(s, azim, elev, radius);
839 
840  /* load the delays associated with the current IRs */
841  delay_l[i] = *(s->sofa.data_delay + 2 * m[i]);
842  delay_r[i] = *(s->sofa.data_delay + 2 * m[i] + 1);
843 
844  if (s->type == TIME_DOMAIN) {
845  offset = i * n_samples; /* no. samples already written */
846  for (j = 0; j < n_samples; j++) {
847  /* load reversed IRs of the specified source position
848  * sample-by-sample for left and right ear; and apply gain */
849  *(data_ir_l + offset + j) = /* left channel */
850  *(s->sofa.data_ir + 2 * m[i] * n_samples + n_samples - 1 - j) * gain_lin;
851  *(data_ir_r + offset + j) = /* right channel */
852  *(s->sofa.data_ir + 2 * m[i] * n_samples + n_samples - 1 - j + n_samples) * gain_lin;
853  }
854  } else {
855  fft_in_l = av_calloc(n_fft, sizeof(*fft_in_l));
856  fft_in_r = av_calloc(n_fft, sizeof(*fft_in_r));
857  if (!fft_in_l || !fft_in_r) {
858  av_free(data_hrtf_l);
859  av_free(data_hrtf_r);
860  av_free(fft_in_l);
861  av_free(fft_in_r);
862  return AVERROR(ENOMEM);
863  }
864 
865  offset = i * n_fft; /* no. samples already written */
866  for (j = 0; j < n_samples; j++) {
867  /* load non-reversed IRs of the specified source position
868  * sample-by-sample and apply gain,
869  * L channel is loaded to real part, R channel to imag part,
870  * IRs ared shifted by L and R delay */
871  fft_in_l[delay_l[i] + j].re = /* left channel */
872  *(s->sofa.data_ir + 2 * m[i] * n_samples + j) * gain_lin;
873  fft_in_r[delay_r[i] + j].re = /* right channel */
874  *(s->sofa.data_ir + (2 * m[i] + 1) * n_samples + j) * gain_lin;
875  }
876 
877  /* actually transform to frequency domain (IRs -> HRTFs) */
878  av_fft_permute(s->fft[0], fft_in_l);
879  av_fft_calc(s->fft[0], fft_in_l);
880  memcpy(data_hrtf_l + offset, fft_in_l, n_fft * sizeof(*fft_in_l));
881  av_fft_permute(s->fft[0], fft_in_r);
882  av_fft_calc(s->fft[0], fft_in_r);
883  memcpy(data_hrtf_r + offset, fft_in_r, n_fft * sizeof(*fft_in_r));
884  }
885 
886  av_log(ctx, AV_LOG_DEBUG, "Index: %d, Azimuth: %f, Elevation: %f, Radius: %f of SOFA file.\n",
887  m[i], *(s->sofa.sp_a + m[i]), *(s->sofa.sp_e + m[i]), *(s->sofa.sp_r + m[i]));
888  }
889 
890  if (s->type == TIME_DOMAIN) {
891  /* copy IRs and delays to allocated memory in the SOFAlizerContext struct: */
892  memcpy(s->data_ir[0], data_ir_l, sizeof(float) * n_conv * n_samples);
893  memcpy(s->data_ir[1], data_ir_r, sizeof(float) * n_conv * n_samples);
894 
895  av_freep(&data_ir_l); /* free temporary IR memory */
896  av_freep(&data_ir_r);
897  } else {
898  s->data_hrtf[0] = av_malloc_array(n_fft * s->n_conv, sizeof(FFTComplex));
899  s->data_hrtf[1] = av_malloc_array(n_fft * s->n_conv, sizeof(FFTComplex));
900  if (!s->data_hrtf[0] || !s->data_hrtf[1]) {
901  av_freep(&data_hrtf_l);
902  av_freep(&data_hrtf_r);
903  av_freep(&fft_in_l);
904  av_freep(&fft_in_r);
905  return AVERROR(ENOMEM); /* memory allocation failed */
906  }
907 
908  memcpy(s->data_hrtf[0], data_hrtf_l, /* copy HRTF data to */
909  sizeof(FFTComplex) * n_conv * n_fft); /* filter struct */
910  memcpy(s->data_hrtf[1], data_hrtf_r,
911  sizeof(FFTComplex) * n_conv * n_fft);
912 
913  av_freep(&data_hrtf_l); /* free temporary HRTF memory */
914  av_freep(&data_hrtf_r);
915 
916  av_freep(&fft_in_l); /* free temporary FFT memory */
917  av_freep(&fft_in_r);
918  }
919 
920  memcpy(s->delay[0], &delay_l[0], sizeof(int) * s->n_conv);
921  memcpy(s->delay[1], &delay_r[0], sizeof(int) * s->n_conv);
922 
923  return 0;
924 }
925 
927 {
928  SOFAlizerContext *s = ctx->priv;
929  int ret;
930 
931  /* load SOFA file, */
932  /* initialize file IDs to 0 before attempting to load SOFA files,
933  * this assures that in case of error, only the memory of already
934  * loaded files is free'd */
935  s->sofa.ncid = 0;
936  ret = load_sofa(ctx, s->filename, &s->sample_rate);
937  if (ret) {
938  /* file loading error */
939  av_log(ctx, AV_LOG_ERROR, "Error while loading SOFA file: '%s'\n", s->filename);
940  } else { /* no file loading error, resampling not required */
941  av_log(ctx, AV_LOG_DEBUG, "File '%s' loaded.\n", s->filename);
942  }
943 
944  if (ret) {
945  av_log(ctx, AV_LOG_ERROR, "No valid SOFA file could be loaded. Please specify valid SOFA file.\n");
946  return ret;
947  }
948 
950  if (!s->fdsp)
951  return AVERROR(ENOMEM);
952 
953  return 0;
954 }
955 
956 static int config_input(AVFilterLink *inlink)
957 {
958  AVFilterContext *ctx = inlink->dst;
959  SOFAlizerContext *s = ctx->priv;
960  int nb_input_channels = inlink->channels; /* no. input channels */
961  int n_max_ir = 0;
962  int n_current;
963  int n_max = 0;
964  int ret;
965 
966  if (s->type == FREQUENCY_DOMAIN) {
967  inlink->partial_buf_size =
968  inlink->min_samples =
969  inlink->max_samples = inlink->sample_rate;
970  }
971 
972  /* gain -3 dB per channel, -6 dB to get LFE on a similar level */
973  s->gain_lfe = expf((s->gain - 3 * inlink->channels - 6) / 20 * M_LN10);
974 
975  s->n_conv = nb_input_channels;
976 
977  /* get size of ringbuffer (longest IR plus max. delay) */
978  /* then choose next power of 2 for performance optimization */
979  n_current = s->sofa.n_samples + max_delay(&s->sofa);
980  if (n_current > n_max) {
981  /* length of longest IR plus max. delay (in all SOFA files) */
982  n_max = n_current;
983  /* length of longest IR (without delay, in all SOFA files) */
984  n_max_ir = s->sofa.n_samples;
985  }
986  /* buffer length is longest IR plus max. delay -> next power of 2
987  (32 - count leading zeros gives required exponent) */
988  s->buffer_length = 1 << (32 - ff_clz(n_max));
989  s->n_fft = 1 << (32 - ff_clz(n_max + inlink->sample_rate));
990 
991  if (s->type == FREQUENCY_DOMAIN) {
992  av_fft_end(s->fft[0]);
993  av_fft_end(s->fft[1]);
994  s->fft[0] = av_fft_init(log2(s->n_fft), 0);
995  s->fft[1] = av_fft_init(log2(s->n_fft), 0);
996  av_fft_end(s->ifft[0]);
997  av_fft_end(s->ifft[1]);
998  s->ifft[0] = av_fft_init(log2(s->n_fft), 1);
999  s->ifft[1] = av_fft_init(log2(s->n_fft), 1);
1000 
1001  if (!s->fft[0] || !s->fft[1] || !s->ifft[0] || !s->ifft[1]) {
1002  av_log(ctx, AV_LOG_ERROR, "Unable to create FFT contexts.\n");
1003  return AVERROR(ENOMEM);
1004  }
1005  }
1006 
1007  /* Allocate memory for the impulse responses, delays and the ringbuffers */
1008  /* size: (longest IR) * (number of channels to convolute) */
1009  s->data_ir[0] = av_malloc_array(n_max_ir, sizeof(float) * s->n_conv);
1010  s->data_ir[1] = av_malloc_array(n_max_ir, sizeof(float) * s->n_conv);
1011  /* length: number of channels to convolute */
1012  s->delay[0] = av_malloc_array(s->n_conv, sizeof(float));
1013  s->delay[1] = av_malloc_array(s->n_conv, sizeof(float));
1014  /* length: (buffer length) * (number of input channels),
1015  * OR: buffer length (if frequency domain processing)
1016  * calloc zero-initializes the buffer */
1017 
1018  if (s->type == TIME_DOMAIN) {
1019  s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
1020  s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
1021  } else {
1022  s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float));
1023  s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float));
1024  s->temp_fft[0] = av_malloc_array(s->n_fft, sizeof(FFTComplex));
1025  s->temp_fft[1] = av_malloc_array(s->n_fft, sizeof(FFTComplex));
1026  if (!s->temp_fft[0] || !s->temp_fft[1])
1027  return AVERROR(ENOMEM);
1028  }
1029 
1030  /* length: number of channels to convolute */
1031  s->speaker_azim = av_calloc(s->n_conv, sizeof(*s->speaker_azim));
1032  s->speaker_elev = av_calloc(s->n_conv, sizeof(*s->speaker_elev));
1033 
1034  /* memory allocation failed: */
1035  if (!s->data_ir[0] || !s->data_ir[1] || !s->delay[1] ||
1036  !s->delay[0] || !s->ringbuffer[0] || !s->ringbuffer[1] ||
1037  !s->speaker_azim || !s->speaker_elev)
1038  return AVERROR(ENOMEM);
1039 
1040  compensate_volume(ctx);
1041 
1042  /* get speaker positions */
1043  if ((ret = get_speaker_pos(ctx, s->speaker_azim, s->speaker_elev)) < 0) {
1044  av_log(ctx, AV_LOG_ERROR, "Couldn't get speaker positions. Input channel configuration not supported.\n");
1045  return ret;
1046  }
1047 
1048  /* load IRs to data_ir[0] and data_ir[1] for required directions */
1049  if ((ret = load_data(ctx, s->rotation, s->elevation, s->radius)) < 0)
1050  return ret;
1051 
1052  av_log(ctx, AV_LOG_DEBUG, "Samplerate: %d Channels to convolute: %d, Length of ringbuffer: %d x %d\n",
1053  inlink->sample_rate, s->n_conv, nb_input_channels, s->buffer_length);
1054 
1055  return 0;
1056 }
1057 
1059 {
1060  SOFAlizerContext *s = ctx->priv;
1061 
1062  if (s->sofa.ncid) {
1063  av_freep(&s->sofa.sp_a);
1064  av_freep(&s->sofa.sp_e);
1065  av_freep(&s->sofa.sp_r);
1066  av_freep(&s->sofa.data_delay);
1067  av_freep(&s->sofa.data_ir);
1068  }
1069  av_fft_end(s->ifft[0]);
1070  av_fft_end(s->ifft[1]);
1071  av_fft_end(s->fft[0]);
1072  av_fft_end(s->fft[1]);
1073  av_freep(&s->delay[0]);
1074  av_freep(&s->delay[1]);
1075  av_freep(&s->data_ir[0]);
1076  av_freep(&s->data_ir[1]);
1077  av_freep(&s->ringbuffer[0]);
1078  av_freep(&s->ringbuffer[1]);
1079  av_freep(&s->speaker_azim);
1080  av_freep(&s->speaker_elev);
1081  av_freep(&s->temp_src[0]);
1082  av_freep(&s->temp_src[1]);
1083  av_freep(&s->temp_fft[0]);
1084  av_freep(&s->temp_fft[1]);
1085  av_freep(&s->data_hrtf[0]);
1086  av_freep(&s->data_hrtf[1]);
1087  av_freep(&s->fdsp);
1088 }
1089 
1090 #define OFFSET(x) offsetof(SOFAlizerContext, x)
1091 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
1092 
1093 static const AVOption sofalizer_options[] = {
1094  { "sofa", "sofa filename", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1095  { "gain", "set gain in dB", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl=0}, -20, 40, .flags = FLAGS },
1096  { "rotation", "set rotation" , OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl=0}, -360, 360, .flags = FLAGS },
1097  { "elevation", "set elevation", OFFSET(elevation), AV_OPT_TYPE_FLOAT, {.dbl=0}, -90, 90, .flags = FLAGS },
1098  { "radius", "set radius", OFFSET(radius), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 3, .flags = FLAGS },
1099  { "type", "set processing", OFFSET(type), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags = FLAGS, "type" },
1100  { "time", "time domain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, .flags = FLAGS, "type" },
1101  { "freq", "frequency domain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, .flags = FLAGS, "type" },
1102  { NULL }
1103 };
1104 
1105 AVFILTER_DEFINE_CLASS(sofalizer);
1106 
1107 static const AVFilterPad inputs[] = {
1108  {
1109  .name = "default",
1110  .type = AVMEDIA_TYPE_AUDIO,
1111  .config_props = config_input,
1112  .filter_frame = filter_frame,
1113  },
1114  { NULL }
1115 };
1116 
1117 static const AVFilterPad outputs[] = {
1118  {
1119  .name = "default",
1120  .type = AVMEDIA_TYPE_AUDIO,
1121  },
1122  { NULL }
1123 };
1124 
1126  .name = "sofalizer",
1127  .description = NULL_IF_CONFIG_SMALL("SOFAlizer (Spatially Oriented Format for Acoustics)."),
1128  .priv_size = sizeof(SOFAlizerContext),
1129  .priv_class = &sofalizer_class,
1130  .init = init,
1131  .uninit = uninit,
1133  .inputs = inputs,
1134  .outputs = outputs,
1136 };
static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: af_sofalizer.c:595
#define NULL
Definition: coverity.c:32
FFTComplex * data_hrtf[2]
Definition: af_sofalizer.c:93
const char * s
Definition: avisynth_c.h:631
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
AVFrame * out
Definition: af_sofalizer.c:499
This structure describes decoded (raw) audio or video data.
Definition: frame.h:181
#define AV_CH_TOP_FRONT_RIGHT
AVOption.
Definition: opt.h:245
av_cold void av_fft_end(FFTContext *s)
Definition: avfft.c:48
AVFormatContext * ctx
Definition: movenc-test.c:48
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
Main libavfilter public API header.
int * n_clippings
Definition: af_sofalizer.c:503
AVFILTER_DEFINE_CLASS(sofalizer)
#define AV_CH_TOP_FRONT_LEFT
FFTContext * fft[2]
Definition: af_sofalizer.c:92
#define AV_CH_TOP_FRONT_CENTER
#define AV_CH_LOW_FREQUENCY_2
float(* scalarproduct_float)(const float *v1, const float *v2, int len)
Calculate the scalar product of two vectors of floats.
Definition: float_dsp.h:159
FFTSample re
Definition: avfft.h:38
void av_fft_permute(FFTContext *s, FFTComplex *z)
Do the permutation needed BEFORE calling ff_fft_calc().
Definition: avfft.c:38
static enum AVSampleFormat formats[]
#define AV_CH_SURROUND_DIRECT_RIGHT
#define AV_CH_LAYOUT_STEREO
AVFilter ff_af_sofalizer
#define log2(x)
Definition: libm.h:404
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
const char * name
Pad name.
Definition: internal.h:59
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:312
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition: formats.c:435
float avpriv_scalarproduct_float_c(const float *v1, const float *v2, int len)
Return the scalar product of two vectors.
Definition: float_dsp.c:108
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1163
AVFrame * in
Definition: af_sofalizer.c:499
#define AV_CH_WIDE_LEFT
#define av_cold
Definition: attributes.h:82
#define av_malloc(s)
float delta
AVOptions.
#define AV_CH_TOP_BACK_LEFT
float ** temp_src
Definition: af_sofalizer.c:505
#define AV_CH_WIDE_RIGHT
#define AV_CH_TOP_BACK_CENTER
#define AV_CH_LOW_FREQUENCY
#define FLAGS
#define AV_CH_BACK_LEFT
static int find_m(SOFAlizerContext *s, int azim, int elev, float radius)
Definition: af_sofalizer.c:440
#define FFALIGN(x, a)
Definition: macros.h:48
#define av_log(a,...)
unsigned m
Definition: audioconvert.c:187
float * data_ir
Definition: af_sofalizer.c:52
A filter pad used for either input or output.
Definition: internal.h:53
#define expf(x)
Definition: libm.h:283
AVFloatDSPContext * fdsp
Definition: af_sofalizer.c:95
static int load_data(AVFilterContext *ctx, int azim, int elev, float radius)
Definition: af_sofalizer.c:785
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:568
#define td
Definition: regdef.h:70
FFTComplex ** temp_fft
Definition: af_sofalizer.c:506
int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
Definition: formats.c:343
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:65
static const uint16_t mask[17]
Definition: lzw.c:38
static int get_speaker_pos(AVFilterContext *ctx, float *speaker_azim, float *speaker_elev)
Definition: af_sofalizer.c:362
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: af_sofalizer.c:709
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:154
static int query_formats(AVFilterContext *ctx)
Definition: af_sofalizer.c:747
static int close_sofa(struct NCSofa *sofa)
Definition: af_sofalizer.c:98
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:176
float * sp_e
Definition: af_sofalizer.c:49
void * priv
private data for use by the filter
Definition: avfilter.h:319
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:113
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
const char * arg
Definition: jacosubdec.c:66
float ** ringbuffer
Definition: af_sofalizer.c:504
float * data_ir[2]
Definition: af_sofalizer.c:80
int ff_add_format(AVFilterFormats **avff, int64_t fmt)
Add fmt to the list of media formats contained in *avff.
Definition: formats.c:337
FFTContext * av_fft_init(int nbits, int inverse)
Set up a complex FFT.
Definition: avfft.c:28
static const uint8_t offset[127][2]
Definition: vf_spp.c:92
static int max_delay(struct NCSofa *sofa)
Definition: af_sofalizer.c:428
#define FFMAX(a, b)
Definition: common.h:94
static const int sample_rates[]
Definition: dcaenc.h:32
int * data_delay
Definition: af_sofalizer.c:46
#define AV_CH_STEREO_RIGHT
See AV_CH_STEREO_LEFT.
#define AV_CH_TOP_CENTER
float * ringbuffer[2]
Definition: af_sofalizer.c:70
float * speaker_azim
Definition: af_sofalizer.c:62
Definition: fft.h:88
#define FFMIN(a, b)
Definition: common.h:96
#define ff_clz
Definition: intmath.h:142
#define TIME_DOMAIN
Definition: af_sofalizer.c:39
void(* vector_fmul_scalar)(float *dst, const float *src, float mul, int len)
Multiply a vector of floats by a scalar float.
Definition: float_dsp.h:69
#define AV_CH_FRONT_LEFT_OF_CENTER
#define AV_CH_FRONT_CENTER
static int load_sofa(AVFilterContext *ctx, char *filename, int *samplingrate)
Definition: af_sofalizer.c:111
int n_samples
Definition: af_sofalizer.c:44
static const AVFilterPad outputs[]
#define src
Definition: vp9dsp.c:530
AVFilterChannelLayouts * ff_all_channel_layouts(void)
Construct an empty AVFilterChannelLayouts/AVFilterFormats struct – representing any channel layout (w...
Definition: formats.c:401
#define AV_CH_FRONT_RIGHT_OF_CENTER
A list of supported channel layouts.
Definition: formats.h:85
FILE * out
Definition: movenc-test.c:54
static const AVOption sofalizer_options[]
sample_rate
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
float im
Definition: fft-test.c:73
FFT functions.
static int config_input(AVFilterLink *inlink)
Definition: af_sofalizer.c:956
float * sp_a
Definition: af_sofalizer.c:48
#define AV_CH_FRONT_LEFT
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(constint16_t *) pi >>8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(constint32_t *) pi >>24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(constfloat *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(constfloat *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(constfloat *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(constdouble *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(constdouble *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(constdouble *) pi *(1U<< 31))))#defineSET_CONV_FUNC_GROUP(ofmt, ifmt) staticvoidset_generic_function(AudioConvert *ac){}voidff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enumAVSampleFormatout_fmt, enumAVSampleFormatin_fmt, intchannels, intsample_rate, intapply_map){AudioConvert *ac;intin_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) returnNULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt)>2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);returnNULL;}returnac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}elseif(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;elseac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);returnac;}intff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){intuse_generic=1;intlen=in->nb_samples;intp;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%dsamples-audio_convert:%sto%s(dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));returnff_convert_dither(ac-> in
int ** delay
Definition: af_sofalizer.c:501
GLint GLenum type
Definition: opengl_enc.c:105
#define AV_CH_TOP_BACK_RIGHT
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:141
int m_dim
Definition: af_sofalizer.c:45
int ncid
Definition: af_sofalizer.c:43
const char * name
Filter name.
Definition: avfilter.h:145
av_cold AVFloatDSPContext * avpriv_float_dsp_alloc(int bit_exact)
Allocate a float DSP context.
Definition: float_dsp.c:119
float * speaker_elev
Definition: af_sofalizer.c:63
static const AVFilterPad inputs[]
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:316
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:434
void * av_calloc(size_t nmemb, size_t size)
Allocate a block of nmemb * size bytes with alignment suitable for all memory accesses (including vec...
Definition: mem.c:260
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:344
static int flags
Definition: cpu.c:47
#define AV_CH_BACK_CENTER
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:192
#define AV_CH_SIDE_RIGHT
static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: af_sofalizer.c:509
#define M_LN10
Definition: mathematics.h:37
FFTContext * ifft[2]
Definition: af_sofalizer.c:92
float * sp_r
Definition: af_sofalizer.c:50
static void fft(const int32_t in[2 *256], cplx32 out[256])
Definition: dcaenc.c:339
FFTSample im
Definition: avfft.h:38
#define FREQUENCY_DOMAIN
Definition: af_sofalizer.c:40
avfilter_execute_func * execute
Definition: internal.h:153
static av_cold int init(AVFilterContext *ctx)
Definition: af_sofalizer.c:926
float re
Definition: fft-test.c:73
#define av_free(p)
int len
float * temp_src[2]
Definition: af_sofalizer.c:82
A list of supported formats for one end of a filter link.
Definition: formats.h:64
#define AV_CH_SURROUND_DIRECT_LEFT
An instance of a filter.
Definition: avfilter.h:304
#define AV_CH_FRONT_RIGHT
static int compensate_volume(AVFilterContext *ctx)
Definition: af_sofalizer.c:468
float ** ir
Definition: af_sofalizer.c:502
#define av_freep(p)
#define OFFSET(x)
#define av_malloc_array(a, b)
#define AV_CH_SIDE_LEFT
internal API functions
FFTComplex * temp_fft[2]
Definition: af_sofalizer.c:83
static av_cold void uninit(AVFilterContext *ctx)
void av_fft_calc(FFTContext *s, FFTComplex *z)
Do a complex FFT with the parameters defined in av_fft_init().
Definition: avfft.c:43
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:235
int ff_set_common_samplerates(AVFilterContext *ctx, AVFilterFormats *samplerates)
Definition: formats.c:556
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:565
GLuint buffer
Definition: opengl_enc.c:102
#define AV_CH_BACK_RIGHT
#define AV_CH_STEREO_LEFT
Stereo downmix.