-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathMFCC.py
More file actions
107 lines (90 loc) · 3.96 KB
/
Copy pathMFCC.py
File metadata and controls
107 lines (90 loc) · 3.96 KB
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
'''MFCC.py
Calculation of MFCC coefficients from frequency-domain data
Adapted from the Vampy example plugin "PyMFCC" by Gyorgy Fazekas
http://code.soundsoftware.ac.uk/projects/vampy/repository/entry/Example%20VamPy%20plugins/PyMFCC.py
Centre for Digital Music, Queen Mary University of London.
Copyright (C) 2009 Gyorgy Fazekas, QMUL.
'''
import sys,numpy
from numpy import abs,log,exp,floor,sum,sqrt,cos,hstack
from numpy.fft import *
class melScaling(object):
def __init__(self,sampleRate,inputSize,numBands,minHz = 0,maxHz = None):
'''Initialise frequency warping and DCT matrix.
Parameters:
sampleRate: audio sample rate
inputSize: length of magnitude spectrum (half of FFT size assumed)
numBands: number of mel Bands (MFCCs)
minHz: lower bound of warping (default = DC)
maxHz: higher bound of warping (default = Nyquist frequency)
'''
self.sampleRate = sampleRate
self.NqHz = sampleRate / 2.0
self.minHz = minHz
if maxHz is None : maxHz = self.NqHz
self.maxHz = maxHz
self.inputSize = inputSize
self.numBands = numBands
self.valid = False
self.updated = False
def update(self):
# make sure this will run only once
# if called from a vamp process
if self.updated: return self.valid
self.updated = True
self.valid = False
print('Updating parameters and recalculating filters: ')
print('Nyquist: ',self.NqHz)
if self.maxHz > self.NqHz :
raise Exception('Maximum frequency must be smaller than the Nyquist frequency')
self.maxMel = 1000*log(1+self.maxHz/700.0)/log(1+1000.0/700.0)
self.minMel = 1000*log(1+self.minHz/700.0)/log(1+1000.0/700.0)
print('minHz:%s\nmaxHz:%s\nminMel:%s\nmaxMel:%s\n' \
%(self.minHz,self.maxHz,self.minMel,self.maxMel))
self.filterMatrix = self.getFilterMatrix(self.inputSize,self.numBands)
self.DCTMatrix = self.getDCTMatrix(self.numBands)
self.valid = True
return self.valid
def getFilterCentres(self,inputSize,numBands):
'''Calculate Mel filter centres around FFT bins.
This function calculates two extra bands at the edges for
finding the starting and end point of the first and last
actual filters.'''
centresMel = numpy.array(range(numBands+2)) * (self.maxMel-self.minMel)/(numBands+1) + self.minMel
centresBin = numpy.floor(0.5 + 700.0*inputSize*(exp(centresMel*log(1+1000.0/700.0)/1000.0)-1)/self.NqHz)
return numpy.array(centresBin,int)
def getFilterMatrix(self,inputSize,numBands):
'''Compose the Mel scaling matrix.'''
filterMatrix = numpy.zeros((numBands,inputSize))
self.filterCentres = self.getFilterCentres(inputSize,numBands)
for i in range(numBands) :
start,centre,end = self.filterCentres[i:i+3]
self.setFilter(filterMatrix[i],start,centre,end)
return filterMatrix.transpose()
def setFilter(self,filt,filterStart,filterCentre,filterEnd):
'''Calculate a single Mel filter.'''
k1 = numpy.float32(filterCentre-filterStart)
k2 = numpy.float32(filterEnd-filterCentre)
up = (numpy.array(range(filterStart,filterCentre))-filterStart)/k1
dn = (filterEnd-numpy.array(range(filterCentre,filterEnd)))/k2
filt[filterStart:filterCentre] = up
filt[filterCentre:filterEnd] = dn
def warpSpectrum(self,magnitudeSpectrum):
'''Compute the Mel scaled spectrum.'''
return numpy.dot(magnitudeSpectrum,self.filterMatrix)
def getDCTMatrix(self,size):
'''Calculate the square DCT transform matrix. Results are
equivalent to Matlab dctmtx(n) with 64 bit precision.'''
DCTmx = numpy.array(range(size),numpy.float64).repeat(size).reshape(size,size)
DCTmxT = numpy.pi * (DCTmx.transpose()+0.5) / size
DCTmxT = (1.0/sqrt( size / 2.0)) * cos(DCTmx * DCTmxT)
DCTmxT[0] = DCTmxT[0] * (sqrt(2.0)/2.0)
return DCTmxT
def dct(self,data_matrix):
'''Compute DCT of input matrix.'''
return numpy.dot(self.DCTMatrix,data_matrix)
def getMFCCs(self,warpedSpectrum,cn=True):
'''Compute MFCC coefficients from Mel warped magnitude spectrum.'''
mfccs=self.dct(numpy.log(numpy.clip(warpedSpectrum, 1e-9, numpy.inf)))
if cn is False : mfccs[0] = 0.0
return mfccs