RAVEN

-removed xml related stuff (in future, this will be part of the RAVEN installation)
parent 13fd0705
function ita_save_xml_material_for_raven(varargin)
%ita_save_xml_material_for_raven(filename, [arguments])
%
%Optional parameters and default values:
%
% 'id', '',
% 'name', '',
% 'description', '',
%
% 'reflection_factor', [],
% 'absorption_coeff', [],
% 'scatter_coeff', [],
% 'impedance', [],
%
% 'frequency', [],
% 'frequency_type', [], % {'none', 'equidistant', 'third-octave', 'octave'}
% 'theta_in', [],
% 'theta_out', [],
% 'phi_in', [],
% 'phi_out', [],
%
% 'order', 'column-major',
% 'mode', 'write', % {'write', 'append', 'replace'}
% 'root', 'material' % {'material', 'material_db'}
%
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
%% Parse input arguments
args = struct(...
'pos1_filepath', '', ...
...
'id', '', ...
'name', '', ...
'description', '', ...
...
'reflection_factor', [], ...
'absorption_coeff', [], ...
'scatter_coeff', [], ...
'impedance', [], ...
...
'frequency', [], ...
'frequency_type', [], ...
'theta_in', [], ...
'theta_out', [], ...
'phi_in', [], ...
'phi_out', [], ...
...
'temperature', [], ...
'huminity', [], ...
'c', [], ...
...
'order', 'column-major', ...
'mode', 'write', ...
'root', 'material');
[filepath, args] = ita_parse_arguments(args, varargin);
switch args.mode
case {'write'}
switch args.root
case {'material'}
document = com.mathworks.xml.XMLUtils.createDocument('material');
case {'material_db'}
document = com.mathworks.xml.XMLUtils.createDocument('material_db');
otherwise
% Error: not a valid root node
exception = MException('fdda:inputTypeError', ...
sprintf('%s not a valid root node. Options are {material|material_db}', args.root) ...
);
throw(exception);
end
case {'append', 'replace'}
document = xmlread(filepath);
document = xml_remove_empty_lines(document);
otherwise
% Error: not a valid mode
exception = MException('fdda:inputTypeError', ...
sprintf('%s not a valid mode. Options are {write|append|replace}', args.mode) ...
);
throw(exception);
end
root_node = document.getDocumentElement;
switch xml_get_node_name(root_node)
case {'material_db'}
try
material_nodes = xml_get_node(root_node, 'material');
catch ME
if strcmp(ME.identifier, 'fdda:xml:invalidPathError')
material_node = create_material_node(document, args.id, 'name', args.name, 'description', args.description);
root_node.appendChild(material_node);
material_nodes = material_node;
else
rethrow(ME);
end
end
if ~iscell(material_nodes)
material_nodes = {material_nodes};
end
material_ids = xml_get_attribute_value(material_nodes, 'id');
first_match = find(strcmp(args.id, material_ids), 1);
if ~isempty(first_match)
material_node = material_nodes{first_match};
else
material_node = create_material_node(document, args.id, 'name', args.name, 'description', args.description);
root_node.appendChild(material_node);
end
case {'material'}
material_node = root_node;
attr_id = document.createAttribute('id');
attr_id.setValue(args.id);
material_node.setAttributeNode(attr_id);
if ~isempty(args.name)
material_node.appendChild(xml_create_string_node(document, 'name', args.name));
end
if ~isempty(args.description)
material_node.appendChild(xml_create_string_node(document, 'description', args.description));
end
otherwise
exception = MException('fdda:inputTypeError', ...
sprintf('%s not a valid root node. Options are {material|material_db}', args.root) ...
);
throw(exception);
end
if ~isempty(args.reflection_factor)
if ~isempty(args.frequency)
f = args.frequency;
else
f = args.reflection_factor.freqVector;
end
node = create_data_node(document, 'reflection_factor', args.reflection_factor.freq, ...
'frequency', f, ...
'frequency_type', args.frequency_type, ...
'theta_in', args.theta_in, ...
'theta_out', args.theta_out, ...
'order', args.order);
material_node.appendChild(node);
end
if ~isempty(args.absorption_coeff)
if ~isempty(args.frequency)
f = args.frequency;
else
f = args.absorption_coeff.freqVector;
end
node = create_data_node(document, 'absorption_coeff', args.absorption_coeff.freq, ...
'frequency', f, ...
'frequency_type', args.frequency_type, ...
'theta_in', args.theta_in, ...
'theta_out', args.theta_out, ...
'order', args.order);
material_node.appendChild(node);
end
if ~isempty(args.scatter_coeff)
if ~isempty(args.frequency)
f = args.frequency;
else
f = args.scatter_coeff.freqVector;
end
node = create_data_node(document, 'scatter_coeff', args.scatter_coeff.freq, ...
'frequency', f, ...
'frequency_type', args.frequency_type, ...
'theta_in', args.theta_in, ...
'theta_out', args.theta_out, ...
'order', args.order);
material_node.appendChild(node);
end
xmlwrite(filepath, document);
edit(filepath);
end
function node = create_material_node(varargin)
args = struct(...
'pos1_document', '', ...
'pos2_id', '', ...
'name', [], ...
'description', []);
[document, id, args] = ita_parse_arguments(args, varargin);
node = document.createElement('material');
attr_id = document.createAttribute('id');
attr_id.setValue(id);
node.setAttributeNode(attr_id);
if ~isempty(args.name)
node.appendChild(xml_create_string_node(document, 'name', args.name));
end
if ~isempty(args.description)
node.appendChild(xml_create_string_node(document, 'description', args.description));
end
end
function node = create_data_node(varargin)
args = struct(...
'pos1_document', '', ...
'pos2_type', '', ...
'pos3_data', '', ...
'theta_in', [], ...
'theta_out', [], ...
'phi_out', [], ...
'frequency', [], ...
'frequency_type', [], ...
'order', 'column-major');
[document, type, data, args] = ita_parse_arguments(args, varargin);
measurement_type = 'normal';
child_nodes = {};
if ~isempty(args.frequency)
child_nodes = [child_nodes {xml_create_real_array_node(document, 'frequency', args.frequency, args.order)}];
end
if ~isempty(args.frequency_type) && ismember(args.frequency_type, {'none', 'equidistant', 'third-octave', 'octave'})
child_nodes = [child_nodes {xml_create_string_node(document, 'frequency_type', args.frequency_type)}];
end
if ~isempty(args.theta_in)
child_nodes = [child_nodes {xml_create_real_array_node(document, 'theta_in', args.theta_in, args.order)}];
measurement_type = 'angle-dependent';
end
if ~isempty(args.theta_out)
child_nodes = [child_nodes {xml_create_real_array_node(document, 'theta_out', args.theta_out, args.order)}];
measurement_type = 'bidirectional';
end
if ~isempty(args.theta_out)
child_nodes = [child_nodes {xml_create_real_array_node(document, 'theta_out', args.theta_out, args.order)}];
end
child_nodes = [child_nodes {xml_create_string_node(document, 'data_type', measurement_type)}];
switch type
case {'reflection_factor', 'impedance'}
child_nodes = [child_nodes {xml_create_complex_array_node(document, 'data', data, args.order)}];
case {'absorption_coeff', 'scatter_coeff'}
child_nodes = [child_nodes {xml_create_real_array_node(document, 'data', data, args.order)}];
otherwise
exception = MException('fdda:inputValueError', ...
sprintf('%s not a valid type. Options are {reflection_factor|impedance|absorption_coeff|scatter_coeff}', type) ...
);
throw(exception);
end
node = document.createElement(type);
for index = 1:numel(child_nodes)
node.appendChild(child_nodes{index});
end
end
function string = shape_to_string(shape)
if numel(shape) > 1
string = [sprintf('%d ', shape(1:end-1)) sprintf('%d', shape(end))];
else
string = sprintf('%d', shape);
end
end
\ No newline at end of file
function ita_save_xml_material_for_raven_from_impcalc_struct(impcalc_struct, xml_filename, optional_filenamediffuse)
%ita_save_xml_material_for_raven_from_impcalc_struct(impcalc_struct, xml_filename, optional_filenamediffuse)
%
% Writes an XML material file for Raven. The input struct can be
% generated using the ITA-Toolbox function ita_impcalc_gui.
%
% Parameters:
% impcalc_struct: struct as stored by ita_impcalc_gui (usually called
% "saveIt").
% xml_filename : filename where the XML file should be stored. Put
% the materials into:
% %RavenPath%\RavenDatabase\MaterialDatabase
% optional_filenamediffuse: use this optional parameter of you want
% to store the diffuse-average version of the
% angle-dependent reflection properties.
%
% Example:
% ita_impcalc_gui
% matStruct = load('my_saved_layer_info.mat');
% ita_save_xml_material_for_raven_from_impcalc_struct(...
% matStruct.saveIt, 'my_xml_material.xml', ...
% 'my_xml_material_diffuse.xml');
%
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
%% angle-dependent
impcalc_struct.sea.senk = 1;
result = ita_utils_sim_layer_model(impcalc_struct, 'theta', 0:5:85, 'save', 'Audio', 'fftDegree', 16, 'samplingRate', 44100, 'f', [0 22050]);
third_octave_reflection = ita_spk2frequencybands(result.reflection_factor, 'bandsperoctave', 3, 'method', 'averaged');
third_octave_absorption = ita_spk2frequencybands(result.absorption_coeff, 'bandsperoctave', 3, 'method', 'averaged');
[~,name,~] = fileparts(xml_filename);
ita_save_xml_material_for_raven(xml_filename, ...
'id', name, ...
'name', name, ...
'description', 'Calculated using ita_impcalc_gui', ...
'reflection_factor', third_octave_reflection, ...
'absorption_coeff', third_octave_absorption, ...
...'scatter_coeff', ?, ...
...'impedance', ?, ...
'frequency_type', 'third-octave', ...
'theta_in', toRadians('degrees', 0:5:85));
%% diffuse
if (nargin > 2)
impcalc_struct.sea.winkel = 0;
impcalc_struct.sea.senk = 0;
result = ita_impcalc_wo_gui(impcalc_struct, 'modus', 'Impedanz', 'save', 'Audio', 'fftDegree', 16, 'sampleRate', 44100);
reflection = result.ch(3);
absorption = result.ch(4);
mask = abs(reflection.freq) > 1;
reflection.freq(mask) = 1 * exp(1i * angle(reflection.freq(mask)));
mask = absorption.freq < 0;
absorption.freq(mask) = 0;
third_octave_reflection = ita_spk2frequencybands(reflection, 'bandsperoctave', 3, 'method', 'averaged');
third_octave_absorption = ita_spk2frequencybands(absorption, 'bandsperoctave', 3, 'method', 'averaged');
[~,name,~] = fileparts(optional_filenamediffuse);
ita_save_xml_material_for_raven(optional_filenamediffuse, ...
'id', name, ...
'name', name, ...
'description', 'Calculated using ita_impcalc_gui', ...
'reflection_factor', third_octave_reflection, ...
'absorption_coeff', third_octave_absorption, ...
...'scatter_coeff', ?, ...
...'impedance', ?, ...
'frequency_type', 'third-octave');
end
end
\ No newline at end of file
function string = ita_utils_matrix_to_string(A, order, format_string, sep_string)
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
if nargin < 2
order = 'column-major';
end
if nargin < 3
format_string = '%.3e';
end
if nargin < 4
sep_string = ' ';
end
switch order
case 'row-major'
string = row_major(A, format_string, sep_string);
case 'column-major'
string = sprintf([format_string sep_string], A);
string = string(1:end-1);
end
end
function string = row_major(A, format_string, sep_string)
D = size(A);
if numel(D) > 2
tmp = nan(D(2:end));
substrings = {}; %cell(1, D(1));
for m = 1:D(1)
tmp(:) = A(m,:);
substrings = [substrings {row_major(tmp, format_string, sep_string)}];
end
else
substrings = {}; %cell(1, D(1) * D(2));
for m = 1:D(1)
for n = 1:D(2)
substrings = [substrings {sprintf(format_string, A(m,n))}];
end
end
end
string = strjoin(substrings, sep_string);
end
\ No newline at end of file
function result = ita_utils_sim_layer_model(varargin)
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
args = struct('pos1_model', '', ...
'theta', 0, ...
'modus', 'Impedanz', ...
'save', 'Result', ...
'fftDegree', 16, ...
'samplingRate', 44100, ...
'f', [] ...
);
[model, args] = ita_parse_arguments(args,varargin);
result.reflection_factor = itaResult;
result.absorption_coeff = itaResult;
result.impedance = itaResult;
if ~isempty(args.f)
model.fb.unten = args.f(1);
model.fb.oben = args.f(2);
model.fb.step = args.samplingRate/2^args.fftDegree;
model.fb.lin = 1;
end
for index = 1:numel(args.theta)
model.sea.winkel = args.theta(index);
% [cli_output, result_theta] = evalc('ita_impcalc_wo_gui(model)');
[cli_output, result_theta] = evalc('ita_impcalc_wo_gui(model, ''modus'', args.modus, ''save'', args.save, ''fftDegree'', args.fftDegree, ''sampleRate'', args.samplingRate)');
result.reflection_factor = merge(result.reflection_factor, result_theta.ch(strcmp('Reflection Factor', result_theta.channelNames)));
result.absorption_coeff = merge(result.absorption_coeff, result_theta.ch(strcmp('Absorption', result_theta.channelNames)));
result.impedance = merge(result.impedance, result_theta.ch(strcmp('Impedance', result_theta.channelNames)));
end
end
\ No newline at end of file
function node = xml_create_complex_array_node(document, name, A, order)
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
node = document.createElement(name);
attr_shape = document.createAttribute('shape');
attr_shape.setValue(ita_utils_matrix_to_string(size(A), order, '%d'));
attr_order = document.createAttribute('order');
attr_order.setValue(order);
subnode_value = document.createElement('value');
subnode_value.appendChild(document.createTextNode(ita_utils_matrix_to_string(abs(A), order)));
subnode_angle = document.createElement('angle');
subnode_angle.appendChild(document.createTextNode(ita_utils_matrix_to_string(angle(A), order)));
node.setAttributeNode(attr_shape);
node.setAttributeNode(attr_order);
node.appendChild(subnode_value);
node.appendChild(subnode_angle);
end
\ No newline at end of file
function node = xml_create_real_array_node(document, name, A, order)
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
node = document.createElement(name);
attr_shape = document.createAttribute('shape');
attr_shape.setValue(ita_utils_matrix_to_string(size(A), order, '%d'));
attr_order = document.createAttribute('order');
attr_order.setValue(order);
node.appendChild(document.createTextNode(ita_utils_matrix_to_string(A, order)));
node.setAttributeNode(attr_shape);
node.setAttributeNode(attr_order);
end
\ No newline at end of file
function node = xml_create_string_node(document, name, value)
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
node = document.createElement(name);
node.appendChild(document.createTextNode(value));
end
\ No newline at end of file
function s = xml_get_attribute_value(root, path, sep)
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
if nargin < 3
sep = '/';
end
if ischar(path)
path = split(path, sep);
end
if numel(path) > 1
root = xml_get_node(root, path(1:end-1), sep);
end
if ~iscell(root)
s = char(root.getAttribute(path(end)));
else
for index = 1:numel(root)
s{index} = char(root{index}.getAttribute(path(end)));
end
end
end
\ No newline at end of file
function node = xml_get_node(root, path, sep)
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
if ~isscalar(root)
% Error: Ambiguous path
% Maybe allow multiple roots later
exception = MException('fdda:xml:ambiguousPathError', ...
sprintf('Ambiguous path. (Maybe support multiple root and non-leaf nodes later.)') ...
);
throw(exception);
end
if nargin < 3
sep = '/';
end
if ischar(path)
path = split(path, sep);
end
if ~iscell(path)
exception = MException('fdda:xml:inputTypeError', ...
sprintf('Path has to be a string or a cell array of strings.') ...
);
throw(exception);
end
if numel(path) > 1
node = xml_get_node(xml_get_node(root, path(1), sep), path(2:end), sep);
else
index = find(strcmp(path{1}, xml_list_child_nodes(root))) - 1;
if isempty(index)
exception = MException('fdda:xml:invalidPathError', ...
sprintf('Node "%s" does not exist.', path{1}) ...
);
throw(exception);