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/avstring.h"
34 #include "libavutil/float_dsp.h"
35 #include "libavutil/intmath.h"
36 #include "libavutil/opt.h"
37 #include "avfilter.h"
38 #include "internal.h"
39 #include "audio.h"
40 
41 #define TIME_DOMAIN 0
42 #define FREQUENCY_DOMAIN 1
43 
44 typedef struct NCSofa { /* contains data of one SOFA file */
45  int ncid; /* netCDF ID of the opened SOFA file */
46  int n_samples; /* length of one impulse response (IR) */
47  int m_dim; /* number of measurement positions */
48  int *data_delay; /* broadband delay of each IR */
49  /* all measurement positions for each receiver (i.e. ear): */
50  float *sp_a; /* azimuth angles */
51  float *sp_e; /* elevation angles */
52  float *sp_r; /* radii */
53  /* data at each measurement position for each receiver: */
54  float *data_ir; /* IRs (time-domain) */
55 } NCSofa;
56 
57 typedef struct VirtualSpeaker {
59  float azim;
60  float elev;
62 
63 typedef struct SOFAlizerContext {
64  const AVClass *class;
65 
66  char *filename; /* name of SOFA file */
67  NCSofa sofa; /* contains data of the SOFA file */
68 
69  int sample_rate; /* sample rate from SOFA file */
70  float *speaker_azim; /* azimuth of the virtual loudspeakers */
71  float *speaker_elev; /* elevation of the virtual loudspeakers */
72  char *speakers_pos; /* custom positions of the virtual loudspeakers */
73  float gain_lfe; /* gain applied to LFE channel */
74  int lfe_channel; /* LFE channel position in channel layout */
75 
76  int n_conv; /* number of channels to convolute */
77 
78  /* buffer variables (for convolution) */
79  float *ringbuffer[2]; /* buffers input samples, length of one buffer: */
80  /* no. input ch. (incl. LFE) x buffer_length */
81  int write[2]; /* current write position to ringbuffer */
82  int buffer_length; /* is: longest IR plus max. delay in all SOFA files */
83  /* then choose next power of 2 */
84  int n_fft; /* number of samples in one FFT block */
85 
86  /* netCDF variables */
87  int *delay[2]; /* broadband delay for each channel/IR to be convolved */
88 
89  float *data_ir[2]; /* IRs for all channels to be convolved */
90  /* (this excludes the LFE) */
91  float *temp_src[2];
93 
94  /* control variables */
95  float gain; /* filter gain (in dB) */
96  float rotation; /* rotation of virtual loudspeakers (in degrees) */
97  float elevation; /* elevation of virtual loudspeakers (in deg.) */
98  float radius; /* distance virtual loudspeakers to listener (in metres) */
99  int type; /* processing type */
100 
102 
103  FFTContext *fft[2], *ifft[2];
105 
108 
109 static int close_sofa(struct NCSofa *sofa)
110 {
111  av_freep(&sofa->data_delay);
112  av_freep(&sofa->sp_a);
113  av_freep(&sofa->sp_e);
114  av_freep(&sofa->sp_r);
115  av_freep(&sofa->data_ir);
116  nc_close(sofa->ncid);
117  sofa->ncid = 0;
118 
119  return 0;
120 }
121 
122 static int load_sofa(AVFilterContext *ctx, char *filename, int *samplingrate)
123 {
124  struct SOFAlizerContext *s = ctx->priv;
125  /* variables associated with content of SOFA file: */
126  int ncid, n_dims, n_vars, n_gatts, n_unlim_dim_id, status;
127  char data_delay_dim_name[NC_MAX_NAME];
128  float *sp_a, *sp_e, *sp_r, *data_ir;
129  char *sofa_conventions;
130  char dim_name[NC_MAX_NAME]; /* names of netCDF dimensions */
131  size_t *dim_length; /* lengths of netCDF dimensions */
132  char *text;
133  unsigned int sample_rate;
134  int data_delay_dim_id[2];
135  int samplingrate_id;
136  int data_delay_id;
137  int n_samples;
138  int m_dim_id = -1;
139  int n_dim_id = -1;
140  int data_ir_id;
141  size_t att_len;
142  int m_dim;
143  int *data_delay;
144  int sp_id;
145  int i, ret;
146 
147  s->sofa.ncid = 0;
148  status = nc_open(filename, NC_NOWRITE, &ncid); /* open SOFA file read-only */
149  if (status != NC_NOERR) {
150  av_log(ctx, AV_LOG_ERROR, "Can't find SOFA-file '%s'\n", filename);
151  return AVERROR(EINVAL);
152  }
153 
154  /* get number of dimensions, vars, global attributes and Id of unlimited dimensions: */
155  nc_inq(ncid, &n_dims, &n_vars, &n_gatts, &n_unlim_dim_id);
156 
157  /* -- get number of measurements ("M") and length of one IR ("N") -- */
158  dim_length = av_malloc_array(n_dims, sizeof(*dim_length));
159  if (!dim_length) {
160  nc_close(ncid);
161  return AVERROR(ENOMEM);
162  }
163 
164  for (i = 0; i < n_dims; i++) { /* go through all dimensions of file */
165  nc_inq_dim(ncid, i, (char *)&dim_name, &dim_length[i]); /* get dimensions */
166  if (!strncmp("M", (const char *)&dim_name, 1)) /* get ID of dimension "M" */
167  m_dim_id = i;
168  if (!strncmp("N", (const char *)&dim_name, 1)) /* get ID of dimension "N" */
169  n_dim_id = i;
170  }
171 
172  if ((m_dim_id == -1) || (n_dim_id == -1)) { /* dimension "M" or "N" couldn't be found */
173  av_log(ctx, AV_LOG_ERROR, "Can't find required dimensions in SOFA file.\n");
174  av_freep(&dim_length);
175  nc_close(ncid);
176  return AVERROR(EINVAL);
177  }
178 
179  n_samples = dim_length[n_dim_id]; /* get length of one IR */
180  m_dim = dim_length[m_dim_id]; /* get number of measurements */
181 
182  av_freep(&dim_length);
183 
184  /* -- check file type -- */
185  /* get length of attritube "Conventions" */
186  status = nc_inq_attlen(ncid, NC_GLOBAL, "Conventions", &att_len);
187  if (status != NC_NOERR) {
188  av_log(ctx, AV_LOG_ERROR, "Can't get length of attribute \"Conventions\".\n");
189  nc_close(ncid);
190  return AVERROR_INVALIDDATA;
191  }
192 
193  /* check whether file is SOFA file */
194  text = av_malloc(att_len + 1);
195  if (!text) {
196  nc_close(ncid);
197  return AVERROR(ENOMEM);
198  }
199 
200  nc_get_att_text(ncid, NC_GLOBAL, "Conventions", text);
201  *(text + att_len) = 0;
202  if (strncmp("SOFA", text, 4)) {
203  av_log(ctx, AV_LOG_ERROR, "Not a SOFA file!\n");
204  av_freep(&text);
205  nc_close(ncid);
206  return AVERROR(EINVAL);
207  }
208  av_freep(&text);
209 
210  status = nc_inq_attlen(ncid, NC_GLOBAL, "License", &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, "License", text);
215  *(text + att_len) = 0;
216  av_log(ctx, AV_LOG_INFO, "SOFA file License: %s\n", text);
217  av_freep(&text);
218  }
219  }
220 
221  status = nc_inq_attlen(ncid, NC_GLOBAL, "SourceDescription", &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, "SourceDescription", text);
226  *(text + att_len) = 0;
227  av_log(ctx, AV_LOG_INFO, "SOFA file SourceDescription: %s\n", text);
228  av_freep(&text);
229  }
230  }
231 
232  status = nc_inq_attlen(ncid, NC_GLOBAL, "Comment", &att_len);
233  if (status == NC_NOERR) {
234  text = av_malloc(att_len + 1);
235  if (text) {
236  nc_get_att_text(ncid, NC_GLOBAL, "Comment", text);
237  *(text + att_len) = 0;
238  av_log(ctx, AV_LOG_INFO, "SOFA file Comment: %s\n", text);
239  av_freep(&text);
240  }
241  }
242 
243  status = nc_inq_attlen(ncid, NC_GLOBAL, "SOFAConventions", &att_len);
244  if (status != NC_NOERR) {
245  av_log(ctx, AV_LOG_ERROR, "Can't get length of attribute \"SOFAConventions\".\n");
246  nc_close(ncid);
247  return AVERROR_INVALIDDATA;
248  }
249 
250  sofa_conventions = av_malloc(att_len + 1);
251  if (!sofa_conventions) {
252  nc_close(ncid);
253  return AVERROR(ENOMEM);
254  }
255 
256  nc_get_att_text(ncid, NC_GLOBAL, "SOFAConventions", sofa_conventions);
257  *(sofa_conventions + att_len) = 0;
258  if (strncmp("SimpleFreeFieldHRIR", sofa_conventions, att_len)) {
259  av_log(ctx, AV_LOG_ERROR, "Not a SimpleFreeFieldHRIR file!\n");
260  av_freep(&sofa_conventions);
261  nc_close(ncid);
262  return AVERROR(EINVAL);
263  }
264  av_freep(&sofa_conventions);
265 
266  /* -- get sampling rate of HRTFs -- */
267  /* read ID, then value */
268  status = nc_inq_varid(ncid, "Data.SamplingRate", &samplingrate_id);
269  status += nc_get_var_uint(ncid, samplingrate_id, &sample_rate);
270  if (status != NC_NOERR) {
271  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.SamplingRate.\n");
272  nc_close(ncid);
273  return AVERROR(EINVAL);
274  }
275  *samplingrate = sample_rate; /* remember sampling rate */
276 
277  /* -- allocate memory for one value for each measurement position: -- */
278  sp_a = s->sofa.sp_a = av_malloc_array(m_dim, sizeof(float));
279  sp_e = s->sofa.sp_e = av_malloc_array(m_dim, sizeof(float));
280  sp_r = s->sofa.sp_r = av_malloc_array(m_dim, sizeof(float));
281  /* delay and IR values required for each ear and measurement position: */
282  data_delay = s->sofa.data_delay = av_calloc(m_dim, 2 * sizeof(int));
283  data_ir = s->sofa.data_ir = av_calloc(m_dim * FFALIGN(n_samples, 16), sizeof(float) * 2);
284 
285  if (!data_delay || !sp_a || !sp_e || !sp_r || !data_ir) {
286  /* if memory could not be allocated */
287  close_sofa(&s->sofa);
288  return AVERROR(ENOMEM);
289  }
290 
291  /* get impulse responses (HRTFs): */
292  /* get corresponding ID */
293  status = nc_inq_varid(ncid, "Data.IR", &data_ir_id);
294  status += nc_get_var_float(ncid, data_ir_id, data_ir); /* read and store IRs */
295  if (status != NC_NOERR) {
296  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.IR!\n");
297  ret = AVERROR(EINVAL);
298  goto error;
299  }
300 
301  /* get source positions of the HRTFs in the SOFA file: */
302  status = nc_inq_varid(ncid, "SourcePosition", &sp_id); /* get corresponding ID */
303  status += nc_get_vara_float(ncid, sp_id, (size_t[2]){ 0, 0 } ,
304  (size_t[2]){ m_dim, 1}, sp_a); /* read & store azimuth angles */
305  status += nc_get_vara_float(ncid, sp_id, (size_t[2]){ 0, 1 } ,
306  (size_t[2]){ m_dim, 1}, sp_e); /* read & store elevation angles */
307  status += nc_get_vara_float(ncid, sp_id, (size_t[2]){ 0, 2 } ,
308  (size_t[2]){ m_dim, 1}, sp_r); /* read & store radii */
309  if (status != NC_NOERR) { /* if any source position variable coudn't be read */
310  av_log(ctx, AV_LOG_ERROR, "Couldn't read SourcePosition.\n");
311  ret = AVERROR(EINVAL);
312  goto error;
313  }
314 
315  /* read Data.Delay, check for errors and fit it to data_delay */
316  status = nc_inq_varid(ncid, "Data.Delay", &data_delay_id);
317  status += nc_inq_vardimid(ncid, data_delay_id, &data_delay_dim_id[0]);
318  status += nc_inq_dimname(ncid, data_delay_dim_id[0], data_delay_dim_name);
319  if (status != NC_NOERR) {
320  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.Delay.\n");
321  ret = AVERROR(EINVAL);
322  goto error;
323  }
324 
325  /* Data.Delay dimension check */
326  /* dimension of Data.Delay is [I R]: */
327  if (!strncmp(data_delay_dim_name, "I", 2)) {
328  /* check 2 characters to assure string is 0-terminated after "I" */
329  int delay[2]; /* delays get from SOFA file: */
330  int *data_delay_r;
331 
332  av_log(ctx, AV_LOG_DEBUG, "Data.Delay has dimension [I R]\n");
333  status = nc_get_var_int(ncid, data_delay_id, &delay[0]);
334  if (status != NC_NOERR) {
335  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.Delay\n");
336  ret = AVERROR(EINVAL);
337  goto error;
338  }
339  data_delay_r = data_delay + m_dim;
340  for (i = 0; i < m_dim; i++) { /* extend given dimension [I R] to [M R] */
341  /* assign constant delay value for all measurements to data_delay fields */
342  data_delay[i] = delay[0];
343  data_delay_r[i] = delay[1];
344  }
345  /* dimension of Data.Delay is [M R] */
346  } else if (!strncmp(data_delay_dim_name, "M", 2)) {
347  av_log(ctx, AV_LOG_ERROR, "Data.Delay in dimension [M R]\n");
348  /* get delays from SOFA file: */
349  status = nc_get_var_int(ncid, data_delay_id, data_delay);
350  if (status != NC_NOERR) {
351  av_log(ctx, AV_LOG_ERROR, "Couldn't read Data.Delay\n");
352  ret = AVERROR(EINVAL);
353  goto error;
354  }
355  } else { /* dimension of Data.Delay is neither [I R] nor [M R] */
356  av_log(ctx, AV_LOG_ERROR, "Data.Delay does not have the required dimensions [I R] or [M R].\n");
357  ret = AVERROR(EINVAL);
358  goto error;
359  }
360 
361  /* save information in SOFA struct: */
362  s->sofa.m_dim = m_dim; /* no. measurement positions */
363  s->sofa.n_samples = n_samples; /* length on one IR */
364  s->sofa.ncid = ncid; /* netCDF ID of SOFA file */
365  nc_close(ncid); /* close SOFA file */
366 
367  av_log(ctx, AV_LOG_DEBUG, "m_dim: %d n_samples %d\n", m_dim, n_samples);
368 
369  return 0;
370 
371 error:
372  close_sofa(&s->sofa);
373  return ret;
374 }
375 
376 static int parse_channel_name(char **arg, int *rchannel, char *buf)
377 {
378  int len, i, channel_id = 0;
379  int64_t layout, layout0;
380 
381  /* try to parse a channel name, e.g. "FL" */
382  if (sscanf(*arg, "%7[A-Z]%n", buf, &len)) {
383  layout0 = layout = av_get_channel_layout(buf);
384  /* channel_id <- first set bit in layout */
385  for (i = 32; i > 0; i >>= 1) {
386  if (layout >= (int64_t)1 << i) {
387  channel_id += i;
388  layout >>= i;
389  }
390  }
391  /* reject layouts that are not a single channel */
392  if (channel_id >= 64 || layout0 != (int64_t)1 << channel_id)
393  return AVERROR(EINVAL);
394  *rchannel = channel_id;
395  *arg += len;
396  return 0;
397  }
398  return AVERROR(EINVAL);
399 }
400 
401 static void parse_speaker_pos(AVFilterContext *ctx, int64_t in_channel_layout)
402 {
403  SOFAlizerContext *s = ctx->priv;
404  char *arg, *tokenizer, *p, *args = av_strdup(s->speakers_pos);
405 
406  if (!args)
407  return;
408  p = args;
409 
410  while ((arg = av_strtok(p, "|", &tokenizer))) {
411  char buf[8];
412  float azim, elev;
413  int out_ch_id;
414 
415  p = NULL;
416  if (parse_channel_name(&arg, &out_ch_id, buf)) {
417  av_log(ctx, AV_LOG_WARNING, "Failed to parse \'%s\' as channel name.\n", buf);
418  continue;
419  }
420  if (sscanf(arg, "%f %f", &azim, &elev) == 2) {
421  s->vspkrpos[out_ch_id].set = 1;
422  s->vspkrpos[out_ch_id].azim = azim;
423  s->vspkrpos[out_ch_id].elev = elev;
424  } else if (sscanf(arg, "%f", &azim) == 1) {
425  s->vspkrpos[out_ch_id].set = 1;
426  s->vspkrpos[out_ch_id].azim = azim;
427  s->vspkrpos[out_ch_id].elev = 0;
428  }
429  }
430 
431  av_free(args);
432 }
433 
435  float *speaker_azim, float *speaker_elev)
436 {
437  struct SOFAlizerContext *s = ctx->priv;
438  uint64_t channels_layout = ctx->inputs[0]->channel_layout;
439  float azim[16] = { 0 };
440  float elev[16] = { 0 };
441  int m, ch, n_conv = ctx->inputs[0]->channels; /* get no. input channels */
442 
443  if (n_conv > 16)
444  return AVERROR(EINVAL);
445 
446  s->lfe_channel = -1;
447 
448  if (s->speakers_pos)
449  parse_speaker_pos(ctx, channels_layout);
450 
451  /* set speaker positions according to input channel configuration: */
452  for (m = 0, ch = 0; ch < n_conv && m < 64; m++) {
453  uint64_t mask = channels_layout & (1ULL << m);
454 
455  switch (mask) {
456  case AV_CH_FRONT_LEFT: azim[ch] = 30; break;
457  case AV_CH_FRONT_RIGHT: azim[ch] = 330; break;
458  case AV_CH_FRONT_CENTER: azim[ch] = 0; break;
459  case AV_CH_LOW_FREQUENCY:
460  case AV_CH_LOW_FREQUENCY_2: s->lfe_channel = ch; break;
461  case AV_CH_BACK_LEFT: azim[ch] = 150; break;
462  case AV_CH_BACK_RIGHT: azim[ch] = 210; break;
463  case AV_CH_BACK_CENTER: azim[ch] = 180; break;
464  case AV_CH_SIDE_LEFT: azim[ch] = 90; break;
465  case AV_CH_SIDE_RIGHT: azim[ch] = 270; break;
466  case AV_CH_FRONT_LEFT_OF_CENTER: azim[ch] = 15; break;
467  case AV_CH_FRONT_RIGHT_OF_CENTER: azim[ch] = 345; break;
468  case AV_CH_TOP_CENTER: azim[ch] = 0;
469  elev[ch] = 90; break;
470  case AV_CH_TOP_FRONT_LEFT: azim[ch] = 30;
471  elev[ch] = 45; break;
472  case AV_CH_TOP_FRONT_CENTER: azim[ch] = 0;
473  elev[ch] = 45; break;
474  case AV_CH_TOP_FRONT_RIGHT: azim[ch] = 330;
475  elev[ch] = 45; break;
476  case AV_CH_TOP_BACK_LEFT: azim[ch] = 150;
477  elev[ch] = 45; break;
478  case AV_CH_TOP_BACK_RIGHT: azim[ch] = 210;
479  elev[ch] = 45; break;
480  case AV_CH_TOP_BACK_CENTER: azim[ch] = 180;
481  elev[ch] = 45; break;
482  case AV_CH_WIDE_LEFT: azim[ch] = 90; break;
483  case AV_CH_WIDE_RIGHT: azim[ch] = 270; break;
484  case AV_CH_SURROUND_DIRECT_LEFT: azim[ch] = 90; break;
485  case AV_CH_SURROUND_DIRECT_RIGHT: azim[ch] = 270; break;
486  case AV_CH_STEREO_LEFT: azim[ch] = 90; break;
487  case AV_CH_STEREO_RIGHT: azim[ch] = 270; break;
488  case 0: break;
489  default:
490  return AVERROR(EINVAL);
491  }
492 
493  if (s->vspkrpos[m].set) {
494  azim[ch] = s->vspkrpos[m].azim;
495  elev[ch] = s->vspkrpos[m].elev;
496  }
497 
498  if (mask)
499  ch++;
500  }
501 
502  memcpy(speaker_azim, azim, n_conv * sizeof(float));
503  memcpy(speaker_elev, elev, n_conv * sizeof(float));
504 
505  return 0;
506 
507 }
508 
509 static int max_delay(struct NCSofa *sofa)
510 {
511  int i, max = 0;
512 
513  for (i = 0; i < sofa->m_dim * 2; i++) {
514  /* search maximum delay in given SOFA file */
515  max = FFMAX(max, sofa->data_delay[i]);
516  }
517 
518  return max;
519 }
520 
521 static int find_m(SOFAlizerContext *s, int azim, int elev, float radius)
522 {
523  /* get source positions and M of currently selected SOFA file */
524  float *sp_a = s->sofa.sp_a; /* azimuth angle */
525  float *sp_e = s->sofa.sp_e; /* elevation angle */
526  float *sp_r = s->sofa.sp_r; /* radius */
527  int m_dim = s->sofa.m_dim; /* no. measurements */
528  int best_id = 0; /* index m currently closest to desired source pos. */
529  float delta = 1000; /* offset between desired and currently best pos. */
530  float current;
531  int i;
532 
533  for (i = 0; i < m_dim; i++) {
534  /* search through all measurements in currently selected SOFA file */
535  /* distance of current to desired source position: */
536  current = fabs(sp_a[i] - azim) +
537  fabs(sp_e[i] - elev) +
538  fabs(sp_r[i] - radius);
539  if (current <= delta) {
540  /* if current distance is smaller than smallest distance so far */
541  delta = current;
542  best_id = i; /* remember index */
543  }
544  }
545 
546  return best_id;
547 }
548 
550 {
551  struct SOFAlizerContext *s = ctx->priv;
552  float compensate;
553  float energy = 0;
554  float *ir;
555  int m;
556 
557  if (s->sofa.ncid) {
558  /* find IR at front center position in the SOFA file (IR closest to 0°,0°,1m) */
559  struct NCSofa *sofa = &s->sofa;
560  m = find_m(s, 0, 0, 1);
561  /* get energy of that IR and compensate volume */
562  ir = sofa->data_ir + 2 * m * sofa->n_samples;
563  if (sofa->n_samples & 31) {
564  energy = avpriv_scalarproduct_float_c(ir, ir, sofa->n_samples);
565  } else {
566  energy = s->fdsp->scalarproduct_float(ir, ir, sofa->n_samples);
567  }
568  compensate = 256 / (sofa->n_samples * sqrt(energy));
569  av_log(ctx, AV_LOG_DEBUG, "Compensate-factor: %f\n", compensate);
570  ir = sofa->data_ir;
571  /* apply volume compensation to IRs */
572  if (sofa->n_samples & 31) {
573  int i;
574  for (i = 0; i < sofa->n_samples * sofa->m_dim * 2; i++) {
575  ir[i] = ir[i] * compensate;
576  }
577  } else {
578  s->fdsp->vector_fmul_scalar(ir, ir, compensate, sofa->n_samples * sofa->m_dim * 2);
579  emms_c();
580  }
581  }
582 
583  return 0;
584 }
585 
586 typedef struct ThreadData {
588  int *write;
589  int **delay;
590  float **ir;
592  float **ringbuffer;
593  float **temp_src;
595 } ThreadData;
596 
597 static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
598 {
599  SOFAlizerContext *s = ctx->priv;
600  ThreadData *td = arg;
601  AVFrame *in = td->in, *out = td->out;
602  int offset = jobnr;
603  int *write = &td->write[jobnr];
604  const int *const delay = td->delay[jobnr];
605  const float *const ir = td->ir[jobnr];
606  int *n_clippings = &td->n_clippings[jobnr];
607  float *ringbuffer = td->ringbuffer[jobnr];
608  float *temp_src = td->temp_src[jobnr];
609  const int n_samples = s->sofa.n_samples; /* length of one IR */
610  const float *src = (const float *)in->data[0]; /* get pointer to audio input buffer */
611  float *dst = (float *)out->data[0]; /* get pointer to audio output buffer */
612  const int in_channels = s->n_conv; /* number of input channels */
613  /* ring buffer length is: longest IR plus max. delay -> next power of 2 */
614  const int buffer_length = s->buffer_length;
615  /* -1 for AND instead of MODULO (applied to powers of 2): */
616  const uint32_t modulo = (uint32_t)buffer_length - 1;
617  float *buffer[16]; /* holds ringbuffer for each input channel */
618  int wr = *write;
619  int read;
620  int i, l;
621 
622  dst += offset;
623  for (l = 0; l < in_channels; l++) {
624  /* get starting address of ringbuffer for each input channel */
625  buffer[l] = ringbuffer + l * buffer_length;
626  }
627 
628  for (i = 0; i < in->nb_samples; i++) {
629  const float *temp_ir = ir; /* using same set of IRs for each sample */
630 
631  *dst = 0;
632  for (l = 0; l < in_channels; l++) {
633  /* write current input sample to ringbuffer (for each channel) */
634  *(buffer[l] + wr) = src[l];
635  }
636 
637  /* loop goes through all channels to be convolved */
638  for (l = 0; l < in_channels; l++) {
639  const float *const bptr = buffer[l];
640 
641  if (l == s->lfe_channel) {
642  /* LFE is an input channel but requires no convolution */
643  /* apply gain to LFE signal and add to output buffer */
644  *dst += *(buffer[s->lfe_channel] + wr) * s->gain_lfe;
645  temp_ir += FFALIGN(n_samples, 16);
646  continue;
647  }
648 
649  /* current read position in ringbuffer: input sample write position
650  * - delay for l-th ch. + diff. betw. IR length and buffer length
651  * (mod buffer length) */
652  read = (wr - *(delay + l) - (n_samples - 1) + buffer_length) & modulo;
653 
654  if (read + n_samples < buffer_length) {
655  memcpy(temp_src, bptr + read, n_samples * sizeof(*temp_src));
656  } else {
657  int len = FFMIN(n_samples - (read % n_samples), buffer_length - read);
658 
659  memcpy(temp_src, bptr + read, len * sizeof(*temp_src));
660  memcpy(temp_src + len, bptr, (n_samples - len) * sizeof(*temp_src));
661  }
662 
663  /* multiply signal and IR, and add up the results */
664  dst[0] += s->fdsp->scalarproduct_float(temp_ir, temp_src, n_samples);
665  temp_ir += FFALIGN(n_samples, 16);
666  }
667 
668  /* clippings counter */
669  if (fabs(*dst) > 1)
670  *n_clippings += 1;
671 
672  /* move output buffer pointer by +2 to get to next sample of processed channel: */
673  dst += 2;
674  src += in_channels;
675  wr = (wr + 1) & modulo; /* update ringbuffer write position */
676  }
677 
678  *write = wr; /* remember write position in ringbuffer for next call */
679 
680  return 0;
681 }
682 
683 static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
684 {
685  SOFAlizerContext *s = ctx->priv;
686  ThreadData *td = arg;
687  AVFrame *in = td->in, *out = td->out;
688  int offset = jobnr;
689  int *write = &td->write[jobnr];
690  FFTComplex *hrtf = s->data_hrtf[jobnr]; /* get pointers to current HRTF data */
691  int *n_clippings = &td->n_clippings[jobnr];
692  float *ringbuffer = td->ringbuffer[jobnr];
693  const int n_samples = s->sofa.n_samples; /* length of one IR */
694  const float *src = (const float *)in->data[0]; /* get pointer to audio input buffer */
695  float *dst = (float *)out->data[0]; /* get pointer to audio output buffer */
696  const int in_channels = s->n_conv; /* number of input channels */
697  /* ring buffer length is: longest IR plus max. delay -> next power of 2 */
698  const int buffer_length = s->buffer_length;
699  /* -1 for AND instead of MODULO (applied to powers of 2): */
700  const uint32_t modulo = (uint32_t)buffer_length - 1;
701  FFTComplex *fft_in = s->temp_fft[jobnr]; /* temporary array for FFT input/output data */
702  FFTContext *ifft = s->ifft[jobnr];
703  FFTContext *fft = s->fft[jobnr];
704  const int n_conv = s->n_conv;
705  const int n_fft = s->n_fft;
706  const float fft_scale = 1.0f / s->n_fft;
707  FFTComplex *hrtf_offset;
708  int wr = *write;
709  int n_read;
710  int i, j;
711 
712  dst += offset;
713 
714  /* find minimum between number of samples and output buffer length:
715  * (important, if one IR is longer than the output buffer) */
716  n_read = FFMIN(s->sofa.n_samples, in->nb_samples);
717  for (j = 0; j < n_read; j++) {
718  /* initialize output buf with saved signal from overflow buf */
719  dst[2 * j] = ringbuffer[wr];
720  ringbuffer[wr] = 0.0; /* re-set read samples to zero */
721  /* update ringbuffer read/write position */
722  wr = (wr + 1) & modulo;
723  }
724 
725  /* initialize rest of output buffer with 0 */
726  for (j = n_read; j < in->nb_samples; j++) {
727  dst[2 * j] = 0;
728  }
729 
730  for (i = 0; i < n_conv; i++) {
731  if (i == s->lfe_channel) { /* LFE */
732  for (j = 0; j < in->nb_samples; j++) {
733  /* apply gain to LFE signal and add to output buffer */
734  dst[2 * j] += src[i + j * in_channels] * s->gain_lfe;
735  }
736  continue;
737  }
738 
739  /* outer loop: go through all input channels to be convolved */
740  offset = i * n_fft; /* no. samples already processed */
741  hrtf_offset = hrtf + offset;
742 
743  /* fill FFT input with 0 (we want to zero-pad) */
744  memset(fft_in, 0, sizeof(FFTComplex) * n_fft);
745 
746  for (j = 0; j < in->nb_samples; j++) {
747  /* prepare input for FFT */
748  /* write all samples of current input channel to FFT input array */
749  fft_in[j].re = src[j * in_channels + i];
750  }
751 
752  /* transform input signal of current channel to frequency domain */
753  av_fft_permute(fft, fft_in);
754  av_fft_calc(fft, fft_in);
755  for (j = 0; j < n_fft; j++) {
756  const FFTComplex *hcomplex = hrtf_offset + j;
757  const float re = fft_in[j].re;
758  const float im = fft_in[j].im;
759 
760  /* complex multiplication of input signal and HRTFs */
761  /* output channel (real): */
762  fft_in[j].re = re * hcomplex->re - im * hcomplex->im;
763  /* output channel (imag): */
764  fft_in[j].im = re * hcomplex->im + im * hcomplex->re;
765  }
766 
767  /* transform output signal of current channel back to time domain */
768  av_fft_permute(ifft, fft_in);
769  av_fft_calc(ifft, fft_in);
770 
771  for (j = 0; j < in->nb_samples; j++) {
772  /* write output signal of current channel to output buffer */
773  dst[2 * j] += fft_in[j].re * fft_scale;
774  }
775 
776  for (j = 0; j < n_samples - 1; j++) { /* overflow length is IR length - 1 */
777  /* write the rest of output signal to overflow buffer */
778  int write_pos = (wr + j) & modulo;
779 
780  *(ringbuffer + write_pos) += fft_in[in->nb_samples + j].re * fft_scale;
781  }
782  }
783 
784  /* go through all samples of current output buffer: count clippings */
785  for (i = 0; i < out->nb_samples; i++) {
786  /* clippings counter */
787  if (fabs(*dst) > 1) { /* if current output sample > 1 */
788  n_clippings[0]++;
789  }
790 
791  /* move output buffer pointer by +2 to get to next sample of processed channel: */
792  dst += 2;
793  }
794 
795  /* remember read/write position in ringbuffer for next call */
796  *write = wr;
797 
798  return 0;
799 }
800 
801 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
802 {
803  AVFilterContext *ctx = inlink->dst;
804  SOFAlizerContext *s = ctx->priv;
805  AVFilterLink *outlink = ctx->outputs[0];
806  int n_clippings[2] = { 0 };
807  ThreadData td;
808  AVFrame *out;
809 
810  out = ff_get_audio_buffer(outlink, in->nb_samples);
811  if (!out) {
812  av_frame_free(&in);
813  return AVERROR(ENOMEM);
814  }
815  av_frame_copy_props(out, in);
816 
817  td.in = in; td.out = out; td.write = s->write;
818  td.delay = s->delay; td.ir = s->data_ir; td.n_clippings = n_clippings;
819  td.ringbuffer = s->ringbuffer; td.temp_src = s->temp_src;
820  td.temp_fft = s->temp_fft;
821 
822  if (s->type == TIME_DOMAIN) {
823  ctx->internal->execute(ctx, sofalizer_convolute, &td, NULL, 2);
824  } else {
825  ctx->internal->execute(ctx, sofalizer_fast_convolute, &td, NULL, 2);
826  }
827  emms_c();
828 
829  /* display error message if clipping occurred */
830  if (n_clippings[0] + n_clippings[1] > 0) {
831  av_log(ctx, AV_LOG_WARNING, "%d of %d samples clipped. Please reduce gain.\n",
832  n_clippings[0] + n_clippings[1], out->nb_samples * 2);
833  }
834 
835  av_frame_free(&in);
836  return ff_filter_frame(outlink, out);
837 }
838 
840 {
841  struct SOFAlizerContext *s = ctx->priv;
844  int ret, sample_rates[] = { 48000, -1 };
845 
846  ret = ff_add_format(&formats, AV_SAMPLE_FMT_FLT);
847  if (ret)
848  return ret;
849  ret = ff_set_common_formats(ctx, formats);
850  if (ret)
851  return ret;
852 
853  layouts = ff_all_channel_layouts();
854  if (!layouts)
855  return AVERROR(ENOMEM);
856 
857  ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->out_channel_layouts);
858  if (ret)
859  return ret;
860 
861  layouts = NULL;
863  if (ret)
864  return ret;
865 
866  ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
867  if (ret)
868  return ret;
869 
870  sample_rates[0] = s->sample_rate;
871  formats = ff_make_format_list(sample_rates);
872  if (!formats)
873  return AVERROR(ENOMEM);
874  return ff_set_common_samplerates(ctx, formats);
875 }
876 
877 static int load_data(AVFilterContext *ctx, int azim, int elev, float radius)
878 {
879  struct SOFAlizerContext *s = ctx->priv;
880  const int n_samples = s->sofa.n_samples;
881  int n_conv = s->n_conv; /* no. channels to convolve */
882  int n_fft = s->n_fft;
883  int delay_l[16]; /* broadband delay for each IR */
884  int delay_r[16];
885  int nb_input_channels = ctx->inputs[0]->channels; /* no. input channels */
886  float gain_lin = expf((s->gain - 3 * nb_input_channels) / 20 * M_LN10); /* gain - 3dB/channel */
887  FFTComplex *data_hrtf_l = NULL;
888  FFTComplex *data_hrtf_r = NULL;
889  FFTComplex *fft_in_l = NULL;
890  FFTComplex *fft_in_r = NULL;
891  float *data_ir_l = NULL;
892  float *data_ir_r = NULL;
893  int offset = 0; /* used for faster pointer arithmetics in for-loop */
894  int m[16]; /* measurement index m of IR closest to required source positions */
895  int i, j, azim_orig = azim, elev_orig = elev;
896 
897  if (!s->sofa.ncid) { /* if an invalid SOFA file has been selected */
898  av_log(ctx, AV_LOG_ERROR, "Selected SOFA file is invalid. Please select valid SOFA file.\n");
899  return AVERROR_INVALIDDATA;
900  }
901 
902  if (s->type == TIME_DOMAIN) {
903  s->temp_src[0] = av_calloc(FFALIGN(n_samples, 16), sizeof(float));
904  s->temp_src[1] = av_calloc(FFALIGN(n_samples, 16), sizeof(float));
905 
906  /* get temporary IR for L and R channel */
907  data_ir_l = av_calloc(n_conv * FFALIGN(n_samples, 16), sizeof(*data_ir_l));
908  data_ir_r = av_calloc(n_conv * FFALIGN(n_samples, 16), sizeof(*data_ir_r));
909  if (!data_ir_r || !data_ir_l || !s->temp_src[0] || !s->temp_src[1]) {
910  av_free(data_ir_l);
911  av_free(data_ir_r);
912  return AVERROR(ENOMEM);
913  }
914  } else {
915  /* get temporary HRTF memory for L and R channel */
916  data_hrtf_l = av_malloc_array(n_fft, sizeof(*data_hrtf_l) * n_conv);
917  data_hrtf_r = av_malloc_array(n_fft, sizeof(*data_hrtf_r) * n_conv);
918  if (!data_hrtf_r || !data_hrtf_l) {
919  av_free(data_hrtf_l);
920  av_free(data_hrtf_r);
921  return AVERROR(ENOMEM);
922  }
923  }
924 
925  for (i = 0; i < s->n_conv; i++) {
926  /* load and store IRs and corresponding delays */
927  azim = (int)(s->speaker_azim[i] + azim_orig) % 360;
928  elev = (int)(s->speaker_elev[i] + elev_orig) % 90;
929  /* get id of IR closest to desired position */
930  m[i] = find_m(s, azim, elev, radius);
931 
932  /* load the delays associated with the current IRs */
933  delay_l[i] = *(s->sofa.data_delay + 2 * m[i]);
934  delay_r[i] = *(s->sofa.data_delay + 2 * m[i] + 1);
935 
936  if (s->type == TIME_DOMAIN) {
937  offset = i * FFALIGN(n_samples, 16); /* no. samples already written */
938  for (j = 0; j < n_samples; j++) {
939  /* load reversed IRs of the specified source position
940  * sample-by-sample for left and right ear; and apply gain */
941  *(data_ir_l + offset + j) = /* left channel */
942  *(s->sofa.data_ir + 2 * m[i] * n_samples + n_samples - 1 - j) * gain_lin;
943  *(data_ir_r + offset + j) = /* right channel */
944  *(s->sofa.data_ir + 2 * m[i] * n_samples + n_samples - 1 - j + n_samples) * gain_lin;
945  }
946  } else {
947  fft_in_l = av_calloc(n_fft, sizeof(*fft_in_l));
948  fft_in_r = av_calloc(n_fft, sizeof(*fft_in_r));
949  if (!fft_in_l || !fft_in_r) {
950  av_free(data_hrtf_l);
951  av_free(data_hrtf_r);
952  av_free(fft_in_l);
953  av_free(fft_in_r);
954  return AVERROR(ENOMEM);
955  }
956 
957  offset = i * n_fft; /* no. samples already written */
958  for (j = 0; j < n_samples; j++) {
959  /* load non-reversed IRs of the specified source position
960  * sample-by-sample and apply gain,
961  * L channel is loaded to real part, R channel to imag part,
962  * IRs ared shifted by L and R delay */
963  fft_in_l[delay_l[i] + j].re = /* left channel */
964  *(s->sofa.data_ir + 2 * m[i] * n_samples + j) * gain_lin;
965  fft_in_r[delay_r[i] + j].re = /* right channel */
966  *(s->sofa.data_ir + (2 * m[i] + 1) * n_samples + j) * gain_lin;
967  }
968 
969  /* actually transform to frequency domain (IRs -> HRTFs) */
970  av_fft_permute(s->fft[0], fft_in_l);
971  av_fft_calc(s->fft[0], fft_in_l);
972  memcpy(data_hrtf_l + offset, fft_in_l, n_fft * sizeof(*fft_in_l));
973  av_fft_permute(s->fft[0], fft_in_r);
974  av_fft_calc(s->fft[0], fft_in_r);
975  memcpy(data_hrtf_r + offset, fft_in_r, n_fft * sizeof(*fft_in_r));
976  }
977 
978  av_log(ctx, AV_LOG_DEBUG, "Index: %d, Azimuth: %f, Elevation: %f, Radius: %f of SOFA file.\n",
979  m[i], *(s->sofa.sp_a + m[i]), *(s->sofa.sp_e + m[i]), *(s->sofa.sp_r + m[i]));
980  }
981 
982  if (s->type == TIME_DOMAIN) {
983  /* copy IRs and delays to allocated memory in the SOFAlizerContext struct: */
984  memcpy(s->data_ir[0], data_ir_l, sizeof(float) * n_conv * FFALIGN(n_samples, 16));
985  memcpy(s->data_ir[1], data_ir_r, sizeof(float) * n_conv * FFALIGN(n_samples, 16));
986 
987  av_freep(&data_ir_l); /* free temporary IR memory */
988  av_freep(&data_ir_r);
989  } else {
990  s->data_hrtf[0] = av_malloc_array(n_fft * s->n_conv, sizeof(FFTComplex));
991  s->data_hrtf[1] = av_malloc_array(n_fft * s->n_conv, sizeof(FFTComplex));
992  if (!s->data_hrtf[0] || !s->data_hrtf[1]) {
993  av_freep(&data_hrtf_l);
994  av_freep(&data_hrtf_r);
995  av_freep(&fft_in_l);
996  av_freep(&fft_in_r);
997  return AVERROR(ENOMEM); /* memory allocation failed */
998  }
999 
1000  memcpy(s->data_hrtf[0], data_hrtf_l, /* copy HRTF data to */
1001  sizeof(FFTComplex) * n_conv * n_fft); /* filter struct */
1002  memcpy(s->data_hrtf[1], data_hrtf_r,
1003  sizeof(FFTComplex) * n_conv * n_fft);
1004 
1005  av_freep(&data_hrtf_l); /* free temporary HRTF memory */
1006  av_freep(&data_hrtf_r);
1007 
1008  av_freep(&fft_in_l); /* free temporary FFT memory */
1009  av_freep(&fft_in_r);
1010  }
1011 
1012  memcpy(s->delay[0], &delay_l[0], sizeof(int) * s->n_conv);
1013  memcpy(s->delay[1], &delay_r[0], sizeof(int) * s->n_conv);
1014 
1015  return 0;
1016 }
1017 
1019 {
1020  SOFAlizerContext *s = ctx->priv;
1021  int ret;
1022 
1023  if (!s->filename) {
1024  av_log(ctx, AV_LOG_ERROR, "Valid SOFA filename must be set.\n");
1025  return AVERROR(EINVAL);
1026  }
1027 
1028  /* load SOFA file, */
1029  /* initialize file IDs to 0 before attempting to load SOFA files,
1030  * this assures that in case of error, only the memory of already
1031  * loaded files is free'd */
1032  s->sofa.ncid = 0;
1033  ret = load_sofa(ctx, s->filename, &s->sample_rate);
1034  if (ret) {
1035  /* file loading error */
1036  av_log(ctx, AV_LOG_ERROR, "Error while loading SOFA file: '%s'\n", s->filename);
1037  } else { /* no file loading error, resampling not required */
1038  av_log(ctx, AV_LOG_DEBUG, "File '%s' loaded.\n", s->filename);
1039  }
1040 
1041  if (ret) {
1042  av_log(ctx, AV_LOG_ERROR, "No valid SOFA file could be loaded. Please specify valid SOFA file.\n");
1043  return ret;
1044  }
1045 
1046  s->fdsp = avpriv_float_dsp_alloc(0);
1047  if (!s->fdsp)
1048  return AVERROR(ENOMEM);
1049 
1050  return 0;
1051 }
1052 
1053 static int config_input(AVFilterLink *inlink)
1054 {
1055  AVFilterContext *ctx = inlink->dst;
1056  SOFAlizerContext *s = ctx->priv;
1057  int nb_input_channels = inlink->channels; /* no. input channels */
1058  int n_max_ir = 0;
1059  int n_current;
1060  int n_max = 0;
1061  int ret;
1062 
1063  if (s->type == FREQUENCY_DOMAIN) {
1064  inlink->partial_buf_size =
1065  inlink->min_samples =
1066  inlink->max_samples = inlink->sample_rate;
1067  }
1068 
1069  /* gain -3 dB per channel, -6 dB to get LFE on a similar level */
1070  s->gain_lfe = expf((s->gain - 3 * inlink->channels - 6) / 20 * M_LN10);
1071 
1072  s->n_conv = nb_input_channels;
1073 
1074  /* get size of ringbuffer (longest IR plus max. delay) */
1075  /* then choose next power of 2 for performance optimization */
1076  n_current = s->sofa.n_samples + max_delay(&s->sofa);
1077  if (n_current > n_max) {
1078  /* length of longest IR plus max. delay (in all SOFA files) */
1079  n_max = n_current;
1080  /* length of longest IR (without delay, in all SOFA files) */
1081  n_max_ir = s->sofa.n_samples;
1082  }
1083  /* buffer length is longest IR plus max. delay -> next power of 2
1084  (32 - count leading zeros gives required exponent) */
1085  s->buffer_length = 1 << (32 - ff_clz(n_max));
1086  s->n_fft = 1 << (32 - ff_clz(n_max + inlink->sample_rate));
1087 
1088  if (s->type == FREQUENCY_DOMAIN) {
1089  av_fft_end(s->fft[0]);
1090  av_fft_end(s->fft[1]);
1091  s->fft[0] = av_fft_init(log2(s->n_fft), 0);
1092  s->fft[1] = av_fft_init(log2(s->n_fft), 0);
1093  av_fft_end(s->ifft[0]);
1094  av_fft_end(s->ifft[1]);
1095  s->ifft[0] = av_fft_init(log2(s->n_fft), 1);
1096  s->ifft[1] = av_fft_init(log2(s->n_fft), 1);
1097 
1098  if (!s->fft[0] || !s->fft[1] || !s->ifft[0] || !s->ifft[1]) {
1099  av_log(ctx, AV_LOG_ERROR, "Unable to create FFT contexts of size %d.\n", s->n_fft);
1100  return AVERROR(ENOMEM);
1101  }
1102  }
1103 
1104  /* Allocate memory for the impulse responses, delays and the ringbuffers */
1105  /* size: (longest IR) * (number of channels to convolute) */
1106  s->data_ir[0] = av_calloc(FFALIGN(n_max_ir, 16), sizeof(float) * s->n_conv);
1107  s->data_ir[1] = av_calloc(FFALIGN(n_max_ir, 16), sizeof(float) * s->n_conv);
1108  /* length: number of channels to convolute */
1109  s->delay[0] = av_malloc_array(s->n_conv, sizeof(float));
1110  s->delay[1] = av_malloc_array(s->n_conv, sizeof(float));
1111  /* length: (buffer length) * (number of input channels),
1112  * OR: buffer length (if frequency domain processing)
1113  * calloc zero-initializes the buffer */
1114 
1115  if (s->type == TIME_DOMAIN) {
1116  s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
1117  s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels);
1118  } else {
1119  s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float));
1120  s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float));
1121  s->temp_fft[0] = av_malloc_array(s->n_fft, sizeof(FFTComplex));
1122  s->temp_fft[1] = av_malloc_array(s->n_fft, sizeof(FFTComplex));
1123  if (!s->temp_fft[0] || !s->temp_fft[1])
1124  return AVERROR(ENOMEM);
1125  }
1126 
1127  /* length: number of channels to convolute */
1128  s->speaker_azim = av_calloc(s->n_conv, sizeof(*s->speaker_azim));
1129  s->speaker_elev = av_calloc(s->n_conv, sizeof(*s->speaker_elev));
1130 
1131  /* memory allocation failed: */
1132  if (!s->data_ir[0] || !s->data_ir[1] || !s->delay[1] ||
1133  !s->delay[0] || !s->ringbuffer[0] || !s->ringbuffer[1] ||
1134  !s->speaker_azim || !s->speaker_elev)
1135  return AVERROR(ENOMEM);
1136 
1137  compensate_volume(ctx);
1138 
1139  /* get speaker positions */
1140  if ((ret = get_speaker_pos(ctx, s->speaker_azim, s->speaker_elev)) < 0) {
1141  av_log(ctx, AV_LOG_ERROR, "Couldn't get speaker positions. Input channel configuration not supported.\n");
1142  return ret;
1143  }
1144 
1145  /* load IRs to data_ir[0] and data_ir[1] for required directions */
1146  if ((ret = load_data(ctx, s->rotation, s->elevation, s->radius)) < 0)
1147  return ret;
1148 
1149  av_log(ctx, AV_LOG_DEBUG, "Samplerate: %d Channels to convolute: %d, Length of ringbuffer: %d x %d\n",
1150  inlink->sample_rate, s->n_conv, nb_input_channels, s->buffer_length);
1151 
1152  return 0;
1153 }
1154 
1156 {
1157  SOFAlizerContext *s = ctx->priv;
1158 
1159  if (s->sofa.ncid) {
1160  av_freep(&s->sofa.sp_a);
1161  av_freep(&s->sofa.sp_e);
1162  av_freep(&s->sofa.sp_r);
1163  av_freep(&s->sofa.data_delay);
1164  av_freep(&s->sofa.data_ir);
1165  }
1166  av_fft_end(s->ifft[0]);
1167  av_fft_end(s->ifft[1]);
1168  av_fft_end(s->fft[0]);
1169  av_fft_end(s->fft[1]);
1170  av_freep(&s->delay[0]);
1171  av_freep(&s->delay[1]);
1172  av_freep(&s->data_ir[0]);
1173  av_freep(&s->data_ir[1]);
1174  av_freep(&s->ringbuffer[0]);
1175  av_freep(&s->ringbuffer[1]);
1176  av_freep(&s->speaker_azim);
1177  av_freep(&s->speaker_elev);
1178  av_freep(&s->temp_src[0]);
1179  av_freep(&s->temp_src[1]);
1180  av_freep(&s->temp_fft[0]);
1181  av_freep(&s->temp_fft[1]);
1182  av_freep(&s->data_hrtf[0]);
1183  av_freep(&s->data_hrtf[1]);
1184  av_freep(&s->fdsp);
1185 }
1186 
1187 #define OFFSET(x) offsetof(SOFAlizerContext, x)
1188 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
1189 
1190 static const AVOption sofalizer_options[] = {
1191  { "sofa", "sofa filename", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1192  { "gain", "set gain in dB", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl=0}, -20, 40, .flags = FLAGS },
1193  { "rotation", "set rotation" , OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl=0}, -360, 360, .flags = FLAGS },
1194  { "elevation", "set elevation", OFFSET(elevation), AV_OPT_TYPE_FLOAT, {.dbl=0}, -90, 90, .flags = FLAGS },
1195  { "radius", "set radius", OFFSET(radius), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 3, .flags = FLAGS },
1196  { "type", "set processing", OFFSET(type), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags = FLAGS, "type" },
1197  { "time", "time domain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, .flags = FLAGS, "type" },
1198  { "freq", "frequency domain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, .flags = FLAGS, "type" },
1199  { "speakers", "set speaker custom positions", OFFSET(speakers_pos), AV_OPT_TYPE_STRING, {.str=0}, 0, 0, .flags = FLAGS },
1200  { NULL }
1201 };
1202 
1203 AVFILTER_DEFINE_CLASS(sofalizer);
1204 
1205 static const AVFilterPad inputs[] = {
1206  {
1207  .name = "default",
1208  .type = AVMEDIA_TYPE_AUDIO,
1209  .config_props = config_input,
1210  .filter_frame = filter_frame,
1211  },
1212  { NULL }
1213 };
1214 
1215 static const AVFilterPad outputs[] = {
1216  {
1217  .name = "default",
1218  .type = AVMEDIA_TYPE_AUDIO,
1219  },
1220  { NULL }
1221 };
1222 
1224  .name = "sofalizer",
1225  .description = NULL_IF_CONFIG_SMALL("SOFAlizer (Spatially Oriented Format for Acoustics)."),
1226  .priv_size = sizeof(SOFAlizerContext),
1227  .priv_class = &sofalizer_class,
1228  .init = init,
1229  .uninit = uninit,
1231  .inputs = inputs,
1232  .outputs = outputs,
1234 };
static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: af_sofalizer.c:683
#define NULL
Definition: coverity.c:32
FFTComplex * data_hrtf[2]
Definition: af_sofalizer.c:104
const char * s
Definition: avisynth_c.h:768
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
AVFrame * out
Definition: af_sofalizer.c:587
This structure describes decoded (raw) audio or video data.
Definition: frame.h:187
#define AV_CH_TOP_FRONT_RIGHT
AVOption.
Definition: opt.h:246
av_cold void av_fft_end(FFTContext *s)
Definition: avfft.c:48
float re
Definition: fft.c:82
#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:591
AVFILTER_DEFINE_CLASS(sofalizer)
#define AV_CH_TOP_FRONT_LEFT
FFTContext * fft[2]
Definition: af_sofalizer.c:103
#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
#define AV_CH_SURROUND_DIRECT_RIGHT
#define AV_CH_LAYOUT_STEREO
AVFilter ff_af_sofalizer
#define src
Definition: vp8dsp.c:254
#define log2(x)
Definition: libm.h:404
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:230
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:60
uint64_t av_get_channel_layout(const char *name)
Return a channel layout id that matches name, or 0 if no match is found.
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:331
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:1125
AVFrame * in
Definition: af_sofalizer.c:587
#define AV_CH_WIDE_LEFT
uint8_t
#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:593
#define AV_CH_WIDE_RIGHT
#define AV_CH_TOP_BACK_CENTER
#define AV_CH_LOW_FREQUENCY
#define FLAGS
static int flags
Definition: log.c:57
#define AV_CH_BACK_LEFT
static int find_m(SOFAlizerContext *s, int azim, int elev, float radius)
Definition: af_sofalizer.c:521
#define FFALIGN(x, a)
Definition: macros.h:48
#define av_log(a,...)
float * data_ir
Definition: af_sofalizer.c:54
A filter pad used for either input or output.
Definition: internal.h:54
#define expf(x)
Definition: libm.h:283
AVFloatDSPContext * fdsp
Definition: af_sofalizer.c:106
static int load_data(AVFilterContext *ctx, int azim, int elev, float radius)
Definition: af_sofalizer.c:877
#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:594
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:86
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:434
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: af_sofalizer.c:801
#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:163
static int query_formats(AVFilterContext *ctx)
Definition: af_sofalizer.c:839
static int close_sofa(struct NCSofa *sofa)
Definition: af_sofalizer.c:109
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:179
float * sp_e
Definition: af_sofalizer.c:51
void * priv
private data for use by the filter
Definition: avfilter.h:338
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:116
#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:592
float * data_ir[2]
Definition: af_sofalizer.c:89
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:509
#define FFMAX(a, b)
Definition: common.h:94
int * data_delay
Definition: af_sofalizer.c:48
#define AV_CH_STEREO_RIGHT
See AV_CH_STEREO_LEFT.
#define AV_CH_TOP_CENTER
float * ringbuffer[2]
Definition: af_sofalizer.c:79
float * speaker_azim
Definition: af_sofalizer.c:70
Definition: fft.h:88
audio channel layout utility functions
#define FFMIN(a, b)
Definition: common.h:96
#define ff_clz
Definition: intmath.h:142
AVS_Value args
Definition: avisynth_c.h:699
AVFormatContext * ctx
Definition: movenc.c:48
#define TIME_DOMAIN
Definition: af_sofalizer.c:41
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:122
int n_samples
Definition: af_sofalizer.c:46
static const AVFilterPad outputs[]
static void error(const char *err)
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
static const AVOption sofalizer_options[]
sample_rate
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:237
FFT functions.
static int config_input(AVFilterLink *inlink)
float * sp_a
Definition: af_sofalizer.c:50
#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
void * buf
Definition: avisynth_c.h:690
int ** delay
Definition: af_sofalizer.c:589
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:144
int m_dim
Definition: af_sofalizer.c:47
int ncid
Definition: af_sofalizer.c:45
float im
Definition: fft.c:82
const char * name
Filter name.
Definition: avfilter.h:148
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:71
static const AVFilterPad inputs[]
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:335
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:434
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:363
#define AV_CH_BACK_CENTER
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:201
#define AV_CH_SIDE_RIGHT
static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: af_sofalizer.c:597
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok()...
Definition: avstring.c:184
#define M_LN10
Definition: mathematics.h:43
FFTContext * ifft[2]
Definition: af_sofalizer.c:103
int
static int parse_channel_name(char **arg, int *rchannel, char *buf)
Definition: af_sofalizer.c:376
float * sp_r
Definition: af_sofalizer.c:52
static void fft(const int32_t in[2 *256], cplx32 out[256])
Definition: dcaenc.c:347
sample_rates
FFTSample im
Definition: avfft.h:38
#define FREQUENCY_DOMAIN
Definition: af_sofalizer.c:42
uint8_t pi<< 24) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8,(uint64_t)((*(constuint8_t *) pi-0x80U))<< 56) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8,(*(constuint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8,(*(constuint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16,(*(constint16_t *) pi >>8)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16,(uint64_t)(*(constint16_t *) pi)<< 48) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16,*(constint16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16,*(constint16_t *) pi *(1.0/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32,(*(constint32_t *) pi >>24)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32,(uint64_t)(*(constint32_t *) pi)<< 32) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32,*(constint32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32,*(constint32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S64,(*(constint64_t *) pi >>56)+0x80) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S64,*(constint64_t *) pi *(1.0f/(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S64,*(constint64_t *) pi *(1.0/(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8(lrintf(*(constfloat *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16(lrintf(*(constfloat *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(constfloat *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(constfloat *) pi *(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8(lrint(*(constdouble *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16(lrint(*(constdouble *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(constdouble *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(constdouble *) pi *(INT64_C(1)<< 63)))#defineFMT_PAIR_FUNC(out, in) staticconv_func_type *constfmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB *AV_SAMPLE_FMT_NB]={FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64),};staticvoidcpy1(uint8_t **dst, constuint8_t **src, intlen){memcpy(*dst,*src, len);}staticvoidcpy2(uint8_t **dst, constuint8_t **src, intlen){memcpy(*dst,*src, 2 *len);}staticvoidcpy4(uint8_t **dst, constuint8_t **src, intlen){memcpy(*dst,*src, 4 *len);}staticvoidcpy8(uint8_t **dst, constuint8_t **src, intlen){memcpy(*dst,*src, 8 *len);}AudioConvert *swri_audio_convert_alloc(enumAVSampleFormatout_fmt, enumAVSampleFormatin_fmt, intchannels, constint *ch_map, intflags){AudioConvert *ctx;conv_func_type *f=fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt)+AV_SAMPLE_FMT_NB *av_get_packed_sample_fmt(in_fmt)];if(!f) returnNULL;ctx=av_mallocz(sizeof(*ctx));if(!ctx) returnNULL;if(channels==1){in_fmt=av_get_planar_sample_fmt(in_fmt);out_fmt=av_get_planar_sample_fmt(out_fmt);}ctx->channels=channels;ctx->conv_f=f;ctx->ch_map=ch_map;if(in_fmt==AV_SAMPLE_FMT_U8||in_fmt==AV_SAMPLE_FMT_U8P) memset(ctx->silence, 0x80, sizeof(ctx->silence));if(out_fmt==in_fmt &&!ch_map){switch(av_get_bytes_per_sample(in_fmt)){case1:ctx->simd_f=cpy1;break;case2:ctx->simd_f=cpy2;break;case4:ctx->simd_f=cpy4;break;case8:ctx->simd_f=cpy8;break;}}if(HAVE_YASM &&1) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels);if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels);if(ARCH_AARCH64) swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels);returnctx;}voidswri_audio_convert_free(AudioConvert **ctx){av_freep(ctx);}intswri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, intlen){intch;intoff=0;constintos=(out->planar?1:out->ch_count)*out->bps;unsignedmisaligned=0;av_assert0(ctx->channels==out->ch_count);if(ctx->in_simd_align_mask){intplanes=in->planar?in->ch_count:1;unsignedm=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) in->ch[ch];misaligned|=m &ctx->in_simd_align_mask;}if(ctx->out_simd_align_mask){intplanes=out->planar?out->ch_count:1;unsignedm=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) out->ch[ch];misaligned|=m &ctx->out_simd_align_mask;}if(ctx->simd_f &&!ctx->ch_map &&!misaligned){off=len &~15;av_assert1(off >=0);av_assert1(off<=len);av_assert2(ctx->channels==SWR_CH_MAX||!in->ch[ctx->channels]);if(off >0){if(out->planar==in->planar){intplanes=out->planar?out->ch_count:1;for(ch=0;ch< planes;ch++){ctx->simd_f(out-> ch ch
Definition: audioconvert.c:56
avfilter_execute_func * execute
Definition: internal.h:155
static av_cold int init(AVFilterContext *ctx)
#define av_free(p)
int len
static void parse_speaker_pos(AVFilterContext *ctx, int64_t in_channel_layout)
Definition: af_sofalizer.c:401
float * temp_src[2]
Definition: af_sofalizer.c:91
A list of supported formats for one end of a filter link.
Definition: formats.h:64
uint64_t layout
#define AV_CH_SURROUND_DIRECT_LEFT
An instance of a filter.
Definition: avfilter.h:323
#define AV_CH_FRONT_RIGHT
VirtualSpeaker vspkrpos[64]
Definition: af_sofalizer.c:101
FILE * out
Definition: movenc.c:54
static int compensate_volume(AVFilterContext *ctx)
Definition: af_sofalizer.c:549
float ** ir
Definition: af_sofalizer.c:590
#define av_freep(p)
#define OFFSET(x)
#define av_malloc_array(a, b)
formats
Definition: signature.h:48
#define AV_CH_SIDE_LEFT
internal API functions
FFTComplex * temp_fft[2]
Definition: af_sofalizer.c:92
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:244
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:596
GLuint buffer
Definition: opengl_enc.c:102
#define AV_CH_BACK_RIGHT
#define AV_CH_STEREO_LEFT
Stereo downmix.