Aufgrund einer Wartung wird GitLab am 28.09. zwischen 10:00 und 11:00 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to maintenance, GitLab will be temporarily unavailable on 28.09. between 10:00 and 11:00 am.

Merging important fixes and improvements from OpenDAFF repository

parent a9eb8078
# OpenDAFF - A free, open source software package for directional audio data
OpenDAFF is distributed under the terms of the GNU Lesser Public License (LGPL) with an exception for static linking permission.
## License
Copyright (c) Institute of Technical Acoustics, RWTH Aachen University, 2009-2016
Visit the OpenDAFF homepage: http://www.opendaff.org
Copyright 2016 Institute of Technical Acoustics, RWTH Aachen University
Licensed under the Apache License, Version 2.0 (the "License");
you may not use the OpenDAFF software package except in compliance with the License.
You may obtain a copy of the License at
<http://www.apache.org/licenses/LICENSE-2.0>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
You should also have received a [copy of the License](LICENSE.md) with the OpenDAFF software package.
## Matlab scripts
......
......@@ -260,12 +260,12 @@ function [] = daffv17_write( varargin )
end
if isfield(args, 'alphares')
args.alphapoints = round(alphaspan / args.alphares);
if (ceil(args.alphapoints) ~= args.alphapoints)
error('Alpha range and alpha resolution are not an integer multiple')
args.alphapoints = alphaspan / args.alphares;
if abs( args.alphapoints - args.alphapoints ) > eps
error( 'Alpha range and alpha resolution are not an integer multiple' )
end
else
args.alphares = round(alphaspan / args.alphapoints);
args.alphares = alphaspan / args.alphapoints;
end
% Beta points and resolution
......@@ -285,7 +285,7 @@ function [] = daffv17_write( varargin )
end
if isfield(args, 'betares')
args.betapoints = round((betaspan / args.betares) + 1);
args.betapoints = (betaspan / args.betares) + 1;
if (ceil(args.betapoints) ~= args.betapoints)
error('Beta range and beta resolution are not an integer multiple')
end
......@@ -311,17 +311,10 @@ function [] = daffv17_write( varargin )
end
% Quantization
if ~isfield(args, 'quantization')
if (contentType == 0)
% For time-domain data => 16-Bit signed integer
args.quantization = 'int16';
else
% For all other data => 32-Bit floating points
args.quantization = 'float32';
end
end
args.quantization = 'float32'; % Default except for IR
quantizationType = 2; % DAFF_FLOAT32
if isfield(args, 'quantization')
if isfield( args, 'quantization' ) && strcmp( args.content, 'IR' )
args.quantization = lower(args.quantization);
switch args.quantization
case 'int16'
......@@ -337,15 +330,18 @@ function [] = daffv17_write( varargin )
quantizationType = 2; % DAFF_FLOAT32
otherwise
error(['Invalid quantization (' args.quantization ')']);
error( 'Invalid quantization (%s)', args.quantization );
end
end
if strcmp(args.content, 'IR')
if strcmp( args.content, 'IR' )
% Validation for IR content
% Zero-threshold (default value)
if ~isfield(args, 'zthreshold'), args.zthreshold = -inf; end;
if ~isfield(args, 'zthreshold')
args.zthreshold = -inf;
end
zthreshold_value = 10^(args.zthreshold/20);
end
......@@ -415,7 +411,9 @@ function [] = daffv17_write( varargin )
props.transformSize = 0;
% Generate a list of all individual input data sets
x = cell( args.alphapoints, args.betapoints, args.channels );
% note: use round here to avoid errors if alphapoints are not exactly
% integers but within epsilon
x = cell( round( args.alphapoints ), round( args.betapoints ), args.channels );
for b=1:args.betapoints
beta = betastart + (b-1)*args.betares;
......@@ -431,16 +429,16 @@ function [] = daffv17_write( varargin )
% --= Impulse responses =--
if strcmp(args.content, 'IR')
if strcmp( args.content, 'IR' )
% Get the data
[data, samplerate, metadata] = args.datafunc(alpha, beta, args.userdata);
[channels, filterlength] = size(data);
[ data, samplerate, metadata ] = args.datafunc( alpha, beta, args.userdata );
[ channels, filterlength] = size( data );
if( ~isa( data, 'double' ) )
if( ~isa( data, 'numeric' ) )
error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta );
end
if isfield(props, 'samplerate')
if isfield( props, 'samplerate' )
if (samplerate ~= props.samplerate)
error( 'Dataset (A%0.1f, B%0.1f): Sampling rate does not match', alpha, beta );
end
......@@ -460,7 +458,7 @@ function [] = daffv17_write( varargin )
% Check filter length for 16-byte alignment
if( mod( filterlength, 4 ) ~= 0 )
error( 'Dataset (A%0.1f, B%0.1f): Filter length is not a multiple of 4 (this is required for memory alignment)', alpha, beta );
error( 'Dataset (A%0.1f, B%0.1f): Filter length is %d which is not a multiple of 4 (this is required for memory alignment)', alpha, beta, filterlength );
end
fprintf('Global properties: Sampling rate = %d Hz, filter length = %d\n',...
......@@ -535,13 +533,13 @@ function [] = daffv17_write( varargin )
[ freqs, data, metadata ] = args.datafunc( alpha, beta, args.userdata );
[channels, numfreqs] = size(data);
if (class(data) ~= 'double')
error( sprintf('Dataset (A%0.1f, B%0.1f): Data function must deliver double values') );
if ~isa( data, 'numeric' )
error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta );
end
if isfield(props, 'freqs')
if (freqs ~= props.freqs)
error( sprintf('Dataset (A%0.1f, B%0.1f): Frequency support does not match', alpha, beta) );
if isfield( props, 'freqs' )
if freqs ~= props.freqs
error( 'Dataset (A%0.1f, B%0.1f): Frequency support does not match', alpha, beta );
end
if (channels ~= args.channels)
......@@ -574,21 +572,23 @@ function [] = daffv17_write( varargin )
end
% Important: Negative magnitudes are forbidden
if (min(min(data)) < 0)
if min( min( data ) ) < 0
error( 'Dataset (A%0.1f, B%0.1f): Contains negative magnitudes', alpha, beta );
end
for c=1:args.channels
for c = 1:args.channels
% Determine the peak value
peak = max(max(data(c,:)));
props.globalPeak = max([props.globalPeak peak]);
x{a,b,c} = struct('peak', peak, ...
'metadata', metadata, ...
'metadataIndex', 0);
peak = max( max( data( c, : ) ) );
props.globalPeak = max( [ props.globalPeak peak ] );
x{a,b,c} = struct( 'peak', peak, ...
'metadata', metadata, ...
'metadataIndex', 0 ...
);
end
write_metadatablock = write_metadatablock || ~isempty(metadata);
write_metadatablock = write_metadatablock || ~isempty(metadata);
% Discard the data
clear data;
......@@ -647,7 +647,8 @@ function [] = daffv17_write( varargin )
x{a,b,c} = struct('metadata', metadata, ...
'metadataIndex', 0);
end
write_metadatablock = write_metadatablock || ~isempty(metadata);
write_metadatablock = write_metadatablock || ~isempty(metadata);
% Discard the data
clear data;
......@@ -660,30 +661,30 @@ function [] = daffv17_write( varargin )
[ freqs, data, metadata ] = args.datafunc( alpha, beta, args.userdata );
[channels, numfreqs] = size(data);
if (class(data) ~= 'double')
error( sprintf('Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta) );
if ~isa( data, 'numeric' )
error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta );
end
if isfield(props, 'freqs')
if (freqs ~= props.freqs)
error( sprintf('Dataset (A%0.1f, B%0.1f): Frequency support does not match', alpha, beta) );
if isfield( props, 'freqs' )
if freqs ~= props.freqs
error( 'Dataset (A%0.1f, B%0.1f): Frequency support does not match', alpha, beta );
end
if (channels ~= args.channels)
error( sprintf('Dataset (A%0.1f, B%0.1f): Number of channels does not match', alpha, beta) );
if channels ~= args.channels
error( 'Dataset (A%0.1f, B%0.1f): Number of channels does not match', alpha, beta );
end
else
% Checks on the frequency support
if (min(freqs) <= 0)
error( sprintf('Dataset (A%0.1f, B%0.1f): Support frequencies must be greater zero', alpha, beta) );
if min(freqs) <= 0
error( 'Dataset (A%0.1f, B%0.1f): Support frequencies must be greater zero', alpha, beta );
end;
if (sort(freqs) ~= freqs)
error( sprintf('Dataset (A%0.1f, B%0.1f): Support frequencies must be stricly increasing', alpha, beta) );
if sort(freqs) ~= freqs
error( 'Dataset (A%0.1f, B%0.1f): Support frequencies must be stricly increasing', alpha, beta );
end
if (length(unique(freqs)) ~= length(freqs))
error( sprintf('Dataset (A%0.1f, B%0.1f): Support frequencies must be unique', alpha, beta) );
if length(unique(freqs)) ~= length(freqs)
error( 'Dataset (A%0.1f, B%0.1f): Support frequencies must be unique', alpha, beta );
end
% Now set the global properties, if they have not been set yet
......@@ -691,18 +692,19 @@ function [] = daffv17_write( varargin )
props.freqs = freqs;
props.elementsPerRecord = length(freqs);
fprintf('Global properties: Number of frequencies = %d\n', numfreqs);
fprintf( 'Global properties: Number of frequencies = %d\n', numfreqs );
end
% Determine the peak value
peak = max(max(abs(data)));
props.globalPeak = max([props.globalPeak peak]);
peak = max( max( abs( data ) ) );
props.globalPeak = max( [ props.globalPeak peak ] );
for c=1:args.channels
x{a,b,c} = struct('metadata', metadata, ... %'peak', peak, ...
'metadataIndex', 0);
end
write_metadatablock = write_metadatablock || ~isempty(metadata);
write_metadatablock = write_metadatablock || ~isempty(metadata);
% Discard the data
clear data;
......@@ -710,37 +712,36 @@ function [] = daffv17_write( varargin )
% --= DFT spectra =--
if strcmp(args.content, 'DFT')
if strcmp( args.content, 'DFT' )
% Get the data
[ data, sampleRate, isSymetric, metadata ] = args.datafunc( alpha, beta, args.userdata );
[ channels, numDFTCoeffs ] = size( data );
if (class(data) ~= 'double')
error( sprintf('Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta) );
if ~isa( data, 'double' )
error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta );
end
% test something (TODO)
if (class(data) ~= 'double')
error( sprintf('Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta) );
if channels ~= args.channels
error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver matching channel numbers (%d != %d) ', alpha, beta, args.channels, channels );
end
if (class(isSymetric) ~= 'logical')
error( sprintf('Dataset (A%0.1f, B%0.1f): third parameter isSymetric must be logical', alpha, beta));
if isa( isSymetric, 'logical' ) == 0
error( 'Dataset (A%0.1f, B%0.1f): third parameter isSymetric must be logical', alpha, beta );
end
if isfield( props, 'samplerate' )
if ( sampleRate ~= props.sampleRate )
error( sprintf( 'Dataset (A%0.1f, B%0.1f): Sample rate does not match', alpha, beta ) );
error( 'Dataset (A%0.1f, B%0.1f): Sample rate does not match', alpha, beta );
end
end
if isfield(props, 'numDFTCoeffs')
if (numDFTCoeffs ~= props.numDFTCoeffs)
error( sprintf('Dataset (A%0.1f, B%0.1f): Number of discrete fourier spectra coefficients is not constant', alpha, beta));
if isfield( props, 'numDFTCoeffs' )
if( numDFTCoeffs ~= props.numDFTCoeffs )
error( 'Dataset (A%0.1f, B%0.1f): Number of discrete fourier spectra coefficients is not constant', alpha, beta );
end
else
if (numDFTCoeffs <= 0)
error( sprintf('Dataset (A%0.1f, B%0.1f): Number of discrete fourier spectra coefficients must be greater than zero', alpha, beta));
if( numDFTCoeffs <= 0 )
error( 'Dataset (A%0.1f, B%0.1f): Number of discrete fourier spectra coefficients must be greater than zero', alpha, beta );
end
props.numDFTCoeffs = numDFTCoeffs;
......@@ -753,19 +754,20 @@ function [] = daffv17_write( varargin )
props.transformSize = numDFTCoeffs;
end
fprintf('Global properties: Sampling rate = %d Hz, dft length = %d, transform size = %d\n',...
props.sampleRate, props.numDFTCoeffs, props.transformSize);
fprintf( 'Global properties: Sampling rate = %d Hz, dft length = %d, transform size = %d\n',...
props.sampleRate, props.numDFTCoeffs, props.transformSize );
end
% Determine the peak value
peak = max(max(abs(data)));
props.globalPeak = max([props.globalPeak peak]);
peak = max( max( abs( data ) ) );
props.globalPeak = max( [ props.globalPeak peak ] );
for c=1:args.channels
for c = 1:args.channels
x{a,b,c} = struct('metadata', metadata, ... %'peak', peak, ...
'metadataIndex', 0);
end
write_metadatablock = write_metadatablock || ~isempty(metadata);
write_metadatablock = write_metadatablock || ~isempty( metadata );
% Discard the data
clear data;
......@@ -775,7 +777,7 @@ function [] = daffv17_write( varargin )
end
end
fprintf('Global peak: %+0.1f dB (%0.6f)\n', 20*log10(props.globalPeak), props.globalPeak);
fprintf( 'Global peak: %+0.1f dB (%0.6f)\n', 20*log10(props.globalPeak), props.globalPeak );
if strcmp(args.content, 'IR')
% Calculate to overall storage saving
......@@ -929,7 +931,7 @@ function [] = daffv17_write( varargin )
% Number of frequencies
fwrite(fid, props.numDFTCoeffs, 'int32');
fwrite(fid, props.transformSize, 'int32');
fwrite(fid, props.sampleRate, 'int32');
fwrite(fid, props.sampleRate, 'float32');
fwrite(fid, props.globalPeak, 'float32');
end
......@@ -997,7 +999,7 @@ function [] = daffv17_write( varargin )
% Clipping check
peak = max(max(abs(data)));
if ((peak > 1) && (~args.quiet))
if ( peak > 1 ) && ( ~args.quiet ) && ( quantizationType ~= 2 )
warning( 'Dataset (A%0.1f, B%0.1f): Clipping occured (peak %0.3f)', alpha, beta, peak );
end
......@@ -1014,7 +1016,7 @@ function [] = daffv17_write( varargin )
case 'int16'
% Dynamic range: 2^15-1 = 32767
cdata = int16( data(c,i1:i2)*32767 );
fwrite(fid, cdata, 'int16');
fwrite( fid, cdata, 'int16' );
case 'int24'
% Dynamic range: 2^23-1 = 8388607
......@@ -1054,8 +1056,8 @@ function [] = daffv17_write( varargin )
% Clipping check
peak = max(max(data));
if ((peak > 1) && (~args.quiet))
warning( sprintf('Dataset (A%0.1f, B%0.1f): Clipping occured (peak %0.3f)', alpha, beta, peak) );
if ( peak > 1.0 ) && ( ~args.quiet ) && ( quantizationType ~= 2 )
warning( 'Dataset (A%0.1f, B%0.1f): Clipping occured (peak %0.3f)', alpha, beta, peak );
end
%x{a,b}.dataOffset = zeros(1, args.channels);
......
function [] = daffv17_convert_from_miro( miro_obj, target_file_path, additional_metadata )
function [] = daffv17_convert_from_miro( miro_obj, target_file_path, additional_metadata, domain )
%
% daffv17_convert_from_miro Converts a MIRO object into DAFF
%
......@@ -14,8 +14,12 @@ if nargin < 1
elseif nargin < 2
target_file_path = [ miro_obj.name '.ir.v17.daff' ];
additional_metadata = [];
domain = 'time';
elseif nargin < 3
additional_metadata = [];
domain = 'time';
elseif nargin < 4
domain = 'time';
end
......@@ -65,17 +69,31 @@ betanums = size( unique( quadrature( :, 2 ) ), 1 );
betarange = rad2deg( [ min( miro_obj.elevation ) max( miro_obj.elevation ) ] );
betares = diff( betarange ) / ( betanums - 1 );
%$ Execute using data function 'dfMIRO'
daffv17_write( 'filename', target_file_path, ...
'datafunc', @dfMIRO, ...
'userdata', miro_obj, ...
'metadata', metadata, ...
'content', 'ir', ...
'alphares', alphares, ...
'alpharange', alpharange, ...
'betares', betares, ...
'betarange', betarange, ...
'orient', [ 0 0 0 ], ...
'channels', 2, ...
'quantization', 'float32' );
\ No newline at end of file
if strcmpi( domain, 'frequency' )
%$ Execute using data function 'dfMIRODFT' (frequency domain)
daffv17_write( 'filename', target_file_path, ...
'datafunc', @dfMIRODFT, ...
'userdata', miro_obj, ...
'metadata', metadata, ...
'content', 'dft', ...
'alphares', alphares, ...
'alpharange', alpharange, ...
'betares', betares, ...
'betarange', betarange, ...
'orient', [ 0 0 0 ], ...
'channels', 2 );
else
%$ Execute using data function 'dfMIRO' (time domain)
daffv17_write( 'filename', target_file_path, ...
'datafunc', @dfMIRO, ...
'userdata', miro_obj, ...
'metadata', metadata, ...
'content', 'ir', ...
'alphares', alphares, ...
'alpharange', alpharange, ...
'betares', betares, ...
'betarange', betarange, ...
'orient', [ 0 0 0 ], ...
'channels', 2, ...
'quantization', 'float32' );
end
\ No newline at end of file
function [ data, sampleRate, isSymetric, metadata ] = dfMIRODFT( alpha, beta, miro_obj )
isSymetric = true;
sampleRate = miro_obj.fs;
if ~isempty( miro_obj.resampleToFS )
sampleRate = miro_obj.resampleToFS;
end
if strcmp( miro_obj.angles, 'DEG' )
[ irID, azimuth, elevation ] = closestIr( miro_obj, alpha, beta );
else
[ irID, azimuth, elevation ] = closestIr( miro_obj, deg2rad( alpha ), deg2rad( beta ) );
end
hrir = getIR( miro_obj, irID );
nResidual = mod( size( hrir, 1 ), 4 );
if nResidual > 0
dft_raw = fft( [ hrir' zeros( 2, 4 - nResidual ) ] );
else
dft_raw = fft( hrir' );
end
fft_size = size( dft_raw, 1 ) / 2 + 1;
data = dft_raw( 1:fft_size, : );
metadata = [];
if strcmp( miro_obj.angles, 'RAD' )
azimuth = rad2deg( azimuth );
elevation = rad2deg( elevation );
end
angle_threshold_deg = 0.2;
if abs( diff( [ azimuth alpha ] ) ) < angle_threshold_deg || ...
abs( diff( [ elevation beta ] ) < angle_threshold_deg )
daffv17_add_metadata( metadata, 'MIRO Nearest Neighbour Search Applied', 'Bool', true );
daffv17_add_metadata( metadata, 'MIRO Nearest Neighbour Azimuth', 'Float', azimuth );
daffv17_add_metadata( metadata, 'MIRO Nearest Neighbour Elevation', 'Float', elevation );
end
end
......@@ -44,3 +44,7 @@ daffv17_convert_from_miro( HRIR_FULL2DEG, 'HRIR_FULL2DEG_48kHz_web.v17.ir.daff',
% ... with resampling to common 44.1 kHz
HRIR_FULL2DEG.resampleToFS = 44.1e3;
daffv17_convert_from_miro( HRIR_FULL2DEG, 'HRIR_FULL2DEG_44kHz_web.v17.ir.daff', additional_metadata );
% ... in frequency domain.
HRIR_FULL2DEG.resampleToFS = HRIR_FULL2DEG.fs; % reset fs
daffv17_convert_from_miro( HRIR_FULL2DEG, 'HRIR_FULL2DEG_44kHz_web.v17.dft.daff', additional_metadata, 'frequency' );
Markdown is supported
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