diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/magnatagatune/MTTMixedFeatureStober11.m	Tue Feb 10 15:05:51 2015 +0000
@@ -0,0 +1,273 @@
+classdef MTTMixedFeatureStober11 < MTTAudioFeature & handle
+    % ---
+    % This Class contains 
+    % features are extracted 
+    % as described in Slaney 08 - LEARNING A METRIC FOR MUSIC SIMILARITY
+    %
+    % The usual workflow for these features constist of three steps
+    % 1. extract: extracts the basic single-file dependent features
+    % 2. define_global_transform: calculates the global feature
+    %       transformation parameters
+    % 3. finalise: applies the common transformations to a specific feature
+    % ---
+    
+    properties(Constant = true)
+        
+        % svn hook
+        my_revision = str2double(substr('$Rev$',  5, -1));
+    end
+
+    properties
+        % ---
+        % Set default parameters
+        % ---
+        my_params = struct(...
+            'stob_lowaudio', 1, ...
+            'stob_highaudio', 1, ... % 
+            'stob_tags', 1, ... %
+            'stob_norm', 1 ...
+            );
+    end
+    
+    % ---
+    % member functions
+    % ---
+    methods
+        
+        % ---
+        % constructor: pointer to feature in database
+        % ---
+        function feature = MTTMixedFeatureStober11(varargin)
+
+            feature = feature@MTTAudioFeature(varargin{:});
+
+        end
+        % ---
+        % extract feature data from raw audio features
+        % ---
+        function data = extract(feature, clip)
+            % ---
+            % get features. this includes possible
+            % local normalisations
+            % ---
+            
+            global globalvars;
+            global stobbase;
+            
+            if isempty(stobbase);
+                stobbase = load('features_stober');
+            end
+            
+            % ---
+            % NOTE: we define feature sets which are included /
+            % excluded according to the specified parameters
+            % ---
+            
+            lowAudio = {'pitchMean', 'pitchSdev', 'timbreMean', 'timbreSdev'};
+            
+            % highAudio features more or less correspond to slaney 08 features
+            hiAudio = {'energy','key','loudness','timeSignature',...
+                'danceability', 'mode', 'tempo'};
+            
+            metadat = {'tags'};
+            
+            allowedFeat = {};
+            
+            % Select the features to keep
+            if feature(1).my_params.stob_lowaudio
+                allowedFeat = {allowedFeat{:},  lowAudio{:}};
+            end
+            if feature(1).my_params.stob_highaudio
+                allowedFeat = {allowedFeat{:},  hiAudio{:}};
+            end
+            if feature(1).my_params.stob_tags
+                allowedFeat = {allowedFeat{:},  metadat{:}};
+            end
+            
+            % get the actual clip id
+            idx = find(stobbase.clipIds == clip.id);
+            
+            % ---
+            % NOTE: we just copy everything in a big matrix and then
+            % normalise the data later
+            % ---
+            data.vector_info = {};
+            data.stobraw = [];
+            fields = fieldnames(stobbase);
+            for i = 1:numel(fields)
+                
+                % skip clip ID field
+                if strcmp(fields{i},'clipIds');
+                    continue;
+                end
+                
+                % skip unwanted features
+                if isempty(strcellfind(allowedFeat, fields{i}))
+                    continue;
+                end
+                
+                % ---
+                % TODO: special case for tag features, including
+                % the tag names
+                % ---
+                
+                % put field info into right position
+                data.vector_info{numel(data.stobraw)+1} = fields{i};
+                
+                % add data to feature
+                if size(stobbase.(fields{i}),1) == 1
+                    data.stobraw(end+1) = stobbase.(fields{i})(idx);
+                else
+                    % concatenate vector
+                    tmpdat = stobbase.(fields{i})(idx,:);
+                    data.stobraw(end+1:end+numel(tmpdat)) = tmpdat;
+                end
+            end
+            % padd further info struct
+            data.vector_info(end+1:numel(data.stobraw)) =...
+                cell(numel(data.stobraw) - numel(data.vector_info) , 1); 
+            
+            % ---
+            % prepare field for final features
+            % ---
+            data.final.vector = [];
+            data.final.vector_info = struct(); 
+            data.final.dim = 0;
+           
+            % save info data
+            data.info.type = 'MTTMixedFeatureStober11';
+            data.info.owner_id = clip.id;
+            data.info.creatorrev = feature.my_revision;
+            
+            % save parameters
+            data.info.params = feature.my_params;
+        end
+        
+        function define_global_transform(features)
+        % calculate and set normalization factors from the group of 
+        % input features. These features will be set for the full database
+         
+        final = zeros(numel(features(1).data.stobraw), numel(features));
+        for i = 1:numel(features)
+             if ~isempty(features(i).data.stobraw)
+                final(:,i) = features(i).data.stobraw';
+             end
+        end
+            
+            if features(1).my_params.stob_norm
+                if numel(features) == 1
+                    error ('Insert feature array for this method, or set normalisation to 0');
+                end
+
+                % ---
+                % here, we only need to define the post-normalisation
+                % ---
+                [final, pstd] = mapminmax(final,0,1);
+                common.stobstats.post_norm = pstd;
+                
+                % ---
+                % NOTE: whitening as in slaney?? 
+                % Would make reading the
+                % mahal matrices really hard
+                % ---
+                
+                features(1).my_db.set_common(common);
+                
+            else
+                
+                features(1).my_db.set_common([1]);
+            end
+            
+            % save the normalised features straight away!
+            features.finalise(final);
+        end
+        
+        
+        function finalise(features, final)
+        % applies a final transformation and
+        % collects the information of this feature within a single vector
+        % see info for types in specific dimensions
+        % check if features have been finalised already
+
+        % ---
+        % set feature labelling
+        % ---
+        
+        info = {};
+                
+        % ---
+        % construct resulting feature vector out of features
+        % ---
+            if nargin == 2 && isempty(final)
+                
+                % the final vector etc already are set to zero;
+                return;
+                
+            elseif nargin == 2 && (numel(features) == size(final, 2))
+                % the features have already been preassembled
+                
+                for i = 1:numel(features)
+
+                    % check for neccesary parameters
+                    if isempty(features(i).my_db.commondb)
+
+                        error('Define the global transformation first')
+                        return;
+                    end
+
+                    features(i).data.final.vector = final(:,i);
+                    features(i).data.final.dim = size(final,1);
+
+                    % fill up info struct and append to feature
+                    features(i).data.final.vector_info.labels = ...
+                        features(i).data.vector_info;
+                end
+            else
+                % ---
+                % if features have been added after gettin gnormalisation
+                % parameters, ther should be still an option to include
+                % them
+                % ---
+               
+                 for i = 1:numel(features)
+
+                    % check for neccesary parameters
+                    if isempty(features(i).my_db.commondb)
+
+                        error('Define the global transformation first')
+                        return;
+                    end
+                    
+                    final = features(i).data.stobraw';
+                    
+                    if features(1).my_params.stob_norm == 1
+                                
+                        [final] = mapminmax('apply', final, features(1).common.stobstats.post_norm);
+                    end
+                    
+                    features(i).data.final.vector = final;
+                    features(i).data.final.dim = size(final,1);
+
+                    % fill up info struct and append to feature
+                    features(i).data.final.vector_info.labels = ...
+                        features(i).data.vector_info;
+                 end
+
+            end
+            
+            % ---
+            % TODO: Maybe delete more basic features again at this point?
+            % ---
+        end
+
+        % ---
+        % destructor: do we really want to remove this 
+        % from the database? No, but 
+        % TODO: create marker for unused objects in db, and a cleanup
+        %  function
+        % ---
+        function delete(feature)
+            
+        end
+    end
+end
\ No newline at end of file