Commit c7331fd9 authored by Adam Mills's avatar Adam Mills
Browse files

Merge branch 'Removing-sofar-dependency-from-HRIR-generation-scripts' into 'main'

Removing the dependency on sofar from the HRIR generation scripts

See merge request !918
parents 74cc87af cbb5d54e
Loading
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -29,8 +29,8 @@
%   the United Nations Convention on Contracts on the International Sales of Goods.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function IR_cldfb = SHD_2_ROM( py_path, rom_c_file, sofa_file, ambi_order, hrir_len )
% SHD_2_ROM( python_path, rom_c_file, sofa_file, ambisonics_order, hrir_length )
function IR_cldfb = SHD_2_ROM( rom_c_file, sofa_file, ambi_order, hrir_len )
% SHD_2_ROM( rom_c_file, sofa_file, ambisonics_order, hrir_length )
%
% - converts sphere-sampled Head Related Impulse Responses (HRIRs) given in sofa_file 
%   to the Spherical Harmonics domain (SHD) using generate_HOA_HRIRs_MOD_lens.m
@@ -55,9 +55,8 @@ end
% python -m pip install numpy

% convert sphere-sampled HRIRs to SHD HRIRs
write_out_sofa = 0;
[sofa_path,sofa_name, sofa_ext] = fileparts(sofa_file);
IR = generate_HOA_HRIRs_MOD_lens(ambi_order, py_path, sofa_path, [sofa_name,sofa_ext], hrir_len, write_out_sofa);
IR = generate_HOA_HRIRs_MOD_lens(ambi_order, sofa_path, [sofa_name,sofa_ext], hrir_len);

%% SHD -> CLDFB via least squares error optimization
[~,num_ears,num_ch] = size(IR);
+4 −4
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@
%   the United Nations Convention on Contracts on the International Sales of Goods.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function convert_SD2SHD_HRIRs(python_path, sofa_path, sofa_file, IR_size)
function convert_SD2SHD_HRIRs(sofa_path, sofa_file, IR_size)

data_struct = struct.empty(3,0);

@@ -38,7 +38,7 @@ sr_short = [48, 32, 16];
sr_dft_size  = [240, 160, 80];

% FOA
data_struct(1).IR_data = generate_HOA_HRIRs_MOD_lens(1, python_path, sofa_path, sofa_file, IR_size, 0);
data_struct(1).IR_data = generate_HOA_HRIRs_MOD_lens(1, sofa_path, sofa_file, IR_size);
data_struct(1).HOA_name     = 'FOA';
data_struct(1).n_HOA_ch     = 4;
data_struct(1).sr           = sr;
@@ -46,7 +46,7 @@ data_struct(1).sr_short = sr_short;
data_struct(1).sr_dft_size  = sr_dft_size;

% HOA2
data_struct(2).IR_data = generate_HOA_HRIRs_MOD_lens(2, python_path, sofa_path, sofa_file, IR_size, 0);
data_struct(2).IR_data = generate_HOA_HRIRs_MOD_lens(2, sofa_path, sofa_file, IR_size);
data_struct(2).HOA_name     = 'HOA2';
data_struct(2).n_HOA_ch     = 9;
data_struct(2).sr           = sr;
@@ -54,7 +54,7 @@ data_struct(2).sr_short = sr_short;
data_struct(2).sr_dft_size  = sr_dft_size;

% HOA3
data_struct(3).IR_data = generate_HOA_HRIRs_MOD_lens(3, python_path, sofa_path, sofa_file, IR_size, 0);
data_struct(3).IR_data = generate_HOA_HRIRs_MOD_lens(3, sofa_path, sofa_file, IR_size);
data_struct(3).HOA_name     = 'HOA3';
data_struct(3).n_HOA_ch     = 16;
data_struct(3).sr           = sr;
+2 −17
Original line number Diff line number Diff line
@@ -29,30 +29,20 @@
%   the United Nations Convention on Contracts on the International Sales of Goods.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function IR_data = generate_HOA_HRIRs_MOD_lens(order, python_path, sofa_path, sofa_file_name, ir_len, write_out_sofa)
function IR_data = generate_HOA_HRIRs_MOD_lens(order, sofa_path, sofa_file_name, ir_len)
    % HRIR convertor - Takes sphere sampled HRIRs and converts them to
    % HOA HRIRs.
    %
    % order - HOA order to be converted to.
    % python_path - path that points to the python binary that has the
    %   sofar python module installed. sofar is needed to read the .sofa
    %   files that contain the HRIRs.
    % sofa_path - path to the directory that contains the sofa files to be
    % converted.
    % sofa_file - file name of the HRTFs to be converted
    % ir_len - length of the IRs to be used.
    % write_out_sofa - boolean to enable/disable writing out of sofa
    %
    % Typical usage:
    %   generate_HOA_HRIRs_MOD_lens(1, "~/.pyenv/versions/3.8.16/bin/python", '~/git/ivas-pc-testfiles/sofa-files/', 'HRIR_128_48000.sofa', 128)
    %   generate_HOA_HRIRs_MOD_lens(1, '~/git/ivas-pc-testfiles/sofa-files/', 'HRIR_128_48000.sofa', 128)
    %

% Pointing to the correct python binary
py_env = pyenv;
if ~strcmp(py_env.Executable, python_path)
   pyenv('Version', python_path);
end

% Load in the support coefs
load('hrtf_support_coefs.mat', 'hrtf_support_coefs');
rmsSphere   = hrtf_support_coefs(order).rmsSphere;
@@ -128,11 +118,6 @@ IR = permute(IR_HOA, [2, 1, 3]);
HOAformat_str = ['HOA',num2str(order),'S'];
save(fullfile(erase(sofa_file_name, ".sofa") + "_converted_" +  HOAformat_str + ".mat"), "IR")

if (write_out_sofa == 1)
    H.updateSOFA(IR);
    H.writeSOFA(fullfile(erase(sofa_file_name, ".sofa") + "_converted_" +  HOAformat_str + ".sofa"));
end

IR_data = IR;


+8 −63
Original line number Diff line number Diff line
@@ -79,8 +79,6 @@ classdef hrtf_library_loader < handle
        Last_HRTFs=[];
        % Remember the unit vectors for the most recent HRTFs computed
        Last_UV=[];

        Sofa_File = [];
    end
  
    methods
@@ -90,14 +88,11 @@ classdef hrtf_library_loader < handle

        function readSOFA(obj, Lib_Name)
            
            % Read in the sofa file using 'sofar' python module
            sofa_file = py.sofar.read_sofa(Lib_Name);
            
            % This looks like a library built from a bunch of discrete
            % locations in free field
            % Let's figure out the source locations used in the HRTF library:
            Pos = hrtf_library_loader.convert_numpy_2darray(sofa_file.SourcePosition)';
            Units = strtrim(strsplit(string(sofa_file.SourcePosition_Units), ','));
            Pos = ncread(Lib_Name, 'SourcePosition');
            Units = strtrim(strsplit(ncreadatt(Lib_Name, 'SourcePosition', 'Units'), ','));
            
            assert( any(strcmpi(Units{1}, {'degree','radian'})), 'Unknown units');
            if strcmpi(Units{1},'degree'), Pos(1,:)=Pos(1,:)*pi/180; end
@@ -113,12 +108,12 @@ classdef hrtf_library_loader < handle
            NumLoc = size(XYZ,2);
            
            % Now, get the impulse repsonses:
            assert( isprop(sofa_file, 'GLOBAL_DataType'), 'Expected field: GLOBAL_DataType');
            Data.IR = hrtf_library_loader.convert_numpy_3darray(sofa_file.Data_IR);
            Data.SamplingRate = double(sofa_file.Data_SamplingRate);
            Data.SamplingRate_Units = string(sofa_file.Data_SamplingRate_Units);
            Data.Delay = hrtf_library_loader.convert_numpy_2darray(sofa_file.Data_Delay);
            switch lower(string(sofa_file.GLOBAL_DataType))
            DataType = ncreadatt(Lib_Name, '/', 'DataType');
            Data.IR = permute(ncread(Lib_Name, 'Data.IR'), [3, 2, 1]);
            Data.SamplingRate = ncread(Lib_Name, 'Data.SamplingRate');
            Data.SamplingRate_Units = ncreadatt(Lib_Name, 'Data.SamplingRate', 'Units');
            Data.Delay = permute(ncread(Lib_Name, 'Data.Delay'), [2, 1]);
            switch lower(DataType)
                case 'fir'
                    assert( size(Data.IR,2)>=2, 'Expecting 2 receivers (ears)');
                    if size(Data.IR,2)>2
@@ -160,18 +155,6 @@ classdef hrtf_library_loader < handle
            H.Info.Scaling      = 'Normalised to unity gain at 1kHz';

            obj.process_lib(H, Data.SamplingRate);
            obj.Sofa_File = sofa_file;
        end
        
        function updateSOFA(obj, data)
            right_shape = permute(data, [3, 2, 1]);
            obj.Sofa_File.Data_IR = py.numpy.array(right_shape);
            d = size(right_shape);
            obj.Sofa_File.SourcePosition = py.numpy.array(zeros(d(1), 3));
        end

        function writeSOFA(obj, file_name)
            py.sofar.write_sofa(file_name, obj.Sofa_File);
        end
        
        function IR = XYZ_to_IR( this, XYZ )
@@ -399,44 +382,6 @@ classdef hrtf_library_loader < handle
    
    methods(Static=true)
    
        function mat = convert_numpy_2darray(np_array)
            py_list = np_array.tolist();
            % List to cell
            matCell = cell(py_list)';
            shape = cell(np_array.shape);
            shape_mat = zeros(1, length(shape));
            for i=1:length(shape)
                shape_mat(i) = double(shape{i});
            end
            mat = zeros(shape_mat);
            for i = 1:length(matCell)
                if isa(matCell{i}, 'py.list')
                    mat(i,:) = cell2mat(cell(matCell{i}));
                end
            end
        end

        function mat = convert_numpy_3darray(np_array)
            py_list = np_array.tolist();
            % List to cell
            matCell = cell(py_list)';
            shape = cell(np_array.shape);
            shape_mat = zeros(1, length(shape));
            for i=1:length(shape)
                shape_mat(i) = double(shape{i});
            end
            mat = zeros(shape_mat);
            for i = 1:length(matCell)
                if isa(matCell{i}, 'py.list')
                    for j = 1:length(matCell{i})
                        if isa(matCell{i}, 'py.list')
                            mat(i,j,:) = cell2mat(cell(matCell{i}{j}));
                        end
                    end
                end
            end
        end
    
        function [Band2FR,FCs]=MakeBand2FR(FFTLen,FSample)
            % Compute the standard band filters for freq domain representations
            %
+0 −21
Original line number Diff line number Diff line
Applies to sofar 

Copyright (c) [2021] [The pyfar developers]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
 No newline at end of file