Mercurial > hg > camir-aes2014
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/magnatagatune/MTTAudioFeatureDBgen.m Tue Feb 10 15:05:51 2015 +0000 @@ -0,0 +1,514 @@ +classdef MTTAudioFeatureDBgen < handle + + % --- + % the database is stored as a global variable + % --- + + properties (Hidden) + + % feature databases + featuredb; + + commondb; + + feature_type; + feature_params; + + % unfortunately we just can have one clip type at a time + clip_type; + end + + + properties (Hidden) + + % --- + % We use a "db_magnaaudiofeat_xxx" class pointer for all the loaded features, + % which is supposed to work like a cache. + % my_dbpos links to the position of this feature in the db. + % --- + + % database hash + featuredb_hash; + end + + % --- + % member functions + % --- + methods + + % constructor + function db = MTTAudioFeatureDBgen(type, matfile) + + if nargin >= 1 + + % --- + % we test for correct type by + % using an call to the empty arg constructor function + % --- + try + feval(type); + + catch err + fprintf('%s\n', err.message); + error('The specified class does not provide an constructor') + end + db.feature_type = type; + + if nargin >=2 && ~isempty(dir(matfile)) + + + % import database if filename given + db.import(matfile); + end + + end + + % try to load a standard db from mat file? + end + + % --- + % database retrieval. + % this should return a handle to a feature class pointing in this + % global feature database. + % + % parameters can be passed via the varargin parameter + % --- + function features = get_features(db, clip, varargin) + + % --- + % TODO: error checking and processing + % --- + + % --- + % prepare for multiple clips + % --- + if numel(clip) > 1 + + % iterate for all the found clips + features = feval(db.feature_type); + for i = 1:numel(clip) + features(i) = get_features(db, clip(i), varargin{:}); + end + else + % --- + % single feature extraction + % --- + + pos = db.get_clip_pos(clip); + if ~pos + + % assign new database position + pos = db.get_next_pos(); + + % call feature constructor + features = feval(db.feature_type, db, varargin{:}); + + % extract / load feature data + + cprint(2 ,'Extracting %s for clip %d \n', db.feature_type, clip.id()); + + if isempty( db.featuredb) + + db.featuredb = features.extract(clip); + else + + db.featuredb(pos) = features.extract(clip); + end + % --- + % NOTE: + % IF WE ARE SURE THAT EVERYTHING HAS WORKED OUT FINE: + % assign new database position in cache + % --- + db.set_pos(pos, clip); + + % --- + % NOTE: feature objects are directly linked to DB + % positions + % --- + features.assign(pos); + else + + % just return the cached link + features = feval(db.feature_type, db, pos); + end + + % --- + % finalise features if possible (commondb not empty) + % --- + if ~isempty(db.commondb) && isempty(features.data.final) && ... + ismethod(features,'finalise') + + % call finalise + features.finalise(); + end + + % set clip type of the db + db.clip_type = class(clip(1)); + + % get last params + db.feature_params = features(1).my_params; + end + end + + function set_common(db, common) + % sets the common database to input + + if isempty(db.commondb) + + cprint(2, 'Setting common feature values\n'); + else + + cprint(1, 'Common feature values changed'); + end + + db.commondb = common; + end + + function export(db, matfile, clips) + % saves featuredb to matlab data file + + global globalvars; + % save revision for later version and compability control + info.creatorrev = globalvars.camir.revision; + + cprint(2, 'Exporting %s database to %s ...\n', db.feature_type, matfile); + if nargin == 3 + % --- + % TODO: create new hash + % --- + for i = 1:numel(clips) + pos(i) = db.get_clip_pos(clips(i)); + + if pos(i) == 0 + error('Corrupted database'); + end + end + + % get specific data set + featuredb = db.featuredb(pos); + + featuredb_hash = db.featuredb_hash(pos); + + else + featuredb = db.featuredb; + + featuredb_hash = db.featuredb_hash; + end + + commondb = db.commondb; + + feature_type = db.feature_type; + + % --- + % save clip type as well + % NOTE: this only works if all clips have the same type (e.g. + % CASIMIRClip or MTTclip + % --- + clip_type = class(clips(1)); + + save(matfile, 'featuredb', 'commondb', 'feature_type', 'featuredb_hash', 'clip_type'); + end + + function [features, clips] = import(db, matfile, type) + % gets featuredb from matlab data file + + cprint(2, 'importing features from %s', matfile) + load(matfile,'-MAT'); + + if ~strcmp(feature_type, db.feature_type) + + error('feature type of db to import does not match'); + end + + % --- + % TODO / FIXME: check parameter hash before importing + % --- + +% if db.size() > 0 +% +% % get a feature param from the db; +% last_pos = db.get_last_pos; +% dummyparams = db.featuredb(last_pos).info.params; +% +% % --- +% % construct a dummy feature and compare parameters to +% % the params in the database +% % --- +% dummyclip = MTTClip(db.featuredb_hash(last_pos)); +% dummyfeat = db.get_features(dummyclip, dummyparams); +% +% if ~dummybsm.eq_params(fparams(i)) +% +% db_magnaaudiofeat_basicsm.reset; +% end +% +% end + + if exist('clip_type','var') + clips = feval(clip_type,featuredb_hash); + db.clip_type = clip_type; + else + clips = MTTClip(featuredb_hash); + db.clip_type = 'MTTClip'; + end + + % --- + % import features individually into db + % --- + + for i = 1:numel(clips) + + % test if database already contains clip + if ~db.get_clip_pos(clips(i)); + + % get position for this database + pos = db.get_next_pos(); + + % copy values + if ~isempty(db.featuredb) + + db.featuredb(pos) = featuredb(i); + elseif pos == 1; + + db.featuredb = featuredb(i); + else + + error ('Corrupted database'); + end + % update hash + db.set_pos(pos, clips(i)); + end + end + +% Set common features + db.set_common(commondb); + + if nargout > 0 + % retrieve features; + features = get_features(db, clips); + end + + end + + function [matfile] = load(db, featuretype, fparams, clips) + % this is the new implementation of MTTAudiofeature_load + + % get filename + matfile = MTTAudioFeatureDBgen.get_db_filename(featuretype, fparams,clips); + + % does it exist? + if exist(matfile,'file') == 2 + import(db, matfile); + else + matfile= []; + end + end + + function [matfile] = save(db) + % this is the new implementation of MTTAudiofeature_load + + % get clips + clips = feval(db.clip_type,db.featuredb_hash); + + % get filename + matfile = MTTAudioFeatureDBgen.get_db_filename(db.feature_type, db.feature_params ,clips); + + % does it exist? + if exist(matfile,'file') == 2 + warning 'overwriting feature file for this config' + end + + % save params in xml + xml_save(sprintf('%s.xml', substr(matfile, 0, -4)),db.feature_params); + + %export features + export(db, matfile, clips); + end + + function remove_features(db, clip) + % weakly deletes clip features from db + + clear_pos(clip); + end + + function delete(db) + % --- + % probably not anything to do here, as we want to + % keep the db! + % see static method destroy + % --- + end + + function reset(db) + % --- + % deletes all the cached data and destroys the + % global feature database + % --- + db.commondb = []; + db.featuredb = []; + db.featuredb_hash = []; + end + + function out = size(db) + % returns the number of features saved in this db + + out = sum(db.featuredb_hash > 0); + end + + function memory(db) + % returns size of whole db in bytes + + % --- + % TODO: Make this work + % --- + + fprintf(' \n This db contains feature sets for %d clips\n ',numel(db.featuredb_hash)) + % get local copies of data + featuredb = db.featuredb; + featuredb_hash = db.featuredb_hash; + commondb = db.commondb; + + whos('featuredb', 'featuredb_hash', 'commondb') + end + end + + % --- + % private functions + % --- + methods (Hidden) + + % --- + % Hash functions + % --- + function out = get_clip_pos(db, clip) + % should become database hashing function + + out = find(db.featuredb_hash == clip.id); + if isempty(out) + out = 0; + end + end + + function out = get_next_pos(db) + % return index for the new clip features + + out = numel(db.featuredb_hash) + 1; + end + + function last_pos = get_last_pos(db) + % return index the last valid db entry + + last_pos = find(db.featuredb_hash > 0, 1, 'last'); + end + + + function set_pos(db, pos, clip) + % set index for the new clip features + + db.featuredb_hash(pos) = clip.id; + end + + function clear_pos(db, clip) + % remove index of the clip features + + db.featuredb_hash(get_clip_pos(db, clip)) = 0; + end + end + + methods (Static) + + % --- + % this resets all feature dbs except the one exluded in the + % 'exclude', {''} cell + % --- + function reset_feature_dbs(varargin) + + [exclude] = process_options(varargin,'exclude',{}); + % --- + % resets all feature dbs except raw features + % --- + vars = whos ('*','global','-regexp', '^db_*'); + + % --- + % check if each is class of DBgen. + % if not in exclude variable, reset + % --- + for i = 1:numel(vars) + + % import global variable + eval(sprintf('global %s',vars(i).name)); + + if strcmp(eval(sprintf('class(%s)',vars(i).name)), 'MTTAudioFeatureDBgen') ... + && isempty(strcellfind(exclude, vars(i).name)) + + eval(sprintf('%s.reset',vars(i).name)); + end + end + end + + function feature_type = import_type(matfile) + % function feature_type = import_type(matfile) + % + % returns the type of the saved feature db. + + load(matfile, 'feature_type', '-MAT'); + end + + function db_nameo = db_name(type) + % returns the standard global var name for a db of given type + + switch type + case 'MTTAudioFeatureRAW' + db_nameo = 'db_magnaaudiofeat'; + + case 'MTTAudioFeatureBasicSm' + db_nameo = 'db_magnaaudiofeat_basicsm'; + + case 'MTTTagFeatureGenreBasic' + db_nameo = 'db_magnatagfeat_genrebasic'; + + case 'MTTMixedFeatureGenreBasicSm' + db_nameo = 'db_magnamixedfeat_genrebasicsm'; + + otherwise + db_nameo = sprintf('db_%s', type); + end + end + + function matfile = get_db_filename(featuretype, fparams,clips) + % get the paramhash + paramhash = MTTAudioFeatureDBgen.param_hash(featuretype, fparams); + + % add the clip hash bit + cliphash = MTTAudioFeatureDBgen.clip_hash(clips); + + % determine the filename + matfile = sprintf('f%s.%s.mat', paramhash,cliphash); + end + + function ph = param_hash(type, varargin) + % loads the params for a feature type and adds the + % given parameter values to it. + + % this function can be static or dynamic + if nargin > 1 + % static case + dummy = feval(type,[], varargin{:}); + else + % dynamic case + dummy = type; + end + ph = hash(xml_format(dummy.my_params),'MD5'); + end + + function ch = clip_hash(clips) + + % returns the hash of a number of clips + ch = hash([class(clips(1)) mat2str(sort(clips.id))],'MD5'); + end + end +end + + + +