writeDAFFFile.m 5.26 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
if( channels < 1 || mod( channels, 2 ) ~= 0 )
145
146
147
    warning('Number of channels per record was not detected correctly, assuming 2 channel records');
    channels = 2;
end
148

149
150
151
152
153
154
155
daff_write_args.channels = channels;


%% Call daff_write and pass argument list

daffv17_write( daff_write_args );

156
157

end