Home > SUpDEq-v5.0.0 > supdeq_dvf.m

supdeq_dvf

PURPOSE ^

% SUpDEq - Spatial Upsampling by Directional Equalization

SYNOPSIS ^

function [shiftedHRTF_L, shiftedHRTF_R, ffShiftedHRTFdataset] = supdeq_dvf(HRTFdataset, newDistance, samplingGrid, shiftToFarField, adjustAmplitude, radius, earPosition, N_HRTF)

DESCRIPTION ^

% SUpDEq - Spatial Upsampling by Directional Equalization

 function [shiftedHRTF_L, shiftedHRTF_R, ffShiftedHRTFdataset] = supdeq_dvf(HRTFdataset, newDistance, samplingGrid ,shiftToFarField, adjustAmplitude, radius, earPosition, N_HRTF)

 This function applies a distance shift to HRTFs using distance variation 
 functions (DVFs). As it works with HRTFs in spherical harmonics domain, 
 acoustic parallax effects (high frequency parallax effects induced by 
 the pinna which are not covered by the rigid sphere transfer functions) 
 can be embedded into the distance shifted HRTFs.

 Output:
 shiftedHRTF_L/R      - Shifted HRTF_L/R in frequency domain (single sided complex spectrum)
 ffShiftedHRTFdataset - Struct with far-field shifted HRTF dataset in SH
                        domain according to input HRTFdataset. Only if
                        'shiftToFarField' was applied

 Input:
 HRTFdataset           - Struct with the HRTF dataset as
                         SH-coefficients for the left (Hl_nm) and 
                         right (Hr_nm) channel/ear, absolute frequency scale f, 
                         transform order N, FFToversize and sourceDistance
                         If field 'sourceDistance' does not exist, the
                         function assumes far-field measurements and option
                         'shiftToFarField' will always be set to 'false'
 newDistance           - New distance of HRTF dataset in m 
 samplingGrid          - Spatial sampling grid (Q x 2 matrix) for the distance shifted HRTFs, 
                         where the first column holds the azimuth and the second 
                         the elevation (both in degree).
                         Azimuth in degree (0=front, 90=left, 180=back, 270=right)
                         (0 points to positive x-axis, 90 to positive y-axis)
                         Elevations in degree (0=North Pole, 90=front, 180=South Pole)
                         (0 points to positive z-axis, 180 to negative z-axis)
 shiftToFarField       - Boolean with true / false. Option to shift
                         measurements, which strictly speaking were not measured in 
                         the far-field (e.g., at d = 3.25 m as our Neumann KU100 set) 
                         and thus still have acoustic parallax effects, to far field before 
                         shifting to new distance. 
                         Default: false
                         Note: If set to false, only the inverse SH
                         transform will be applied to get HRTFs for the
                         new distance according to the sampling grid.
                         Thus, processing will be much faster. If set to
                         true, various forward and inverse SH transform
                         are gonne be performed on a high order grid, so
                         processing takes longer.
 adjustAmplitude       - Boolen with true / false. Option to adjust the HRTF level
                         according to the 1/r law.
                         Default: false --> HRTF have roughly the same
                         amplitude after distance shift
 radius                - Define radius of rigid sphere / HRTFs in m
                         Default: 0.0875
 earPosition           - 4 x 1 row vector describing the position of the ears in
                         spherical coordinates in degree [azL, elL, azR, elR]
                         Default: [90, 90, 270, 90] (left-right symmetrical)
 N_HRTF                - Spherical harmonics order for HRTF processing. If
                         not specified, Nmax from the HRTFdataset struct will be applied (mostly
                         the best choice)
                         Default: Nmax from HRTFdataset struct

 Dependencies: -

 References:
 [1] A. Kan, C. Jin, and A. van Schaik, “A psychophysical evaluation of 
 near-field head-related transfer functions synthesized using a distance 
 variation function,” J. Acoust. Soc. Am., vol. 125, no. 4, pp. 2233–2242, 2009.

 [2] S. Spagnol, E. Tavazzi, and F. Avanzini, “Distance rendering and 
 perception of nearby virtual sound sources with a near-field filter model,” 
 Appl. Acoust., vol. 115, pp. 61–73, 2017.

 [3] D. Romblom and B. Cook, “Near-Field Compensation for HRTF Processing,” 
 in Proceedings of the 125th AES Convention, San Francisco, USA, 2008, pp. 1–6.

 (C) 2020 by JMA, Johannes M. Arend
             TH Köln - University of Applied Sciences
             Institute of Communications Engineering
             Department of Acoustics and Audio Signal Processing

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% SUpDEq - Spatial Upsampling by Directional Equalization
0002 %
0003 % function [shiftedHRTF_L, shiftedHRTF_R, ffShiftedHRTFdataset] = supdeq_dvf(HRTFdataset, newDistance, samplingGrid ,shiftToFarField, adjustAmplitude, radius, earPosition, N_HRTF)
0004 %
0005 % This function applies a distance shift to HRTFs using distance variation
0006 % functions (DVFs). As it works with HRTFs in spherical harmonics domain,
0007 % acoustic parallax effects (high frequency parallax effects induced by
0008 % the pinna which are not covered by the rigid sphere transfer functions)
0009 % can be embedded into the distance shifted HRTFs.
0010 %
0011 % Output:
0012 % shiftedHRTF_L/R      - Shifted HRTF_L/R in frequency domain (single sided complex spectrum)
0013 % ffShiftedHRTFdataset - Struct with far-field shifted HRTF dataset in SH
0014 %                        domain according to input HRTFdataset. Only if
0015 %                        'shiftToFarField' was applied
0016 %
0017 % Input:
0018 % HRTFdataset           - Struct with the HRTF dataset as
0019 %                         SH-coefficients for the left (Hl_nm) and
0020 %                         right (Hr_nm) channel/ear, absolute frequency scale f,
0021 %                         transform order N, FFToversize and sourceDistance
0022 %                         If field 'sourceDistance' does not exist, the
0023 %                         function assumes far-field measurements and option
0024 %                         'shiftToFarField' will always be set to 'false'
0025 % newDistance           - New distance of HRTF dataset in m
0026 % samplingGrid          - Spatial sampling grid (Q x 2 matrix) for the distance shifted HRTFs,
0027 %                         where the first column holds the azimuth and the second
0028 %                         the elevation (both in degree).
0029 %                         Azimuth in degree (0=front, 90=left, 180=back, 270=right)
0030 %                         (0 points to positive x-axis, 90 to positive y-axis)
0031 %                         Elevations in degree (0=North Pole, 90=front, 180=South Pole)
0032 %                         (0 points to positive z-axis, 180 to negative z-axis)
0033 % shiftToFarField       - Boolean with true / false. Option to shift
0034 %                         measurements, which strictly speaking were not measured in
0035 %                         the far-field (e.g., at d = 3.25 m as our Neumann KU100 set)
0036 %                         and thus still have acoustic parallax effects, to far field before
0037 %                         shifting to new distance.
0038 %                         Default: false
0039 %                         Note: If set to false, only the inverse SH
0040 %                         transform will be applied to get HRTFs for the
0041 %                         new distance according to the sampling grid.
0042 %                         Thus, processing will be much faster. If set to
0043 %                         true, various forward and inverse SH transform
0044 %                         are gonne be performed on a high order grid, so
0045 %                         processing takes longer.
0046 % adjustAmplitude       - Boolen with true / false. Option to adjust the HRTF level
0047 %                         according to the 1/r law.
0048 %                         Default: false --> HRTF have roughly the same
0049 %                         amplitude after distance shift
0050 % radius                - Define radius of rigid sphere / HRTFs in m
0051 %                         Default: 0.0875
0052 % earPosition           - 4 x 1 row vector describing the position of the ears in
0053 %                         spherical coordinates in degree [azL, elL, azR, elR]
0054 %                         Default: [90, 90, 270, 90] (left-right symmetrical)
0055 % N_HRTF                - Spherical harmonics order for HRTF processing. If
0056 %                         not specified, Nmax from the HRTFdataset struct will be applied (mostly
0057 %                         the best choice)
0058 %                         Default: Nmax from HRTFdataset struct
0059 %
0060 % Dependencies: -
0061 %
0062 % References:
0063 % [1] A. Kan, C. Jin, and A. van Schaik, “A psychophysical evaluation of
0064 % near-field head-related transfer functions synthesized using a distance
0065 % variation function,” J. Acoust. Soc. Am., vol. 125, no. 4, pp. 2233–2242, 2009.
0066 %
0067 % [2] S. Spagnol, E. Tavazzi, and F. Avanzini, “Distance rendering and
0068 % perception of nearby virtual sound sources with a near-field filter model,”
0069 % Appl. Acoust., vol. 115, pp. 61–73, 2017.
0070 %
0071 % [3] D. Romblom and B. Cook, “Near-Field Compensation for HRTF Processing,”
0072 % in Proceedings of the 125th AES Convention, San Francisco, USA, 2008, pp. 1–6.
0073 %
0074 % (C) 2020 by JMA, Johannes M. Arend
0075 %             TH Köln - University of Applied Sciences
0076 %             Institute of Communications Engineering
0077 %             Department of Acoustics and Audio Signal Processing
0078 
0079 function [shiftedHRTF_L, shiftedHRTF_R, ffShiftedHRTFdataset] = supdeq_dvf(HRTFdataset, newDistance, samplingGrid, shiftToFarField, adjustAmplitude, radius, earPosition, N_HRTF)
0080 
0081 if nargin < 2 || isempty(newDistance)
0082    error('Please specify new distance in m'); 
0083 end
0084 
0085 if nargin < 3 || isempty(samplingGrid)
0086    error('Please define sampling grid'); 
0087 end
0088 
0089 if nargin < 4 || isempty(shiftToFarField)
0090    shiftToFarField = false;
0091 end
0092 
0093 if nargin < 5 || isempty(adjustAmplitude)
0094    adjustAmplitude = false; 
0095 end
0096 
0097 if nargin < 6 || isempty(radius)
0098    radius = 0.0875; 
0099 end
0100 
0101 if nargin < 7 || isempty(earPosition)
0102     earPosition = [90, 90, 270, 90];
0103 end
0104 
0105 if nargin < 8 || isempty(N_HRTF)
0106     if isfield(HRTFdataset,'N')
0107         N_HRTF = HRTFdataset.N; 
0108     end
0109     if isfield(HRTFdataset,'Nmax')
0110         N_HRTF = HRTFdataset.Nmax; 
0111     end
0112 end
0113 
0114 if isfield(HRTFdataset,'sourceDistance')
0115     md = HRTFdataset.sourceDistance;
0116 else
0117     md = 100; %Assume far field
0118     shiftToFarField = false;
0119 end
0120 
0121 NFFT = length(HRTFdataset.f)*2-2;
0122 fs = HRTFdataset.f(end)*2;
0123 ffShiftedHRTFdataset = nan;
0124 
0125 %% Get various grids
0126 
0127 %Omit weights of samplingGrid if defined
0128 samplingGrid = samplingGrid(:,1:2);
0129 
0130 %Get sg for STF
0131 sgSTF = samplingGrid; sgSTF(:,2) = 90-sgSTF(:,2);
0132 sgSTF_nd = sgSTF; sgSTF_nd(:,3) = newDistance;
0133 sgSTF_md = sgSTF; sgSTF_md(:,3) = md;
0134 ffDistance = 100;
0135 sgSTF_ff = sgSTF; sgSTF_ff(:,3) = ffDistance;
0136 
0137 earPositionSTF = earPosition; earPositionSTF(2) = 90-earPositionSTF(2); earPositionSTF(4) = 90-earPositionSTF(4);
0138 
0139 %Get parallax grids of new distance
0140 [sg_nd_para_l,sg_nd_para_r] = supdeq_parallax(samplingGrid,newDistance,radius,earPosition);
0141 
0142 %% Get rigid sphere transfer functions for new distance
0143 
0144 stf_nd      = AKsphericalHead(sgSTF_nd,earPositionSTF,false,radius,newDistance,100,NFFT,fs);
0145 stf_nd_L    = AKboth2singleSidedSpectrum(fft(squeeze(stf_nd(:,:,1))));
0146 stf_nd_R    = AKboth2singleSidedSpectrum(fft(squeeze(stf_nd(:,:,2))));
0147 
0148 
0149 %% If dataset should be shifted to far field first before shifting to new distance
0150 %This compensates parallax effects which are already in the measurement
0151 
0152 if shiftToFarField
0153     
0154     disp('Shifting measured HRTFs first to far field');
0155     
0156     %Get Lebedev sampling grid according to N
0157     lebN = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59,62,65];
0158      
0159     %Get closest N
0160     [~,cId] = min(abs(N_HRTF-lebN));
0161     N_HRTF_leb = lebN(cId);
0162         
0163     if N_HRTF_leb < N_HRTF
0164         cId = cId + 1;
0165         N_HRTF = lebN(cId);
0166     else
0167         N_HRTF = N_HRTF_leb;
0168     end
0169 
0170     %Get sampling grid according to N_HRTF for internal sh processing
0171     sg_int = supdeq_lebedev([],N_HRTF); 
0172     %Omit weights
0173     sg_int = sg_int(:,1:2);
0174     
0175     %Get parallax grid for measurement distance
0176     [sg_md_para_l,sg_md_para_r] = supdeq_parallax(sg_int,md,radius,earPosition);
0177     
0178     %Get STFs for far field position on dense grid
0179     ffDistance = 100;
0180     sgSTF_int_ff = sg_int; sgSTF_int_ff(:,2) = 90-sgSTF_int_ff(:,2);
0181     sgSTF_int_ff(:,3) = ffDistance;
0182     stf_int_ff  = AKsphericalHead(sgSTF_int_ff,earPositionSTF,false,radius,ffDistance,100,NFFT,fs);
0183     stf_int_ff_L= AKboth2singleSidedSpectrum(fft(squeeze(stf_int_ff(:,:,1))));
0184     stf_int_ff_R= AKboth2singleSidedSpectrum(fft(squeeze(stf_int_ff(:,:,2))));
0185     
0186     %Get STFs for measurement position on dense grid
0187     sgSTF_int_md = sg_int; sgSTF_int_md(:,2) = 90-sgSTF_int_md(:,2);
0188     sgSTF_int_md(:,3) = md;
0189     stf_int_md  = AKsphericalHead(sgSTF_int_md,earPositionSTF,false,radius,md,100,NFFT,fs);
0190     stf_int_md_L= AKboth2singleSidedSpectrum(fft(squeeze(stf_int_md(:,:,1))));
0191     stf_int_md_R= AKboth2singleSidedSpectrum(fft(squeeze(stf_int_md(:,:,2))));
0192     
0193     %Calculate DVFs for left and right ear, Target = far
0194     DVF_int_L = stf_int_ff_L./stf_int_md_L; 
0195     DVF_int_R = stf_int_ff_R./stf_int_md_R; 
0196     
0197     %Get parallaxe grid HRTFs of measured dataset for measurement position
0198     [hrtf_L] = supdeq_getArbHRTF(HRTFdataset,sg_md_para_l,'DEG',0,'ak');
0199     [~,hrtf_R] = supdeq_getArbHRTF(HRTFdataset,sg_md_para_r,'DEG',1,'ak');
0200     
0201     %Apply DVF to shift to far-field
0202     ff_hrtf_L = (DVF_int_L.').*hrtf_L; 
0203     ff_hrtf_R = (DVF_int_R.').*hrtf_R; 
0204     
0205     %Transform far-field shifted HRTF set to SH domain again for further
0206     %processing
0207     ffShiftedHRTFdataset = supdeq_hrtf2sfd(ff_hrtf_L,ff_hrtf_R,N_HRTF,sg_int,fs,'ak');
0208     
0209     %Get some parameters
0210     ffShiftedHRTFdataset.FFToversize = HRTFdataset.FFToversize;
0211     ffShiftedHRTFdataset.sourceDistance = 100;
0212     ffShiftedHRTFdataset.ffShifted = true;
0213 end
0214 
0215 %% Apply DVFs
0216 
0217 disp('Shifting HRTFs to new position');
0218 
0219 if shiftToFarField
0220     %Calculate DVFs for left and right ear, Target = close
0221     %Work with far-field distance STFs
0222     stf_ff      = AKsphericalHead(sgSTF_ff,earPositionSTF,false,radius,ffDistance,100,NFFT,fs);
0223     stf_ff_L    = AKboth2singleSidedSpectrum(fft(squeeze(stf_ff(:,:,1))));
0224     stf_ff_R    = AKboth2singleSidedSpectrum(fft(squeeze(stf_ff(:,:,2))));
0225     
0226     DVF_L = stf_nd_L./stf_ff_L; 
0227     DVF_R = stf_nd_R./stf_ff_R; 
0228     
0229     %Get parallaxe grid HRTFs of far-field dataset for new position
0230     [hrtf_L] = supdeq_getArbHRTF(ffShiftedHRTFdataset,sg_nd_para_l,'DEG',0,'ak');
0231     [~,hrtf_R] = supdeq_getArbHRTF(ffShiftedHRTFdataset,sg_nd_para_r,'DEG',1,'ak');
0232     
0233 else
0234     %Calculate DVFs for left and right ear, Target = close
0235     %Work with measurement distance STFs
0236     stf_md      = AKsphericalHead(sgSTF_md,earPositionSTF,false,radius,md,100,NFFT,fs);
0237     stf_md_L    = AKboth2singleSidedSpectrum(fft(squeeze(stf_md(:,:,1))));
0238     stf_md_R    = AKboth2singleSidedSpectrum(fft(squeeze(stf_md(:,:,2))));
0239     
0240     DVF_L = stf_nd_L./stf_md_L; 
0241     DVF_R = stf_nd_R./stf_md_R; 
0242     
0243     %Get parallaxe grid HRTFs of far-field dataset for new position
0244     [hrtf_L] = supdeq_getArbHRTF(HRTFdataset,sg_nd_para_l,'DEG',0,'ak');
0245     [~,hrtf_R] = supdeq_getArbHRTF(HRTFdataset,sg_nd_para_r,'DEG',1,'ak');
0246 end
0247 
0248 %Apply DVFs
0249 shiftedHRTF_L = (DVF_L.').*hrtf_L; 
0250 shiftedHRTF_R = (DVF_R.').*hrtf_R; 
0251 
0252 if adjustAmplitude
0253     
0254     %Set referenceDistance to 1 if md was not defined
0255     if md == 100
0256         refDistance = 1;
0257     else
0258         refDistance = md;
0259     end
0260     
0261     shiftedHRTF_L = shiftedHRTF_L*(refDistance/newDistance);
0262     shiftedHRTF_R = shiftedHRTF_R*(refDistance/newDistance);
0263     
0264 end
0265 
0266 disp('Done...');
0267 
0268 end
0269

Generated on Wed 30-Nov-2022 14:15:00 by m2html © 2005