annotate core/magnatagatune/MTTMixedFeatureStober11.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
rev   line source
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