-
Notifications
You must be signed in to change notification settings - Fork 11
/
libmfcc.c
165 lines (141 loc) · 4.59 KB
/
libmfcc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
* libmfcc.c - Code implementation for libMFCC
* Copyright (c) 2010 Jeremy Sawruk
*
* This code is released under the MIT License.
* For conditions of distribution and use, see the license in LICENSE
*/
#include <math.h>
#include "libmfcc.h"
/*
* Computes the specified (mth) MFCC
*
* spectralData - array of doubles containing the results of FFT computation. This data is already assumed to be purely real
* samplingRate - the rate that the original time-series data was sampled at (i.e 44100)
* NumFilters - the number of filters to use in the computation. Recommended value = 48
* binSize - the size of the spectralData array, usually a power of 2
* m - The mth MFCC coefficient to compute
*
*/
double GetCoefficient(double* spectralData, unsigned int samplingRate, unsigned int NumFilters, unsigned int binSize, unsigned int m)
{
double result = 0.0f;
double outerSum = 0.0f;
double innerSum = 0.0f;
unsigned int k, l;
// 0 <= m < L
if(m >= NumFilters)
{
// This represents an error condition - the specified coefficient is greater than or equal to the number of filters. The behavior in this case is undefined.
return 0.0f;
}
result = NormalizationFactor(NumFilters, m);
for(l = 1; l <= NumFilters; l++)
{
// Compute inner sum
innerSum = 0.0f;
for(k = 0; k < binSize - 1; k++)
{
innerSum += fabs(spectralData[k] * GetFilterParameter(samplingRate, binSize, k, l));
}
if(innerSum > 0.0f)
{
innerSum = log(innerSum); // The log of 0 is undefined, so don't use it
}
innerSum = innerSum * cos(((m * PI) / NumFilters) * (l - 0.5f));
outerSum += innerSum;
}
result *= outerSum;
return result;
}
/*
* Computes the Normalization Factor (Equation 6)
* Used for internal computation only - not to be called directly
*/
double NormalizationFactor(int NumFilters, int m)
{
double normalizationFactor = 0.0f;
if(m == 0)
{
normalizationFactor = sqrt(1.0f / NumFilters);
}
else
{
normalizationFactor = sqrt(2.0f / NumFilters);
}
return normalizationFactor;
}
/*
* Compute the filter parameter for the specified frequency and filter bands (Eq. 2)
* Used for internal computation only - not the be called directly
*/
double GetFilterParameter(unsigned int samplingRate, unsigned int binSize, unsigned int frequencyBand, unsigned int filterBand)
{
double filterParameter = 0.0f;
double boundary = (frequencyBand * samplingRate) / binSize; // k * Fs / N
double prevCenterFrequency = GetCenterFrequency(filterBand - 1); // fc(l - 1) etc.
double thisCenterFrequency = GetCenterFrequency(filterBand);
double nextCenterFrequency = GetCenterFrequency(filterBand + 1);
if(boundary >= 0 && boundary < prevCenterFrequency)
{
filterParameter = 0.0f;
}
else if(boundary >= prevCenterFrequency && boundary < thisCenterFrequency)
{
filterParameter = (boundary - prevCenterFrequency) / (thisCenterFrequency - prevCenterFrequency);
filterParameter *= GetMagnitudeFactor(filterBand);
}
else if(boundary >= thisCenterFrequency && boundary < nextCenterFrequency)
{
filterParameter = (boundary - nextCenterFrequency) / (thisCenterFrequency - nextCenterFrequency);
filterParameter *= GetMagnitudeFactor(filterBand);
}
else if(boundary >= nextCenterFrequency && boundary < samplingRate)
{
filterParameter = 0.0f;
}
return filterParameter;
}
/*
* Compute the band-dependent magnitude factor for the given filter band (Eq. 3)
* Used for internal computation only - not the be called directly
*/
double GetMagnitudeFactor(unsigned int filterBand)
{
double magnitudeFactor = 0.0f;
if(filterBand >= 1 && filterBand <= 14)
{
magnitudeFactor = 0.015;
}
else if(filterBand >= 15 && filterBand <= 48)
{
magnitudeFactor = 2.0f / (GetCenterFrequency(filterBand + 1) - GetCenterFrequency(filterBand -1));
}
return magnitudeFactor;
}
/*
* Compute the center frequency (fc) of the specified filter band (l) (Eq. 4)
* This where the mel-frequency scaling occurs. Filters are specified so that their
* center frequencies are equally spaced on the mel scale
* Used for internal computation only - not the be called directly
*/
double GetCenterFrequency(unsigned int filterBand)
{
double centerFrequency = 0.0f;
double exponent;
if(filterBand == 0)
{
centerFrequency = 0;
}
else if(filterBand >= 1 && filterBand <= 14)
{
centerFrequency = (200.0f * filterBand) / 3.0f;
}
else
{
exponent = filterBand - 14.0f;
centerFrequency = pow(1.0711703, exponent);
centerFrequency *= 1073.4;
}
return centerFrequency;
}