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