wolffd@0: function features = xml_parse_mtt(file) wolffd@0: % features = xml_parse_mtt(file) wolffd@0: % wolffd@0: % parses the magnatagatune xml file to retrieve the audio wolffd@0: % analysis results. The file isexpected to use the deprecated wolffd@0: % EchoNest XML format wolffd@0: % wolffd@0: % time always travels an the horizontal axis wolffd@0: wolffd@0: % --- wolffd@0: % TODO: Add Error checking to certan tags as chroma number, wolffd@0: % loudness max etc. wolffd@0: % --- wolffd@0: wolffd@0: fdata = fileread(file); wolffd@0: try wolffd@0: % --- wolffd@0: % TODO: check for other than the p-code exceptions wolffd@0: % --- wolffd@0: wolffd@0: data = xml_parseany(fdata); wolffd@0: catch exception wolffd@0: end wolffd@0: %% ------------------------------------------------------------------------ wolffd@0: % --- wolffd@0: % copy general track data wolffd@0: % --- wolffd@0: wolffd@0: fields = fieldnames(data.track{1}.ATTRIBUTE); wolffd@0: for i = 1:length(fields) wolffd@0: features.(fields{i}) = str2double(data.track{1}.ATTRIBUTE.(fields{i})); wolffd@0: end wolffd@0: wolffd@0: %% ------------------------------------------------------------------------ wolffd@0: % --- wolffd@0: % get harmonic analysis. this is stored in segments wolffd@0: % --- wolffd@0: dsegments = data.track{1}.segments{1}.segment; wolffd@0: wolffd@0: for i = 1:numel(dsegments) wolffd@0: wolffd@0: % get start and duration wolffd@0: segments(i).start = str2double(dsegments{i}.ATTRIBUTE.start); wolffd@0: segments(i).duration = str2double(dsegments{i}.ATTRIBUTE.duration); wolffd@0: wolffd@0: % --- wolffd@0: % NOTE: for the chroma and mfcc features, we assume that the classes wolffd@0: % are always saved and parsed in correct order, thus we can afford to wolffd@0: % refrain from saving the class number with the class wolffd@0: % --- wolffd@0: wolffd@0: % assemble chroma features wolffd@0: segments(i).pitches = zeros(12,1); wolffd@0: for j = 1:12 wolffd@0: wolffd@0: segments(i).pitches(j) = str2double(... wolffd@0: dsegments{i}.pitches{1}.pitch{j}.CONTENT); wolffd@0: end wolffd@0: wolffd@0: % assemble mfcc features; wolffd@0: segments(i).timbre = zeros(numel(dsegments{i}.timbre{1}.coeff),1); wolffd@0: for j = 1:numel(dsegments{i}.timbre{1}.coeff) wolffd@0: wolffd@0: segments(i).timbre(j) = str2double(... wolffd@0: dsegments{i}.timbre{1}.coeff{j}.CONTENT); wolffd@0: end wolffd@0: wolffd@0: % get loudness measurements in dB and time wolffd@0: segments(i).loudness = str2double(... wolffd@0: dsegments{i}.loudness{1}.dB{1}.CONTENT); wolffd@0: wolffd@0: segments(i).loudness_time = str2double(... wolffd@0: dsegments{i}.loudness{1}.dB{1}.ATTRIBUTE.time); wolffd@0: wolffd@0: segments(i).loudness_max = str2double(... wolffd@0: dsegments{i}.loudness{1}.dB{2}.CONTENT); wolffd@0: wolffd@0: segments(i).loudness_max_time = str2double(... wolffd@0: dsegments{i}.loudness{1}.dB{2}.ATTRIBUTE.time); wolffd@0: end wolffd@0: wolffd@0: features.segments = segments; wolffd@0: wolffd@0: %% ------------------------------------------------------------------------ wolffd@0: % --- wolffd@0: % get sections wolffd@0: % --- wolffd@0: dsections = data.track{1}.sections{1}.section; wolffd@0: wolffd@0: secstart = zeros(1,numel(dsections)); wolffd@0: secduration = zeros(1,numel(dsections)); wolffd@0: for i = 1:numel(dsections) wolffd@0: sections(i).start = str2double(dsections{i}.ATTRIBUTE.start); wolffd@0: sections(i).duration = str2double(dsections{i}.ATTRIBUTE.duration); wolffd@0: end wolffd@0: wolffd@0: features.sections = sections; wolffd@0: wolffd@0: %% ------------------------------------------------------------------------ wolffd@0: % --- wolffd@0: % get beat and rythm data. the metric data is structured wolffd@0: % hierarchically, as each bar contains several beats, wolffd@0: % which contaisn several tatums. wolffd@0: % NOTE: Although the metrum and tempo have been evaluated and fixed wolffd@0: % on a global scale, the number of bars and tatum vary greatly. wolffd@0: % --- wolffd@0: dbars = data.track{1}.meter{1}.bar; wolffd@0: wolffd@0: for i = 1:numel(dbars) wolffd@0: wolffd@0: % get bar information wolffd@0: bars(i).confidence = str2double(dbars{i}.ATTRIBUTE.conf); wolffd@0: for j = 1:numel(dbars{i}.beat) wolffd@0: wolffd@0: % get beat information wolffd@0: bars(i).beat(j).confidence = str2double(dbars{i}.beat{j}.ATTRIBUTE.conf); wolffd@0: wolffd@0: for k = 1:numel(dbars{i}.beat{j}.tatum) wolffd@0: wolffd@0: % get tatum information wolffd@0: if ~isempty(dbars{i}.beat{j}.tatum{k}.ATTRIBUTE) wolffd@0: bars(i).beat(j).tatum(k).time = str2double(dbars{i}.beat{j}.tatum{k}.CONTENT); wolffd@0: bars(i).beat(j).tatum(k).confidence = str2double(dbars{i}.beat{j}.tatum{k}.ATTRIBUTE.conf); wolffd@0: wolffd@0: else wolffd@0: % save empty struct wolffd@0: bars(i).beat(j).tatum = struct([]); wolffd@0: end wolffd@0: wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: features.bars = bars; wolffd@0: