annotate mirex2012-matlab/genCQTkernel.m @ 116:91bb029a847a timing

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