Module: Mfcc
- Defined in:
- lib/mfcc.rb,
lib/mfcc/dct.rb,
lib/mfcc/dft.rb,
lib/mfcc/mel.rb,
lib/mfcc/frame.rb,
lib/mfcc/hamming.rb,
lib/mfcc/version.rb,
lib/mfcc/compressor.rb,
lib/mfcc/preemphasis.rb
Overview
MFCCs are commonly derived as follows:
-
Take the Fourier transform of (a windowed excerpt of) a signal.
-
Map the powers of the spectrum obtained above onto the mel scale, using triangular overlapping windows.
-
Take the logs of the powers at each of the mel frequencies.
-
Take the discrete cosine transform of the list of mel log powers, as if it were a signal.
-
The MFCCs are the amplitudes of the resulting spectrum.
(en.wikipedia.org/wiki/Mel-frequency_cepstrum)
Defined Under Namespace
Modules: Compressor, Dct, Dft, Frame, Hamming, Mel, Preemphasis
Classes: Calculator, FilterBanks
Constant Summary
collapse
- VERSION =
'0.0.1'
- LOG10_ERROR_VALUE =
-0.00000001
Class Method Summary
collapse
-
.compress(data) ⇒ Object
-
.dct(data, order = 13, orthogonalize = true) ⇒ Object
-
.dct_matrix(n, m) ⇒ Object
-
.dft(data) ⇒ Object
-
.frame(data, size, step) ⇒ Object
-
.h(alpha, beta, size, i) ⇒ Object
-
.hamming(data, alpha = 0.46) ⇒ Object
-
.magnitude(data) ⇒ Object
-
.mel(data, filter_banks) ⇒ Object
-
.plus_imaginary(data) ⇒ Object
-
.preemphasis(data, emph = 0.97) ⇒ Object
Class Method Details
.compress(data) ⇒ Object
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# File 'lib/mfcc/compressor.rb', line 10
def self.compress(data)
return to_enum(:compress, data) { data.size } unless block_given?
data.each do |d|
v = if d == 0
LOG10_ERROR_VALUE
else
Math.log10(d)
end
yield v
end
end
|
.dct(data, order = 13, orthogonalize = true) ⇒ Object
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# File 'lib/mfcc/dct.rb', line 10
def self.dct(data, order = 13, orthogonalize = true)
length = data.size
scales = if orthogonalize
[Math.sqrt(1.0 / (4 * length)), Math.sqrt(1.0 / (2 * length))]
else
[1, 1]
end
dct_matrix(order, length).each_with_index.map do |row, index|
scale = index == 0 ? scales[0] : scales[1]
scale * row.zip(data).inject(0) { |memo, (a, b)| memo + (2 * a * b) }
end
end
|
.dct_matrix(n, m) ⇒ Object
25
26
27
28
29
30
31
32
|
# File 'lib/mfcc/dct.rb', line 25
def self.dct_matrix(n, m)
n.times.map do |i|
freq = (Math::PI * i) / m
m.times.map do |j|
Math.cos(freq * (j + 0.5))
end
end
end
|
.dft(data) ⇒ Object
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
# File 'lib/mfcc/dft.rb', line 10
def self.dft(data)
return to_enum(:dft, data) { data.size } unless block_given?
n = data.size
data = plus_imaginary(data)
data.each_with_index do |_, k|
sumreal = 0
sumimag = 0
data.each_with_index do |d, t|
angle = 2 * Math::PI * t * k / n
sumreal += d.real * Math.cos(angle) + d.imaginary * Math.sin(angle)
sumimag += -1 * d.real * Math.sin(angle) + d.imaginary * Math.cos(angle)
end
yield Complex(sumreal, sumimag)
end
end
|
.frame(data, size, step) ⇒ Object
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
|
# File 'lib/mfcc/frame.rb', line 8
def self.frame(data, size, step)
return to_enum(:frame, data, size, step) unless block_given?
buffer = []
data.each do |d|
buffer.push(d)
if buffer.size == size
yield buffer
buffer = buffer.slice(step..buffer.length)
end
end
length = buffer.length
(length / step.to_f).ceil.times do
buffer.fill(0, buffer.size...size)
yield buffer
buffer = buffer.slice(step..buffer.length)
end
end
|
.h(alpha, beta, size, i) ⇒ Object
19
20
21
|
# File 'lib/mfcc/hamming.rb', line 19
def self.h(alpha, beta, size, i)
alpha - beta * Math.cos(2 * Math::PI * i / (size - 1))
end
|
.hamming(data, alpha = 0.46) ⇒ Object
8
9
10
11
12
13
14
15
16
17
|
# File 'lib/mfcc/hamming.rb', line 8
def self.hamming(data, alpha = 0.46)
return to_enum(:hamming, data, alpha) { data.size } unless block_given?
beta = 1 - alpha
length = data.size
data.each_with_index do |d, i|
yield d * h(alpha, beta, length, i)
end
end
|
.magnitude(data) ⇒ Object
45
46
47
48
49
50
51
|
# File 'lib/mfcc/dft.rb', line 45
def self.magnitude(data)
return to_enum(:magnitude, data) { data.size } unless block_given?
data.each do |d|
yield d.respond_to?(:magnitude) ? d.magnitude : d
end
end
|
.mel(data, filter_banks) ⇒ Object
12
13
14
|
# File 'lib/mfcc/mel.rb', line 12
def self.mel(data, filter_banks)
filter_banks.process(data)
end
|
.plus_imaginary(data) ⇒ Object
32
33
34
35
36
37
38
39
40
41
42
43
|
# File 'lib/mfcc/dft.rb', line 32
def self.plus_imaginary(data)
return to_enum(:plus_imaginary, data) { data.size } unless block_given?
data.each do |d|
yield case d
when Complex
d
else
Complex(d, 0)
end
end
end
|
.preemphasis(data, emph = 0.97) ⇒ Object
8
9
10
11
12
13
14
15
16
17
18
19
|
# File 'lib/mfcc/preemphasis.rb', line 8
def self.preemphasis(data, emph = 0.97)
return data if emph == 0
return to_enum(:preemphasis, data, emph) { |d, _| d.size || Float::INFINITY } unless block_given?
prev = 0
data.each do |y|
yield (y - emph * prev)
prev = y
end
end
|