Dimitrios@0
|
1 function Xcqt = cqt(x,fmin,fmax,bins,fs,varargin)
|
Dimitrios@0
|
2 %Xcqt = cqt(x,fmin,fmax,bins,fs,varargin) calculates the constant-Q transform of the input signal x.
|
Dimitrios@0
|
3 %
|
Dimitrios@0
|
4 %INPUT:
|
Dimitrios@0
|
5 % fmin ... lowest frequency of interest
|
Dimitrios@0
|
6 % fmax ... highest frequency of interest
|
Dimitrios@0
|
7 % bins ... frequency bins per octave
|
Dimitrios@0
|
8 % fs ... sampling rate
|
Dimitrios@0
|
9 %
|
Dimitrios@0
|
10 % optional input parameters (parameter name/value pairs):
|
Dimitrios@0
|
11 %
|
Dimitrios@0
|
12 % 'atomHopFactor' ... overlap of temporal atoms in percent. Default: 0.25.
|
Dimitrios@0
|
13 %
|
Dimitrios@0
|
14 % 'q' ... the maximum value for optimal reconstruction is q=1.
|
Dimitrios@0
|
15 % For values smaller than 1 the bandwidths of the spectral
|
Dimitrios@0
|
16 % atoms (filter) are increased retaining their center
|
Dimitrios@0
|
17 % frequencies (frequency 'smearing', frequency domain redundancy
|
Dimitrios@0
|
18 % increases, time resolutin improves). Default: 1.
|
Dimitrios@0
|
19 % 'thresh' ... all values in the cqt kernel smaller than tresh are
|
Dimitrios@0
|
20 % rounded to zero. A high value for thresh yields a
|
Dimitrios@0
|
21 % very sparse kernel (fast) but introduces a bigger error.
|
Dimitrios@0
|
22 % The default value is chosen so that the error due to rounding is negligible.
|
Dimitrios@0
|
23 % 'kernel' ... if the cqt kernel structure has been precomputed
|
Dimitrios@0
|
24 % (using function 'genCQTkernel'), the computation of the kernel
|
Dimitrios@0
|
25 % will be by-passed below).
|
Dimitrios@0
|
26 % 'win' ... defines which window will be used for the CQT. Valid
|
Dimitrios@0
|
27 % values are: 'blackman','hann' and 'blackmanharris'. To
|
Dimitrios@0
|
28 % use the square root of each window use the prefix 'sqrt_'
|
Dimitrios@0
|
29 % (i.e. 'sqrt_blackman'). Default: 'sqrt_blackmanharris'
|
Dimitrios@0
|
30 % 'coeffB',
|
Dimitrios@0
|
31 % 'coeffA' ... Filter coefficients for the anti-aliasing filter, where
|
Dimitrios@0
|
32 % 'coeffB' is the numerator and 'coeffA' is the
|
Dimitrios@0
|
33 % denominator (listed in descending powers of z).
|
Dimitrios@0
|
34 %
|
Dimitrios@0
|
35 %OUTPUT:
|
Dimitrios@0
|
36 % Xcqt ... struct that comprises various fields:
|
Dimitrios@0
|
37 % spCQT: CQT coefficients in the form of a sparse matrix
|
Dimitrios@0
|
38 % (rasterized, not interpolated)
|
Dimitrios@0
|
39 % fKernel: spectral Kernel
|
Dimitrios@0
|
40 % fmin: frequency of the lowest bin
|
Dimitrios@0
|
41 % fmax: frequency of the hiqhest bin
|
Dimitrios@0
|
42 % octaveNr: number of octaves processed
|
Dimitrios@0
|
43 % bins: number of bins per octave
|
Dimitrios@0
|
44 % intParams: structure containing additional parameters for the inverse transform
|
Dimitrios@0
|
45 %
|
Dimitrios@0
|
46 %Christian Schörkhuber, Anssi Klapuri 2010-06
|
Dimitrios@0
|
47
|
Dimitrios@0
|
48 %% input checking
|
Dimitrios@0
|
49 if size(x,2) > 1 && size(x,1) > 1, error('cqt requires one-dimensional input!'); end;
|
Dimitrios@0
|
50 if size(x,2) > 1, x = x(:); end; %column vector
|
Dimitrios@0
|
51
|
Dimitrios@0
|
52 %% input parameters
|
Dimitrios@0
|
53 q = 1; %default value
|
Dimitrios@0
|
54 atomHopFactor = 0.25; %default value
|
Dimitrios@0
|
55 thresh = 0.0005; %default value
|
Dimitrios@0
|
56 winFlag = 'sqrt_blackmanharris';
|
Dimitrios@0
|
57
|
Dimitrios@0
|
58 for ain = 1:1:length(varargin)
|
Dimitrios@0
|
59 if strcmp(varargin{ain},'q'), q = varargin{ain+1}; end;
|
Dimitrios@0
|
60 if strcmp(varargin{ain},'atomHopFactor'), atomHopFactor = varargin{ain+1}; end;
|
Dimitrios@0
|
61 if strcmp(varargin{ain},'thresh'), thresh = varargin{ain+1}; end;
|
Dimitrios@0
|
62 if strcmp(varargin{ain},'kernel'), cqtKernel = varargin{ain+1}; end;
|
Dimitrios@0
|
63 if strcmp(varargin{ain},'win'), winFlag = varargin{ain+1}; end;
|
Dimitrios@0
|
64 if strcmp(varargin{ain},'coeffB'), B = varargin{ain+1}; end;
|
Dimitrios@0
|
65 if strcmp(varargin{ain},'coeffA'), A = varargin{ain+1}; end;
|
Dimitrios@0
|
66 end
|
Dimitrios@0
|
67
|
Dimitrios@0
|
68 %% define
|
Dimitrios@0
|
69 octaveNr = ceil(log2(fmax/fmin));
|
Dimitrios@0
|
70 xlen_init = length(x);
|
Dimitrios@0
|
71
|
Dimitrios@0
|
72 %% design lowpass filter
|
Dimitrios@0
|
73 if ~exist('B','var') || ~exist('A','var')
|
Dimitrios@0
|
74 LPorder = 6; %order of the anti-aliasing filter
|
Dimitrios@0
|
75 cutoff = 0.5;
|
Dimitrios@0
|
76 [B A] = butter(LPorder,cutoff,'low'); %design f_nyquist/2-lowpass filter
|
Dimitrios@0
|
77 end
|
Dimitrios@0
|
78
|
Dimitrios@0
|
79 %% design kernel for one octave
|
Dimitrios@0
|
80 if ~exist('cqtKernel','var')
|
Dimitrios@0
|
81 cqtKernel = genCQTkernel(fmax, bins,fs,'q',q,'atomHopFactor',atomHopFactor,'thresh',thresh,'win',winFlag);
|
Dimitrios@0
|
82 end
|
Dimitrios@0
|
83
|
Dimitrios@0
|
84 %% calculate CQT
|
Dimitrios@0
|
85 cellCQT = cell(1,octaveNr);
|
Dimitrios@0
|
86 maxBlock = cqtKernel.fftLEN * 2^(octaveNr-1); %largest FFT Block (virtual)
|
Dimitrios@0
|
87 suffixZeros = maxBlock;
|
Dimitrios@0
|
88 prefixZeros = maxBlock;
|
Dimitrios@0
|
89 x = [zeros(prefixZeros,1); x; zeros(suffixZeros,1)]; %zeropadding
|
Dimitrios@0
|
90 OVRLP = cqtKernel.fftLEN - cqtKernel.fftHOP;
|
Dimitrios@0
|
91 K = cqtKernel.fKernel'; %conjugate spectral kernel for cqt transformation
|
Dimitrios@0
|
92
|
Dimitrios@0
|
93 for i = 1:octaveNr
|
Dimitrios@0
|
94 xx = buffer(x,cqtKernel.fftLEN, OVRLP,'nodelay'); %generating FFT blocks
|
Dimitrios@0
|
95 XX = fft(xx); %applying fft to each column (each FFT frame)
|
Dimitrios@0
|
96 cellCQT{i} = K*XX; %calculating cqt coefficients for all FFT frames for this octave
|
Dimitrios@0
|
97
|
Dimitrios@0
|
98 if i~=octaveNr
|
Dimitrios@0
|
99 x = filtfilt(B,A,x); %anti aliasing filter
|
Dimitrios@0
|
100 x = x(1:2:end); %drop samplerate by 2
|
Dimitrios@0
|
101 end
|
Dimitrios@0
|
102 end
|
Dimitrios@0
|
103
|
Dimitrios@0
|
104 %% map to sparse matrix representation
|
Dimitrios@0
|
105 spCQT = cell2sparse(cellCQT,octaveNr,bins,cqtKernel.firstcenter,cqtKernel.atomHOP,cqtKernel.atomNr);
|
Dimitrios@0
|
106
|
Dimitrios@0
|
107 %% return
|
Dimitrios@0
|
108 intParam = struct('sufZeros',suffixZeros,'preZeros',prefixZeros,'xlen_init',xlen_init,'fftLEN',cqtKernel.fftLEN,'fftHOP',cqtKernel.fftHOP,...
|
Dimitrios@0
|
109 'q',q,'filtCoeffA',A,'filtCoeffB',B,'firstcenter',cqtKernel.firstcenter,'atomHOP',cqtKernel.atomHOP,...
|
Dimitrios@0
|
110 'atomNr',cqtKernel.atomNr,'Nk_max',cqtKernel.Nk_max,'Q',cqtKernel.Q,'rast',0);
|
Dimitrios@0
|
111
|
Dimitrios@0
|
112 Xcqt = struct('spCQT',spCQT,'fKernel',cqtKernel.fKernel,'fmax',fmax,'fmin',fmin*2^(1/bins),'octaveNr',octaveNr,'bins',cqtKernel.bins,'intParams',intParam);
|
Dimitrios@0
|
113
|
Dimitrios@0
|
114
|