Commit a6991753 authored by Dipl.-Ing. Jonas Stienen's avatar Dipl.-Ing. Jonas Stienen
Browse files

Merging important fixes and improvements from OpenDAFF repository

parent a9eb8078
# OpenDAFF - A free, open source software package for directional audio data # 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 Copyright 2016 Institute of Technical Acoustics, RWTH Aachen University
Visit the OpenDAFF homepage: http://www.opendaff.org
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 ## Matlab scripts
......
...@@ -260,12 +260,12 @@ function [] = daffv17_write( varargin ) ...@@ -260,12 +260,12 @@ function [] = daffv17_write( varargin )
end end
if isfield(args, 'alphares') if isfield(args, 'alphares')
args.alphapoints = round(alphaspan / args.alphares); args.alphapoints = alphaspan / args.alphares;
if (ceil(args.alphapoints) ~= args.alphapoints) if abs( args.alphapoints - args.alphapoints ) > eps
error('Alpha range and alpha resolution are not an integer multiple') error( 'Alpha range and alpha resolution are not an integer multiple' )
end end
else else
args.alphares = round(alphaspan / args.alphapoints); args.alphares = alphaspan / args.alphapoints;
end end
% Beta points and resolution % Beta points and resolution
...@@ -285,7 +285,7 @@ function [] = daffv17_write( varargin ) ...@@ -285,7 +285,7 @@ function [] = daffv17_write( varargin )
end end
if isfield(args, 'betares') if isfield(args, 'betares')
args.betapoints = round((betaspan / args.betares) + 1); args.betapoints = (betaspan / args.betares) + 1;
if (ceil(args.betapoints) ~= args.betapoints) if (ceil(args.betapoints) ~= args.betapoints)
error('Beta range and beta resolution are not an integer multiple') error('Beta range and beta resolution are not an integer multiple')
end end
...@@ -311,17 +311,10 @@ function [] = daffv17_write( varargin ) ...@@ -311,17 +311,10 @@ function [] = daffv17_write( varargin )
end end
% Quantization % Quantization
if ~isfield(args, 'quantization') args.quantization = 'float32'; % Default except for IR
if (contentType == 0) quantizationType = 2; % DAFF_FLOAT32
% 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
if isfield(args, 'quantization') if isfield( args, 'quantization' ) && strcmp( args.content, 'IR' )
args.quantization = lower(args.quantization); args.quantization = lower(args.quantization);
switch args.quantization switch args.quantization
case 'int16' case 'int16'
...@@ -337,15 +330,18 @@ function [] = daffv17_write( varargin ) ...@@ -337,15 +330,18 @@ function [] = daffv17_write( varargin )
quantizationType = 2; % DAFF_FLOAT32 quantizationType = 2; % DAFF_FLOAT32
otherwise otherwise
error(['Invalid quantization (' args.quantization ')']); error( 'Invalid quantization (%s)', args.quantization );
end end
end end
if strcmp(args.content, 'IR') if strcmp( args.content, 'IR' )
% Validation for IR content % Validation for IR content
% Zero-threshold (default value) % 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); zthreshold_value = 10^(args.zthreshold/20);
end end
...@@ -415,7 +411,9 @@ function [] = daffv17_write( varargin ) ...@@ -415,7 +411,9 @@ function [] = daffv17_write( varargin )
props.transformSize = 0; props.transformSize = 0;
% Generate a list of all individual input data sets % 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 for b=1:args.betapoints
beta = betastart + (b-1)*args.betares; beta = betastart + (b-1)*args.betares;
...@@ -431,16 +429,16 @@ function [] = daffv17_write( varargin ) ...@@ -431,16 +429,16 @@ function [] = daffv17_write( varargin )
% --= Impulse responses =-- % --= Impulse responses =--
if strcmp(args.content, 'IR') if strcmp( args.content, 'IR' )
% Get the data % Get the data
[data, samplerate, metadata] = args.datafunc(alpha, beta, args.userdata); [ data, samplerate, metadata ] = args.datafunc( alpha, beta, args.userdata );
[channels, filterlength] = size(data); [ 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 ); error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta );
end end
if isfield(props, 'samplerate') if isfield( props, 'samplerate' )
if (samplerate ~= props.samplerate) if (samplerate ~= props.samplerate)
error( 'Dataset (A%0.1f, B%0.1f): Sampling rate does not match', alpha, beta ); error( 'Dataset (A%0.1f, B%0.1f): Sampling rate does not match', alpha, beta );
end end
...@@ -460,7 +458,7 @@ function [] = daffv17_write( varargin ) ...@@ -460,7 +458,7 @@ function [] = daffv17_write( varargin )
% Check filter length for 16-byte alignment % Check filter length for 16-byte alignment
if( mod( filterlength, 4 ) ~= 0 ) 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 end
fprintf('Global properties: Sampling rate = %d Hz, filter length = %d\n',... fprintf('Global properties: Sampling rate = %d Hz, filter length = %d\n',...
...@@ -535,13 +533,13 @@ function [] = daffv17_write( varargin ) ...@@ -535,13 +533,13 @@ function [] = daffv17_write( varargin )
[ freqs, data, metadata ] = args.datafunc( alpha, beta, args.userdata ); [ freqs, data, metadata ] = args.datafunc( alpha, beta, args.userdata );
[channels, numfreqs] = size(data); [channels, numfreqs] = size(data);
if (class(data) ~= 'double') if ~isa( data, 'numeric' )
error( sprintf('Dataset (A%0.1f, B%0.1f): Data function must deliver double values') ); error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta );
end end
if isfield(props, 'freqs') if isfield( props, 'freqs' )
if (freqs ~= props.freqs) if freqs ~= props.freqs
error( sprintf('Dataset (A%0.1f, B%0.1f): Frequency support does not match', alpha, beta) ); error( 'Dataset (A%0.1f, B%0.1f): Frequency support does not match', alpha, beta );
end end
if (channels ~= args.channels) if (channels ~= args.channels)
...@@ -574,21 +572,23 @@ function [] = daffv17_write( varargin ) ...@@ -574,21 +572,23 @@ function [] = daffv17_write( varargin )
end end
% Important: Negative magnitudes are forbidden % 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 ); error( 'Dataset (A%0.1f, B%0.1f): Contains negative magnitudes', alpha, beta );
end end
for c=1:args.channels for c = 1:args.channels
% Determine the peak value % Determine the peak value
peak = max(max(data(c,:))); peak = max( max( data( c, : ) ) );
props.globalPeak = max([props.globalPeak peak]); props.globalPeak = max( [ props.globalPeak peak ] );
x{a,b,c} = struct('peak', peak, ... x{a,b,c} = struct( 'peak', peak, ...
'metadata', metadata, ... 'metadata', metadata, ...
'metadataIndex', 0); 'metadataIndex', 0 ...
);
end end
write_metadatablock = write_metadatablock || ~isempty(metadata);
write_metadatablock = write_metadatablock || ~isempty(metadata);
% Discard the data % Discard the data
clear data; clear data;
...@@ -647,7 +647,8 @@ function [] = daffv17_write( varargin ) ...@@ -647,7 +647,8 @@ function [] = daffv17_write( varargin )
x{a,b,c} = struct('metadata', metadata, ... x{a,b,c} = struct('metadata', metadata, ...
'metadataIndex', 0); 'metadataIndex', 0);
end end
write_metadatablock = write_metadatablock || ~isempty(metadata);
write_metadatablock = write_metadatablock || ~isempty(metadata);
% Discard the data % Discard the data
clear data; clear data;
...@@ -660,30 +661,30 @@ function [] = daffv17_write( varargin ) ...@@ -660,30 +661,30 @@ function [] = daffv17_write( varargin )
[ freqs, data, metadata ] = args.datafunc( alpha, beta, args.userdata ); [ freqs, data, metadata ] = args.datafunc( alpha, beta, args.userdata );
[channels, numfreqs] = size(data); [channels, numfreqs] = size(data);
if (class(data) ~= 'double') if ~isa( data, 'numeric' )
error( sprintf('Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta) ); error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta );
end end
if isfield(props, 'freqs') if isfield( props, 'freqs' )
if (freqs ~= props.freqs) if freqs ~= props.freqs
error( sprintf('Dataset (A%0.1f, B%0.1f): Frequency support does not match', alpha, beta) ); error( 'Dataset (A%0.1f, B%0.1f): Frequency support does not match', alpha, beta );
end end
if (channels ~= args.channels) if channels ~= args.channels
error( sprintf('Dataset (A%0.1f, B%0.1f): Number of channels does not match', alpha, beta) ); error( 'Dataset (A%0.1f, B%0.1f): Number of channels does not match', alpha, beta );
end end
else else
% Checks on the frequency support % Checks on the frequency support
if (min(freqs) <= 0) if min(freqs) <= 0
error( sprintf('Dataset (A%0.1f, B%0.1f): Support frequencies must be greater zero', alpha, beta) ); error( 'Dataset (A%0.1f, B%0.1f): Support frequencies must be greater zero', alpha, beta );
end; end;
if (sort(freqs) ~= freqs) if sort(freqs) ~= freqs
error( sprintf('Dataset (A%0.1f, B%0.1f): Support frequencies must be stricly increasing', alpha, beta) ); error( 'Dataset (A%0.1f, B%0.1f): Support frequencies must be stricly increasing', alpha, beta );
end end
if (length(unique(freqs)) ~= length(freqs)) if length(unique(freqs)) ~= length(freqs)
error( sprintf('Dataset (A%0.1f, B%0.1f): Support frequencies must be unique', alpha, beta) ); error( 'Dataset (A%0.1f, B%0.1f): Support frequencies must be unique', alpha, beta );
end end
% Now set the global properties, if they have not been set yet % Now set the global properties, if they have not been set yet
...@@ -691,18 +692,19 @@ function [] = daffv17_write( varargin ) ...@@ -691,18 +692,19 @@ function [] = daffv17_write( varargin )
props.freqs = freqs; props.freqs = freqs;
props.elementsPerRecord = length(freqs); props.elementsPerRecord = length(freqs);
fprintf('Global properties: Number of frequencies = %d\n', numfreqs); fprintf( 'Global properties: Number of frequencies = %d\n', numfreqs );
end end
% Determine the peak value % Determine the peak value
peak = max(max(abs(data))); peak = max( max( abs( data ) ) );
props.globalPeak = max([props.globalPeak peak]); 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, ... x{a,b,c} = struct('metadata', metadata, ... %'peak', peak, ...
'metadataIndex', 0); 'metadataIndex', 0);
end end
write_metadatablock = write_metadatablock || ~isempty(metadata);
write_metadatablock = write_metadatablock || ~isempty(metadata);
% Discard the data % Discard the data
clear data; clear data;
...@@ -710,37 +712,36 @@ function [] = daffv17_write( varargin ) ...@@ -710,37 +712,36 @@ function [] = daffv17_write( varargin )
% --= DFT spectra =-- % --= DFT spectra =--
if strcmp(args.content, 'DFT') if strcmp( args.content, 'DFT' )
% Get the data % Get the data
[ data, sampleRate, isSymetric, metadata ] = args.datafunc( alpha, beta, args.userdata ); [ data, sampleRate, isSymetric, metadata ] = args.datafunc( alpha, beta, args.userdata );
[ channels, numDFTCoeffs ] = size( data ); [ channels, numDFTCoeffs ] = size( data );
if (class(data) ~= 'double') if ~isa( data, 'double' )
error( sprintf('Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta) ); error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta );
end end
% test something (TODO) if channels ~= args.channels
if (class(data) ~= 'double') error( 'Dataset (A%0.1f, B%0.1f): Data function must deliver matching channel numbers (%d != %d) ', alpha, beta, args.channels, channels );
error( sprintf('Dataset (A%0.1f, B%0.1f): Data function must deliver double values', alpha, beta) );
end end
if (class(isSymetric) ~= 'logical') if isa( isSymetric, 'logical' ) == 0
error( sprintf('Dataset (A%0.1f, B%0.1f): third parameter isSymetric must be logical', alpha, beta)); error( 'Dataset (A%0.1f, B%0.1f): third parameter isSymetric must be logical', alpha, beta );
end end
if isfield( props, 'samplerate' ) if isfield( props, 'samplerate' )
if ( sampleRate ~= 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
end end
if isfield(props, 'numDFTCoeffs') if isfield( props, 'numDFTCoeffs' )
if (numDFTCoeffs ~= 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)); error( 'Dataset (A%0.1f, B%0.1f): Number of discrete fourier spectra coefficients is not constant', alpha, beta );
end end
else else
if (numDFTCoeffs <= 0) 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)); error( 'Dataset (A%0.1f, B%0.1f): Number of discrete fourier spectra coefficients must be greater than zero', alpha, beta );
end end
props.numDFTCoeffs = numDFTCoeffs; props.numDFTCoeffs = numDFTCoeffs;
...@@ -753,19 +754,20 @@ function [] = daffv17_write( varargin ) ...@@ -753,19 +754,20 @@ function [] = daffv17_write( varargin )
props.transformSize = numDFTCoeffs; props.transformSize = numDFTCoeffs;
end end
fprintf('Global properties: Sampling rate = %d Hz, dft length = %d, transform size = %d\n',... fprintf( 'Global properties: Sampling rate = %d Hz, dft length = %d, transform size = %d\n',...
props.sampleRate, props.numDFTCoeffs, props.transformSize); props.sampleRate, props.numDFTCoeffs, props.transformSize );
end end
% Determine the peak value % Determine the peak value
peak = max(max(abs(data))); peak = max( max( abs( data ) ) );
props.globalPeak = max([props.globalPeak peak]); 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, ... x{a,b,c} = struct('metadata', metadata, ... %'peak', peak, ...
'metadataIndex', 0); 'metadataIndex', 0);
end end
write_metadatablock = write_metadatablock || ~isempty(metadata);
write_metadatablock = write_metadatablock || ~isempty( metadata );
% Discard the data % Discard the data
clear data; clear data;
...@@ -775,7 +777,7 @@ function [] = daffv17_write( varargin ) ...@@ -775,7 +777,7 @@ function [] = daffv17_write( varargin )
end end
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') if strcmp(args.content, 'IR')
% Calculate to overall storage saving % Calculate to overall storage saving
...@@ -929,7 +931,7 @@ function [] = daffv17_write( varargin ) ...@@ -929,7 +931,7 @@ function [] = daffv17_write( varargin )
% Number of frequencies % Number of frequencies
fwrite(fid, props.numDFTCoeffs, 'int32'); fwrite(fid, props.numDFTCoeffs, 'int32');
fwrite(fid, props.transformSize, 'int32'); fwrite(fid, props.transformSize, 'int32');
fwrite(fid, props.sampleRate, 'int32'); fwrite(fid, props.sampleRate, 'float32');
fwrite(fid, props.globalPeak, 'float32'); fwrite(fid, props.globalPeak, 'float32');
end end
...@@ -997,7 +999,7 @@ function [] = daffv17_write( varargin ) ...@@ -997,7 +999,7 @@ function [] = daffv17_write( varargin )
% Clipping check % Clipping check
peak = max(max(abs(data))); 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 ); warning( 'Dataset (A%0.1f, B%0.1f): Clipping occured (peak %0.3f)', alpha, beta, peak );
end end
...@@ -1014,7 +1016,7 @@ function [] = daffv17_write( varargin ) ...@@ -1014,7 +1016,7 @@ function [] = daffv17_write( varargin )
case 'int16' case 'int16'
% Dynamic range: 2^15-1 = 32767 % Dynamic range: 2^15-1 = 32767
cdata = int16( data(c,i1:i2)*32767 ); cdata = int16( data(c,i1:i2)*32767 );
fwrite(fid, cdata, 'int16'); fwrite( fid, cdata, 'int16' );
case 'int24' case 'int24'
% Dynamic range: 2^23-1 = 8388607 % Dynamic range: 2^23-1 = 8388607
...@@ -1054,8 +1056,8 @@ function [] = daffv17_write( varargin ) ...@@ -1054,8 +1056,8 @@ function [] = daffv17_write( varargin )
% Clipping check % Clipping check
peak = max(max(data)); peak = max(max(data));
if ((peak > 1) && (~args.quiet)) if ( peak > 1.0 ) && ( ~args.quiet ) && ( quantizationType ~= 2 )
warning( sprintf('Dataset (A%0.1f, B%0.1f): Clipping occured (peak %0.3f)', alpha, beta, peak) ); warning( 'Dataset (A%0.1f, B%0.1f): Clipping occured (peak %0.3f)', alpha, beta, peak );
end end
%x{a,b}.dataOffset = zeros(1, args.channels); %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 % daffv17_convert_from_miro Converts a MIRO object into DAFF
% %
...@@ -14,8 +14,12 @@ if nargin < 1 ...@@ -14,8 +14,12 @@ if nargin < 1
elseif nargin < 2 elseif nargin < 2
target_file_path = [ miro_obj.name '.ir.v17.daff' ]; target_file_path = [ miro_obj.name '.ir.v17.daff' ];
additional_metadata = []; additional_metadata = [];
domain = 'time';
elseif nargin < 3 elseif nargin < 3
additional_metadata = []; additional_metadata = [];
domain = 'time';
elseif nargin < 4
domain = 'time';
end end
...@@ -65,17 +69,31 @@ betanums = size( unique( quadrature( :, 2 ) ), 1 ); ...@@ -65,17 +69,31 @@ betanums = size( unique( quadrature( :, 2 ) ), 1 );
betarange = rad2deg( [ min( miro_obj.elevation ) max( miro_obj.elevation ) ] ); betarange = rad2deg( [ min( miro_obj.elevation ) max( miro_obj.elevation ) ] );
betares = diff( betarange ) / ( betanums - 1 ); betares = diff( betarange ) / ( betanums - 1 );
%$ Execute using data function 'dfMIRO' if strcmpi( domain, 'frequency' )
daffv17_write( 'filename', target_file_path, ... %$ Execute using data function 'dfMIRODFT' (frequency domain)
'datafunc', @dfMIRO, ... daffv17_write( 'filename', target_file_path, ...
'userdata', miro_obj, ... 'datafunc', @dfMIRODFT, ...
'metadata', metadata, ... 'userdata', miro_obj, ...
'content', 'ir', ... 'metadata', metadata, ...
'alphares', alphares, ... 'content', 'dft', ...
'alpharange', alpharange, ... 'alphares', alphares, ...
'betares', betares, ... 'alpharange', alpharange, ...
'betarange', betarange, ... 'betares', betares, ...
'orient', [ 0 0 0 ], ... 'betarange', betarange, ...
'channels', 2, ... 'orient', [ 0 0 0 ], ...
'quantization', 'float32' ); 'channels', 2 );
else
\ No newline at end of file %$ 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 )