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