writeDAFFFile.m 5.42 KB
Newer Older
1 2 3 4 5 6 7
function writeDAFFFile( this, file_path, varargin )
% Exports itaHRTF to a DAFF file using daffv17_write
%
% Will export the entire angle range of the itaHRTF data set from
% minimum angle to maximum angle in theta and phi by an angular 
% resulution of the range divided by the number of available spatial
% points as a equi-angular grid (regular grid, Gaussian sampling).
8
%
9
% Input:    file_path (string) [optional]
10
%           write_daff_args optional arguments (passed to daffv17_write) [optional]
11 12 13 14 15 16 17
%
% Required: OpenDAFF matlab scripts, http://www.opendaff.org
%           (but included in ITA-Toolbox)
%
% Output: none

hrtf_variable_name = inputname( 1 );
18
file_name = [ hrtf_variable_name '_' int2str( this.nSamples ) 'samples_' int2str( this.resAzimuth ) 'x' int2str( this.resElevation ) '.daff'];
19
if nargin >= 2
20
    file_name = file_path;    
21 22 23 24 25 26 27
end

if nargin == 0
    error( 'Not enough input arguments' );
end


28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
%% Prepare daff_write arguments

if strcmp( this.domain, 'time' )

    % Content type switcher between time domain (ir) and frequency domain (dft)
    % (requires different data functions and content descriptor)
    
    sIn.content = 'ir';
    sIn.datafunc = @dfitaHRIRDAFFDataFunc;
    sIn.zthreshold = -400; % zero threshold for discarding samples in beginning and end region of IR (where only noise is present)
    
elseif strcmp( this.domain, 'freq' )
    
    sIn.content = 'dft';
    sIn.datafunc = @dfitaHRTFDAFFDataFunc;
    
end

sIn.metadata = this.mMetadata;
sIn.quantization = 'float32';
sIn.userdata = this;
sIn.orient = [ 0 0 0 ];
sIn.quiet = false;

if ~isempty( varargin )
    daff_write_args = ita_parse_arguments( sIn, varargin{ 1 } );
else
    daff_write_args = ita_parse_arguments( sIn, varargin );
end


59 60 61 62 63 64 65
%% Inject content type indicator 'ir' or 'dft' into file name

ct_indicator = 'ir';
if strcmp( this.domain, 'freq' )
    ct_indicator = 'dft';
end

66
[ file_path, file_base_name, file_suffix ] = fileparts( file_name );
67
if ~strcmp( file_suffix, '.daff' ) && ~isempty( file_suffix )
68
    file_path = fullfile( file_path, strjoin( {file_base_name file_suffix 'v17' ct_indicator 'daff' }, '.' ) );
69
else
70
    file_path = fullfile( file_path, strjoin( {file_base_name 'v17' ct_indicator 'daff'}, '.' ) );
71 72
end

73 74
daff_write_args.filename = file_path;

75 76 77 78 79

%% Prepare angle ranges and resolution

theta_start_deg = rad2deg( min( this.channelCoordinates.theta ) );
theta_end_deg = rad2deg( max( this.channelCoordinates.theta ) );
80
theta_num_elements = size( uniquetol( this.channelCoordinates.theta ), 1 );
81

82 83
phi_start_deg = rad2deg( min( mod( this.channelCoordinates.phi, 2 * pi ) ) );
phi_end_deg = rad2deg( max( mod( this.channelCoordinates.phi, 2 * pi ) ) );
84
phi_num_elements = size( uniquetol( this.channelCoordinates.phi ), 1 );
85 86 87 88 89

assert( phi_num_elements ~= 0 );
alphares = ( phi_end_deg - phi_start_deg ) / phi_num_elements; % phi end does not cover entire circle in this case
alphares_full_circle = ( phi_end_deg - phi_start_deg ) / ( phi_num_elements - 1 ); % phi end does not cover entire circle in this case
if phi_end_deg + alphares_full_circle >= 360.0
90
    alpharange = [ phi_start_deg 360 ]; % Account for full circle and force end of range to 360 deg
91 92 93 94 95
    alphares = alphares_full_circle;
else
    alpharange = [ phi_start_deg phi_end_deg ];
end

96 97 98
assert( alpharange( 1 ) >= 0.0 )
assert( alpharange( 2 ) <= 360.0 )

99 100 101 102
assert( theta_num_elements ~= 0 );
betares = ( theta_end_deg - theta_start_deg ) / ( theta_num_elements - 1 ); % phi end does not cover entire circle
betarange = 180 - [ theta_start_deg theta_end_deg ]; % Flip poles (DAFF starts at south pole)

103 104 105
assert( betarange( 2 ) >= 0.0 )
assert( betarange( 1 ) <= 180.0 )

106 107 108 109 110
daff_write_args.betarange = alpharange;
daff_write_args.alphares = alphares;
daff_write_args.betarange = betarange;
daff_write_args.betares = betares;

111

112 113 114
%% Assemble metadata (if not already present)

keyname = 'Generation script';
115 116
if isempty(daff_write_args.metadata) || ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
    daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', 'writeDAFFFile.m' );
117 118 119
end

keyname = 'Generation toolkit';
120 121
if ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
    daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', 'ITA-Toolkit' );
122 123 124
end

keyname = 'Generation date';
125 126
if ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
    daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', date );
127 128
end

129
keyname = 'Git Version';
130
if ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
131
    versionHash = ita_git_getMasterCommitHash;
132
    daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', versionHash );
133 134
end

135
keyname = 'Web resource';
136 137
if ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
    daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', 'http://www.ita-toolkit.org' );
138 139
end

140

141 142
%% Channels

143
channels=this.nChannels/this.nDirections;
144 145
if( channels < 1 )
    warning( 'Number of channels per record was smaller than one, assuming 2 channel records' );
146
    channels = 2;
147 148 149
elseif( mod( channels, 2 ) ~= 0 )
    warning( [ 'Number of channels per record was not and integer number, trying floor() of ' num2str( channels ) ] );
    channels = floor( channels );
150
end
151

152 153 154 155 156 157 158
daff_write_args.channels = channels;


%% Call daff_write and pass argument list

daffv17_write( daff_write_args );

159 160

end