% SUpDEq - Spatial Upsampling by Directional Equalization function hrtfDataset = supdeq_sofa2hrtf(SOFAobj, N, samplingGrid, FFToversize) This function transformes a 'SimpleFreeFieldHRIR' SOFA file to frequency domain and writes a hrtf dataset struct suitable for the SUpDEq toolbox. Output: hrtfDataset - Struct with HRTFsfor the left (HRTF_L) and right (HRTF_R) channel/ear, absolute frequency scale f, maximum transform order N, FFToversize, and samplingGrid Input: SOFAobj - Measurement data in form of a SOFA object N - Maximal transform order N samplingGrid - Optional input [default = nan] If a spatial sampling grid is passed, it must be a Qx3 matrix where the first column holds the azimuth, the second the elevation, and the third the sampling weights. In this case, the sampling grid with weights will be written to the struct. Otherwise, the sampling grid stored in the SOFA file, transformed to SH coordinates, will be written to the struct. Azimuth positions in degree. Can be scalar or vector of size(el) (0=front, 90=left, 180=back, 270=right) (0 points to positive x-axis, 90 to positive y-axis) Elevations in degree. Can be scalar or vector of size(az) (0=North Pole, 90=front, 180=South Pole) (0 points to positive z-axis, 180 to negative z-axis) FFToversize - FFToversize rises the FFT Blocksize [default = 1] A FFT of the blocksize (FFToversize*NFFT) is applied to the time domain data, where NFFT is determinded as the next power of two of the signalSize which is signalSize = (lastSample-firstSample). Dependencies: SOFA API (C) 2018 by JMA, Johannes M. Arend TH Köln - University of Applied Sciences Institute of Communications Engineering Department of Acoustics and Audio Signal Processing
0001 %% SUpDEq - Spatial Upsampling by Directional Equalization 0002 % 0003 % function hrtfDataset = supdeq_sofa2hrtf(SOFAobj, N, samplingGrid, FFToversize) 0004 % 0005 % This function transformes a 'SimpleFreeFieldHRIR' SOFA file to frequency 0006 % domain and writes a hrtf dataset struct suitable for the SUpDEq toolbox. 0007 % 0008 % Output: 0009 % hrtfDataset - Struct with HRTFsfor the left (HRTF_L) and right (HRTF_R) 0010 % channel/ear, absolute frequency scale f, 0011 % maximum transform order N, FFToversize, and samplingGrid 0012 % 0013 % Input: 0014 % SOFAobj - Measurement data in form of a SOFA object 0015 % N - Maximal transform order N 0016 % samplingGrid - Optional input [default = nan] 0017 % If a spatial sampling grid is passed, it must be a Qx3 0018 % matrix where the first column holds the azimuth, the 0019 % second the elevation, and the third the sampling weights. 0020 % In this case, the sampling grid with weights will be 0021 % written to the struct. Otherwise, the sampling grid 0022 % stored in the SOFA file, transformed to SH coordinates, 0023 % will be written to the struct. 0024 % Azimuth positions in degree. Can be scalar or vector of size(el) 0025 % (0=front, 90=left, 180=back, 270=right) 0026 % (0 points to positive x-axis, 90 to positive y-axis) 0027 % Elevations in degree. Can be scalar or vector of size(az) 0028 % (0=North Pole, 90=front, 180=South Pole) 0029 % (0 points to positive z-axis, 180 to negative z-axis) 0030 % FFToversize - FFToversize rises the FFT Blocksize [default = 1] 0031 % A FFT of the blocksize (FFToversize*NFFT) is applied 0032 % to the time domain data, where NFFT is determinded 0033 % as the next power of two of the signalSize which is 0034 % signalSize = (lastSample-firstSample). 0035 % 0036 % Dependencies: SOFA API 0037 % 0038 % (C) 2018 by JMA, Johannes M. Arend 0039 % TH Köln - University of Applied Sciences 0040 % Institute of Communications Engineering 0041 % Department of Acoustics and Audio Signal Processing 0042 0043 function hrtfDataset = supdeq_sofa2hrtf(SOFAobj, N, samplingGrid, FFToversize) 0044 0045 if nargin < 3 0046 samplingGrid = []; 0047 end 0048 0049 if nargin < 4 0050 FFToversize = 1; 0051 end 0052 0053 %Check FFToversize parameter 0054 if FFToversize < 1 0055 warning('FFToversize needs to >= 1. Set to default = 1.'); 0056 FFToversize = 1; 0057 end 0058 0059 %Check grid if passed 0060 if ~isempty(samplingGrid) 0061 if size(samplingGrid,2) > size(samplingGrid,1) 0062 samplingGrid = samplingGrid'; 0063 end 0064 0065 if size(samplingGrid,2) ~= 3 0066 warning('No sampling weights passed. Using sampling grid defined in SOFA object.') 0067 samplingGrid = []; 0068 end 0069 end 0070 0071 %Check SOFA object 0072 if ~strcmp(SOFAobj.GLOBAL_SOFAConventions,'SimpleFreeFieldHRIR') 0073 error('Function only valid for SOFA convention "SimpleFreeFieldHRIR"'); 0074 end 0075 0076 %% Transform data to frequency domain 0077 0078 %Get IRs 0079 irL = squeeze(SOFAobj.Data.IR(:,1,:)); 0080 irR = squeeze(SOFAobj.Data.IR(:,2,:)); 0081 0082 %Zero pad to get length according to FFToversize 0083 if FFToversize > 1 0084 NFFT = 2^nextpow2(size(irL,2)); 0085 NFFT = NFFT*FFToversize; 0086 irL = [irL, zeros(size(irL,1),NFFT-size(irL,2))]; 0087 irR = [irR, zeros(size(irR,1),NFFT-size(irR,2))]; 0088 else 0089 if size(irL,2) == 2^nextpow2(size(irL,2)) 0090 NFFT = size(irL,2); 0091 else 0092 NFFT = 2^nextpow2(size(irL,2)); 0093 irL = [irL, zeros(size(irL,1),NFFT-size(irL,2))]; 0094 irR = [irR, zeros(size(irR,1),NFFT-size(irR,2))]; 0095 end 0096 end 0097 0098 %Transform HRIRs to frequency domain (HRTFs) 0099 HRTF_L = fft(irL,[],2); 0100 HRTF_R = fft(irR,[],2); 0101 %Cut at fs/2 0102 HRTF_L = HRTF_L(:,1:end/2+1); 0103 HRTF_R = HRTF_R(:,1:end/2+1); 0104 0105 %If no samplingGrid was passed, use samplingGrid from SOFA 0106 if isempty(samplingGrid) 0107 %Get samplingGrid from SOFA object 0108 samplingGrid = SOFAobj.SourcePosition(:,1:2); 0109 0110 %Transform samplingGrid to SH coordinate system 0111 samplingGrid(:,1) = mod(samplingGrid(:,1),360); 0112 samplingGrid(:,2) = 90-samplingGrid(:,2); 0113 end 0114 0115 %Write f 0116 f = linspace(0,SOFAobj.Data.SamplingRate/2,NFFT/2+1); 0117 0118 %Write output struct 0119 hrtfDataset.HRTF_L = HRTF_L; 0120 hrtfDataset.HRTF_R = HRTF_R; 0121 hrtfDataset.f = f; 0122 hrtfDataset.Nmax = N; 0123 hrtfDataset.FFToversize = FFToversize; 0124 hrtfDataset.samplingGrid = samplingGrid; 0125 hrtfDataset.sourceDistance = SOFAobj.SourcePosition(1,3); 0126 0127 end 0128