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 
+
+
+
+