annotate genCQTkernel.m @ 1:3ea8ed09af0f tip

additional clarifications
author Dimitrios Giannoulis
date Wed, 13 Mar 2013 11:57:24 +0000
parents 22b10c5b72e8
children
rev   line source
Dimitrios@0 1 function cqtKernel = genCQTkernel(fmax, bins, fs, varargin)
Dimitrios@0 2 %Calculating the CQT Kernel for one octave. All atoms are center-stacked.
Dimitrios@0 3 %Atoms are placed so that the stacks of lower octaves are centered at the
Dimitrios@0 4 %same positions in time, however, their amount is reduced by factor two for
Dimitrios@0 5 %each octave down.
Dimitrios@0 6 %
Dimitrios@0 7 %INPUT:
Dimitrios@0 8 % fmax ... highest frequency of interest
Dimitrios@0 9 % bins ... number of bins per octave
Dimitrios@0 10 % fs ... sampling frequency
Dimitrios@0 11 %
Dimitrios@0 12 %optional input parameters (parameter name/value pairs):
Dimitrios@0 13 %
Dimitrios@0 14 % 'q' ... Q scaling factor. Default: 1.
Dimitrios@0 15 % 'atomHopFactor' ... relative hop size corresponding to the shortest
Dimitrios@0 16 % temporal atom. Default: 0.25.
Dimitrios@0 17 % 'thresh' ... values smaller than 'tresh' in the spectral kernel are rounded to
Dimitrios@0 18 % zero. Default: 0.0005.
Dimitrios@0 19 % 'win' ... defines which window will be used for the CQT. Valid
Dimitrios@0 20 % values are: 'blackman','hann' and 'blackmanharris'. To
Dimitrios@0 21 % use the square root of each window use the prefix 'sqrt_'
Dimitrios@0 22 % (i.e. 'sqrt_blackman'). Default: 'sqrt_blackmanharris'
Dimitrios@0 23 % 'perfRast' ... if set to 1 the kernel is designed in order to
Dimitrios@0 24 % enable perfect rasterization using the function
Dimitrios@0 25 % cqtPerfectRast() (Default: perRast=0). See documentation of
Dimitrios@0 26 % 'cqtPerfectRast' for further information.
Dimitrios@0 27 %
Dimitrios@0 28 %OUTPUT:
Dimitrios@0 29 % cqtKernel ... Structure that contains the spectral kernel 'fKernel'
Dimitrios@0 30 % additional design parameters used in cqt(), cqtPerfectRast() and icqt().
Dimitrios@0 31 %
Dimitrios@0 32 %Christian Schörkhuber, Anssi Klapuri 2010-06
Dimitrios@0 33
Dimitrios@0 34 %% input parameters
Dimitrios@0 35 q = 1; %default value
Dimitrios@0 36 atomHopFactor = 0.25; %default value
Dimitrios@0 37 thresh = 0.0005; %default value
Dimitrios@0 38 winFlag = 'sqrt_blackmanharris'; %default value
Dimitrios@0 39 perfRast = 0; %default value
Dimitrios@0 40
Dimitrios@0 41 for ain = 1:length(varargin)
Dimitrios@0 42 if strcmp(varargin{ain},'q'), q = varargin{ain+1}; end;
Dimitrios@0 43 if strcmp(varargin{ain},'atomHopFactor'), atomHopFactor = varargin{ain+1}; end;
Dimitrios@0 44 if strcmp(varargin{ain},'thresh'), thresh = varargin{ain+1}; end;
Dimitrios@0 45 if strcmp(varargin{ain},'win'), winFlag = varargin{ain+1}; end;
Dimitrios@0 46 if strcmp(varargin{ain},'perfRast'), perfRast = varargin{ain+1}; end;
Dimitrios@0 47 end
Dimitrios@0 48
Dimitrios@0 49 %% define
Dimitrios@0 50 fmin = (fmax/2)*2^(1/bins);
Dimitrios@0 51 Q = 1/(2^(1/bins)-1);
Dimitrios@0 52 Q = Q*q;
Dimitrios@0 53 Nk_max = Q * fs / fmin;
Dimitrios@0 54 Nk_max = round(Nk_max); %length of the largest atom [samples]
Dimitrios@0 55
Dimitrios@0 56
Dimitrios@0 57 %% Compute FFT size, FFT hop, atom hop, ...
Dimitrios@0 58 Nk_min = round( Q * fs / (fmin*2^((bins-1)/bins)) ); %length of the shortest atom [samples]
Dimitrios@0 59 atomHOP = round(Nk_min*atomHopFactor); %atom hop size
Dimitrios@0 60 first_center = ceil(Nk_max/2); %first possible center position within the frame
Dimitrios@0 61 first_center = atomHOP * ceil(first_center/atomHOP); %lock the first center to an integer multiple of the atom hop size
Dimitrios@0 62 FFTLen = 2^nextpow2(first_center+ceil(Nk_max/2)); %use smallest possible FFT size (increase sparsity)
Dimitrios@0 63
Dimitrios@0 64 if perfRast
Dimitrios@0 65 winNr = floor((FFTLen-ceil(Nk_max/2)-first_center)/atomHOP); %number of temporal atoms per FFT Frame
Dimitrios@0 66 if winNr == 0
Dimitrios@0 67 FFTLen = FFTLen * 2;
Dimitrios@0 68 winNr = floor((FFTLen-ceil(Nk_max/2)-first_center)/atomHOP);
Dimitrios@0 69 end
Dimitrios@0 70 else
Dimitrios@0 71 winNr = floor((FFTLen-ceil(Nk_max/2)-first_center)/atomHOP)+1; %number of temporal atoms per FFT Frame
Dimitrios@0 72 end
Dimitrios@0 73
Dimitrios@0 74 last_center = first_center + (winNr-1)*atomHOP;
Dimitrios@0 75 fftHOP = (last_center + atomHOP) - first_center; % hop size of FFT frames
Dimitrios@0 76 fftOLP = (FFTLen-fftHOP/FFTLen)*100; %overlap of FFT frames in percent ***AK:needed?
Dimitrios@0 77
Dimitrios@0 78 %% init variables
Dimitrios@0 79 tempKernel= zeros(1,FFTLen);
Dimitrios@0 80 sparKernel= [];
Dimitrios@0 81
Dimitrios@0 82 %% Compute kernel
Dimitrios@0 83 atomInd = 0;
Dimitrios@0 84 for k = 1:bins
Dimitrios@0 85
Dimitrios@0 86 Nk = round( Q * fs / (fmin*2^((k-1)/bins)) ); %N[k] = (fs/fk)*Q. Rounding will be omitted in future versions
Dimitrios@0 87
Dimitrios@0 88 switch winFlag
Dimitrios@0 89 case 'sqrt_blackmanharris'
Dimitrios@0 90 winFct = sqrt(blackmanharris(Nk));
Dimitrios@0 91 case 'blackmanharris'
Dimitrios@0 92 winFct = blackmanharris(Nk);
Dimitrios@0 93 case 'sqrt_hann'
Dimitrios@0 94 winFct = sqrt(hann(Nk,'periodic'));
Dimitrios@0 95 case 'hann'
Dimitrios@0 96 winFct = hann(Nk,'periodic');
Dimitrios@0 97 case 'sqrt_blackman'
Dimitrios@0 98 winFct = sqrt(hann(blackman,'periodic'));
Dimitrios@0 99 case 'blackman'
Dimitrios@0 100 winFct = blackman(Nk,'periodic');
Dimitrios@0 101 otherwise
Dimitrios@0 102 winFct = sqrt(blackmanharris(Nk));
Dimitrios@0 103 if k==1, warning('CQT:INPUT','Non-existing window function. Default window is used!'); end;
Dimitrios@0 104 end
Dimitrios@0 105
Dimitrios@0 106 fk = fmin*2^((k-1)/bins);
Dimitrios@0 107 tempKernelBin = (winFct/Nk) .* exp(2*pi*1i*fk*(0:Nk-1)'/fs);
Dimitrios@0 108 atomOffset = first_center - ceil(Nk/2);
Dimitrios@0 109
Dimitrios@0 110 for i = 1:winNr
Dimitrios@0 111 shift = atomOffset + ((i-1) * atomHOP);
Dimitrios@0 112 tempKernel(1+shift:Nk+shift) = tempKernelBin;
Dimitrios@0 113 atomInd = atomInd+1;
Dimitrios@0 114 specKernel= fft(tempKernel);
Dimitrios@0 115 specKernel(abs(specKernel)<=thresh)= 0;
Dimitrios@0 116 sparKernel= sparse([sparKernel; specKernel]);
Dimitrios@0 117 tempKernel = zeros(1,FFTLen); %reset window
Dimitrios@0 118 end
Dimitrios@0 119 end
Dimitrios@0 120 sparKernel = (sparKernel.')/FFTLen;
Dimitrios@0 121
Dimitrios@0 122 %% Normalize the magnitudes of the atoms
Dimitrios@0 123 [ignore,wx1]=max(sparKernel(:,1));
Dimitrios@0 124 [ignore,wx2]=max(sparKernel(:,end));
Dimitrios@0 125 wK=sparKernel(wx1:wx2,:);
Dimitrios@0 126 wK = diag(wK * wK');
Dimitrios@0 127 wK = wK(round(1/q)+1:(end-round(1/q)-2));
Dimitrios@0 128 weight = 1./mean(abs(wK));
Dimitrios@0 129 weight = weight.*(fftHOP/FFTLen);
Dimitrios@0 130 weight = sqrt(weight); %sqrt because the same weight is applied in icqt again
Dimitrios@0 131 sparKernel = weight.*sparKernel;
Dimitrios@0 132
Dimitrios@0 133 %% return
Dimitrios@0 134 cqtKernel = struct('fKernel',sparKernel,'fftLEN',FFTLen,'fftHOP',fftHOP,'fftOverlap',fftOLP,'perfRast',perfRast,...
Dimitrios@0 135 'bins',bins,'firstcenter',first_center,'atomHOP',atomHOP,'atomNr',winNr,'Nk_max',Nk_max,'Q',Q,'fmin',fmin);