annotate mirex2012-matlab/cqt.m @ 135:8db5e4ab56ce

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