Skip to content

Commit

Permalink
Merge pull request #21 from r9y9/mfcc
Browse files Browse the repository at this point in the history
Add MFCC and tests
  • Loading branch information
r9y9 committed Sep 11, 2015
2 parents 7e83b99 + 19f44a2 commit d280fc3
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 0 deletions.
10 changes: 10 additions & 0 deletions pysptk/sptk.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ cdef enum Window:
TRAPEZOID = 4
RECTANGULAR = 5

cdef enum Boolean:
FA = 0
TR = 1

cdef extern from "../lib/SPTK/include/SPTK.h":

# Library routines
Expand Down Expand Up @@ -48,6 +52,12 @@ cdef extern from "../lib/SPTK/include/SPTK.h":
int _lpc "lpc"(double *x, const int flng, double *a, const int m, const double f)


# MFCC
void _mfcc "mfcc"(double *in_mfcc, double *mc, const double sampleFreq,
const double alpha, const double eps, const int wlng,
const int flng, const int m, const int n, const int ceplift,
const Boolean dftmode, const Boolean usehamming)

# LPC, LSP and PARCOR conversions
void _lpc2c "lpc2c"(double *a, int m1, double *c, const int m2)
int _lpc2lsp "lpc2lsp"(double *lpc, double *lsp, const int order, const int numsp,
Expand Down
114 changes: 114 additions & 0 deletions pysptk/sptk.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ Mel-generalized cepstrum analysis
fftcep
lpc
MFCC
----
.. autosummary::
:toctree: generated/
mfcc
LPC, LSP and PARCOR conversions
-------------------------------
.. autosummary::
Expand Down Expand Up @@ -951,6 +958,113 @@ def lpc(np.ndarray[np.float64_t, ndim=1, mode="c"] windowed not None,
return a


### MFCC ###

def mfcc(np.ndarray[np.float64_t, ndim=1, mode="c"] x not None,
order=14, fs=16000, alpha=0.97, eps=1.0, window_len=None,
frame_len=None, num_filterbanks=20, cepslift=22, use_dft=False,
use_hamming=False, czero=False, power=False):
"""MFCC
Parameters
----------
x : array
A input signal
order : int
Order of MFCC. Default is 14.
fs : int
Sampling frequency. Default is 160000.
alpha : float
Pre-emphasis coefficient. Default is 0.97.
eps : float
Flooring value for calculating ``log(x)`` in filterbank analysis.
Default is 1.0.
window_len : int
Window lenght. Default is ``len(x)``.
frame_len : int
Frame length. Default is ``len(x)``.
num_filterbanks : int
Number of mel-filter banks.
cepslift : int
Liftering coefficient. Default is 22.
use_dft : bool
Use DFT (not FFT) or not.
use_hamming : bool
Use hamming window or not.
czero : bool
If True, ``mfcc`` returns 0-th coefficient as well. Default is False.
power : bool
If True, ``mfcc`` returns power coefficient as well. Default is False.
Returns
-------
cc : array
MFCC vector, which is ordered as:
mfcc[0], mfcc[1], mfcc[2], ... mfcc[order-1], c0, Power.
Note that c0 and Power are optional.
Shape of ``cc`` is:
- ``order`` by default.
- ``orde + 1`` if ``czero`` or ``power`` is set to True.
- ``order + 2`` if both ``czero`` and ``power`` is set to True.
Raises
------
ValueError
if ``num_filterbanks`` is less than or equal to ``order``
See Also
--------
pysptk.sptk.gcep
pysptk.sptk.mcep
pysptk.sptk.mgcep
"""

if not (num_filterbanks > order):
raise ValueError("Number of filterbanks must be greater than order of MFCC")

if window_len is None:
window_len = len(x)
if frame_len is None:
frame_len = len(x)

cdef np.ndarray[np.float64_t, ndim=1, mode="c"] cc
cc = np.zeros(order + 2)

cdef Boolean _dft_mode = TR if use_dft else FA
cdef Boolean _use_hamming = TR if use_hamming else FA

# after ccall we get
# mfcc[0], mfcc[1], mfcc[2], ... mfcc[m-1], c0, Power
_mfcc(&x[0], &cc[0], fs, alpha, eps, window_len, frame_len, order+1,
num_filterbanks, cepslift,_dft_mode, _use_hamming)

if (not czero) and power:
cc[-2] = cc[-1]
if not power:
cc = cc[:-1]
if not czero:
cc = cc[:-1]

return cc


### LPC, LSP and PARCOR conversions ###

def lpc2c(np.ndarray[np.float64_t, ndim=1, mode="c"] lpc not None,
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from glob import glob
from os.path import join


min_cython_ver = '0.19.0'
try:
import Cython
Expand Down
48 changes: 48 additions & 0 deletions tests/test_mfcc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# coding: utf-8

import numpy as np
import pysptk
from nose.tools import raises


def test_mfcc_options():
np.random.seed(98765)
dummy_input = np.random.rand(512)

# with c0
cc = pysptk.mfcc(dummy_input, 12, czero=True)
assert len(cc) == 13

# wth c0 + power
cc = pysptk.mfcc(dummy_input, 12, czero=True, power=True)
assert len(cc) == 14

# with power
cc = pysptk.mfcc(dummy_input, 12, power=True)
assert len(cc) == 13


def test_mfcc_num_filterbanks():
def __test(n):
np.random.seed(98765)
dummy_input = np.random.rand(512)
cc = pysptk.mfcc(dummy_input, 20, num_filterbanks=n)
assert np.all(np.isfinite(cc))

for n in [21, 23, 25]:
yield __test, n

for n in [19, 20]:
yield raises(ValueError)(__test), n


def test_mfcc():
def __test(length, order):
np.random.seed(98765)
dummy_input = np.random.rand(length)
cc = pysptk.mfcc(dummy_input, order, czero=True, power=True)
assert np.all(np.isfinite(cc))

for length in [256, 512, 1024, 2048, 4096]:
for order in [12, 14, 16, 18]:
yield __test, length, order

0 comments on commit d280fc3

Please sign in to comment.