Mercurial > hg > silvet
diff mirex2012-matlab/genCQTkernel.m @ 2:8017dd4a650d
Add MIREX 2012 code
author | Chris Cannam |
---|---|
date | Wed, 19 Mar 2014 09:09:23 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mirex2012-matlab/genCQTkernel.m Wed Mar 19 09:09:23 2014 +0000 @@ -0,0 +1,135 @@ +function cqtKernel = genCQTkernel(fmax, bins, fs, varargin) +%Calculating the CQT Kernel for one octave. All atoms are center-stacked. +%Atoms are placed so that the stacks of lower octaves are centered at the +%same positions in time, however, their amount is reduced by factor two for +%each octave down. +% +%INPUT: +% fmax ... highest frequency of interest +% bins ... number of bins per octave +% fs ... sampling frequency +% +%optional input parameters (parameter name/value pairs): +% +% 'q' ... Q scaling factor. Default: 1. +% 'atomHopFactor' ... relative hop size corresponding to the shortest +% temporal atom. Default: 0.25. +% 'thresh' ... values smaller than 'tresh' in the spectral kernel are rounded to +% zero. Default: 0.0005. +% 'win' ... defines which window will be used for the CQT. Valid +% values are: 'blackman','hann' and 'blackmanharris'. To +% use the square root of each window use the prefix 'sqrt_' +% (i.e. 'sqrt_blackman'). Default: 'sqrt_blackmanharris' +% 'perfRast' ... if set to 1 the kernel is designed in order to +% enable perfect rasterization using the function +% cqtPerfectRast() (Default: perRast=0). See documentation of +% 'cqtPerfectRast' for further information. +% +%OUTPUT: +% cqtKernel ... Structure that contains the spectral kernel 'fKernel' +% additional design parameters used in cqt(), cqtPerfectRast() and icqt(). +% +%Christian Schörkhuber, Anssi Klapuri 2010-06 + +%% input parameters +q = 1; %default value +atomHopFactor = 0.25; %default value +thresh = 0.0005; %default value +winFlag = 'sqrt_blackmanharris'; %default value +perfRast = 0; %default value + +for ain = 1:length(varargin) + if strcmp(varargin{ain},'q'), q = varargin{ain+1}; end; + if strcmp(varargin{ain},'atomHopFactor'), atomHopFactor = varargin{ain+1}; end; + if strcmp(varargin{ain},'thresh'), thresh = varargin{ain+1}; end; + if strcmp(varargin{ain},'win'), winFlag = varargin{ain+1}; end; + if strcmp(varargin{ain},'perfRast'), perfRast = varargin{ain+1}; end; +end + +%% define +fmin = (fmax/2)*2^(1/bins); +Q = 1/(2^(1/bins)-1); +Q = Q*q; +Nk_max = Q * fs / fmin; +Nk_max = round(Nk_max); %length of the largest atom [samples] + + +%% Compute FFT size, FFT hop, atom hop, ... +Nk_min = round( Q * fs / (fmin*2^((bins-1)/bins)) ); %length of the shortest atom [samples] +atomHOP = round(Nk_min*atomHopFactor); %atom hop size +first_center = ceil(Nk_max/2); %first possible center position within the frame +first_center = atomHOP * ceil(first_center/atomHOP); %lock the first center to an integer multiple of the atom hop size +FFTLen = 2^nextpow2(first_center+ceil(Nk_max/2)); %use smallest possible FFT size (increase sparsity) + +if perfRast + winNr = floor((FFTLen-ceil(Nk_max/2)-first_center)/atomHOP); %number of temporal atoms per FFT Frame + if winNr == 0 + FFTLen = FFTLen * 2; + winNr = floor((FFTLen-ceil(Nk_max/2)-first_center)/atomHOP); + end +else + winNr = floor((FFTLen-ceil(Nk_max/2)-first_center)/atomHOP)+1; %number of temporal atoms per FFT Frame +end + +last_center = first_center + (winNr-1)*atomHOP; +fftHOP = (last_center + atomHOP) - first_center; % hop size of FFT frames +fftOLP = (FFTLen-fftHOP/FFTLen)*100; %overlap of FFT frames in percent ***AK:needed? + +%% init variables +tempKernel= zeros(1,FFTLen); +sparKernel= []; + +%% Compute kernel +atomInd = 0; +for k = 1:bins + + Nk = round( Q * fs / (fmin*2^((k-1)/bins)) ); %N[k] = (fs/fk)*Q. Rounding will be omitted in future versions + + switch winFlag + case 'sqrt_blackmanharris' + winFct = sqrt(blackmanharris(Nk)); + case 'blackmanharris' + winFct = blackmanharris(Nk); + case 'sqrt_hann' + winFct = sqrt(hann(Nk,'periodic')); + case 'hann' + winFct = hann(Nk,'periodic'); + case 'sqrt_blackman' + winFct = sqrt(hann(blackman,'periodic')); + case 'blackman' + winFct = blackman(Nk,'periodic'); + otherwise + winFct = sqrt(blackmanharris(Nk)); + if k==1, warning('CQT:INPUT','Non-existing window function. Default window is used!'); end; + end + + fk = fmin*2^((k-1)/bins); + tempKernelBin = (winFct/Nk) .* exp(2*pi*1i*fk*(0:Nk-1)'/fs); + atomOffset = first_center - ceil(Nk/2); + + for i = 1:winNr + shift = atomOffset + ((i-1) * atomHOP); + tempKernel(1+shift:Nk+shift) = tempKernelBin; + atomInd = atomInd+1; + specKernel= fft(tempKernel); + specKernel(abs(specKernel)<=thresh)= 0; + sparKernel= sparse([sparKernel; specKernel]); + tempKernel = zeros(1,FFTLen); %reset window + end +end +sparKernel = (sparKernel.')/FFTLen; + +%% Normalize the magnitudes of the atoms +[ignore,wx1]=max(sparKernel(:,1)); +[ignore,wx2]=max(sparKernel(:,end)); +wK=sparKernel(wx1:wx2,:); +wK = diag(wK * wK'); +wK = wK(round(1/q)+1:(end-round(1/q)-2)); +weight = 1./mean(abs(wK)); +weight = weight.*(fftHOP/FFTLen); +weight = sqrt(weight); %sqrt because the same weight is applied in icqt again +sparKernel = weight.*sparKernel; + +%% return +cqtKernel = struct('fKernel',sparKernel,'fftLEN',FFTLen,'fftHOP',fftHOP,'fftOverlap',fftOLP,'perfRast',perfRast,... + 'bins',bins,'firstcenter',first_center,'atomHOP',atomHOP,'atomNr',winNr,'Nk_max',Nk_max,'Q',Q,'fmin',fmin);