b@12
|
1 % Script to convert APE toolbox [1] (MATLAB) .mat output files to WAET
|
b@12
|
2 % toolbox [2] (HTML5/JavaScript) XML output files.
|
b@12
|
3 %
|
b@12
|
4 % [1] B. De Man and Joshua D. Reiss, ?APE: Audio Perceptual Evaluation
|
b@12
|
5 % toolbox for MATLAB,? 136th Convention of the Audio Engineering Society,
|
b@12
|
6 % 2014.
|
b@12
|
7 %
|
b@12
|
8 % [2] Nicholas Jillings, Brecht De Man, David Moffat and Joshua D. Reiss,
|
b@12
|
9 % "Web Audio Evaluation Tool: A Browser-Based Listening Test Environment,"
|
b@12
|
10 % 12th Sound and Music Computing Conference, July 2015.
|
b@11
|
11
|
b@11
|
12 % CONFIGURATION:
|
b@11
|
13 location = 'CIRMMT Critical Listening Lab';
|
b@12
|
14 day = 5;
|
b@12
|
15 month = 2;
|
b@12
|
16 year = 2015;
|
b@11
|
17
|
b@12
|
18 % IMPORT FILES
|
b@12
|
19 sourcefolder = ... %'.';
|
b@12
|
20 '/Users/Brecht/Google Drive/Writings/Mixing experiments/McGill/results/2015spring/mat';
|
b@12
|
21 outputfolder = [sourcefolder '/../xml'];
|
b@12
|
22 list = dir([sourcefolder '/*.mat']); % find all '.mat' files in this folder
|
b@11
|
23
|
b@12
|
24 % remove hidden files from list
|
b@12
|
25 % see http://www.mathworks.co.uk/matlabcentral/newsreader/view_thread/258220
|
b@12
|
26 for k = length(list):-1:1
|
b@12
|
27 fname = list(k).name;
|
b@12
|
28 if fname(1) == '.'
|
b@12
|
29 list(k) = [ ];
|
b@11
|
30 end
|
b@11
|
31 end
|
b@11
|
32
|
b@12
|
33 aliastable = {{'JohnSmith', 'anon1'};
|
b@12
|
34 {'JaneDoe', 'anon2'}};
|
b@12
|
35
|
b@12
|
36 % TODO: create output folder if doesn't exist yet
|
b@11
|
37
|
b@12
|
38 for i = 1:length(list) % for every file in the list
|
b@12
|
39 matfile = load([sourcefolder '/' list(i).name]);
|
b@12
|
40 name = fieldnames(matfile);
|
b@12
|
41 test = matfile.(char(name)); % store loaded file in 'test'
|
b@12
|
42
|
b@12
|
43 docNode = com.mathworks.xml.XMLUtils.createDocument('browserevaluationresult');
|
b@12
|
44 docRootNode = docNode.getDocumentElement;
|
b@12
|
45
|
b@12
|
46 % DATE AND TIME
|
b@12
|
47 datetime = docNode.createElement('datetime'); % create 'datetime' child
|
b@12
|
48 docRootNode.appendChild(datetime);
|
b@12
|
49 date = docNode.createElement('date'); % create 'date' child
|
b@12
|
50 datetime.appendChild(date);
|
b@12
|
51 date.setAttribute('year', num2str(year)); % add 'year' as attribute
|
b@12
|
52 date.setAttribute('month', num2str(month)); % add 'month' as attribute
|
b@12
|
53 date.setAttribute('day', num2str(day)); % add 'day' as attribute
|
b@12
|
54 datestr = sprintf('%i/%i/%i', year, month, day);
|
b@12
|
55 date.appendChild(docNode.createTextNode(datestr));
|
b@12
|
56
|
b@12
|
57 % PRETEST
|
b@12
|
58 pretest = docNode.createElement('pretest');
|
b@12
|
59 docRootNode.appendChild(pretest);
|
b@12
|
60 sessionID_comment = docNode.createElement('comment');
|
b@12
|
61 pretest.appendChild(sessionID_comment);
|
b@12
|
62
|
b@12
|
63 % Session ID: entered id or file name
|
b@12
|
64 sessionID_comment.setAttribute('id', 'SessionID');
|
b@12
|
65 %sessionID_comment.appendChild(docNode.createTextNode(test.id));
|
b@12
|
66 str = anonymise(list(i).name(1:end-4), aliastable);
|
b@12
|
67 sessionID_comment.appendChild(docNode.createTextNode(str));
|
b@12
|
68
|
b@12
|
69 location_comment = docNode.createElement('comment');
|
b@12
|
70 pretest.appendChild(location_comment);
|
b@12
|
71 location_comment.setAttribute('id', 'location');
|
b@12
|
72 location_comment.appendChild(docNode.createTextNode(location));
|
b@12
|
73
|
b@12
|
74
|
b@12
|
75 % AUDIOHOLDER
|
b@12
|
76 % for each song in the test:
|
b@12
|
77 for song = 1:length(test.tstDat)/2 % 2 structs for every song
|
b@12
|
78 song_id = song*2; % every second field corresponds with a song
|
b@12
|
79
|
b@12
|
80 % only add song if 'rsl' present
|
b@12
|
81 if isfield(test.tstDat{1,song_id}, 'rsl')
|
b@12
|
82 % create audioholder
|
b@12
|
83 audioholder = docNode.createElement('audioholder');
|
b@12
|
84 docRootNode.appendChild(audioholder);
|
b@12
|
85 % save song name
|
b@12
|
86 songname = test.tstDat{1,song_id-1}.tstFile(2:end-4); % chop off '_*.txt'
|
b@12
|
87 audioholder.setAttribute('id', songname);
|
b@12
|
88 % add pretest (empty)
|
b@12
|
89 pretest = docNode.createElement('pretest');
|
b@12
|
90 audioholder.appendChild(pretest);
|
b@12
|
91 % add posttest (empty)
|
b@12
|
92 posttest = docNode.createElement('posttest');
|
b@12
|
93 audioholder.appendChild(posttest);
|
b@12
|
94 % add metric
|
b@12
|
95 metric = docNode.createElement('metric');
|
b@12
|
96 audioholder.appendChild(metric);
|
b@12
|
97 metricresult = docNode.createElement('metricresult');
|
b@12
|
98 metric.appendChild(metricresult);
|
b@12
|
99 metricresult.setAttribute('id', 'testTime');
|
b@12
|
100 testduration = 60*test.tstDat{1,song_id}.rsl.duration; % minutes to seconds
|
b@12
|
101 metricresult.appendChild(docNode.createTextNode(num2str(testduration)));
|
b@12
|
102
|
b@12
|
103 % go over audio files in the order they were presented
|
b@12
|
104 permVec = test.tstDat{1,song_id}.rsl.permVec;
|
b@12
|
105 Naudioelements = length(permVec);
|
b@12
|
106 invPermVec(permVec(1:Naudioelements)) = 1:Naudioelements;
|
b@12
|
107 for index=1:length(permVec) % ('index' is presented id)
|
b@12
|
108 actualID = invPermVec(index);
|
b@12
|
109 % create audioelement and attach to audioholder
|
b@12
|
110 audioelement = docNode.createElement('audioelement');
|
b@12
|
111 audioholder.appendChild(audioelement);
|
b@12
|
112 % save mix name
|
b@12
|
113 mixname = ...
|
b@12
|
114 anonymise(test.tstDat{1,song_id-1}.rsl.sounds(actualID).name, ...
|
b@12
|
115 aliastable);
|
b@12
|
116 % distinguish between pro1 and pro2 (Spring 2014)
|
b@12
|
117 if strcmp(mixname, 'McG-pro')
|
b@12
|
118 if strcmp(songname, 'PouringRoom')
|
b@12
|
119 mixname = [mixname '1'];
|
b@12
|
120 else if strcmp(songname, 'InTheMeantime')
|
b@12
|
121 mixname = [mixname '2'];
|
b@12
|
122 end
|
b@12
|
123 end
|
b@12
|
124 end
|
b@12
|
125 audioelement.setAttribute('id', mixname);
|
b@12
|
126 %...strcat('McG-', mixname)); % Prefix 'McG-'
|
b@12
|
127 % add presented id
|
b@12
|
128 audioelement.setAttribute('presentedid', num2str(index));
|
b@12
|
129 % add comment
|
b@12
|
130 comment = docNode.createElement('comment');
|
b@12
|
131 audioelement.appendChild(comment);
|
b@12
|
132 % add comment question and response
|
b@12
|
133 question = docNode.createElement('question');
|
b@12
|
134 comment.appendChild(question);
|
b@12
|
135 str = sprintf('Comment on track %i', index);
|
b@12
|
136 question.appendChild(docNode.createTextNode(str));
|
b@12
|
137 response = docNode.createElement('response');
|
b@12
|
138 comment.appendChild(response);
|
b@12
|
139 % comment order as shown
|
b@12
|
140 str = char(test.tstDat{1,song_id}.rsl.hcom(index));
|
b@12
|
141 % avoid errors due to multiline strings:
|
b@12
|
142 str_t = str'; % transpose str
|
b@12
|
143 str = str_t(:)'; % concatenate columns and transpose again
|
b@12
|
144 if length(str)<4% get rid of shot, meaningless comments
|
b@12
|
145 if length(str)>1
|
b@12
|
146 if strncmp(str(2), ':', 1) % if a number and a column
|
b@12
|
147 str = ''; % omit entirely
|
b@12
|
148 end
|
b@12
|
149 else % if just a number
|
b@12
|
150 str = ''; % omit
|
b@12
|
151 end
|
b@12
|
152 else % strip numbers off comments
|
b@12
|
153 if strncmp(str(2:3), ': ', 2)
|
b@12
|
154 str = str(4:end); % strip '1: ' off string
|
b@12
|
155 else if strncmp(str(2), ':', 1)
|
b@12
|
156 str = str(3:end); % strip '1:' off string
|
b@12
|
157 else if strncmp(str(3:4), ': ', 2) % strip '10: ' off string
|
b@12
|
158 str = str(5:end);
|
b@12
|
159 else if strncmp(str(3), ':', 1) % strip '10:' off string
|
b@12
|
160 str = str(4:end);
|
b@12
|
161 end
|
b@12
|
162 end
|
b@12
|
163 end
|
b@12
|
164 end
|
b@12
|
165 end
|
b@12
|
166 response.appendChild(docNode.createTextNode(str));
|
b@12
|
167 % add rating
|
b@12
|
168 value = docNode.createElement('value');
|
b@12
|
169 audioelement.appendChild(value);
|
b@12
|
170 % divide by 100 to be within 0-1
|
b@12
|
171 rating = test.tstDat{1,song_id}.rsl.mat(actualID)/100;
|
b@12
|
172 value.appendChild(docNode.createTextNode(num2str(rating)));
|
b@12
|
173 % add metric (only 'has been played')
|
b@12
|
174 metric = docNode.createElement('metric');
|
b@12
|
175 audioelement.appendChild(metric);
|
b@12
|
176 metricresult = docNode.createElement('metricresult');
|
b@12
|
177 metric.appendChild(metricresult);
|
b@12
|
178 hasbeenplayed = test.tstDat{1,song_id}.rsl.playVec(actualID); % I guess?
|
b@12
|
179 if hasbeenplayed
|
b@12
|
180 metricresult.appendChild(docNode.createTextNode('true'));
|
b@12
|
181 else
|
b@12
|
182 metricresult.appendChild(docNode.createTextNode('false'));
|
b@12
|
183 end
|
b@12
|
184 end
|
b@12
|
185 end
|
b@12
|
186 end
|
b@12
|
187
|
b@12
|
188 xmlFileName = [outputfolder '/' anonymise(list(i).name(1:end-4), aliastable) '.xml'];
|
b@12
|
189 xmlwrite(xmlFileName,docNode);
|
b@12
|
190 % type(xmlFileName); % display XML in CLI
|
b@12
|
191 end |