44#define FREQUENCY_DOMAIN 1
126 mysofa_lookup_free(sofa->
lookup);
129 mysofa_free(sofa->
hrtf);
139 struct MYSOFA_HRTF *mysofa;
143 mysofa = mysofa_load(filename, &
ret);
144 s->sofa.hrtf = mysofa;
145 if (
ret || !mysofa) {
150 ret = mysofa_check(mysofa);
151 if (
ret != MYSOFA_OK) {
156 if (!mysofa->N || !mysofa->M || mysofa->DataIR.elements / mysofa->M / mysofa->R < mysofa->N ||
157 (mysofa->DataDelay.elements != mysofa->R && mysofa->DataDelay.elements / mysofa->R < mysofa->M)) {
163 mysofa_loudness(
s->sofa.hrtf);
166 mysofa_minphase(
s->sofa.hrtf, 0.01f);
168 mysofa_tocartesian(
s->sofa.hrtf);
170 s->sofa.lookup = mysofa_lookup_init(
s->sofa.hrtf);
171 if (
s->sofa.lookup ==
NULL)
175 s->sofa.neighborhood = mysofa_neighborhood_init_withstepdefine(
s->sofa.hrtf,
180 s->sofa.fir =
av_calloc(
s->sofa.hrtf->N *
s->sofa.hrtf->R,
sizeof(*
s->sofa.fir));
184 if (mysofa->DataSamplingRate.elements != 1)
187 *samplingrate = mysofa->DataSamplingRate.values[0];
188 license = mysofa_getAttribute(mysofa->attributes, (
char *)
"License");
204 if (channel_id < 0 || channel_id >= 64) {
209 *rchannel = channel_id;
213 if (channel_id < 0 || channel_id >= 64) {
217 *rchannel = channel_id;
227 char *
arg, *tokenizer, *p, *args =
av_strdup(
s->speakers_pos);
242 s->vspkrpos[out_ch_id].set = 1;
243 s->vspkrpos[out_ch_id].azim = azim;
244 s->vspkrpos[out_ch_id].elev = elev;
246 s->vspkrpos[out_ch_id].set = 1;
247 s->vspkrpos[out_ch_id].azim = azim;
248 s->vspkrpos[out_ch_id].elev = 0;
256 float *speaker_azim,
float *speaker_elev)
260 float azim[64] = { 0 };
261 float elev[64] = { 0 };
262 int ch,
n_conv =
ctx->inputs[0]->ch_layout.nb_channels;
273 for (ch = 0; ch <
n_conv; ch++) {
290 elev[ch] = 90;
break;
292 elev[ch] = 45;
break;
294 elev[ch] = 45;
break;
296 elev[ch] = 45;
break;
298 elev[ch] = 45;
break;
300 elev[ch] = 45;
break;
302 elev[ch] = 45;
break;
313 if (
s->vspkrpos[ch].set) {
314 azim[ch] =
s->vspkrpos[ch].azim;
315 elev[ch] =
s->vspkrpos[ch].elev;
345 int *write = &td->
write[jobnr];
346 const int *
const delay = td->
delay[jobnr];
347 const float *
const ir = td->
ir[jobnr];
350 float *temp_src = td->
temp_src[jobnr];
351 const int ir_samples =
s->sofa.ir_samples;
352 const int n_samples =
s->sofa.n_samples;
354 const int mult = 1 + !planar;
356 float *
dst = (
float *)
out->extended_data[jobnr * planar];
357 const int in_channels =
s->n_conv;
359 const int buffer_length =
s->buffer_length;
361 const uint32_t modulo = (uint32_t)buffer_length - 1;
370 for (l = 0; l < in_channels; l++) {
372 buffer[l] = ringbuffer + l * buffer_length;
376 const float *temp_ir = ir;
380 for (l = 0; l < in_channels; l++) {
387 for (l = 0; l < in_channels; l++) {
394 for (l = 0; l < in_channels; l++) {
395 const float *
const bptr =
buffer[l];
397 if (l ==
s->lfe_channel) {
400 dst[0] += *(
buffer[
s->lfe_channel] + wr) *
s->gain_lfe;
401 temp_ir += n_samples;
408 read = (wr - delay[l] - (ir_samples - 1) + buffer_length) & modulo;
410 if (
read + ir_samples < buffer_length) {
411 memmove(temp_src, bptr +
read, ir_samples *
sizeof(*temp_src));
415 memmove(temp_src, bptr +
read,
len *
sizeof(*temp_src));
416 memmove(temp_src +
len, bptr, (n_samples -
len) *
sizeof(*temp_src));
420 dst[0] +=
s->fdsp->scalarproduct_float(temp_ir, temp_src,
FFALIGN(ir_samples, 32));
421 temp_ir += n_samples;
431 wr = (wr + 1) & modulo;
445 int *write = &td->
write[jobnr];
449 const int ir_samples =
s->sofa.ir_samples;
451 const int mult = 1 + !planar;
452 float *
dst = (
float *)
out->extended_data[jobnr * planar];
453 const int in_channels =
s->n_conv;
455 const int buffer_length =
s->buffer_length;
457 const uint32_t modulo = (uint32_t)buffer_length - 1;
465 const int n_conv =
s->n_conv;
466 const int n_fft =
s->n_fft;
467 const float fft_scale = 1.0f /
s->n_fft;
479 for (j = 0; j < n_read; j++) {
481 dst[
mult * j] = ringbuffer[wr];
482 ringbuffer[wr] = 0.0f;
484 wr = (wr + 1) & modulo;
495 for (
i = 0;
i < n_conv;
i++) {
498 if (
i ==
s->lfe_channel) {
502 dst[2 * j] +=
src[
i + j * in_channels] *
s->gain_lfe;
507 dst[j] +=
src[j] *
s->gain_lfe;
515 hrtf_offset = hrtf +
offset;
524 fft_in[j].
re =
src[j * in_channels +
i];
530 fft_in[j].
re =
src[j];
535 tx_fn(fft, fft_out, fft_in,
sizeof(*fft_in));
537 for (j = 0; j < n_fft; j++) {
539 const float re = fft_out[j].
re;
540 const float im = fft_out[j].
im;
544 fft_acc[j].
re += re * hcomplex->
re - im * hcomplex->
im;
546 fft_acc[j].
im += re * hcomplex->
im + im * hcomplex->
re;
551 itx_fn(ifft, fft_out, fft_acc,
sizeof(*fft_acc));
555 dst[
mult * j] += fft_out[j].
re * fft_scale;
558 for (j = 0; j < ir_samples - 1; j++) {
560 int write_pos = (wr + j) & modulo;
562 *(ringbuffer + write_pos) += fft_out[in->
nb_samples + j].
re * fft_scale;
566 for (
i = 0;
i <
out->nb_samples;
i++) {
584 int n_clippings[2] = { 0 };
609 if (n_clippings[0] + n_clippings[1] > 0) {
611 n_clippings[0] + n_clippings[1],
out->nb_samples * 2);
681 float *
left,
float *right,
682 float *delay_left,
float *delay_right)
685 float c[3], delays[2];
691 c[0] = x,
c[1] = y,
c[2] = z;
692 nearest = mysofa_lookup(
s->sofa.lookup,
c);
696 if (
s->interpolate) {
697 neighbors = mysofa_neighborhood(
s->sofa.neighborhood, nearest);
698 res = mysofa_interpolate(
s->sofa.hrtf,
c,
700 s->sofa.fir, delays);
702 if (
s->sofa.hrtf->DataDelay.elements >
s->sofa.hrtf->R) {
703 delays[0] =
s->sofa.hrtf->DataDelay.values[nearest *
s->sofa.hrtf->R];
704 delays[1] =
s->sofa.hrtf->DataDelay.values[nearest *
s->sofa.hrtf->R + 1];
706 delays[0] =
s->sofa.hrtf->DataDelay.values[0];
707 delays[1] =
s->sofa.hrtf->DataDelay.values[1];
709 res =
s->sofa.hrtf->DataIR.values + nearest *
s->sofa.hrtf->N *
s->sofa.hrtf->R;
712 *delay_left = delays[0];
713 *delay_right = delays[1];
716 fr = res +
s->sofa.hrtf->N;
718 memcpy(
left, fl,
sizeof(
float) *
s->sofa.hrtf->N);
719 memcpy(right, fr,
sizeof(
float) *
s->sofa.hrtf->N);
733 int nb_input_channels =
ctx->inputs[0]->ch_layout.nb_channels;
734 float gain_lin = expf((
s->gain - 3 * nb_input_channels) / 20 *
M_LN10);
741 float *data_ir_l =
NULL;
742 float *data_ir_r =
NULL;
744 int i, j, azim_orig = azim, elev_orig = elev;
750 s->sofa.ir_samples =
s->sofa.hrtf->N;
751 s->sofa.n_samples =
FFMAX(32, 1 << (32 -
ff_clz(
s->sofa.ir_samples)));
753 n_samples =
s->sofa.n_samples;
754 ir_samples =
s->sofa.ir_samples;
757 s->data_ir[0] =
av_calloc(n_samples,
sizeof(
float) *
s->n_conv);
758 s->data_ir[1] =
av_calloc(n_samples,
sizeof(
float) *
s->n_conv);
760 if (!
s->data_ir[0] || !
s->data_ir[1]) {
769 if (!
s->delay[0] || !
s->delay[1]) {
777 if (!data_ir_r || !data_ir_l) {
783 s->temp_src[0] =
av_calloc(n_samples,
sizeof(
float));
784 s->temp_src[1] =
av_calloc(n_samples,
sizeof(
float));
785 if (!
s->temp_src[0] || !
s->temp_src[1]) {
791 s->speaker_azim =
av_calloc(
s->n_conv,
sizeof(*
s->speaker_azim));
792 s->speaker_elev =
av_calloc(
s->n_conv,
sizeof(*
s->speaker_elev));
793 if (!
s->speaker_azim || !
s->speaker_elev) {
800 av_log(
ctx,
AV_LOG_ERROR,
"Couldn't get speaker positions. Input channel configuration not supported.\n");
804 for (
i = 0;
i <
s->n_conv;
i++) {
805 float coordinates[3];
808 azim = (int)(
s->speaker_azim[
i] + azim_orig) % 360;
809 elev = (int)(
s->speaker_elev[
i] + elev_orig) % 90;
811 coordinates[0] = azim;
812 coordinates[1] = elev;
815 mysofa_s2c(coordinates);
819 data_ir_l + n_samples *
i,
820 data_ir_r + n_samples *
i,
828 s->sofa.max_delay =
FFMAX3(
s->sofa.max_delay,
s->delay[0][
i],
s->delay[1][
i]);
833 n_current = n_samples +
s->sofa.max_delay;
835 n_max =
FFMAX(n_max, n_current);
839 s->buffer_length = 1 << (32 -
ff_clz(n_max));
864 s->ringbuffer[0] =
av_calloc(
s->buffer_length,
sizeof(
float) * nb_input_channels);
865 s->ringbuffer[1] =
av_calloc(
s->buffer_length,
sizeof(
float) * nb_input_channels);
870 if (!data_hrtf_r || !data_hrtf_l) {
875 s->ringbuffer[0] =
av_calloc(
s->buffer_length,
sizeof(
float));
876 s->ringbuffer[1] =
av_calloc(
s->buffer_length,
sizeof(
float));
883 if (!
s->in_fft[0] || !
s->in_fft[1] ||
884 !
s->out_fft[0] || !
s->out_fft[1] ||
885 !
s->temp_afft[0] || !
s->temp_afft[1]) {
891 if (!
s->ringbuffer[0] || !
s->ringbuffer[1]) {
901 if (!fft_in_l || !fft_in_r ||
902 !fft_out_l || !fft_out_r) {
908 for (
i = 0;
i <
s->n_conv;
i++) {
917 for (j = 0; j < ir_samples; j++) {
920 s->data_ir[0][
offset + j] = lir[ir_samples - 1 - j] * gain_lin;
921 s->data_ir[1][
offset + j] = rir[ir_samples - 1 - j] * gain_lin;
924 memset(fft_in_l, 0,
n_fft *
sizeof(*fft_in_l));
925 memset(fft_in_r, 0,
n_fft *
sizeof(*fft_in_r));
928 for (j = 0; j < ir_samples; j++) {
933 fft_in_l[
s->delay[0][
i] + j].
re = lir[j] * gain_lin;
934 fft_in_r[
s->delay[1][
i] + j].
re = rir[j] * gain_lin;
938 s->tx_fn[0](
s->fft[0], fft_out_l, fft_in_l,
sizeof(*fft_in_l));
939 memcpy(data_hrtf_l +
offset, fft_out_l,
n_fft *
sizeof(*fft_out_l));
940 s->tx_fn[1](
s->fft[1], fft_out_r, fft_in_r,
sizeof(*fft_in_r));
941 memcpy(data_hrtf_r +
offset, fft_out_r,
n_fft *
sizeof(*fft_out_r));
948 if (!
s->data_hrtf[0] || !
s->data_hrtf[1]) {
953 memcpy(
s->data_hrtf[0], data_hrtf_l,
955 memcpy(
s->data_hrtf[1], data_hrtf_r,
1013 s->nb_samples =
s->framesize;
1024 av_log(
ctx,
AV_LOG_DEBUG,
"Samplerate: %d Channels to convolute: %d, Length of ringbuffer: %d x %d\n",
1064#define OFFSET(x) offsetof(SOFAlizerContext, x)
1065#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
1098 .p.name =
"sofalizer",
1100 .p.priv_class = &sofalizer_class,
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
static enum AVSampleFormat sample_fmts[]
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static const AVFilterPad inputs[]
static int config_input(AVFilterLink *inlink)
static int preload_sofa(AVFilterContext *ctx, char *filename, int *samplingrate)
const FFFilter ff_af_sofalizer
static int close_sofa(struct MySofa *sofa)
static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int sample_rate)
static int config_input(AVFilterLink *inlink)
static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static const AVOption sofalizer_options[]
static int get_speaker_pos(AVFilterContext *ctx, float *speaker_azim, float *speaker_elev)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static int activate(AVFilterContext *ctx)
static av_cold void uninit(AVFilterContext *ctx)
static int getfilter_float(AVFilterContext *ctx, float x, float y, float z, float *left, float *right, float *delay_left, float *delay_right)
static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static void parse_speaker_pos(AVFilterContext *ctx)
static int parse_channel_name(AVFilterContext *ctx, char **arg, int *rchannel)
static AVFormatContext * ctx
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, AVFrame **rframe)
Take samples from the link's FIFO and update the link's stats.
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
Main libavfilter public API header.
int av_sscanf(const char *string, const char *format,...)
static uint32_t BS_FUNC read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
static int BS_FUNC left(const BSCTX *bc)
Return the number of the bits left in a buffer.
#define i(width, name, range_min, range_max)
Public libavutil channel layout APIs header.
static __device__ float fabsf(float a)
static const uint16_t channel_layouts[7]
static const int sample_rates[]
int(* init)(AVBSFContext *ctx)
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
#define AV_CHANNEL_LAYOUT_STEREO
enum AVChannel av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, unsigned int idx)
Get the channel with the given index in a channel layout.
enum AVChannel av_channel_from_string(const char *str)
This is the inverse function of av_channel_name().
@ AV_CHAN_FRONT_RIGHT_OF_CENTER
@ AV_CHAN_TOP_FRONT_RIGHT
@ AV_CHAN_FRONT_LEFT_OF_CENTER
@ AV_CHAN_LOW_FREQUENCY_2
@ AV_CHAN_TOP_BACK_CENTER
@ AV_CHAN_SURROUND_DIRECT_RIGHT
@ AV_CHAN_STEREO_RIGHT
See above.
@ AV_CHAN_SURROUND_DIRECT_LEFT
@ AV_CHAN_STEREO_LEFT
Stereo downmix.
@ AV_CHAN_TOP_FRONT_CENTER
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_LOG_INFO
Standard information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
AVSampleFormat
Audio sample formats.
@ AV_SAMPLE_FMT_FLTP
float, planar
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().
static void scale(int *out, const int *in, const int w, const int h, const int shift)
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
static int16_t mult(Float11 *f1, Float11 *f2)
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
#define FF_FILTER_FORWARD_WANTED(outlink, inlink)
Forward the frame_wanted_out flag from an output link to an input link.
#define FF_FILTER_FORWARD_STATUS(inlink, outlink)
Acknowledge the status on an input link and forward it to an output link.
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
#define AVFILTER_DEFINE_CLASS(fname)
#define FILTER_QUERY_FUNC2(func)
av_cold AVFloatDSPContext * avpriv_float_dsp_alloc(int bit_exact)
Allocate a float DSP context.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
enum MovChannelLayoutTag * layouts
An AVChannelLayout holds information about the channel layout of audio data.
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
A list of supported channel layouts.
A link between two filters.
int sample_rate
samples per second
AVChannelLayout ch_layout
channel layout of current buffer (see libavutil/channel_layout.h)
AVFilterContext * dst
dest filter
A filter pad used for either input or output.
This structure describes decoded (raw) audio or video data.
int nb_samples
number of audio samples (per channel) described by this frame
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
uint8_t ** extended_data
pointers to the data planes/channels.
struct MYSOFA_NEIGHBORHOOD * neighborhood
struct MYSOFA_HRTF * hrtf
struct MYSOFA_LOOKUP * lookup
AVComplexFloat * in_fft[2]
AVComplexFloat * temp_afft[2]
AVComplexFloat * out_fft[2]
VirtualSpeaker vspkrpos[64]
AVComplexFloat * data_hrtf[2]
Used for passing data between threads.
AVComplexFloat ** out_fft
AVComplexFloat ** temp_afft
#define av_malloc_array(a, b)
static void interpolate(float *out, float v1, float v2, int size)
av_cold void av_tx_uninit(AVTXContext **ctx)
Frees a context and sets *ctx to NULL, does nothing when *ctx == NULL.
av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, int inv, int len, const void *scale, uint64_t flags)
Initialize a transform context with the given configuration (i)MDCTs with an odd length are currently...
@ AV_TX_FLOAT_FFT
Standard complex to complex FFT with sample data type of AVComplexFloat, AVComplexDouble or AVComplex...
void(* av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride)
Function pointer to a function to perform the transform.