Commit 151f6aaf authored by Hark Braren's avatar Hark Braren
Browse files

Moving sofa import of HRTFs to external function and clean up of HRTF class

parent 9e4cb72b
......@@ -110,10 +110,13 @@ classdef itaHRTF < itaAudio
itaAudio2itaHRTF;
init;
hdf2itaHRTF;
sofa2itaHRTF;
nDirections = [];
end
properties (Dependent = true, SetAccess = private)
end
methods % Special functions that implement operations that are usually performed only on instances of the class
%% Input
function this = itaHRTF(varargin)
......@@ -155,7 +158,7 @@ classdef itaHRTF < itaAudio
end
% sofa input
if ~isempty(find(strcmpi(varargin,'SOFA')==1, 1))
this.sofa2itaHRTF = varargin{find(strcmpi(varargin,'SOFA')==1)+1};
this = ita_read_sofa_hrtf(arargin{find(strcmpi(varargin,'SOFA')==1)+1});
end
elseif nargin == 1
......@@ -188,9 +191,9 @@ classdef itaHRTF < itaAudio
this.itaAudio2itaHRTF = varargin{1};
elseif ischar(varargin{1}) % openDaff/ sofa/ hdf5 input
if strfind(lower(varargin{1}),'.daff'), this.openDAFF2itaHRTF = varargin{1};
elseif strfind(lower(varargin{1}),'.hdf5'), this.hdf2itaHRTF = varargin{1};
elseif strfind(lower(varargin{1}),'.sofa'), this.sofa2itaHRTF = varargin{1};
if contains(lower(varargin{1}),'.daff'), this.openDAFF2itaHRTF = varargin{1};
elseif contains(lower(varargin{1}),'.hdf5'), this.hdf2itaHRTF = varargin{1};
elseif contains(lower(varargin{1}),'.sofa'), this = ita_read_sofa_hrtf(varargin{1});
end
end
end
......@@ -557,82 +560,7 @@ classdef itaHRTF < itaAudio
this.channelNames = ita_sprintf('%s ( %2.0f, %2.0f)',...
this.mEarSide , ...
this.channelCoordinates.theta_deg, this.channelCoordinates.phi_deg);
end
function this = set.sofa2itaHRTF(this,pathFile)
%% check if sofa is installed
if ~exist('SOFAstart.m','file')
error('SOFA not installed. Run ita_sofa_install');
end
if ~exist(pathFile,'file')
f=filesep;
pathFile=[SOFAdbPath f 'SOFA' f pathFile];
end
handleSofa = SOFAload(pathFile);
% get the number of measurement positions
numPositions = length(handleSofa.SourcePosition);
% data
% the data is saved as positions x channel x filterdata
this.samplingRate = handleSofa.Data.SamplingRate;
data = zeros(size(handleSofa.Data.IR,3),numPositions*2);
data(:,1:2:numPositions*2) = squeeze(handleSofa.Data.IR(:,1,:)).';
data(:,2:2:numPositions*2) = squeeze(handleSofa.Data.IR(:,2,:)).';
% coordinates
coordinates = ita_sofa_getCoordinates(handleSofa,'channelCoordinateType','SourcePosition');
% duplicate the coordinates for both channels
channelCoordinates = itaCoordinates(numPositions*2);
channelCoordinates.x(1:2:numPositions*2) = coordinates.x;
channelCoordinates.x(2:2:numPositions*2) = coordinates.x;
channelCoordinates.y(1:2:numPositions*2) = coordinates.y;
channelCoordinates.y(2:2:numPositions*2) = coordinates.y;
channelCoordinates.z(1:2:numPositions*2) = coordinates.z;
channelCoordinates.z(2:2:numPositions*2) = coordinates.z;
% added view and up vector
this.objectViewVector = itaCoordinates(handleSofa.ListenerView);
this.objectUpVector = itaCoordinates(handleSofa.ListenerUp);
this.objectCoordinates = itaCoordinates(handleSofa.ListenerPosition);
warning('ITA_HRTF: Sofa Up and View vectors are ignored');
this.data = data;
this.channelCoordinates = channelCoordinates;
this.mDirCoord = coordinates;
this.mEarSide = repmat(['L'; 'R'],numPositions, 1);
this.signalType = 'energy';
this.channelNames = ita_sprintf('%s ( %2.0f, %2.0f)',...
this.mEarSide ,...
this.channelCoordinates.theta_deg, this.channelCoordinates.phi_deg );
%% user data
userDataFields = {'GLOBAL_Conventions','GLOBAL_Version','GLOBAL_SOFAConventions','GLOBAL_SOFAConventionsVersion' ...
,'GLOBAL_APIName','GLOBAL_APIVersion','GLOBAL_ApplicationName','GLOBAL_ApplicationVersion','GLOBAL_AuthorContact' ...
,'GLOBAL_Comment','GLOBAL_DataType','GLOBAL_History','GLOBAL_License','GLOBAL_Organization','GLOBAL_References' ...
,'GLOBAL_RoomType','GLOBAL_Origin','GLOBAL_DateCreated','GLOBAL_DateModified','GLOBAL_Title','GLOBAL_DatabaseName' ...
,'GLOBAL_RoomDescription','GLOBAL_ListenerShortName','API','ListenerPosition','ListenerPosition_Type','ListenerPosition_Units'...
,'EmitterPosition','EmitterPosition_Type','EmitterPosition_Units','RoomCornerA','RoomCornerA_Type','RoomCornerA_Units' ...
,'RoomCornerB','RoomCornerB_Type','RoomCornerB_Units','','','','','','',''};
for index = 1:length(userDataFields)
if isfield(handleSofa,userDataFields{index})
userData.(userDataFields{index}) = handleSofa.(userDataFields{index});
end
end
this.userData = userData;
end
end
%% .......................SET......................................
function this = set.dirCoord(this,dirCoord)
......@@ -1700,7 +1628,7 @@ classdef itaHRTF < itaAudio
function result = propertiesSphereType
result = {'cap', 'ring','full','undefined'};
end
end
end
function result = ita_read_sofa_hrtf(filename,varargin)
%ITA_READ_SOFA - +++ Short Description here +++
% This function ++++ FILL IN INFO HERE ++*
% <ITA-Toolbox>
% This file is part of the ITA-Toolbox. Some rights reserved.
% You can find the license for this m-file in the license.txt file in the ITA-Toolbox folder.
% </ITA-Toolbox>
% Author: Jan Gerrit Richter -- Email: jan.richter@akustik.rwth-aachen.de
% Created: 30-Sep-2014
% Updated: 14-Oct-2020 Hark Braren -- Email: hark.braren@akustik.rwth-aachen.de
%% Return type of data this function can read
if nargin == 0
result{1}.extension = '.sofa';
result{1}.comment = 'SOFA Files (*.sofa)';
return
end
sArgs = struct('samplingRate',-1);
ita_parse_arguments(sArgs,varargin);
%% check if sofa is installed
if ~exist('SOFAstart.m','file')
error('SOFA not installed. Run ita_sofa_install');
end
%% Open the sofaFile
if ~exist(filename,'file')
f=filesep;
filename=[SOFAdbPath f 'SOFA' f filename];
end
handleSofa = SOFAload(filename);
%% check HRTF
isHrtf = ismember(handleSofa.GLOBAL_SOFAConventions,{'SimpleFreeFieldHRIR','SimpleFreeFieldHRTF','SimpleFreeFieldTF'});
if ~isHrtf
error("Datatype not typically used for HRTFs");
end
%% get positional data
% head position coordinates and orientation
recieverCoordinates = ita_sofa_getCoordinates(handleSofa,'coordinateType','ReceiverPosition');
listenerView = ita_sofa_getCoordinates(handleSofa,'coordinateType','ListenerView');
listenerUp = listenerView;
listenerUp.(listenerUp.coordSystem) = handleSofa.ListenerUp;
%source coordinates
sourceCoordinates = ita_sofa_getCoordinates(handleSofa,'coordinateType','SourcePosition');
%% get datatype info
switch handleSofa.GLOBAL_DataType
case 'TF'
audioData = getSofaFreqData(handleSofa);
case {'FIR','FIR-E','FIRE'}
audioData = getSofaTimeData(handleSofa);
case 'SOS'
error('SOS type not yet implemented for ITA-Toolbox');
end
% set direction
audioData(1).channelCoordinates = sourceCoordinates;
audioData(2).channelCoordinates = sourceCoordinates;
%% final data as HRTF
if isa(audioData,'itaResult')
result = audioData;
return
else
result = itaHRTF(audioData);
end
result.objectCoordinates = recieverCoordinates;
result.objectUpVector = listenerUp;
result.objectViewVector = listenerView;
%% add metaData as userData
result.userData = getSofaMetadata(handleSofa);
end
function audioData = getSofaTimeData(handleSofa)
data = handleSofa.Data.IR;
samplingrate = handleSofa.Data.SamplingRate;
if size(data,2) ~= 2
error('unknown data structure')
end
leftEarData = itaAudio(squeeze(data(:,1,:)).',samplingrate,'time');
rightEarData = itaAudio(squeeze(data(:,2,:)).',samplingrate,'time');
audioData = [leftEarData, rightEarData];
end
function [audioData] = getSofaFreqData(handleSofa,sArgs)
% handle frequency domain transfer functions:
% decide wether to return itaAudio or itaResult object
if ~ismember(handleSofa.N_LongName,{'f','frequency'})
error('Unspecified content of N in sofa object');
end
if ~ismember(handleSofa.N_Units,{'hertz','hz','Hertz','Hz'})
error('Uknown frequency unit in sofa object');
end
frequencies = handleSofa.N;
data = handleSofa.data.Real+1j*handleSofa.Data.Imag;
if std(diff(frequencies)) > 0.01*mean(diff(frequencies))
ita_verbose_info('Please check frequency Vector. It seems there are some values missing - returnin itaResult',0);
dataL = itaResult(squeeze(data(:,1,:)).',frequencies,'freq');
dataR = itaResult(squeeze(data(:,2,:)).',frequencies,'freq');
audioData = [dataL, dataR];
return
else
ita_verbose_info('Automatically converting from equidistantly sampled frequency domain data, handle with care',1)
end
if size(data,2) ~= 2
error('unknown data structure')
end
samplingrate = 2*max(fVec);
dataL = itaAudio(squeeze(data(:,1,:)).',samplingrate,'freq');
dataR = itaAudio(squeeze(data(:,2,:)).',samplingrate,'freq');
audioData = [dataL, dataR];
end
function result = getSofaMetadata(handleSofa)
% get meta data to keep with the ITA files
%list of possible dataFields
metaDataFields = {'GLOBAL_Conventions','GLOBAL_Version','GLOBAL_SOFAConventions','GLOBAL_SOFAConventionsVersion' ...
,'GLOBAL_APIName','GLOBAL_APIVersion','GLOBAL_ApplicationName','GLOBAL_ApplicationVersion','GLOBAL_AuthorContact' ...
,'GLOBAL_Comment','GLOBAL_DataType','GLOBAL_History','GLOBAL_License','GLOBAL_Organization','GLOBAL_References' ...
,'GLOBAL_RoomType','GLOBAL_Origin','GLOBAL_DateCreated','GLOBAL_DateModified','GLOBAL_Title','GLOBAL_DatabaseName' ...
,'GLOBAL_RoomDescription','GLOBAL_ListenerShortName','API','ListenerPosition','ListenerPosition_Type','ListenerPosition_Units'...
,'EmitterPosition','EmitterPosition_Type','EmitterPosition_Units','RoomCornerA','RoomCornerA_Type','RoomCornerA_Units' ...
,'RoomCornerB','RoomCornerB_Type','RoomCornerB_Units','','','','','','',''};
for index = 1:length(metaDataFields)
if isfield(handleSofa,metaDataFields{index})
result.(metaDataFields{index}) = handleSofa.(metaDataFields{index});
end
end
end %getSofaMetadata()
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment