Mercurial > hg > camir-aes2014
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