[vlc-devel] [PATCH] audio_filter: SOFAlizer new module

Rémi Denis-Courmont remi at remlab.net
Fri Jan 30 18:10:52 CET 2015


Le vendredi 30 janvier 2015, 17:51:32 Wolfgang Hrauda a écrit :
> diff --git a/modules/audio_filter/sofalizer.c
> b/modules/audio_filter/sofalizer.c new file mode 100644
> index 0000000..2ad5c6c
> --- /dev/null
> +++ b/modules/audio_filter/sofalizer.c
> @@ -0,0 +1,1097 @@
> +/*************************************************************************
> ***** + * sofalizer.c : SOFAlizer plugin to use SOFA files in vlc
> +
> ***************************************************************************
> ** + * Copyright (C) 2013-2014 Andreas Fuchs, Wolfgang Hrauda, ARI
> + *
> + * Authors: Andreas Fuchs <andi.fuchs.mail at gmail.com>
> + *          Wolfgang Hrauda <wolfgang.hrauda at gmx.at>
> + *
> + * Project coordinator: Piotr Majdak <piotr at majdak.at>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by
> + * the Free Software Foundation; either version 2.1 of the License, or + *
> (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> +**************************************************************************
> ***/ +
> +/**************************************************************************
> *** + * Preamble
> +
> ***************************************************************************
> **/ +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <vlc_common.h>
> +#include <vlc_plugin.h>
> +#include <vlc_aout.h>
> +#include <vlc_filter.h>
> +#include <vlc_block.h>
> +#include <vlc_modules.h>
> +
> +#include <math.h>
> +#include <netcdf.h>
> +
> +#define N_SOFA 3 /* number of SOFA files loaded by the filter (for
> comparison by instant switching) */

This is arbitrary and undesirable. If you want to change the mapping at run-
time, just put a callback on the file path variable.

> +#define N_POSITIONS 4 /* number of
> virtual source positions (defined in advanced settings) */
> +
> +/**************************************************************************
> *** + * Local prototypes
> +
> ***************************************************************************
> **/ +
> +struct nc_sofa_t /* contains data of one SOFA file */
> +{
> +   int i_ncid; /* ID of the opened SOFA file (netCDF ID) */
> +   int i_n_samples; /* length of one impulse response (IR) (i.e. number of
> samples) */ +   int i_m_dim; /* length of measurements dimension (i.e.
> number of measurement positions) */ +   int *p_data_delay; /* broadband
> delay of IR, either for: each receiver or: for each receiver and each
> measurement position (delay has same time unit as the IR data) */ +   float
> *p_sp_a; /* azimuth angles of all measurement positions for each receiver
> (i.e. two ears) */ +   float *p_sp_e; /* elevation angles of all
> measurement positions for each receiver (i.e. two ears) */ +   float
> *p_sp_r; /* radii of all measurement positions for each receiver (i.e. two
> ears) */ +   float *p_data_ir; /* impulse responses at each measurement
> position for each receiver (i.e. two ears) */ +};
> +
> +struct filter_sys_t /* is one field of struct filter_t, which describes the
> filter */ +{
> +    struct nc_sofa_t sofa[N_SOFA]; /* contains data of the SOFA files */
> +
> +    /*  mutually exclusive lock */
> +    vlc_mutex_t lock; /*  avoid interference by simultaneously running
> threads */ +
> +    float *p_speaker_pos; /* positions of all loudspekaers (i.e. source
> channels) */ +
> +    int i_n_conv; /* number of channels to convolute */
> +
> +    /* buffer variables */
> +    float *p_ringbuffer_l; /* used as a buffer for the computation of the
> convolution */ +    float *p_ringbuffer_r; /* length of ringbuffer is:
> number of input channels (incl. LFE) x buffer length */ +    int i_write;
> /* counter variable for write position in ringbuffer (during convolution)
> */ +    int i_buffer_length; /* buffer length is: longest IR plus max.
> delay in all SOFA files -> next power of 2 */ +
> +    /* netCDF variables */
> +    int i_i_sofa;  /* selected SOFA file (zero-based as opposed to
> corresponding "Select" switch on GUI!) */ +    int *p_delay_l; /* broadband
> delay for each channel/IR to be convoluted */ +    int *p_delay_r;
> +    float *p_ir_l; /* IRs for all channels to be convoluted (this excludes
> the LFE) */ +    float *p_ir_r;
> +
> +    /* control variables */
> +    float f_gain; /* gain obtained from the GUI (in dB) */
> +    float f_rotation; /* rotation of the virtual loudspeakers obtained from
> the GUI (in degrees) */ +    float f_elevation; /* elevation of the virtual
> loudspeakers obtained from the GUI (in degrees) */ +    float f_radius; /*
> distance between the virtual loudspeakers and the listener (in metres) */ +
>    int i_azimuth_array[N_POSITIONS]; /* azimuth angle for each virtual
> source position (in degrees), obtained from advanced settings */ +    int
> i_elevation_array[N_POSITIONS]; /* elevation angle in degrees for each
> virtual source position (in degrees), obtained from advanced settings */ + 
>   int i_switch; /* 0 activates user's rotation and elevation settings on
> GUI, 1-4 chooses virtual source positions defined in the advanced settings
> */ +    bool b_mute; /* mutes audio output if set to true (e.g. when an
> invalid SOFA file is selected) */ +
> +    bool b_lfe; /* whether or not the LFE channel is used */
> +};
> +
> +struct t_thread_data /* contains data for audio processing of left or right
> channel, respectively */ +{
> +    filter_sys_t *p_sys; /* contains the filter data (see struct
> filter_sys_t) */ +    block_t *p_in_buf; /* contains input buffer samples
> and information (is originally passed to the DoWork function) */ +    int
> *p_input_nb; /* points to i_input_nb (number of input channels incl. LFE)
> */ +    int *p_delay; /* broadband delay for each channel/IR to be
> convoluted */ +    int i_write; /* counter variable for write position in
> ringbuffer (during convolution) */ +    int *p_n_clippings; /* points to
> i_n_clippings_l and ..._r (counts output samples equal or greather than 1)
> */ +    float *p_ringbuffer; /* ringbuffer for the computation of the
> convolution, same as one ringbuffer in struct filter_sys_t */ +    float
> *p_dest; /* points to output buffer (p_out_buf->p_buffer), samples of left
> and right channels are alternating in the memory */ +    float *p_ir; /*
> IRs for all channels to be convoluted (this excludes the LFE) */ +    float
> f_gain_lfe; /* LFE gain (obtained from the GUI, but corrected by -3dB per
> channel and -6dB), (linear, not in dB) */ +};
> +
> +struct data_findM_t /* struct used to find the impulse response (IR)
> closest to a required position */ +{
> +    filter_sys_t *p_sys; /* contains all filter data */
> +    int i_azim; /* azimuth angle of the IR to be found */
> +    int i_elev; /* elevation angle of the IR to be found */
> +    int *p_m; /* pointer to the measurement index m closest to the required
> position */ +    float f_radius; /* radius of the IR to be found */
> +};
> +
> +static int  Open ( vlc_object_t *p_this ); /* opens the filter module */
> +static void Close( vlc_object_t * ); /* closes the filter module and frees
> memory */ +static block_t *DoWork( filter_t *, block_t * ); /* audio
> processing */ +
> +static int LoadIR ( filter_t *p_filter, int i_azim, int i_elev, float
> f_radius); /* load required IRs based on current GUI settings  */ +void
> sofalizer_Convolute ( void *data ); /* actually computes convolution for
> one output channel (left or right) */ +void sofalizer_FindM ( void *data );
> /* find IR with the source position closest to a required source position
> */ +
> +#define DECLARECB(fn) static int fn (vlc_object_t *,char const *, \
> +                                     vlc_value_t, vlc_value_t, void *)
> +DECLARECB( GainCallback  ); /* declare callbacks for the GUI controls */
> +DECLARECB( RotationCallback   );
> +DECLARECB( ElevationCallback   );
> +DECLARECB( SelectCallback  );
> +DECLARECB( RadiusCallback );
> +DECLARECB( SwitchCallback );
> +
> +#undef  DECLARECB

If you don´t like forward declaration, then reorder the code, please.

> +
> +/**************************************************************************
> *** + * Module descriptor
> +
> ***************************************************************************
> **/ +
> +#define HELP_TEXT N_( "SOFAlizer creates a virtual auditory display, i.e.,
> virtual loudspeakers around the user for listening via headphones. The
> position of the virtual loudspeakers depends on the audio format of the
> input file (up to 8.1 supported). SOFAlizer filters audio channels with
> head-related transfer functions (HRTFs) stored in SOFA files
> (www.sofaconventions.org) following the SimpleFreeFieldHRIR Convention. A
> database of SOFA files can be found at www.sofacoustics.org.\nSOFAlizer is
> developed at the Acoustics Research Institute (ARI) of the Austrian Academy
> of Sciences." ) +
> +#define GAIN_VALUE_TEXT N_( "Gain [dB]" )
> +#define GAIN_VALUE_LONGTEXT N_( "Sets the gain of the module." )
> +
> +#define FILE1_NAME_TEXT N_( "SOFA file 1" )
> +#define FILE2_NAME_TEXT N_( "SOFA file 2" )
> +#define FILE3_NAME_TEXT N_( "SOFA file 3" )
> +
> +#define FILE_NAME_LONGTEXT N_( "The sampling rate of the different files
> must equal to the sampling rate of the first (loaded) file." ) +
> +#define SELECT_VALUE_TEXT N_( "Select SOFA file" )
> +#define SELECT_VALUE_LONGTEXT N_( "SOFAlizer allows to load 3 different
> SOFA files and easily switch between them for better comparison." ) +
> +#define ROTATION_VALUE_TEXT N_( "Rotation [°]" )
> +#define ROTATION_VALUE_LONGTEXT N_( "Rotates virtual loudspeakers." )
> +
> +#define ELEVATION_VALUE_TEXT N_( "Elevation [°]" )
> +#define ELEVATION_VALUE_LONGTEXT N_( "Elevates the virtual loudspeakers." )
> +
> +#define RADIUS_VALUE_TEXT N_( "Radius [m]")
> +#define RADIUS_VALUE_LONGTEXT N_( "Varies the distance between the
> loudspeakers and the listener with near-field HRTFs." ) +
> +#define SWITCH_VALUE_TEXT N_( "Switch" )
> +#define SWITCH_VALUE_LONGTEXT N_( "Presents all audio channels from one of
> four pre-defined virtual positions. Position 0 activates Rotation and
> Elevation." ) +
> +#define POS_VALUE_LONGTEXT N_( "Only active for Switch 1-4." )
> +
> +#define POS1_AZIMUTH_VALUE_TEXT N_( "Azimuth Position 1 ")
> +#define POS1_ELEVATION_VALUE_TEXT N_( "Elevation Position 1 ")
> +#define POS2_AZIMUTH_VALUE_TEXT N_( "Azimuth Position 2 ")
> +#define POS2_ELEVATION_VALUE_TEXT N_( "Elevation Position 2 ")
> +#define POS3_AZIMUTH_VALUE_TEXT N_( "Azimuth Position 3 ")
> +#define POS3_ELEVATION_VALUE_TEXT N_( "Elevation Position 3 ")
> +#define POS4_AZIMUTH_VALUE_TEXT N_( "Azimuth Position 4 ")
> +#define POS4_ELEVATION_VALUE_TEXT N_( "Elevation Position 4 ")
> +
> +vlc_module_begin ()
> +    set_description( N_("SOFAlizer") )
> +    set_shortname( N_("SOFAlizer") )
> +    set_capability( "audio filter", 0)
> +    set_help( HELP_TEXT )
> +    add_loadfile( "sofalizer-filename1", "", FILE1_NAME_TEXT,
> FILE_NAME_LONGTEXT, false) /* define advanced user settings */ +   
> add_loadfile( "sofalizer-filename2", "", FILE2_NAME_TEXT,
> FILE_NAME_LONGTEXT, false) +    add_loadfile( "sofalizer-filename3", "",
> FILE3_NAME_TEXT, FILE_NAME_LONGTEXT, false) +    add_float_with_range(
> "sofalizer-select", 1 , 1 , 3,  SELECT_VALUE_TEXT, SELECT_VALUE_LONGTEXT,
> false) +    add_float_with_range( "sofalizer-gain", 0.0, -20, 40, 
> GAIN_VALUE_TEXT, GAIN_VALUE_LONGTEXT, false ) +    add_float_with_range(
> "sofalizer-rotation", 0, -360, 360, ROTATION_VALUE_TEXT,
> ROTATION_VALUE_LONGTEXT, false ) +    add_float_with_range(
> "sofalizer-elevation", 0, -90, 90, ELEVATION_VALUE_TEXT,
> ELEVATION_VALUE_LONGTEXT, false ) +    add_float_with_range(
> "sofalizer-radius", 1, 0, 2.1,  RADIUS_VALUE_TEXT, RADIUS_VALUE_LONGTEXT,
> false ) +    add_float_with_range( "sofalizer-switch", 0, 0, 4,
> SWITCH_VALUE_TEXT, SWITCH_VALUE_LONGTEXT, false ) +   
> add_integer_with_range( "sofalizer-pos1-azi", 90, -180,
> 180,POS1_AZIMUTH_VALUE_TEXT, POS_VALUE_LONGTEXT, false ) +   
> add_integer_with_range( "sofalizer-pos1-ele", 0, -90, 90,
> POS1_ELEVATION_VALUE_TEXT, POS_VALUE_LONGTEXT, false ) +   
> add_integer_with_range( "sofalizer-pos2-azi", 180, -180, 180,
> POS2_AZIMUTH_VALUE_TEXT, POS_VALUE_LONGTEXT, false ) +   
> add_integer_with_range( "sofalizer-pos2-ele", 0, -90, 90,
> POS2_ELEVATION_VALUE_TEXT, POS_VALUE_LONGTEXT, false ) +   
> add_integer_with_range( "sofalizer-pos3-azi", -90, -180, 180,
> POS3_AZIMUTH_VALUE_TEXT, POS_VALUE_LONGTEXT, false ) +   
> add_integer_with_range( "sofalizer-pos3-ele", 0, -90, 90,
> POS3_ELEVATION_VALUE_TEXT, POS_VALUE_LONGTEXT, false ) +   
> add_integer_with_range( "sofalizer-pos4-azi", 0, -180, 180,
> POS4_AZIMUTH_VALUE_TEXT, POS_VALUE_LONGTEXT, false ) +   
> add_integer_with_range( "sofalizer-pos4-ele", 90, -90, 90,
> POS4_ELEVATION_VALUE_TEXT, POS_VALUE_LONGTEXT, false ) +    add_shortcut(
> "sofalizer" )
> +    set_category( CAT_AUDIO )
> +    set_subcategory( SUBCAT_AUDIO_AFILTER )
> +    set_callbacks( Open, Close )
> +vlc_module_end ()
> +
> +/**************************************************************************
> *** +* CloseSofa: Closes the given SOFA file and frees its allocated memory.
> +* LoadSofa: Loads the given SOFA file, check for the most important
> SOFAconventions +*     and load the whole IR Data, Source-Positions and
> Delays
> +* GetSpeakerPos: Get the Speaker Positions for current input.
> +* MaxDelay: Find the Maximum Delay in the Sofa File
> +* CompensateVolume: Compensate the Volume of the Sofa file. The Energy of
> the +*     IR closest to ( 0°, 0°, 1m ) to the left ear is calculated. +*
> FreeAllSofa: Frees Memory allocated in LoadSofa of all Sofa files +*
> FreeFilter: Frees Memory allocated in Open
> +***************************************************************************
> ***/ +
> +static int CloseSofa ( struct nc_sofa_t *sofa ) /* close given SOFA file
> and free associated memory */ +{
> +    free( sofa->p_data_delay );
> +    free( sofa->p_sp_a );
> +    free( sofa->p_sp_e );
> +    free( sofa->p_sp_r );
> +    free( sofa->p_data_ir );
> +    nc_close( sofa->i_ncid );
> +    sofa->i_ncid = 0;
> +    return VLC_SUCCESS;
> +}
> +
> +static int LoadSofa ( filter_t *p_filter, char *c_filename, int i_i_sofa ,
> int *p_samplingrate) +{
> +    struct filter_sys_t *p_sys = p_filter->p_sys;
> +    int i_ncid, i_n_dims, i_n_vars, i_n_gatts, i_n_unlim_dim_id, i_status;
> /* variables associated with content of SOFA file */ +    unsigned int
> i_samplingrate;
> +    int i_n_samples = 0;
> +    int i_m_dim = 0;
> +    p_sys->sofa[i_i_sofa].i_ncid = 0;
> +    i_status = nc_open( c_filename , NC_NOWRITE, &i_ncid); /* open SOFA
> file read-only */ +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Can't find SOFA-file '%s'", c_filename);
> +        return VLC_EGENERIC;
> +    }
> +    nc_inq(i_ncid, &i_n_dims, &i_n_vars, &i_n_gatts, &i_n_unlim_dim_id); /*
> get number of dimensions, vars, global attributes and Id of unlimited
> dimensions */ +
> +    char c_dim_names[i_n_dims][NC_MAX_NAME];   /* names of netCDF
> dimensions */ +    uint32_t i_dim_length[i_n_dims]; /* lengths of netCDF
> dimensions */ +    int i_m_dim_id = 0;
> +    int i_n_dim_id = 0;
> +    for( int ii = 0; ii<i_n_dims; ii++ ) /* go through all dimensions in
> SOFA file */ +    {
> +        nc_inq_dim( i_ncid, ii, c_dim_names[ii], &i_dim_length[ii] ); /*
> get dimensions */ +        if ( !strcmp("M", c_dim_names[ii] ) ) /* get ID
> of dimension "M" (number of measurements) */ +            i_m_dim_id = ii;
> +        if ( !strcmp("N", c_dim_names[ii] ) ) /* get ID of dimension "N"
> (number of data samples per measurement (i.e. length of one IR)) */ +      
>      i_n_dim_id = ii;
> +        else { }
> +    }
> +    i_n_samples = i_dim_length[i_n_dim_id]; /* get number of measurements
> */ +    i_m_dim =  i_dim_length[i_m_dim_id]; /* get number of data samples
> per measurement (i.e. length of one IR) */ +
> +    uint32_t i_att_len; /* get length of attritube "Conventions" */
> +    i_status = nc_inq_attlen(i_ncid, NC_GLOBAL, "Conventions", &i_att_len);
> +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Can't get Length of Attribute Conventions.");
> +        nc_close(i_ncid);
> +        return VLC_EGENERIC;
> +    }
> +
> +    char psz_conventions[i_att_len + 1]; /* check whether attritube
> "Conventions" is "SOFA" (i.e. file is a SOFA file) */ +    nc_get_att_text(
> i_ncid , NC_GLOBAL, "Conventions", psz_conventions); +    *(
> psz_conventions + i_att_len ) = 0;
> +    if ( strcmp( "SOFA" , psz_conventions ) )
> +    {
> +        msg_Err(p_filter, "Not a SOFA file!");
> +        nc_close(i_ncid);
> +        return VLC_EGENERIC;
> +    }
> +    nc_inq_attlen (i_ncid, NC_GLOBAL, "SOFAConventions", &i_att_len ); /*
> get length of and check attribute "SOFAConventions" (must be
> "SimpleFreeFieldHRIR") */ +    char psz_sofa_conventions[i_att_len + 1];
> +    nc_get_att_text(i_ncid, NC_GLOBAL, "SOFAConventions",
> psz_sofa_conventions); +    *( psz_sofa_conventions + i_att_len ) = 0;
> +    if ( strcmp( "SimpleFreeFieldHRIR" , psz_sofa_conventions ) )
> +    {
> +       msg_Err(p_filter, "No SimpleFreeFieldHRIR file!");
> +       nc_close(i_ncid);
> +       return VLC_EGENERIC;
> +    }
> +
> +    int i_samplingrate_id; /* get ID of sampling rate variable */
> +    i_status = nc_inq_varid( i_ncid, "Data.SamplingRate",
> &i_samplingrate_id); +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read variable Data.SamplingRate ID");
> +        nc_close(i_ncid);
> +        return VLC_EGENERIC;
> +    }
> +
> +    i_status = nc_get_var_uint( i_ncid, i_samplingrate_id, &i_samplingrate
> ); /* get value of sampling rate */ +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read value of Data.SamplingRate.");
> +        nc_close(i_ncid);
> +        return VLC_EGENERIC;
> +    }
> +    *p_samplingrate = i_samplingrate; /* store sampling rate in variable
> passed to the function by-reference */ +
> +    int i_data_ir_id; /* get ID of impulse responses variable */
> +    i_status = nc_inq_varid( i_ncid, "Data.IR", &i_data_ir_id);
> +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read Id of Data.IR." );
> +        return VLC_EGENERIC;
> +    }
> +
> +    /* allocate memory for one value for each measurement position; and for
> two ears, respectively in case of p_data_delay: */ +    int *p_data_delay =
> p_sys->sofa[i_i_sofa].p_data_delay = calloc ( sizeof( int ) , i_m_dim * 2
> ); +    float *p_sp_a = p_sys->sofa[i_i_sofa].p_sp_a = malloc(
> sizeof(float) * i_m_dim); +    float *p_sp_e = p_sys->sofa[i_i_sofa].p_sp_e
> = malloc( sizeof(float) * i_m_dim); +    float *p_sp_r =
> p_sys->sofa[i_i_sofa].p_sp_r = malloc( sizeof(float) * i_m_dim); +    float
> *p_data_ir = p_sys->sofa[i_i_sofa].p_data_ir = malloc( sizeof( float ) * 2
> * i_m_dim * i_n_samples ); +
> +    if ( !p_data_delay || !p_sp_a || !p_sp_e || !p_sp_r || !p_data_ir ) /*
> if memory could not be allocated */ +    {
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_ENOMEM;
> +    }
> +
> +    i_status = nc_get_var_float( i_ncid, i_data_ir_id, p_data_ir ); /* read
> and store IRs */ +    if ( i_status != NC_NOERR )
> +    {
> +        msg_Err( p_filter, "Couldn't read Data.IR!" );
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +
> +    int i_sp_id;
> +    i_status = nc_inq_varid(i_ncid, "SourcePosition", &i_sp_id); /* get ID
> of source position variable (source positions of the HRTFs in the SOFA
> file) */ +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read ID of SourcePosition");
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +
> +    i_status = nc_get_vara_float (i_ncid, i_sp_id, (uint32_t[2]){ 0 , 0 } ,
> (uint32_t[2]){ i_m_dim , 1 } , p_sp_a ); /* read & store azimuth angles of
> source positions */ +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read SourcePosition.");
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +
> +    i_status = nc_get_vara_float (i_ncid, i_sp_id, (uint32_t[2]){ 0 , 1 } ,
> (uint32_t[2]){ i_m_dim , 1 } , p_sp_e ); /* read & store elevation angles
> of source positions */ +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read SourcePosition.");
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +
> +    i_status = nc_get_vara_float (i_ncid, i_sp_id, (uint32_t[2]){ 0 , 2 } ,
> (uint32_t[2]){ i_m_dim , 1 } , p_sp_r ); /* read & store radii of source
> positions */ +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read SourcePosition.");
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +
> +    /* read Data.Delay, check for errors and fit it to p_data_delay */
> +    int i_data_delay_id;
> +    int i_data_delay_dim_id[2];
> +    char i_data_delay_dim_name[NC_MAX_NAME];
> +
> +    i_status = nc_inq_varid(i_ncid, "Data.Delay", &i_data_delay_id);
> +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read Id of Data.Delay." );
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +    i_status = nc_inq_vardimid ( i_ncid, i_data_delay_id,
> &i_data_delay_dim_id[0]); +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read Dimension Ids of Data.Delay." );
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +    i_status = nc_inq_dimname ( i_ncid, i_data_delay_dim_id[0],
> i_data_delay_dim_name ); +    if (i_status != NC_NOERR)
> +    {
> +        msg_Err(p_filter, "Couldn't read Dimension Name of Data.Delay." );
> +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +    /* Data.Delay dimension check */
> +    if ( !strncmp ( i_data_delay_dim_name, "I", 1 ) ) /* if dimension of
> Data.Delay is [I R] */ +    {
> +        msg_Dbg ( p_filter, "Data.Delay has dimension [I R]");
> +        int i_Delay[2];
> +        i_status = nc_get_var_int( i_ncid, i_data_delay_id, &i_Delay[0] );
> /* get Data.Delay from SOFA file */ +        if ( i_status != NC_NOERR )
> +        {
> +            msg_Err(p_filter, "Couldn't read Data.Delay");
> +            CloseSofa( &p_sys->sofa[i_i_sofa] );
> +            return VLC_EGENERIC;
> +        }
> +        int *p_data_delay_r = p_data_delay + i_m_dim;
> +        for ( int i = 0 ; i < i_m_dim ; i++ ) /* extend given dimension [I
> R] to [M R] */ +        { /* assign constant delay value for all
> measurements to data_delay fields */ +            *( p_data_delay + i ) =
> i_Delay[0];
> +            *( p_data_delay_r + i ) = i_Delay[1];
> +        }
> +    }
> +    else if ( strncmp ( i_data_delay_dim_name, "M", 1 ) ) /* dimension of
> Data.Delay is neither [I R] nor [M R] */ +    {
> +        msg_Err ( p_filter, "Data.Delay does not have the required
> dimensions [I R] or [M R]."); +        CloseSofa( &p_sys->sofa[i_i_sofa] );
> +        return VLC_EGENERIC;
> +    }
> +    else if ( !strncmp ( i_data_delay_dim_name, "M", 1 ) ) /* if dimension
> of Data.Delay is [M R] */ +    {
> +        msg_Dbg( p_filter, "Data.Delay in dimension [M R]");
> +        i_status = nc_get_var_int( i_ncid, i_data_delay_id, p_data_delay );
> /* get Data.Delay from SOFA file */ +        if (i_status != NC_NOERR)
> +        {
> +            msg_Err(p_filter, "Couldn't read Data.Delay");
> +            CloseSofa( &p_sys->sofa[i_i_sofa] );
> +            return VLC_EGENERIC;
> +        }
> +    }
> +    p_sys->sofa[i_i_sofa].i_m_dim = i_m_dim; /* save number of measurement
> positions in SOFA struct */ +    p_sys->sofa[i_i_sofa].i_n_samples =
> i_n_samples; /* save number of samples in one measurement (IR) in SOFA
> struct */ +    p_sys->sofa[i_i_sofa].i_ncid = i_ncid; /* save netCDF ID of
> SOFA file in SOFA struct */ +    nc_close(i_ncid); /* close SOFA file */
> +    return VLC_SUCCESS;
> +}

I don´t mind variable-sized arrays, but you need to ensure that the maximum 
size is bound to a low value. If it is controlled by the input file, VLAs are 
not acceptable.

> +
> +static int GetSpeakerPos ( filter_t *p_filter, float *p_speaker_pos )
> +{
> +    uint16_t i_physical_channels =
> p_filter->fmt_in.audio.i_physical_channels; /* get input channel
> configuration */ +    float *p_pos_temp;
> +    int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio ); /*
> get number of input channels */ +    int i_n_conv = i_input_nb;
> +    if ( i_physical_channels & AOUT_CHAN_LFE ) /* if LEF is used */
> +    {
> +        i_n_conv = i_input_nb - 1; /* decrease number of channels to be
> convolved */ +    }
> +
> +    switch ( i_physical_channels ) /* set speaker positions according to
> input channel configuration */ +    {
> +    case AOUT_CHAN_CENTER:  p_pos_temp = (float[1]){ 0 };
> +                            break;
> +    case AOUT_CHANS_STEREO:
> +    case AOUT_CHANS_2_1:    p_pos_temp = (float[2]){ 30 , 330 };
> +                            break;
> +    case AOUT_CHANS_3_0:
> +    case AOUT_CHANS_3_1:    p_pos_temp = (float[3]){ 30 , 330 , 0 };
> +                            break;
> +    case AOUT_CHANS_4_0:
> +    case AOUT_CHANS_4_1:    p_pos_temp = (float[4]){ 30 , 330 , 120 , 240
> }; +                            break;
> +    case AOUT_CHANS_5_0:
> +    case AOUT_CHANS_5_1:
> +    case ( AOUT_CHANS_5_0_MIDDLE | AOUT_CHAN_LFE ):
> +    case AOUT_CHANS_5_0_MIDDLE: p_pos_temp = (float[5]){ 30 , 330 , 120 ,
> 240 , 0 }; +                                break;
> +    case AOUT_CHANS_6_0:    p_pos_temp = (float[6]){ 30 , 330 , 90 , 270 ,
> 150 , 210 }; +                            break;
> +    case AOUT_CHANS_7_0:
> +    case AOUT_CHANS_7_1:    p_pos_temp = (float[7]){ 30 , 330 , 90 , 270 ,
> 150 , 210 , 0 }; +                            break;
> +    case AOUT_CHANS_8_1:    p_pos_temp = (float[8]){ 30 , 330 , 90 , 270 ,
> 150 , 210 , 180 , 0 }; +                            break;
> +    default: return VLC_EGENERIC;
> +             break;
> +    }
> +    memcpy( p_speaker_pos , p_pos_temp , i_n_conv * sizeof( float ) );

This is undefined behaviour, I think.

> +    return VLC_SUCCESS;
> +
> +}
> +
> +static int MaxDelay ( struct nc_sofa_t *sofa )
> +{
> +    int i_max = 0;
> +    for ( int  i = 0; i < ( sofa->i_m_dim * 2 ) ; i++ ) /* i was not
> initialized (changed on 3/12/14) */ +    {
> +        if ( *( sofa->p_data_delay + i ) > i_max ) /* search maximum delay
> in given SOFA file */ +            i_max = *( sofa->p_data_delay + i) ;
> +    }
> +    return i_max;
> +}
> +
> +static int CompensateVolume( filter_t *p_filter)
> +{
> +    struct filter_sys_t *p_sys = p_filter->p_sys;
> +    float f_energy = 0;
> +    vlc_thread_t thread_find_m;
> +    struct data_findM_t data_find_m;
> +    int i_m;
> +    int i_i_sofa_backup = p_sys->i_i_sofa;
> +    float *p_ir;
> +    float f_compensate;
> +    /* compensate volume for each SOFA file */
> +    for ( int i = 0 ; i < N_SOFA ; i++ ) /* go through all SOFA files */
> +    {
> +        if( p_sys->sofa[i].i_ncid )
> +        {
> +            /* find IR at front center position in i-th SOFA file (IR
> closest to 0°,0°,1m) */ +            struct nc_sofa_t *p_sofa =
> &p_sys->sofa[i];
> +            p_sys->i_i_sofa = i;
> +            data_find_m.p_sys = p_sys;
> +            data_find_m.i_azim = 0;
> +            data_find_m.i_elev = 0;
> +            data_find_m.f_radius = 1;
> +            data_find_m.p_m = &i_m;
> +            if ( vlc_clone( &thread_find_m, (void *)&sofalizer_FindM, (void
> *)&data_find_m, VLC_THREAD_PRIORITY_LOW ) ) {} ;
> +            vlc_join( thread_find_m , NULL );

This will crash on error, and is utterly pointless. Call FindM directly.

> +            /* get energy of that IR and compensate volume */
> +            p_ir = p_sofa->p_data_ir + 2 * i_m * p_sofa->i_n_samples;
> +            for ( int j = 0 ; j < p_sofa->i_n_samples ; j ++ )
> +            {
> +                f_energy += *( p_ir + j ) * *(p_ir + j );
> +            }
> +            f_compensate = 256 / ( p_sofa->i_n_samples * sqrt( f_energy )
> ); +            msg_Dbg( p_filter, "Compensate-factor: %f", f_compensate );
> +            p_ir = p_sofa->p_data_ir;
> +            for ( int j = 0 ; j < ( p_sofa->i_n_samples * p_sofa->i_m_dim *
> 2 ) ; j++ ) +            {
> +                *( p_ir + j ) *= f_compensate; /* apply volume compensation
> to IRs */ +            }
> +        }
> +    }
> +    p_sys->i_i_sofa = i_i_sofa_backup;
> +    return VLC_SUCCESS;
> +}
> +
> +static void FreeAllSofa ( filter_t *p_filter )
> +{
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    for ( int i = 0 ; i < N_SOFA ; i++) /* go through all SOFA files and
> free associated memory */ +    {
> +        if ( p_sys->sofa[i].i_ncid )
> +        {
> +            free ( p_sys->sofa[i].p_sp_a );
> +            free ( p_sys->sofa[i].p_sp_e );
> +            free ( p_sys->sofa[i].p_sp_r );
> +            free ( p_sys->sofa[i].p_data_delay );
> +            free ( p_sys->sofa[i].p_data_ir );
> +        }
> +    }
> +}
> +
> +static void FreeFilter( filter_t *p_filter )
> +{
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    free ( p_sys->p_delay_l );
> +    free ( p_sys->p_delay_r );
> +    free ( p_sys->p_ir_l );
> +    free ( p_sys->p_ir_r );
> +    free ( p_sys->p_ringbuffer_l );
> +    free ( p_sys->p_ringbuffer_r );
> +    free ( p_sys->p_speaker_pos );
> +    free ( p_sys );
> +}
> +
> +/**************************************************************************
> *** +* Open:
> +***************************************************************************
> ***/ +
> +static int Open( vlc_object_t *p_this )
> +{
> +    filter_t *p_filter = (filter_t *)p_this;
> +    filter_sys_t *p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
> +    if( unlikely( p_sys == NULL ) )
> +        return VLC_ENOMEM;
> +
> +    vlc_object_t *p_out = p_filter->p_parent; /* assign filter output */
> +    char *c_filename[N_SOFA];
> +    const char *psz_var_names_filename[N_SOFA] = { "sofalizer-filename1",
> "sofalizer-filename2", "sofalizer-filename3" }; +    for ( int i = 0 ; i <
> N_SOFA ; i++ )
> +    {
> +        c_filename[i] = var_CreateGetStringCommand( p_filter,
> psz_var_names_filename[i] ); /* get SOFA file names from advanced settings
> */ +    }
> +    p_sys->f_rotation   = abs ( ( - (int) var_CreateGetFloat ( p_out,
> "sofalizer-rotation" ) + 720 ) % 360 ); /* get user settings */ +   
> p_sys->i_i_sofa     = (int) (var_CreateGetFloat ( p_out, "sofalizer-select"
> ) ) - 1; +    p_sys->i_switch     = (int) ( var_CreateGetFloat ( p_out,
> "sofalizer-switch" ) ); +    p_sys->f_gain       = var_CreateGetFloat(
> p_out, "sofalizer-gain" ); +    p_sys->f_elevation  = var_CreateGetFloat(
> p_out, "sofalizer-elevation" ); +    p_sys->f_radius     =
> var_CreateGetFloat( p_out, "sofalizer-radius"); +
> +
> +    const char *psz_var_names_azimuth_array[N_POSITIONS] = {
> "sofalizer-pos1-azi" , "sofalizer-pos2-azi", "sofalizer-pos3-azi",
> "sofalizer-pos4-azi" }; +    for ( int i = 0 ; i < N_POSITIONS ; i++ ) /*
> get azimuth angles of virtual source positions from advanced settings */ + 
>   {
> +        p_sys->i_azimuth_array[i] = ( var_InheritInteger ( p_out,
> psz_var_names_azimuth_array[i] ) + 720 ) % 360 ; +    }
> +
> +    const char *psz_var_names_elevation_array[N_POSITIONS] = {
> "sofalizer-pos1-ele", "sofalizer-pos2-ele", "sofalizer-pos3-ele",
> "sofalizer-pos4-ele" }; +    for ( int i = 0 ; i < N_POSITIONS ; i++ ) /*
> get elevation angles of virtual source positions from advanced settings */
> +    {
> +        p_sys->i_elevation_array[i] = var_InheritInteger( p_out,
> psz_var_names_elevation_array[i] ) ; +    }
> +
> +    int i_samplingrate = 0;
> +    int i_samplingrate_old = 0;
> +    int b_found_valid = false;
> +    p_sys->b_mute = false ;
> +    p_sys->i_write = 0;
> +
> +    /* load SOFA files, check for sampling Rate and valid selection in the
> preferences */ +    for ( int i = 0 ; i < N_SOFA ; i++ )
> +    {
> +        if ( LoadSofa ( p_filter, c_filename[i], i , &i_samplingrate) !=
> VLC_SUCCESS ) +        {
> +            msg_Err(p_filter, "Error while loading SOFA file %d: '%s'", i +
> 1, c_filename[i] ); +        }
> +        else /* if no error occured when loading file */
> +        {
> +            msg_Dbg( p_filter , "File %d: '%s' loaded", i + 1 ,
> c_filename[i] ); +            if ( !b_found_valid ) /* if no valid SOFA
> file has been found so far -> this is the first valid SOFA file */ +       
>     {
> +                if ( p_sys->sofa[i].i_ncid ) /* if SOFA file has a valid
> netCDF ID */ +                {
> +                    i_samplingrate_old = i_samplingrate; /* remember
> sampling rate of the first valid SOFA file */ +                   
> b_found_valid = true; /* remember that a valid SOFA file has been found */
> +                }
> +            }
> +            if ( p_sys->sofa[i].i_ncid && i_samplingrate !=
> i_samplingrate_old ) +            { /* if SOFA file has valid ID but
> sampling rate is different from sampling rate of first valid SOFA file */ +
>                msg_Err ( p_filter, " SOFA file %d '%s' with different
> Sampling Rate. Discarded.", i + 1, c_filename[i] ); /* currently: discard
> SOFA file */ +                CloseSofa( &p_sys->sofa[i] ); /* note:
> discarding a SOFA file due to sampling rate should be removed; work on a
> solution is in progress */ +                p_sys->sofa[i].i_ncid = 0; /*
> set file ID to 0 */ +            }
> +        }
> +    }
> +    if ( !p_sys->sofa[p_sys->i_i_sofa].i_ncid ) /* if SOFA file selected in
> settings/GUI is not valid */ +    {
> +        b_found_valid = false;
> +        for ( int i = 0 ; i < N_SOFA ; i++) /* go through all SOFA files
> and search for an other, valid file */ +        {
> +             if ( !b_found_valid && p_sys->sofa[i].i_ncid )
> +             {
> +                p_sys->i_i_sofa = i;
> +                msg_Err ( p_filter, "Selected File from Settings invalid.
> Use File %d", i + 1 ); +                b_found_valid = true;
> +             }
> +        }
> +        if ( !b_found_valid ) /* if still valid file could be found, at all
> */ +        {
> +            msg_Err ( p_filter, "No valid file found." );
> +            FreeAllSofa( p_filter );
> +            free( p_sys );
> +            return VLC_EGENERIC;
> +        }
> +    }
> +
> +    /* set filter settings and calculate speaker positions*/
> +    p_filter->fmt_in.audio.i_rate = i_samplingrate_old;
> +    p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32 ;
> +    p_filter->fmt_out.audio = p_filter->fmt_in.audio;
> +
> +    p_filter->fmt_out.audio.i_physical_channels = AOUT_CHANS_STEREO; /*
> required for filter output set to stereo */ +   
> p_filter->fmt_out.audio.i_original_channels = AOUT_CHANS_STEREO; +
> +    int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio ); /*
> number of input channels */ +    if (
> p_filter->fmt_in.audio.i_physical_channels & AOUT_CHAN_LFE ) /* if LFE is
> used */ +    {
> +        p_sys->b_lfe = true;
> +        p_sys->i_n_conv = i_input_nb - 1 ; /* LFE is an input channel but
> requries no convolution */ +    }
> +    else /* if LFE is not used */
> +    {
> +        p_sys->b_lfe = false;
> +        p_sys->i_n_conv = i_input_nb ;
> +    }
> +
> +    /* Find the minimum size (length of impulse response plus maximal
> Delay) of the Ringbuffer as power of 2.  */ +    int i_n_max = 0;
> +    int i_n_current;
> +    int i_n_max_ir = 0;
> +    for ( int i = 0 ; i < N_SOFA ; i++ ) /* go through all SOFA files and
> determine the longest IR */ +    {
> +        if ( p_sys->sofa[i].i_ncid != 0 )
> +        {
> +            i_n_current = p_sys->sofa[i].i_n_samples + MaxDelay (
> &p_sys->sofa[i] ); +            if ( i_n_current > i_n_max )
> +            {
> +                i_n_max = i_n_current; /* length of longest IR plus maximum
> delay (in all SOFA files) */ +                i_n_max_ir =
> p_sys->sofa[i].i_n_samples; /* length of longest IR (without delay, in all
> SOFA files) */ +            }
> +        }
> +    }
> +    p_sys->i_buffer_length = pow(2, ceil(log( i_n_max )/ log(2) ) ); /*
> buffer length as power of 2 (determined from longest IR plus max. delay) */
> +
> +    /* Allocate Memory for the impulse responses, delays and the
> ringbuffers */ +    p_sys->p_ir_l = malloc( sizeof(float) * i_n_max_ir *
> p_sys->i_n_conv  ); /* size: (longest IR) * (number of channels to
> convolute), without LFE */ +    p_sys->p_ir_r = malloc( sizeof(float) *
> i_n_max_ir * p_sys->i_n_conv ); +    p_sys->p_delay_l = malloc ( sizeof(
> int ) * p_sys->i_n_conv ); /* size:  number of channels to convolute */ +  
>  p_sys->p_delay_r = malloc ( sizeof( int ) * p_sys->i_n_conv ); +   
> p_sys->p_ringbuffer_l = calloc( p_sys->i_buffer_length * i_input_nb,
> sizeof( float ) ); /* size: (buffer length) * (number of input channels) 
> */ +    p_sys->p_ringbuffer_r = calloc( p_sys->i_buffer_length *
> i_input_nb, sizeof( float ) ); +    p_sys->p_speaker_pos = malloc( sizeof(
> float) * p_sys->i_n_conv ); /* size: number of channels to convolute */ +
> +    if ( !p_sys->p_ir_l || !p_sys->p_ir_r || !p_sys->p_delay_l ||
> !p_sys->p_delay_r || !p_sys->p_ringbuffer_l || !p_sys->p_ringbuffer_r ||
> !p_sys->p_speaker_pos ) +    {
> +        FreeAllSofa( p_filter );
> +        FreeFilter( p_filter );
> +        return VLC_ENOMEM;
> +    }
> +
> +    CompensateVolume ( p_filter );
> +
> +    /* Get speaker positions and then load the impulse responses into
> p_ir_l and p_ir_r for the required directions */ +    if ( GetSpeakerPos (
> p_filter, p_sys->p_speaker_pos ) != VLC_SUCCESS ) +    {
> +        msg_Err (p_filter, "Couldn't get Speaker Positions. Input Channel
> Configuration not supported. "); +        FreeAllSofa( p_filter );
> +        FreeFilter( p_filter );
> +        return VLC_EGENERIC;
> +    }
> +    vlc_mutex_init( &p_sys->lock );
> +    if ( LoadIR ( p_filter, p_sys->f_rotation, p_sys->f_elevation,
> p_sys->f_radius ) != VLC_SUCCESS ) +    {
> +        FreeAllSofa( p_filter );
> +        FreeFilter( p_filter );
> +        return VLC_ENOMEM;
> +    }
> +
> +    msg_Dbg( p_filter, "Samplerate: %d\n Channels to convolute: %d,
> Ringbufferlength: %d x %d" ,p_filter->fmt_in.audio.i_rate  ,
> p_sys->i_n_conv, i_input_nb, (int )p_sys->i_buffer_length ); +
> +    p_filter->pf_audio_filter = DoWork; /* DoWork does the audio processing
> */ +
> +    /* Callbacks can call function LoadIR */
> +    var_AddCallback( p_out, "sofalizer-gain", GainCallback, p_filter );
> +    var_AddCallback( p_out, "sofalizer-rotation", RotationCallback,
> p_filter ); +    var_AddCallback( p_out, "sofalizer-elevation",
> ElevationCallback, p_filter ); +    var_AddCallback( p_out,
> "sofalizer-switch", SwitchCallback, p_filter ); +    var_AddCallback(
> p_out, "sofalizer-select", SelectCallback, p_filter ); +   
> var_AddCallback( p_out, "sofalizer-radius", RadiusCallback, p_filter ); +
> +    return VLC_SUCCESS;
> +}

At least some of the error paths are wrong. They are not consistent.

> +
> +/**************************************************************************
> *** +* DoWork: Prepares the data structures for the threads and starts them
> +* sofalizer_Convolute: Writes the samples of the input buffer in the
> ringbuffer +* and convolutes with the impulse response
> +***************************************************************************
> ***/ +
> +static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
> +{
> +    struct filter_sys_t *p_sys = p_filter->p_sys; /* get pointer to
> filter_t struct */ +    int i_n_clippings_l = 0; /* count output samples
> equal to or greather than 1 (i.e. clipping occurs) */ +    int
> i_n_clippings_r = 0;
> +
> +    int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio ); /*
> get number of input channels */ +    int i_output_nb =
> aout_FormatNbChannels( &p_filter->fmt_out.audio ); /* get number of output
> channels */ +
> +    /* get and prepare output buffer */
> +    size_t i_out_size = p_in_buf->i_buffer * i_output_nb / i_input_nb; /*
> output buffer size is input buffer size scaled according to number of
> in/out channels */ +    block_t *p_out_buf = block_Alloc( i_out_size ); /*
> allocate memory for output buffer */ +    if ( unlikely( !p_out_buf ) )
> +    {
> +        msg_Warn( p_filter, "can't get output buffer" );
> +        block_Release( p_in_buf );
> +        goto out;
> +    }
> +    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples; /* set output buffer
> parameters */ +    p_out_buf->i_dts        = p_in_buf->i_dts;
> +    p_out_buf->i_pts        = p_in_buf->i_pts;
> +    p_out_buf->i_length     = p_in_buf->i_length;
> +
> +    vlc_thread_t left_thread, right_thread; /* threads for simultaneous
> computation of left and right channel */ +    struct t_thread_data
> t_data_l, t_data_r;
> +
> +    float f_gain_lfe = exp( (p_sys->f_gain - 3 * i_input_nb - 6) / 20 *
> log(10)); /* -3 dB per channel and additional -6 dB to get LFE on a similar
> level */ +
> +    /* prepare t_thread_data structs for left and right channel,
> respectively */ +    t_data_l.p_sys = t_data_r.p_sys = p_sys;
> +    t_data_l.p_in_buf = t_data_r.p_in_buf = p_in_buf;
> +    t_data_l.p_input_nb = t_data_r.p_input_nb = &i_input_nb;
> +    t_data_l.f_gain_lfe = t_data_r.f_gain_lfe = f_gain_lfe;
> +    t_data_l.i_write = t_data_r.i_write = p_sys->i_write;
> +    t_data_l.p_ringbuffer = p_sys->p_ringbuffer_l;
> +    t_data_r.p_ringbuffer = p_sys->p_ringbuffer_r;
> +    t_data_l.p_ir = p_sys->p_ir_l;
> +    t_data_r.p_ir = p_sys->p_ir_r;
> +    t_data_l.p_n_clippings = &i_n_clippings_l;
> +    t_data_r.p_n_clippings = &i_n_clippings_r;
> +    t_data_l.p_dest = (float *)p_out_buf->p_buffer;
> +    t_data_r.p_dest = (float *)p_out_buf->p_buffer + 1;
> +    t_data_l.p_delay = p_sys->p_delay_l;
> +    t_data_r.p_delay = p_sys->p_delay_r;
> +
> +    if ( p_sys->b_mute ) /* mutes output (e.g. when an invalid SOFA file is
> selected) */ +    {
> +        memset( (float *)p_out_buf->p_buffer , 0 , sizeof( float ) *
> p_in_buf->i_nb_samples * 2 ); +    }
> +    else /* do the actual convolution for left and right channel */
> +    {
> +        if( vlc_clone( &left_thread, (void *)&sofalizer_Convolute, (void
> *)&t_data_l, VLC_THREAD_PRIORITY_HIGHEST ) ) goto out;
> +        if( vlc_clone( &right_thread, (void *)&sofalizer_Convolute, (void 
*)&t_data_r, VLC_THREAD_PRIORITY_HIGHEST ) ) goto out;

This can´t be right,

> +        vlc_join ( left_thread, NULL );
> +        vlc_join ( right_thread, NULL );
> +        p_sys->i_write = t_data_l.i_write;
> +    }
> +
> +    if ( ( i_n_clippings_l + i_n_clippings_r ) > 0 ) /* display error
> message if clipping occured */ +    {
> +        msg_Err(p_filter, "%d of %d Samples in the Outputbuffer clipped.
> Please reduce gain.", i_n_clippings_l + i_n_clippings_r,
> p_out_buf->i_nb_samples * 2 ); +    }
> +out: block_Release( p_in_buf );
> +    return p_out_buf; /* DoWork returns the modified output buffer */
> +}
> +
> +void sofalizer_Convolute ( void *p_ptr )
> +{
> +    struct t_thread_data *t_data;
> +    t_data = (struct t_thread_data *)p_ptr;
> +    struct filter_sys_t *p_sys = t_data->p_sys;
> +    int i_n_samples = p_sys->sofa[p_sys->i_i_sofa].i_n_samples; /* length
> of one impulse response (IR) (i.e. number of samples) */ +    float *p_src
> = (float *)t_data->p_in_buf->p_buffer; /* get pointer to audio input buffer
> */ +    float *p_temp_ir;
> +    float *p_dest = t_data->p_dest; /* get pointer to audio output buffer
> */ +    int i_read;
> +    int *p_delay = t_data->p_delay; /* broadband delay for each input
> channel/IR to be convoluted */ +    int i_input_nb = *t_data->p_input_nb;
> /* number of input channels */ +    int i_buffer_length =
> p_sys->i_buffer_length; /* buffer length is: longest IR plus max. delay in
> all SOFA files -> next power of 2 */ +    uint32_t i_modulo = (uint32_t)
> i_buffer_length -1 ; /* -1 for AND instead MODULO */ +    float
> *p_ringbuffer[i_input_nb];
> +    for ( int l = 0 ; l < i_input_nb ; l++ ) /* initialize ringbuffer for
> each input channel */ +    {
> +        p_ringbuffer[l] = t_data->p_ringbuffer + l * i_buffer_length ;
> +    }
> +    int i_write = t_data->i_write;
> +    float *p_ir = t_data->p_ir;
> +
> +    for ( int i = t_data->p_in_buf->i_nb_samples ; i-- ; ) /* outer loop:
> go through all samples of current input buffer */ +    {
> +        *( p_dest ) = 0;
> +        for ( int l = 0 ; l < i_input_nb ; l++ ) /* get pointers to each
> channel's input buffer */ +        {
> +            *( p_ringbuffer[l] + i_write ) = *( p_src++);
> +        }
> +        p_temp_ir = p_ir;
> +        for ( int l = 0 ; l < p_sys->i_n_conv ; l++ ) /* go through all
> channels to be convolved (this excludes LFE) */ +        {
> +            i_read = ( i_write - *( p_delay + l )- (i_n_samples - 1 )  +
> i_buffer_length ) & i_modulo ; /* current read offset for ringbuffer */ +  
>          for ( int j = i_n_samples ; j-- ; ) /* go through samples of IR */
> +            {
> +                *( p_dest ) += *( p_ringbuffer[l] + ( ( i_read++ ) &
> i_modulo ) ) * *( p_temp_ir++ ); /* multiply signal and IR, and add up the
> results */ +            }
> +        }
> +        if ( p_sys->b_lfe ) /* LFE */
> +        {
> +            *( p_dest ) += *( p_ringbuffer[p_sys->i_n_conv] + i_write ) *
> t_data->f_gain_lfe; /* apply LFE gain and write to output buffer */ +      
>  }
> +        if ( *( p_dest ) >= 1 ) /* update clippings counter, if clipping
> occurs (output signal greater than or equal 1) */ +        {
> +            *t_data->p_n_clippings = *t_data->p_n_clippings + 1;
> +        }
> +        p_dest   += 2; /* move output buffer pointer by +2, because every
> second sample belongs to the same channel (left or right) */ +       
> i_write  = ( i_write + 1 ) & i_modulo; /* i_write is a counter variable for
> the input buffer */ +    }
> +    t_data->i_write = i_write;
> +    return;
> +}
> +
> +/**************************************************************************
> *** +* LoadIR: Load the impulse responses (reversed) for directions in
> p_ir_l and +*     p_ir_r and applies the gain to them.
> +*
> +* FindM: Find the correct impulse response with FindM threads.
> +***************************************************************************
> ***/ +
> +static int LoadIR ( filter_t *p_filter, int i_azim, int i_elev, float
> f_radius) +{
> +    struct filter_sys_t *p_sys = p_filter->p_sys;
> +    vlc_thread_t thread_find_m[p_sys->i_n_conv]; /* thread for finding IRs
> closest to the desired source (i.e. loudspeaker) positions */ +    struct
> data_findM_t data_find_m[p_sys->i_n_conv];
> +    int i_n_samples = p_sys->sofa[p_sys->i_i_sofa].i_n_samples; /* length
> of one impulse response (IR) (i.e. number of samples) */ +    int i_n_conv
> = p_sys->i_n_conv; /* number of channels to convolve (excludes LFE) */ +   
> int i_delay_l[i_n_conv]; /* broadband delay for each channel to be
> convolved */ +    int i_delay_r[i_n_conv];
> +    int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio ); /*
> get number of input channels */ +    float f_gain_lin = exp( (p_sys->f_gain
> - 3 * i_input_nb) / 20 * log(10)); /* gain setting from GUI and -3dB per
> channel (is applied to the audio output stream) */ +
> +    float
> p_ir_l[p_sys->i_n_conv][p_sys->sofa[p_sys->i_i_sofa].i_n_samples]; /* IRs
> for each channel to be convolved */ +    float
> p_ir_r[p_sys->i_n_conv][p_sys->sofa[p_sys->i_i_sofa].i_n_samples]; +
> +    int i_m[p_sys->i_n_conv]; /* measurement index m of IR closest to the
> required source (i.e. loudspeaker) positions */ +    if ( p_sys->i_switch )
> /* if switch on GUI not zero -> use pre-defined virtual source positions */
> +    {
> +        i_azim = p_sys->i_azimuth_array[p_sys->i_switch - 1];
> +        i_elev = p_sys->i_elevation_array[p_sys->i_switch -1];
> +    }
> +    for ( int i = 0 ; i < p_sys->i_n_conv ; i++ ) /* find IR closest to the
> given desired source position for each channel to convolute */ +    {
> +        data_find_m[i].p_sys = p_sys;
> +        data_find_m[i].i_azim = (int)(p_sys->p_speaker_pos[i] + i_azim ) %
> 360; +        data_find_m[i].i_elev = i_elev;
> +        data_find_m[i].f_radius = f_radius;
> +        data_find_m[i].p_m = &i_m[i];
> +        if ( vlc_clone ( &thread_find_m[i] , (void *)&sofalizer_FindM,
> (void *)&data_find_m[i],  VLC_THREAD_PRIORITY_LOW ) ) {} +    }
> +    for ( int i = 0 ; i < p_sys->i_n_conv ; i++ ) /* load and store IRs and
> corresponding delays */ +    {
> +        vlc_join( thread_find_m[i] , NULL );
> +        for ( int j = 0 ; j < i_n_samples ; j++ )
> +        {
> +            /* load the reversed IRs of the specified source position
> sample-by-sample for left and right ear; and apply gain */ +           
> p_ir_l[i][j] = *( p_sys->sofa[p_sys->i_i_sofa].p_data_ir + 2 * i_m[i] *
> i_n_samples + i_n_samples - 1 - j ) * f_gain_lin; +            p_ir_r[i][j]
> = *( p_sys->sofa[p_sys->i_i_sofa].p_data_ir + 2 * i_m[i] * i_n_samples +
> i_n_samples - 1 - j  + i_n_samples ) * f_gain_lin; +
> +        }
> +        msg_Dbg( p_filter, "Index: %d, Azimuth: %f, Elevation: %f, Radius:
> %f of SOFA file.", i_m[i], *(p_sys->sofa[p_sys->i_i_sofa].p_sp_a + i_m[i]),
> *(p_sys->sofa[p_sys->i_i_sofa].p_sp_e + i_m[i]),
> *(p_sys->sofa[p_sys->i_i_sofa].p_sp_r + i_m[i]) ); +
> +        i_delay_l[i] = *( p_sys->sofa[p_sys->i_i_sofa].p_data_delay + 2 *
> i_m[i] ); /* load the delays associated with the desired IRs */ +       
> i_delay_r[i] = *( p_sys->sofa[p_sys->i_i_sofa].p_data_delay + 2 * i_m[i] +
> 1); +    }
> +
> +    /* copy IRs and delays to allocated memory in the filter_sys_t struct:
> */ +    vlc_mutex_lock( &p_sys->lock );
> +    memcpy ( p_sys->p_ir_l , &p_ir_l[0][0] , sizeof( float ) *
> p_sys->i_n_conv * p_sys->sofa[p_sys->i_i_sofa].i_n_samples ); +    memcpy (
> p_sys->p_ir_r , &p_ir_r[0][0] , sizeof( float ) * p_sys->i_n_conv *
> p_sys->sofa[p_sys->i_i_sofa].i_n_samples ); +    memcpy ( p_sys->p_delay_l
> , &i_delay_l[0] , sizeof( int ) * p_sys->i_n_conv ); +    memcpy (
> p_sys->p_delay_r , &i_delay_r[0] , sizeof( int ) * p_sys->i_n_conv ); +   
> vlc_mutex_unlock( &p_sys->lock );
> +    return VLC_SUCCESS;
> +}
> +
> +void sofalizer_FindM ( void *p_ptr)
> +{
> +    struct data_findM_t *t_data;
> +    t_data = (struct data_findM_t *)p_ptr;
> +    struct filter_sys_t *p_sys = t_data->p_sys;
> +    int i_azim = t_data->i_azim; /* desired azimuth angle of source
> position */ +    int i_elev = t_data->i_elev; /* desired elevation angle of
> source position */ +    float f_radius = t_data->f_radius; /* desired
> radius of source position */ +    int *p_m = t_data->p_m; /* measurement
> index m associated with the measurement closest to the desired source
> position */ +    float *p_sp_a = p_sys->sofa[p_sys->i_i_sofa].p_sp_a; /*
> get source positions of currently selected SOFA file */ +    float *p_sp_e
> = p_sys->sofa[p_sys->i_i_sofa].p_sp_e;
> +    float *p_sp_r = p_sys->sofa[p_sys->i_i_sofa].p_sp_r;
> +    int i_m_dim = p_sys->sofa[p_sys->i_i_sofa].i_m_dim; /* get number of
> measurements of currently selected SOFA file */ +    int i_i_best = 0; /*
> temporary best measurement index m (closest to desired source position) */
> +    float f_delta = 1000;
> +    float f_current;
> +    for ( int i = 0; i < i_m_dim ; i++ ) /* search through all measurements
> in currently selected SOFA file */ +    {
> +        f_current = fabs ( *(p_sp_a++) - i_azim ) + fabs( *(p_sp_e++) -
> i_elev ) +  fabs( *(p_sp_r++) - f_radius ); /* distance of current to
> desired source position */ +        if ( f_current <= f_delta ) /* if
> current distance is smaller than smallest distance so far */ +        {
> +                f_delta = f_current;
> +                i_i_best = i; /* remember index */
> +        }
> +    }
> +    *p_m = i_i_best;
> +    return;
> +}
> +
> +/**************************************************************************
> *** +* Callbacks
> +***************************************************************************
> ***/ +
> +static int GainCallback( vlc_object_t *p_this, char const *psz_var,
> +                          vlc_value_t oldval, vlc_value_t newval, void
> *p_data ) +{
> +    VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
> +    filter_t *p_filter = (filter_t *)p_data;
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    vlc_mutex_lock( &p_sys->lock );
> +    p_sys->f_gain = newval.f_float;
> +    vlc_mutex_unlock( &p_sys->lock );
> +    LoadIR( p_filter, p_sys->f_rotation, p_sys->f_elevation,
> p_sys->f_radius ); /* re-load IRs based on new GUI settings */ +   
> msg_Dbg( p_this , "New Gain-value: %f", newval.f_float );
> +    return VLC_SUCCESS;
> +}
> +
> +static int RotationCallback( vlc_object_t *p_this, char const *psz_var,
> +                          vlc_value_t oldval, vlc_value_t newval, void
> *p_data) +{
> +    VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
> +    filter_t *p_filter = (filter_t *)p_data;
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    float f_temp= (int) (- newval.f_float + 720 ) % 360  ;
> +    vlc_mutex_lock( &p_sys->lock );
> +    p_sys->f_rotation = f_temp ;
> +    vlc_mutex_unlock( &p_sys->lock );
> +    LoadIR( p_filter, f_temp, p_sys->f_elevation, p_sys->f_radius ); /*
> re-load IRs based on new GUI settings */ +    msg_Dbg( p_filter, "New
> azimuth-value: %f", f_temp  );
> +    return VLC_SUCCESS;
> +}
> +
> +static int ElevationCallback( vlc_object_t *p_this, char const *psz_var,
> +                          vlc_value_t oldval, vlc_value_t newval, void
> *p_data ) +{
> +    VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
> +    filter_t *p_filter = (filter_t *)p_data;
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    vlc_mutex_lock( &p_sys->lock );
> +    p_sys->f_elevation = newval.f_float ;
> +    vlc_mutex_unlock( &p_sys->lock ) ;
> +    LoadIR( p_filter, p_sys->f_rotation, newval.f_float, p_sys->f_radius );
> /* re-load IRs based on new GUI settings */ +    msg_Dbg( p_filter, "New
> elevation-value: %f", newval.f_float ); +    return VLC_SUCCESS;
> +}
> +
> +static int RadiusCallback( vlc_object_t *p_this, char const *psz_var,
> +                          vlc_value_t oldval, vlc_value_t newval, void
> *p_data ) +{
> +    VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
> +    filter_t *p_filter = (filter_t *)p_data;
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    vlc_mutex_lock( &p_sys->lock );
> +    p_sys->f_radius = newval.f_float ;
> +    vlc_mutex_unlock( &p_sys->lock ) ;
> +    LoadIR( p_filter, p_sys->f_rotation, p_sys->f_elevation, 
> newval.f_float ); /* re-load IRs based on new GUI settings */ +    msg_Dbg(
> p_filter, "New radius-value: %f", newval.f_float );
> +    return VLC_SUCCESS;
> +}
> +
> +
> +static int SwitchCallback( vlc_object_t *p_this, char const *psz_var,
> +                          vlc_value_t oldval, vlc_value_t newval, void
> *p_data ) /* new virtual source position selected */ +{
> +    VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
> +    filter_t *p_filter = (filter_t *)p_data;
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    vlc_mutex_lock( &p_sys->lock );
> +    p_sys->i_switch = (int) newval.f_float ;
> +    if ( p_sys->i_switch ) /* if switch is not zero, pre-defined virtual
> source positions are used */ +    {
> +        for ( int i = 0 ; i < p_sys->i_n_conv ; i++ )
> *(p_sys->p_speaker_pos + i ) = 0; +    }
> +    else /* if switch is zero */
> +    {
> +        GetSpeakerPos ( p_filter, p_sys->p_speaker_pos ); /* get speaker
> positions depending on current input format */ +    }
> +    vlc_mutex_unlock( &p_sys->lock ) ;
> +    LoadIR ( p_filter, p_sys->f_rotation, p_sys->f_elevation,
> p_sys->f_radius ); /* re-load IRs based on new GUI settings */ +   
> msg_Dbg( p_filter, "New Switch-Position: %d", (int) newval.f_float ); +   
> return VLC_SUCCESS;
> +}
> +
> +static int SelectCallback( vlc_object_t *p_this, char const *psz_var,
> +                          vlc_value_t oldval, vlc_value_t newval, void
> *p_data ) /* new SOFA file selected */ +{
> +    VLC_UNUSED(p_this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
> +    filter_t *p_filter = (filter_t *)p_data;
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    vlc_mutex_lock( &p_sys->lock );
> +    if ( p_sys->sofa[((int)newval.f_float + 5 - 1 ) % 5].i_ncid )
> +    {
> +        p_sys->i_i_sofa = ( (int) newval.f_float + 5 - 1) % 5 ;
> +        p_sys->b_mute = false;
> +        vlc_mutex_unlock( &p_sys->lock ) ;
> +        LoadIR ( p_filter, p_sys->f_rotation, p_sys->f_elevation ,
> p_sys->f_radius ); /* re-load IRs based on new GUI settings */ +       
> msg_Dbg( p_filter, "New Sofa-Select: %f", newval.f_float ); +    }
> +    else
> +    {
> +        msg_Dbg( p_filter, "Invalid File selected!" );
> +        p_sys->b_mute = true;
> +        vlc_mutex_unlock( &p_sys->lock ) ;
> +    }
> +    return VLC_SUCCESS;
> +}
> +
> +/**************************************************************************
> *** +* Close:
> +***************************************************************************
> ***/ +
> +static void Close( vlc_object_t *p_this )
> +{
> +    filter_t *p_filter = ( filter_t* )p_this;
> +    filter_sys_t *p_sys = p_filter->p_sys;
> +    vlc_object_t *p_out = p_filter->p_parent;
> +
> +    var_DelCallback( p_out, "sofalizer-gain", GainCallback, p_filter ); /*
> delete GUI callbacks */ +    var_DelCallback( p_out, "sofalizer-rotation",
> RotationCallback, p_filter ); +    var_DelCallback( p_out,
> "sofalizer-elevation", ElevationCallback, p_filter ); +    var_DelCallback(
> p_out, "sofalizer-switch", SwitchCallback, p_filter ); +   
> var_DelCallback( p_out, "sofalizer-select", SelectCallback, p_filter ); +  
>  var_DelCallback( p_out, "sofalizer-radius", RadiusCallback, p_filter ); +
> +    vlc_mutex_destroy( &p_sys->lock ); /* get rid of mutex lock */
> +
> +    FreeAllSofa( p_filter ); /* free memory used for the SOFA files' data
> */ +    FreeFilter( p_filter ); /* free filter memory */
> +}
> diff --git a/modules/gui/qt4/components/extended_panels.cpp
> b/modules/gui/qt4/components/extended_panels.cpp index d05c0b3..c01d1ce
> 100644

UI changes belong in a separate patch.

Also please wrap the lines better. The review would be more readable if you 
had done it.

-- 
Rémi Denis-Courmont
http://www.remlab.net/




More information about the vlc-devel mailing list