wolffd@0
|
1 classdef MTTMixedFeatureStober11 < MTTAudioFeature & handle
|
wolffd@0
|
2 % ---
|
wolffd@0
|
3 % This Class contains
|
wolffd@0
|
4 % features are extracted
|
wolffd@0
|
5 % as described in Slaney 08 - LEARNING A METRIC FOR MUSIC SIMILARITY
|
wolffd@0
|
6 %
|
wolffd@0
|
7 % The usual workflow for these features constist of three steps
|
wolffd@0
|
8 % 1. extract: extracts the basic single-file dependent features
|
wolffd@0
|
9 % 2. define_global_transform: calculates the global feature
|
wolffd@0
|
10 % transformation parameters
|
wolffd@0
|
11 % 3. finalise: applies the common transformations to a specific feature
|
wolffd@0
|
12 % ---
|
wolffd@0
|
13
|
wolffd@0
|
14 properties(Constant = true)
|
wolffd@0
|
15
|
wolffd@0
|
16 % svn hook
|
wolffd@0
|
17 my_revision = str2double(substr('$Rev$', 5, -1));
|
wolffd@0
|
18 end
|
wolffd@0
|
19
|
wolffd@0
|
20 properties
|
wolffd@0
|
21 % ---
|
wolffd@0
|
22 % Set default parameters
|
wolffd@0
|
23 % ---
|
wolffd@0
|
24 my_params = struct(...
|
wolffd@0
|
25 'stob_lowaudio', 1, ...
|
wolffd@0
|
26 'stob_highaudio', 1, ... %
|
wolffd@0
|
27 'stob_tags', 1, ... %
|
wolffd@0
|
28 'stob_norm', 1 ...
|
wolffd@0
|
29 );
|
wolffd@0
|
30 end
|
wolffd@0
|
31
|
wolffd@0
|
32 % ---
|
wolffd@0
|
33 % member functions
|
wolffd@0
|
34 % ---
|
wolffd@0
|
35 methods
|
wolffd@0
|
36
|
wolffd@0
|
37 % ---
|
wolffd@0
|
38 % constructor: pointer to feature in database
|
wolffd@0
|
39 % ---
|
wolffd@0
|
40 function feature = MTTMixedFeatureStober11(varargin)
|
wolffd@0
|
41
|
wolffd@0
|
42 feature = feature@MTTAudioFeature(varargin{:});
|
wolffd@0
|
43
|
wolffd@0
|
44 end
|
wolffd@0
|
45 % ---
|
wolffd@0
|
46 % extract feature data from raw audio features
|
wolffd@0
|
47 % ---
|
wolffd@0
|
48 function data = extract(feature, clip)
|
wolffd@0
|
49 % ---
|
wolffd@0
|
50 % get features. this includes possible
|
wolffd@0
|
51 % local normalisations
|
wolffd@0
|
52 % ---
|
wolffd@0
|
53
|
wolffd@0
|
54 global globalvars;
|
wolffd@0
|
55 global stobbase;
|
wolffd@0
|
56
|
wolffd@0
|
57 if isempty(stobbase);
|
wolffd@0
|
58 stobbase = load('features_stober');
|
wolffd@0
|
59 end
|
wolffd@0
|
60
|
wolffd@0
|
61 % ---
|
wolffd@0
|
62 % NOTE: we define feature sets which are included /
|
wolffd@0
|
63 % excluded according to the specified parameters
|
wolffd@0
|
64 % ---
|
wolffd@0
|
65
|
wolffd@0
|
66 lowAudio = {'pitchMean', 'pitchSdev', 'timbreMean', 'timbreSdev'};
|
wolffd@0
|
67
|
wolffd@0
|
68 % highAudio features more or less correspond to slaney 08 features
|
wolffd@0
|
69 hiAudio = {'energy','key','loudness','timeSignature',...
|
wolffd@0
|
70 'danceability', 'mode', 'tempo'};
|
wolffd@0
|
71
|
wolffd@0
|
72 metadat = {'tags'};
|
wolffd@0
|
73
|
wolffd@0
|
74 allowedFeat = {};
|
wolffd@0
|
75
|
wolffd@0
|
76 % Select the features to keep
|
wolffd@0
|
77 if feature(1).my_params.stob_lowaudio
|
wolffd@0
|
78 allowedFeat = {allowedFeat{:}, lowAudio{:}};
|
wolffd@0
|
79 end
|
wolffd@0
|
80 if feature(1).my_params.stob_highaudio
|
wolffd@0
|
81 allowedFeat = {allowedFeat{:}, hiAudio{:}};
|
wolffd@0
|
82 end
|
wolffd@0
|
83 if feature(1).my_params.stob_tags
|
wolffd@0
|
84 allowedFeat = {allowedFeat{:}, metadat{:}};
|
wolffd@0
|
85 end
|
wolffd@0
|
86
|
wolffd@0
|
87 % get the actual clip id
|
wolffd@0
|
88 idx = find(stobbase.clipIds == clip.id);
|
wolffd@0
|
89
|
wolffd@0
|
90 % ---
|
wolffd@0
|
91 % NOTE: we just copy everything in a big matrix and then
|
wolffd@0
|
92 % normalise the data later
|
wolffd@0
|
93 % ---
|
wolffd@0
|
94 data.vector_info = {};
|
wolffd@0
|
95 data.stobraw = [];
|
wolffd@0
|
96 fields = fieldnames(stobbase);
|
wolffd@0
|
97 for i = 1:numel(fields)
|
wolffd@0
|
98
|
wolffd@0
|
99 % skip clip ID field
|
wolffd@0
|
100 if strcmp(fields{i},'clipIds');
|
wolffd@0
|
101 continue;
|
wolffd@0
|
102 end
|
wolffd@0
|
103
|
wolffd@0
|
104 % skip unwanted features
|
wolffd@0
|
105 if isempty(strcellfind(allowedFeat, fields{i}))
|
wolffd@0
|
106 continue;
|
wolffd@0
|
107 end
|
wolffd@0
|
108
|
wolffd@0
|
109 % ---
|
wolffd@0
|
110 % TODO: special case for tag features, including
|
wolffd@0
|
111 % the tag names
|
wolffd@0
|
112 % ---
|
wolffd@0
|
113
|
wolffd@0
|
114 % put field info into right position
|
wolffd@0
|
115 data.vector_info{numel(data.stobraw)+1} = fields{i};
|
wolffd@0
|
116
|
wolffd@0
|
117 % add data to feature
|
wolffd@0
|
118 if size(stobbase.(fields{i}),1) == 1
|
wolffd@0
|
119 data.stobraw(end+1) = stobbase.(fields{i})(idx);
|
wolffd@0
|
120 else
|
wolffd@0
|
121 % concatenate vector
|
wolffd@0
|
122 tmpdat = stobbase.(fields{i})(idx,:);
|
wolffd@0
|
123 data.stobraw(end+1:end+numel(tmpdat)) = tmpdat;
|
wolffd@0
|
124 end
|
wolffd@0
|
125 end
|
wolffd@0
|
126 % padd further info struct
|
wolffd@0
|
127 data.vector_info(end+1:numel(data.stobraw)) =...
|
wolffd@0
|
128 cell(numel(data.stobraw) - numel(data.vector_info) , 1);
|
wolffd@0
|
129
|
wolffd@0
|
130 % ---
|
wolffd@0
|
131 % prepare field for final features
|
wolffd@0
|
132 % ---
|
wolffd@0
|
133 data.final.vector = [];
|
wolffd@0
|
134 data.final.vector_info = struct();
|
wolffd@0
|
135 data.final.dim = 0;
|
wolffd@0
|
136
|
wolffd@0
|
137 % save info data
|
wolffd@0
|
138 data.info.type = 'MTTMixedFeatureStober11';
|
wolffd@0
|
139 data.info.owner_id = clip.id;
|
wolffd@0
|
140 data.info.creatorrev = feature.my_revision;
|
wolffd@0
|
141
|
wolffd@0
|
142 % save parameters
|
wolffd@0
|
143 data.info.params = feature.my_params;
|
wolffd@0
|
144 end
|
wolffd@0
|
145
|
wolffd@0
|
146 function define_global_transform(features)
|
wolffd@0
|
147 % calculate and set normalization factors from the group of
|
wolffd@0
|
148 % input features. These features will be set for the full database
|
wolffd@0
|
149
|
wolffd@0
|
150 final = zeros(numel(features(1).data.stobraw), numel(features));
|
wolffd@0
|
151 for i = 1:numel(features)
|
wolffd@0
|
152 if ~isempty(features(i).data.stobraw)
|
wolffd@0
|
153 final(:,i) = features(i).data.stobraw';
|
wolffd@0
|
154 end
|
wolffd@0
|
155 end
|
wolffd@0
|
156
|
wolffd@0
|
157 if features(1).my_params.stob_norm
|
wolffd@0
|
158 if numel(features) == 1
|
wolffd@0
|
159 error ('Insert feature array for this method, or set normalisation to 0');
|
wolffd@0
|
160 end
|
wolffd@0
|
161
|
wolffd@0
|
162 % ---
|
wolffd@0
|
163 % here, we only need to define the post-normalisation
|
wolffd@0
|
164 % ---
|
wolffd@0
|
165 [final, pstd] = mapminmax(final,0,1);
|
wolffd@0
|
166 common.stobstats.post_norm = pstd;
|
wolffd@0
|
167
|
wolffd@0
|
168 % ---
|
wolffd@0
|
169 % NOTE: whitening as in slaney??
|
wolffd@0
|
170 % Would make reading the
|
wolffd@0
|
171 % mahal matrices really hard
|
wolffd@0
|
172 % ---
|
wolffd@0
|
173
|
wolffd@0
|
174 features(1).my_db.set_common(common);
|
wolffd@0
|
175
|
wolffd@0
|
176 else
|
wolffd@0
|
177
|
wolffd@0
|
178 features(1).my_db.set_common([1]);
|
wolffd@0
|
179 end
|
wolffd@0
|
180
|
wolffd@0
|
181 % save the normalised features straight away!
|
wolffd@0
|
182 features.finalise(final);
|
wolffd@0
|
183 end
|
wolffd@0
|
184
|
wolffd@0
|
185
|
wolffd@0
|
186 function finalise(features, final)
|
wolffd@0
|
187 % applies a final transformation and
|
wolffd@0
|
188 % collects the information of this feature within a single vector
|
wolffd@0
|
189 % see info for types in specific dimensions
|
wolffd@0
|
190 % check if features have been finalised already
|
wolffd@0
|
191
|
wolffd@0
|
192 % ---
|
wolffd@0
|
193 % set feature labelling
|
wolffd@0
|
194 % ---
|
wolffd@0
|
195
|
wolffd@0
|
196 info = {};
|
wolffd@0
|
197
|
wolffd@0
|
198 % ---
|
wolffd@0
|
199 % construct resulting feature vector out of features
|
wolffd@0
|
200 % ---
|
wolffd@0
|
201 if nargin == 2 && isempty(final)
|
wolffd@0
|
202
|
wolffd@0
|
203 % the final vector etc already are set to zero;
|
wolffd@0
|
204 return;
|
wolffd@0
|
205
|
wolffd@0
|
206 elseif nargin == 2 && (numel(features) == size(final, 2))
|
wolffd@0
|
207 % the features have already been preassembled
|
wolffd@0
|
208
|
wolffd@0
|
209 for i = 1:numel(features)
|
wolffd@0
|
210
|
wolffd@0
|
211 % check for neccesary parameters
|
wolffd@0
|
212 if isempty(features(i).my_db.commondb)
|
wolffd@0
|
213
|
wolffd@0
|
214 error('Define the global transformation first')
|
wolffd@0
|
215 return;
|
wolffd@0
|
216 end
|
wolffd@0
|
217
|
wolffd@0
|
218 features(i).data.final.vector = final(:,i);
|
wolffd@0
|
219 features(i).data.final.dim = size(final,1);
|
wolffd@0
|
220
|
wolffd@0
|
221 % fill up info struct and append to feature
|
wolffd@0
|
222 features(i).data.final.vector_info.labels = ...
|
wolffd@0
|
223 features(i).data.vector_info;
|
wolffd@0
|
224 end
|
wolffd@0
|
225 else
|
wolffd@0
|
226 % ---
|
wolffd@0
|
227 % if features have been added after gettin gnormalisation
|
wolffd@0
|
228 % parameters, ther should be still an option to include
|
wolffd@0
|
229 % them
|
wolffd@0
|
230 % ---
|
wolffd@0
|
231
|
wolffd@0
|
232 for i = 1:numel(features)
|
wolffd@0
|
233
|
wolffd@0
|
234 % check for neccesary parameters
|
wolffd@0
|
235 if isempty(features(i).my_db.commondb)
|
wolffd@0
|
236
|
wolffd@0
|
237 error('Define the global transformation first')
|
wolffd@0
|
238 return;
|
wolffd@0
|
239 end
|
wolffd@0
|
240
|
wolffd@0
|
241 final = features(i).data.stobraw';
|
wolffd@0
|
242
|
wolffd@0
|
243 if features(1).my_params.stob_norm == 1
|
wolffd@0
|
244
|
wolffd@0
|
245 [final] = mapminmax('apply', final, features(1).common.stobstats.post_norm);
|
wolffd@0
|
246 end
|
wolffd@0
|
247
|
wolffd@0
|
248 features(i).data.final.vector = final;
|
wolffd@0
|
249 features(i).data.final.dim = size(final,1);
|
wolffd@0
|
250
|
wolffd@0
|
251 % fill up info struct and append to feature
|
wolffd@0
|
252 features(i).data.final.vector_info.labels = ...
|
wolffd@0
|
253 features(i).data.vector_info;
|
wolffd@0
|
254 end
|
wolffd@0
|
255
|
wolffd@0
|
256 end
|
wolffd@0
|
257
|
wolffd@0
|
258 % ---
|
wolffd@0
|
259 % TODO: Maybe delete more basic features again at this point?
|
wolffd@0
|
260 % ---
|
wolffd@0
|
261 end
|
wolffd@0
|
262
|
wolffd@0
|
263 % ---
|
wolffd@0
|
264 % destructor: do we really want to remove this
|
wolffd@0
|
265 % from the database? No, but
|
wolffd@0
|
266 % TODO: create marker for unused objects in db, and a cleanup
|
wolffd@0
|
267 % function
|
wolffd@0
|
268 % ---
|
wolffd@0
|
269 function delete(feature)
|
wolffd@0
|
270
|
wolffd@0
|
271 end
|
wolffd@0
|
272 end
|
wolffd@0
|
273 end |