annotate toolboxes/MIRtoolbox1.3.2/AuditoryToolbox/mfcc.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
rev   line source
wolffd@0 1 % mfcc - Mel frequency cepstrum coefficient analysis.
wolffd@0 2 % [ceps,freqresp,fb,fbrecon,freqrecon] = ...
wolffd@0 3 % mfcc(input, samplingRate, [frameRate])
wolffd@0 4 % Find the cepstral coefficients (ceps) corresponding to the
wolffd@0 5 % input. Four other quantities are optionally returned that
wolffd@0 6 % represent:
wolffd@0 7 % the detailed fft magnitude (freqresp) used in MFCC calculation,
wolffd@0 8 % the mel-scale filter bank output (fb)
wolffd@0 9 % the filter bank output by inverting the cepstrals with a cosine
wolffd@0 10 % transform (fbrecon),
wolffd@0 11 % the smooth frequency response by interpolating the fb reconstruction
wolffd@0 12 % (freqrecon)
wolffd@0 13 % -- Malcolm Slaney, August 1993
wolffd@0 14 % Modified a bit to make testing an algorithm easier... 4/15/94
wolffd@0 15 % Fixed Cosine Transform (indices of cos() were swapped) - 5/26/95
wolffd@0 16 % Added optional frameRate argument - 6/8/95
wolffd@0 17 % Added proper filterbank reconstruction using inverse DCT - 10/27/95
wolffd@0 18 % Added filterbank inversion to reconstruct spectrum - 11/1/95
wolffd@0 19
wolffd@0 20 % (c) 1998 Interval Research Corporation
wolffd@0 21
wolffd@0 22 function [ceps,freqresp,fb,fbrecon,freqrecon] = ...
wolffd@0 23 mfcc(input, samplingRate, frameRate)
wolffd@0 24 global mfccDCTMatrix mfccFilterWeights
wolffd@0 25
wolffd@0 26 [r c] = size(input);
wolffd@0 27 if (r > c)
wolffd@0 28 input=input';
wolffd@0 29 end
wolffd@0 30
wolffd@0 31 % Filter bank parameters
wolffd@0 32 lowestFrequency = 133.3333;
wolffd@0 33 linearFilters = 13;
wolffd@0 34 linearSpacing = 66.66666666;
wolffd@0 35 logFilters = 27;
wolffd@0 36 logSpacing = 1.0711703;
wolffd@0 37 fftSize = 512;
wolffd@0 38 cepstralCoefficients = 13;
wolffd@0 39 windowSize = 400;
wolffd@0 40 windowSize = 256; % Standard says 400, but 256 makes more sense
wolffd@0 41 % Really should be a function of the sample
wolffd@0 42 % rate (and the lowestFrequency) and the
wolffd@0 43 % frame rate.
wolffd@0 44 if (nargin < 2) samplingRate = 16000; end;
wolffd@0 45 if (nargin < 3) frameRate = 100; end;
wolffd@0 46
wolffd@0 47 % Keep this around for later....
wolffd@0 48 totalFilters = linearFilters + logFilters;
wolffd@0 49
wolffd@0 50 % Now figure the band edges. Interesting frequencies are spaced
wolffd@0 51 % by linearSpacing for a while, then go logarithmic. First figure
wolffd@0 52 % all the interesting frequencies. Lower, center, and upper band
wolffd@0 53 % edges are all consequtive interesting frequencies.
wolffd@0 54
wolffd@0 55 freqs = lowestFrequency + (0:linearFilters-1)*linearSpacing;
wolffd@0 56 freqs(linearFilters+1:totalFilters+2) = ...
wolffd@0 57 freqs(linearFilters) * logSpacing.^(1:logFilters+2);
wolffd@0 58
wolffd@0 59 lower = freqs(1:totalFilters);
wolffd@0 60 center = freqs(2:totalFilters+1);
wolffd@0 61 upper = freqs(3:totalFilters+2);
wolffd@0 62
wolffd@0 63 % We now want to combine FFT bins so that each filter has unit
wolffd@0 64 % weight, assuming a triangular weighting function. First figure
wolffd@0 65 % out the height of the triangle, then we can figure out each
wolffd@0 66 % frequencies contribution
wolffd@0 67 mfccFilterWeights = zeros(totalFilters,fftSize);
wolffd@0 68 triangleHeight = 2./(upper-lower);
wolffd@0 69 fftFreqs = (0:fftSize-1)/fftSize*samplingRate;
wolffd@0 70
wolffd@0 71 for chan=1:totalFilters
wolffd@0 72 mfccFilterWeights(chan,:) = ...
wolffd@0 73 (fftFreqs > lower(chan) & fftFreqs <= center(chan)).* ...
wolffd@0 74 triangleHeight(chan).*(fftFreqs-lower(chan))/(center(chan)-lower(chan)) + ...
wolffd@0 75 (fftFreqs > center(chan) & fftFreqs < upper(chan)).* ...
wolffd@0 76 triangleHeight(chan).*(upper(chan)-fftFreqs)/(upper(chan)-center(chan));
wolffd@0 77 end
wolffd@0 78 %semilogx(fftFreqs,mfccFilterWeights')
wolffd@0 79 %axis([lower(1) upper(totalFilters) 0 max(max(mfccFilterWeights))])
wolffd@0 80
wolffd@0 81 hamWindow = 0.54 - 0.46*cos(2*pi*(0:windowSize-1)/windowSize);
wolffd@0 82
wolffd@0 83 if 0 % Window it like ComplexSpectrum
wolffd@0 84 windowStep = samplingRate/frameRate;
wolffd@0 85 a = .54;
wolffd@0 86 b = -.46;
wolffd@0 87 wr = sqrt(windowStep/windowSize);
wolffd@0 88 phi = pi/windowSize;
wolffd@0 89 hamWindow = 2*wr/sqrt(4*a*a+2*b*b)* ...
wolffd@0 90 (a + b*cos(2*pi*(0:windowSize-1)/windowSize + phi));
wolffd@0 91 end
wolffd@0 92
wolffd@0 93 % Figure out Discrete Cosine Transform. We want a matrix
wolffd@0 94 % dct(i,j) which is totalFilters x cepstralCoefficients in size.
wolffd@0 95 % The i,j component is given by
wolffd@0 96 % cos( i * (j+0.5)/totalFilters pi )
wolffd@0 97 % where we have assumed that i and j start at 0.
wolffd@0 98 mfccDCTMatrix = 1/sqrt(totalFilters/2)*cos((0:(cepstralCoefficients-1))' * ...
wolffd@0 99 (2*(0:(totalFilters-1))+1) * pi/2/totalFilters);
wolffd@0 100 mfccDCTMatrix(1,:) = mfccDCTMatrix(1,:) * sqrt(2)/2;
wolffd@0 101
wolffd@0 102 %imagesc(mfccDCTMatrix);
wolffd@0 103
wolffd@0 104 % Filter the input with the preemphasis filter. Also figure how
wolffd@0 105 % many columns of data we will end up with.
wolffd@0 106 if 1
wolffd@0 107 preEmphasized = filter([1 -.97], 1, input);
wolffd@0 108 else
wolffd@0 109 preEmphasized = input;
wolffd@0 110 end
wolffd@0 111 windowStep = samplingRate/frameRate;
wolffd@0 112 cols = fix((length(input)-windowSize)/windowStep);
wolffd@0 113
wolffd@0 114 % Allocate all the space we need for the output arrays.
wolffd@0 115 ceps = zeros(cepstralCoefficients, cols);
wolffd@0 116 if (nargout > 1) freqresp = zeros(fftSize/2, cols); end;
wolffd@0 117 if (nargout > 2) fb = zeros(totalFilters, cols); end;
wolffd@0 118
wolffd@0 119 % Invert the filter bank center frequencies. For each FFT bin
wolffd@0 120 % we want to know the exact position in the filter bank to find
wolffd@0 121 % the original frequency response. The next block of code finds the
wolffd@0 122 % integer and fractional sampling positions.
wolffd@0 123 if (nargout > 4)
wolffd@0 124 fr = (0:(fftSize/2-1))'/(fftSize/2)*samplingRate/2;
wolffd@0 125 j = 1;
wolffd@0 126 for i=1:(fftSize/2)
wolffd@0 127 if fr(i) > center(j+1)
wolffd@0 128 j = j + 1;
wolffd@0 129 end
wolffd@0 130 if j > totalFilters-1
wolffd@0 131 j = totalFilters-1;
wolffd@0 132 end
wolffd@0 133 fr(i) = min(totalFilters-.0001, ...
wolffd@0 134 max(1,j + (fr(i)-center(j))/(center(j+1)-center(j))));
wolffd@0 135 end
wolffd@0 136 fri = fix(fr);
wolffd@0 137 frac = fr - fri;
wolffd@0 138
wolffd@0 139 freqrecon = zeros(fftSize/2, cols);
wolffd@0 140 end
wolffd@0 141
wolffd@0 142 % Ok, now let's do the processing. For each chunk of data:
wolffd@0 143 % * Window the data with a hamming window,
wolffd@0 144 % * Shift it into FFT order,
wolffd@0 145 % * Find the magnitude of the fft,
wolffd@0 146 % * Convert the fft data into filter bank outputs,
wolffd@0 147 % * Find the log base 10,
wolffd@0 148 % * Find the cosine transform to reduce dimensionality.
wolffd@0 149 for start=0:cols-1
wolffd@0 150 first = start*windowStep + 1;
wolffd@0 151 last = first + windowSize-1;
wolffd@0 152 fftData = zeros(1,fftSize);
wolffd@0 153 fftData(1:windowSize) = preEmphasized(first:last).*hamWindow;
wolffd@0 154 fftMag = abs(fft(fftData));
wolffd@0 155 earMag = log10(mfccFilterWeights * fftMag');
wolffd@0 156
wolffd@0 157 ceps(:,start+1) = mfccDCTMatrix * earMag;
wolffd@0 158 if (nargout > 1) freqresp(:,start+1) = fftMag(1:fftSize/2)'; end;
wolffd@0 159 if (nargout > 2) fb(:,start+1) = earMag; end
wolffd@0 160 if (nargout > 3)
wolffd@0 161 fbrecon(:,start+1) = ...
wolffd@0 162 mfccDCTMatrix(1:cepstralCoefficients,:)' * ...
wolffd@0 163 ceps(:,start+1);
wolffd@0 164 end
wolffd@0 165 if (nargout > 4)
wolffd@0 166 f10 = 10.^fbrecon(:,start+1);
wolffd@0 167 freqrecon(:,start+1) = samplingRate/fftSize * ...
wolffd@0 168 (f10(fri).*(1-frac) + f10(fri+1).*frac);
wolffd@0 169 end
wolffd@0 170 end
wolffd@0 171
wolffd@0 172 % OK, just to check things, let's also reconstruct the original FB
wolffd@0 173 % output. We do this by multiplying the cepstral data by the transpose
wolffd@0 174 % of the original DCT matrix. This all works because we were careful to
wolffd@0 175 % scale the DCT matrix so it was orthonormal.
wolffd@0 176 if 1 & (nargout > 3)
wolffd@0 177 fbrecon = mfccDCTMatrix(1:cepstralCoefficients,:)' * ceps;
wolffd@0 178 % imagesc(mt(:,1:cepstralCoefficients)*mfccDCTMatrix);
wolffd@0 179 end;
wolffd@0 180
wolffd@0 181