annotate core/magnatagatune/MTTAudioFeatureDBgen.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 MTTAudioFeatureDBgen < handle
wolffd@0 2
wolffd@0 3 % ---
wolffd@0 4 % the database is stored as a global variable
wolffd@0 5 % ---
wolffd@0 6
wolffd@0 7 properties (Hidden)
wolffd@0 8
wolffd@0 9 % feature databases
wolffd@0 10 featuredb;
wolffd@0 11
wolffd@0 12 commondb;
wolffd@0 13
wolffd@0 14 feature_type;
wolffd@0 15 feature_params;
wolffd@0 16
wolffd@0 17 % unfortunately we just can have one clip type at a time
wolffd@0 18 clip_type;
wolffd@0 19 end
wolffd@0 20
wolffd@0 21
wolffd@0 22 properties (Hidden)
wolffd@0 23
wolffd@0 24 % ---
wolffd@0 25 % We use a "db_magnaaudiofeat_xxx" class pointer for all the loaded features,
wolffd@0 26 % which is supposed to work like a cache.
wolffd@0 27 % my_dbpos links to the position of this feature in the db.
wolffd@0 28 % ---
wolffd@0 29
wolffd@0 30 % database hash
wolffd@0 31 featuredb_hash;
wolffd@0 32 end
wolffd@0 33
wolffd@0 34 % ---
wolffd@0 35 % member functions
wolffd@0 36 % ---
wolffd@0 37 methods
wolffd@0 38
wolffd@0 39 % constructor
wolffd@0 40 function db = MTTAudioFeatureDBgen(type, matfile)
wolffd@0 41
wolffd@0 42 if nargin >= 1
wolffd@0 43
wolffd@0 44 % ---
wolffd@0 45 % we test for correct type by
wolffd@0 46 % using an call to the empty arg constructor function
wolffd@0 47 % ---
wolffd@0 48 try
wolffd@0 49 feval(type);
wolffd@0 50
wolffd@0 51 catch err
wolffd@0 52 fprintf('%s\n', err.message);
wolffd@0 53 error('The specified class does not provide an constructor')
wolffd@0 54 end
wolffd@0 55 db.feature_type = type;
wolffd@0 56
wolffd@0 57 if nargin >=2 && ~isempty(dir(matfile))
wolffd@0 58
wolffd@0 59
wolffd@0 60 % import database if filename given
wolffd@0 61 db.import(matfile);
wolffd@0 62 end
wolffd@0 63
wolffd@0 64 end
wolffd@0 65
wolffd@0 66 % try to load a standard db from mat file?
wolffd@0 67 end
wolffd@0 68
wolffd@0 69 % ---
wolffd@0 70 % database retrieval.
wolffd@0 71 % this should return a handle to a feature class pointing in this
wolffd@0 72 % global feature database.
wolffd@0 73 %
wolffd@0 74 % parameters can be passed via the varargin parameter
wolffd@0 75 % ---
wolffd@0 76 function features = get_features(db, clip, varargin)
wolffd@0 77
wolffd@0 78 % ---
wolffd@0 79 % TODO: error checking and processing
wolffd@0 80 % ---
wolffd@0 81
wolffd@0 82 % ---
wolffd@0 83 % prepare for multiple clips
wolffd@0 84 % ---
wolffd@0 85 if numel(clip) > 1
wolffd@0 86
wolffd@0 87 % iterate for all the found clips
wolffd@0 88 features = feval(db.feature_type);
wolffd@0 89 for i = 1:numel(clip)
wolffd@0 90 features(i) = get_features(db, clip(i), varargin{:});
wolffd@0 91 end
wolffd@0 92 else
wolffd@0 93 % ---
wolffd@0 94 % single feature extraction
wolffd@0 95 % ---
wolffd@0 96
wolffd@0 97 pos = db.get_clip_pos(clip);
wolffd@0 98 if ~pos
wolffd@0 99
wolffd@0 100 % assign new database position
wolffd@0 101 pos = db.get_next_pos();
wolffd@0 102
wolffd@0 103 % call feature constructor
wolffd@0 104 features = feval(db.feature_type, db, varargin{:});
wolffd@0 105
wolffd@0 106 % extract / load feature data
wolffd@0 107
wolffd@0 108 cprint(2 ,'Extracting %s for clip %d \n', db.feature_type, clip.id());
wolffd@0 109
wolffd@0 110 if isempty( db.featuredb)
wolffd@0 111
wolffd@0 112 db.featuredb = features.extract(clip);
wolffd@0 113 else
wolffd@0 114
wolffd@0 115 db.featuredb(pos) = features.extract(clip);
wolffd@0 116 end
wolffd@0 117 % ---
wolffd@0 118 % NOTE:
wolffd@0 119 % IF WE ARE SURE THAT EVERYTHING HAS WORKED OUT FINE:
wolffd@0 120 % assign new database position in cache
wolffd@0 121 % ---
wolffd@0 122 db.set_pos(pos, clip);
wolffd@0 123
wolffd@0 124 % ---
wolffd@0 125 % NOTE: feature objects are directly linked to DB
wolffd@0 126 % positions
wolffd@0 127 % ---
wolffd@0 128 features.assign(pos);
wolffd@0 129 else
wolffd@0 130
wolffd@0 131 % just return the cached link
wolffd@0 132 features = feval(db.feature_type, db, pos);
wolffd@0 133 end
wolffd@0 134
wolffd@0 135 % ---
wolffd@0 136 % finalise features if possible (commondb not empty)
wolffd@0 137 % ---
wolffd@0 138 if ~isempty(db.commondb) && isempty(features.data.final) && ...
wolffd@0 139 ismethod(features,'finalise')
wolffd@0 140
wolffd@0 141 % call finalise
wolffd@0 142 features.finalise();
wolffd@0 143 end
wolffd@0 144
wolffd@0 145 % set clip type of the db
wolffd@0 146 db.clip_type = class(clip(1));
wolffd@0 147
wolffd@0 148 % get last params
wolffd@0 149 db.feature_params = features(1).my_params;
wolffd@0 150 end
wolffd@0 151 end
wolffd@0 152
wolffd@0 153 function set_common(db, common)
wolffd@0 154 % sets the common database to input
wolffd@0 155
wolffd@0 156 if isempty(db.commondb)
wolffd@0 157
wolffd@0 158 cprint(2, 'Setting common feature values\n');
wolffd@0 159 else
wolffd@0 160
wolffd@0 161 cprint(1, 'Common feature values changed');
wolffd@0 162 end
wolffd@0 163
wolffd@0 164 db.commondb = common;
wolffd@0 165 end
wolffd@0 166
wolffd@0 167 function export(db, matfile, clips)
wolffd@0 168 % saves featuredb to matlab data file
wolffd@0 169
wolffd@0 170 global globalvars;
wolffd@0 171 % save revision for later version and compability control
wolffd@0 172 info.creatorrev = globalvars.camir.revision;
wolffd@0 173
wolffd@0 174 cprint(2, 'Exporting %s database to %s ...\n', db.feature_type, matfile);
wolffd@0 175 if nargin == 3
wolffd@0 176 % ---
wolffd@0 177 % TODO: create new hash
wolffd@0 178 % ---
wolffd@0 179 for i = 1:numel(clips)
wolffd@0 180 pos(i) = db.get_clip_pos(clips(i));
wolffd@0 181
wolffd@0 182 if pos(i) == 0
wolffd@0 183 error('Corrupted database');
wolffd@0 184 end
wolffd@0 185 end
wolffd@0 186
wolffd@0 187 % get specific data set
wolffd@0 188 featuredb = db.featuredb(pos);
wolffd@0 189
wolffd@0 190 featuredb_hash = db.featuredb_hash(pos);
wolffd@0 191
wolffd@0 192 else
wolffd@0 193 featuredb = db.featuredb;
wolffd@0 194
wolffd@0 195 featuredb_hash = db.featuredb_hash;
wolffd@0 196 end
wolffd@0 197
wolffd@0 198 commondb = db.commondb;
wolffd@0 199
wolffd@0 200 feature_type = db.feature_type;
wolffd@0 201
wolffd@0 202 % ---
wolffd@0 203 % save clip type as well
wolffd@0 204 % NOTE: this only works if all clips have the same type (e.g.
wolffd@0 205 % CASIMIRClip or MTTclip
wolffd@0 206 % ---
wolffd@0 207 clip_type = class(clips(1));
wolffd@0 208
wolffd@0 209 save(matfile, 'featuredb', 'commondb', 'feature_type', 'featuredb_hash', 'clip_type');
wolffd@0 210 end
wolffd@0 211
wolffd@0 212 function [features, clips] = import(db, matfile, type)
wolffd@0 213 % gets featuredb from matlab data file
wolffd@0 214
wolffd@0 215 cprint(2, 'importing features from %s', matfile)
wolffd@0 216 load(matfile,'-MAT');
wolffd@0 217
wolffd@0 218 if ~strcmp(feature_type, db.feature_type)
wolffd@0 219
wolffd@0 220 error('feature type of db to import does not match');
wolffd@0 221 end
wolffd@0 222
wolffd@0 223 % ---
wolffd@0 224 % TODO / FIXME: check parameter hash before importing
wolffd@0 225 % ---
wolffd@0 226
wolffd@0 227 % if db.size() > 0
wolffd@0 228 %
wolffd@0 229 % % get a feature param from the db;
wolffd@0 230 % last_pos = db.get_last_pos;
wolffd@0 231 % dummyparams = db.featuredb(last_pos).info.params;
wolffd@0 232 %
wolffd@0 233 % % ---
wolffd@0 234 % % construct a dummy feature and compare parameters to
wolffd@0 235 % % the params in the database
wolffd@0 236 % % ---
wolffd@0 237 % dummyclip = MTTClip(db.featuredb_hash(last_pos));
wolffd@0 238 % dummyfeat = db.get_features(dummyclip, dummyparams);
wolffd@0 239 %
wolffd@0 240 % if ~dummybsm.eq_params(fparams(i))
wolffd@0 241 %
wolffd@0 242 % db_magnaaudiofeat_basicsm.reset;
wolffd@0 243 % end
wolffd@0 244 %
wolffd@0 245 % end
wolffd@0 246
wolffd@0 247 if exist('clip_type','var')
wolffd@0 248 clips = feval(clip_type,featuredb_hash);
wolffd@0 249 db.clip_type = clip_type;
wolffd@0 250 else
wolffd@0 251 clips = MTTClip(featuredb_hash);
wolffd@0 252 db.clip_type = 'MTTClip';
wolffd@0 253 end
wolffd@0 254
wolffd@0 255 % ---
wolffd@0 256 % import features individually into db
wolffd@0 257 % ---
wolffd@0 258
wolffd@0 259 for i = 1:numel(clips)
wolffd@0 260
wolffd@0 261 % test if database already contains clip
wolffd@0 262 if ~db.get_clip_pos(clips(i));
wolffd@0 263
wolffd@0 264 % get position for this database
wolffd@0 265 pos = db.get_next_pos();
wolffd@0 266
wolffd@0 267 % copy values
wolffd@0 268 if ~isempty(db.featuredb)
wolffd@0 269
wolffd@0 270 db.featuredb(pos) = featuredb(i);
wolffd@0 271 elseif pos == 1;
wolffd@0 272
wolffd@0 273 db.featuredb = featuredb(i);
wolffd@0 274 else
wolffd@0 275
wolffd@0 276 error ('Corrupted database');
wolffd@0 277 end
wolffd@0 278 % update hash
wolffd@0 279 db.set_pos(pos, clips(i));
wolffd@0 280 end
wolffd@0 281 end
wolffd@0 282
wolffd@0 283 % Set common features
wolffd@0 284 db.set_common(commondb);
wolffd@0 285
wolffd@0 286 if nargout > 0
wolffd@0 287 % retrieve features;
wolffd@0 288 features = get_features(db, clips);
wolffd@0 289 end
wolffd@0 290
wolffd@0 291 end
wolffd@0 292
wolffd@0 293 function [matfile] = load(db, featuretype, fparams, clips)
wolffd@0 294 % this is the new implementation of MTTAudiofeature_load
wolffd@0 295
wolffd@0 296 % get filename
wolffd@0 297 matfile = MTTAudioFeatureDBgen.get_db_filename(featuretype, fparams,clips);
wolffd@0 298
wolffd@0 299 % does it exist?
wolffd@0 300 if exist(matfile,'file') == 2
wolffd@0 301 import(db, matfile);
wolffd@0 302 else
wolffd@0 303 matfile= [];
wolffd@0 304 end
wolffd@0 305 end
wolffd@0 306
wolffd@0 307 function [matfile] = save(db)
wolffd@0 308 % this is the new implementation of MTTAudiofeature_load
wolffd@0 309
wolffd@0 310 % get clips
wolffd@0 311 clips = feval(db.clip_type,db.featuredb_hash);
wolffd@0 312
wolffd@0 313 % get filename
wolffd@0 314 matfile = MTTAudioFeatureDBgen.get_db_filename(db.feature_type, db.feature_params ,clips);
wolffd@0 315
wolffd@0 316 % does it exist?
wolffd@0 317 if exist(matfile,'file') == 2
wolffd@0 318 warning 'overwriting feature file for this config'
wolffd@0 319 end
wolffd@0 320
wolffd@0 321 % save params in xml
wolffd@0 322 xml_save(sprintf('%s.xml', substr(matfile, 0, -4)),db.feature_params);
wolffd@0 323
wolffd@0 324 %export features
wolffd@0 325 export(db, matfile, clips);
wolffd@0 326 end
wolffd@0 327
wolffd@0 328 function remove_features(db, clip)
wolffd@0 329 % weakly deletes clip features from db
wolffd@0 330
wolffd@0 331 clear_pos(clip);
wolffd@0 332 end
wolffd@0 333
wolffd@0 334 function delete(db)
wolffd@0 335 % ---
wolffd@0 336 % probably not anything to do here, as we want to
wolffd@0 337 % keep the db!
wolffd@0 338 % see static method destroy
wolffd@0 339 % ---
wolffd@0 340 end
wolffd@0 341
wolffd@0 342 function reset(db)
wolffd@0 343 % ---
wolffd@0 344 % deletes all the cached data and destroys the
wolffd@0 345 % global feature database
wolffd@0 346 % ---
wolffd@0 347 db.commondb = [];
wolffd@0 348 db.featuredb = [];
wolffd@0 349 db.featuredb_hash = [];
wolffd@0 350 end
wolffd@0 351
wolffd@0 352 function out = size(db)
wolffd@0 353 % returns the number of features saved in this db
wolffd@0 354
wolffd@0 355 out = sum(db.featuredb_hash > 0);
wolffd@0 356 end
wolffd@0 357
wolffd@0 358 function memory(db)
wolffd@0 359 % returns size of whole db in bytes
wolffd@0 360
wolffd@0 361 % ---
wolffd@0 362 % TODO: Make this work
wolffd@0 363 % ---
wolffd@0 364
wolffd@0 365 fprintf(' \n This db contains feature sets for %d clips\n ',numel(db.featuredb_hash))
wolffd@0 366 % get local copies of data
wolffd@0 367 featuredb = db.featuredb;
wolffd@0 368 featuredb_hash = db.featuredb_hash;
wolffd@0 369 commondb = db.commondb;
wolffd@0 370
wolffd@0 371 whos('featuredb', 'featuredb_hash', 'commondb')
wolffd@0 372 end
wolffd@0 373 end
wolffd@0 374
wolffd@0 375 % ---
wolffd@0 376 % private functions
wolffd@0 377 % ---
wolffd@0 378 methods (Hidden)
wolffd@0 379
wolffd@0 380 % ---
wolffd@0 381 % Hash functions
wolffd@0 382 % ---
wolffd@0 383 function out = get_clip_pos(db, clip)
wolffd@0 384 % should become database hashing function
wolffd@0 385
wolffd@0 386 out = find(db.featuredb_hash == clip.id);
wolffd@0 387 if isempty(out)
wolffd@0 388 out = 0;
wolffd@0 389 end
wolffd@0 390 end
wolffd@0 391
wolffd@0 392 function out = get_next_pos(db)
wolffd@0 393 % return index for the new clip features
wolffd@0 394
wolffd@0 395 out = numel(db.featuredb_hash) + 1;
wolffd@0 396 end
wolffd@0 397
wolffd@0 398 function last_pos = get_last_pos(db)
wolffd@0 399 % return index the last valid db entry
wolffd@0 400
wolffd@0 401 last_pos = find(db.featuredb_hash > 0, 1, 'last');
wolffd@0 402 end
wolffd@0 403
wolffd@0 404
wolffd@0 405 function set_pos(db, pos, clip)
wolffd@0 406 % set index for the new clip features
wolffd@0 407
wolffd@0 408 db.featuredb_hash(pos) = clip.id;
wolffd@0 409 end
wolffd@0 410
wolffd@0 411 function clear_pos(db, clip)
wolffd@0 412 % remove index of the clip features
wolffd@0 413
wolffd@0 414 db.featuredb_hash(get_clip_pos(db, clip)) = 0;
wolffd@0 415 end
wolffd@0 416 end
wolffd@0 417
wolffd@0 418 methods (Static)
wolffd@0 419
wolffd@0 420 % ---
wolffd@0 421 % this resets all feature dbs except the one exluded in the
wolffd@0 422 % 'exclude', {''} cell
wolffd@0 423 % ---
wolffd@0 424 function reset_feature_dbs(varargin)
wolffd@0 425
wolffd@0 426 [exclude] = process_options(varargin,'exclude',{});
wolffd@0 427 % ---
wolffd@0 428 % resets all feature dbs except raw features
wolffd@0 429 % ---
wolffd@0 430 vars = whos ('*','global','-regexp', '^db_*');
wolffd@0 431
wolffd@0 432 % ---
wolffd@0 433 % check if each is class of DBgen.
wolffd@0 434 % if not in exclude variable, reset
wolffd@0 435 % ---
wolffd@0 436 for i = 1:numel(vars)
wolffd@0 437
wolffd@0 438 % import global variable
wolffd@0 439 eval(sprintf('global %s',vars(i).name));
wolffd@0 440
wolffd@0 441 if strcmp(eval(sprintf('class(%s)',vars(i).name)), 'MTTAudioFeatureDBgen') ...
wolffd@0 442 && isempty(strcellfind(exclude, vars(i).name))
wolffd@0 443
wolffd@0 444 eval(sprintf('%s.reset',vars(i).name));
wolffd@0 445 end
wolffd@0 446 end
wolffd@0 447 end
wolffd@0 448
wolffd@0 449 function feature_type = import_type(matfile)
wolffd@0 450 % function feature_type = import_type(matfile)
wolffd@0 451 %
wolffd@0 452 % returns the type of the saved feature db.
wolffd@0 453
wolffd@0 454 load(matfile, 'feature_type', '-MAT');
wolffd@0 455 end
wolffd@0 456
wolffd@0 457 function db_nameo = db_name(type)
wolffd@0 458 % returns the standard global var name for a db of given type
wolffd@0 459
wolffd@0 460 switch type
wolffd@0 461 case 'MTTAudioFeatureRAW'
wolffd@0 462 db_nameo = 'db_magnaaudiofeat';
wolffd@0 463
wolffd@0 464 case 'MTTAudioFeatureBasicSm'
wolffd@0 465 db_nameo = 'db_magnaaudiofeat_basicsm';
wolffd@0 466
wolffd@0 467 case 'MTTTagFeatureGenreBasic'
wolffd@0 468 db_nameo = 'db_magnatagfeat_genrebasic';
wolffd@0 469
wolffd@0 470 case 'MTTMixedFeatureGenreBasicSm'
wolffd@0 471 db_nameo = 'db_magnamixedfeat_genrebasicsm';
wolffd@0 472
wolffd@0 473 otherwise
wolffd@0 474 db_nameo = sprintf('db_%s', type);
wolffd@0 475 end
wolffd@0 476 end
wolffd@0 477
wolffd@0 478 function matfile = get_db_filename(featuretype, fparams,clips)
wolffd@0 479 % get the paramhash
wolffd@0 480 paramhash = MTTAudioFeatureDBgen.param_hash(featuretype, fparams);
wolffd@0 481
wolffd@0 482 % add the clip hash bit
wolffd@0 483 cliphash = MTTAudioFeatureDBgen.clip_hash(clips);
wolffd@0 484
wolffd@0 485 % determine the filename
wolffd@0 486 matfile = sprintf('f%s.%s.mat', paramhash,cliphash);
wolffd@0 487 end
wolffd@0 488
wolffd@0 489 function ph = param_hash(type, varargin)
wolffd@0 490 % loads the params for a feature type and adds the
wolffd@0 491 % given parameter values to it.
wolffd@0 492
wolffd@0 493 % this function can be static or dynamic
wolffd@0 494 if nargin > 1
wolffd@0 495 % static case
wolffd@0 496 dummy = feval(type,[], varargin{:});
wolffd@0 497 else
wolffd@0 498 % dynamic case
wolffd@0 499 dummy = type;
wolffd@0 500 end
wolffd@0 501 ph = hash(xml_format(dummy.my_params),'MD5');
wolffd@0 502 end
wolffd@0 503
wolffd@0 504 function ch = clip_hash(clips)
wolffd@0 505
wolffd@0 506 % returns the hash of a number of clips
wolffd@0 507 ch = hash([class(clips(1)) mat2str(sort(clips.id))],'MD5');
wolffd@0 508 end
wolffd@0 509 end
wolffd@0 510 end
wolffd@0 511
wolffd@0 512
wolffd@0 513
wolffd@0 514