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);
|