b@12: % Script to convert APE toolbox [1] (MATLAB) .mat output files to WAET b@12: % toolbox [2] (HTML5/JavaScript) XML output files. b@12: % b@12: % [1] B. De Man and Joshua D. Reiss, ?APE: Audio Perceptual Evaluation b@12: % toolbox for MATLAB,? 136th Convention of the Audio Engineering Society, b@12: % 2014. b@12: % b@12: % [2] Nicholas Jillings, Brecht De Man, David Moffat and Joshua D. Reiss, b@12: % "Web Audio Evaluation Tool: A Browser-Based Listening Test Environment," b@12: % 12th Sound and Music Computing Conference, July 2015. b@11: b@11: % CONFIGURATION: b@11: location = 'CIRMMT Critical Listening Lab'; b@12: day = 5; b@12: month = 2; b@12: year = 2015; b@11: b@12: % IMPORT FILES b@12: sourcefolder = ... %'.'; b@12: '/Users/Brecht/Google Drive/Writings/Mixing experiments/McGill/results/2015spring/mat'; b@12: outputfolder = [sourcefolder '/../xml']; b@12: list = dir([sourcefolder '/*.mat']); % find all '.mat' files in this folder b@11: b@12: % remove hidden files from list b@12: % see http://www.mathworks.co.uk/matlabcentral/newsreader/view_thread/258220 b@12: for k = length(list):-1:1 b@12: fname = list(k).name; b@12: if fname(1) == '.' b@12: list(k) = [ ]; b@11: end b@11: end b@11: b@12: aliastable = {{'JohnSmith', 'anon1'}; b@12: {'JaneDoe', 'anon2'}}; b@12: b@12: % TODO: create output folder if doesn't exist yet b@11: b@12: for i = 1:length(list) % for every file in the list b@12: matfile = load([sourcefolder '/' list(i).name]); b@12: name = fieldnames(matfile); b@12: test = matfile.(char(name)); % store loaded file in 'test' b@12: b@12: docNode = com.mathworks.xml.XMLUtils.createDocument('browserevaluationresult'); b@12: docRootNode = docNode.getDocumentElement; b@12: b@12: % DATE AND TIME b@12: datetime = docNode.createElement('datetime'); % create 'datetime' child b@12: docRootNode.appendChild(datetime); b@12: date = docNode.createElement('date'); % create 'date' child b@12: datetime.appendChild(date); b@12: date.setAttribute('year', num2str(year)); % add 'year' as attribute b@12: date.setAttribute('month', num2str(month)); % add 'month' as attribute b@12: date.setAttribute('day', num2str(day)); % add 'day' as attribute b@12: datestr = sprintf('%i/%i/%i', year, month, day); b@12: date.appendChild(docNode.createTextNode(datestr)); b@12: b@12: % PRETEST b@12: pretest = docNode.createElement('pretest'); b@12: docRootNode.appendChild(pretest); b@12: sessionID_comment = docNode.createElement('comment'); b@12: pretest.appendChild(sessionID_comment); b@12: b@12: % Session ID: entered id or file name b@12: sessionID_comment.setAttribute('id', 'SessionID'); b@12: %sessionID_comment.appendChild(docNode.createTextNode(test.id)); b@12: str = anonymise(list(i).name(1:end-4), aliastable); b@12: sessionID_comment.appendChild(docNode.createTextNode(str)); b@12: b@12: location_comment = docNode.createElement('comment'); b@12: pretest.appendChild(location_comment); b@12: location_comment.setAttribute('id', 'location'); b@12: location_comment.appendChild(docNode.createTextNode(location)); b@12: b@12: b@12: % AUDIOHOLDER b@12: % for each song in the test: b@12: for song = 1:length(test.tstDat)/2 % 2 structs for every song b@12: song_id = song*2; % every second field corresponds with a song b@12: b@12: % only add song if 'rsl' present b@12: if isfield(test.tstDat{1,song_id}, 'rsl') b@12: % create audioholder b@12: audioholder = docNode.createElement('audioholder'); b@12: docRootNode.appendChild(audioholder); b@12: % save song name b@12: songname = test.tstDat{1,song_id-1}.tstFile(2:end-4); % chop off '_*.txt' b@12: audioholder.setAttribute('id', songname); b@12: % add pretest (empty) b@12: pretest = docNode.createElement('pretest'); b@12: audioholder.appendChild(pretest); b@12: % add posttest (empty) b@12: posttest = docNode.createElement('posttest'); b@12: audioholder.appendChild(posttest); b@12: % add metric b@12: metric = docNode.createElement('metric'); b@12: audioholder.appendChild(metric); b@12: metricresult = docNode.createElement('metricresult'); b@12: metric.appendChild(metricresult); b@12: metricresult.setAttribute('id', 'testTime'); b@12: testduration = 60*test.tstDat{1,song_id}.rsl.duration; % minutes to seconds b@12: metricresult.appendChild(docNode.createTextNode(num2str(testduration))); b@12: b@12: % go over audio files in the order they were presented b@12: permVec = test.tstDat{1,song_id}.rsl.permVec; b@12: Naudioelements = length(permVec); b@12: invPermVec(permVec(1:Naudioelements)) = 1:Naudioelements; b@12: for index=1:length(permVec) % ('index' is presented id) b@12: actualID = invPermVec(index); b@12: % create audioelement and attach to audioholder b@12: audioelement = docNode.createElement('audioelement'); b@12: audioholder.appendChild(audioelement); b@12: % save mix name b@12: mixname = ... b@12: anonymise(test.tstDat{1,song_id-1}.rsl.sounds(actualID).name, ... b@12: aliastable); b@12: % distinguish between pro1 and pro2 (Spring 2014) b@12: if strcmp(mixname, 'McG-pro') b@12: if strcmp(songname, 'PouringRoom') b@12: mixname = [mixname '1']; b@12: else if strcmp(songname, 'InTheMeantime') b@12: mixname = [mixname '2']; b@12: end b@12: end b@12: end b@12: audioelement.setAttribute('id', mixname); b@12: %...strcat('McG-', mixname)); % Prefix 'McG-' b@12: % add presented id b@12: audioelement.setAttribute('presentedid', num2str(index)); b@12: % add comment b@12: comment = docNode.createElement('comment'); b@12: audioelement.appendChild(comment); b@12: % add comment question and response b@12: question = docNode.createElement('question'); b@12: comment.appendChild(question); b@12: str = sprintf('Comment on track %i', index); b@12: question.appendChild(docNode.createTextNode(str)); b@12: response = docNode.createElement('response'); b@12: comment.appendChild(response); b@12: % comment order as shown b@12: str = char(test.tstDat{1,song_id}.rsl.hcom(index)); b@12: % avoid errors due to multiline strings: b@12: str_t = str'; % transpose str b@12: str = str_t(:)'; % concatenate columns and transpose again b@12: if length(str)<4% get rid of shot, meaningless comments b@12: if length(str)>1 b@12: if strncmp(str(2), ':', 1) % if a number and a column b@12: str = ''; % omit entirely b@12: end b@12: else % if just a number b@12: str = ''; % omit b@12: end b@12: else % strip numbers off comments b@12: if strncmp(str(2:3), ': ', 2) b@12: str = str(4:end); % strip '1: ' off string b@12: else if strncmp(str(2), ':', 1) b@12: str = str(3:end); % strip '1:' off string b@12: else if strncmp(str(3:4), ': ', 2) % strip '10: ' off string b@12: str = str(5:end); b@12: else if strncmp(str(3), ':', 1) % strip '10:' off string b@12: str = str(4:end); b@12: end b@12: end b@12: end b@12: end b@12: end b@12: response.appendChild(docNode.createTextNode(str)); b@12: % add rating b@12: value = docNode.createElement('value'); b@12: audioelement.appendChild(value); b@12: % divide by 100 to be within 0-1 b@12: rating = test.tstDat{1,song_id}.rsl.mat(actualID)/100; b@12: value.appendChild(docNode.createTextNode(num2str(rating))); b@12: % add metric (only 'has been played') b@12: metric = docNode.createElement('metric'); b@12: audioelement.appendChild(metric); b@12: metricresult = docNode.createElement('metricresult'); b@12: metric.appendChild(metricresult); b@12: hasbeenplayed = test.tstDat{1,song_id}.rsl.playVec(actualID); % I guess? b@12: if hasbeenplayed b@12: metricresult.appendChild(docNode.createTextNode('true')); b@12: else b@12: metricresult.appendChild(docNode.createTextNode('false')); b@12: end b@12: end b@12: end b@12: end b@12: b@12: xmlFileName = [outputfolder '/' anonymise(list(i).name(1:end-4), aliastable) '.xml']; b@12: xmlwrite(xmlFileName,docNode); b@12: % type(xmlFileName); % display XML in CLI b@12: end