avatar

Tutorial on PocketSphinx with Python 3.4


13-05-2015 14:05 by depado

Tutorial on PocketSphinx with Python 3.4

Disclaimer

This code is actually getting kind of old. I suspect some of the code samples won't work as expected. Please let me know in the comments if so ☺

Introduction

CMUSphinx is a great project that I wanted to try for a really long time. I'm getting tired of speech recognition libraries that just make calls to the Google API. That requires a constant use of an internet connection. We will use mainly two components of the CMUSphinx project : sphinxbase and pocketsphinx.

This tutorial will cover the following points :

  • Installation
    • Sphinxbase
    • Pocketsphinx
  • Installing a support for another language (french)
  • Python

We will work in a test directory, so just a create a new one and go in it.

$ mkdir sphinx_test
$ cd sphinx_test

Installation Part


Sphinxbase Installation

$ git clone https://github.com/cmusphinx/sphinxbase
$ cd sphinxbase
$ ./autogen.sh --prefix=/usr

Note that I set the prefix to /usr so that the library is installed in the same place all the other libs are. Otherwise it will install it in /usr/local/lib/python3.x/site-packages (where x is your python version) which isn't a problem if you set your PYTHONPATH environment variable accordingly.

"But but, why do you stop here ? Can't we just make and make install ?"

Answer : You can. Long answer : You can. But you'll soon notice that there are errors in the makefile concerning the documentation. Actually sphinx will be useable but your doc would be unuseable. I don't know about you, but I prefer when my system has all the docs I need to develop. Problem comes from dox2swig.py which needs to be executed using a 2.x version of Python. So we will just open the doc/Makefile file and replace the line that says PYTHON=/usr/bin/python to PYTHON=/usr/bin/python2. Now go on, you can run your make and make install. And no, it won't affect anything else than the document generation.

$ make
$ sudo make install

Pocketsphinx Installation

Hey remember what you just did in the above section ? Well just do the same for pocketsphinx. (Exactly the same, like... Really.)

$ git clone https://github.com/cmusphinx/pocketsphinx
$ cd pocketsphinx
$ ./autogen.sh --prefix=/usr

Modify doc/Makefile

$ make
$ sudo make install

French

You'll need to download the following files : french3g62K.lm.dmp frenchWords62K.dic lium_french_f0.tar.gz If you installed sphinxbase and pocketsphinx correctly, then you'll have a folder in /usr/share/pocketsphinx/model/ which already contains an english model.

$ cd /usr/share/pocketsphinx/model/
$ sudo mkdir fr_FR; cd fr_FR
$ sudo mv ~/Downloads/{french3g62K.lm.dmp,frenchWords62K.dic,lium_french_f0.tar.gz} .
$ sudo mkdir fr_FR
$ sudo tar xvf lium_french_f0.tar.gz fr_FR/

So you'll have the following files now :

├── french3g62K.lm.dmp
├── frenchWords62K.dic
└── fr_FR
    ├── feat.params
    ├── LICENSE
    ├── mdef
    ├── means
    ├── mixture_weights
    ├── noisedict
    ├── README
    ├── transition_matrices
    └── variances

1 directory, 12 files

Now your pocketsphinx installation supports the french language. Note that I put those files in that directory only for conveniance, so that all my models are in the same place. But you can totally put them wherever you want.


Python

Here is a script that I took and modified from Mattz69's blog. Here is the original article.

#!/usr/bin/env python

import os
import sys
from ctypes import *
from contextlib import contextmanager

import pyaudio
from pocketsphinx.pocketsphinx import *
from sphinxbase.sphinxbase import *

script_dir = os.path.dirname(os.path.realpath(__file__))
model_dir = "/usr/share/pocketsphinx/model/fr_FR/"

hmm = os.path.join(model_dir, "fr_FR")
lm = os.path.join(model_dir, "french3g62K.lm.dmp")
dic = os.path.join(model_dir, "frenchWords62K.dic")

sys.stderr = open(os.path.join(script_dir, "stderr.log"), "a")

ERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, c_char_p)


def py_error_handler(filename, line, function, err, fmt):
    pass
c_error_handler = ERROR_HANDLER_FUNC(py_error_handler)


@contextmanager
def noalsaerr():
    asound = cdll.LoadLibrary('libasound.so')
    asound.snd_lib_error_set_handler(c_error_handler)
    yield
    asound.snd_lib_error_set_handler(None)

config = Decoder.default_config()
config.set_string('-hmm', hmm)
config.set_string('-lm', lm)
config.set_string('-dict', dic)
config.set_string('-logfn', '/dev/null')
decoder = Decoder(config)

with noalsaerr():
    p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=1024)
stream.start_stream()
in_speech_bf = True
decoder.start_utt()
while True:
    buf = stream.read(1024)
    if buf:
        decoder.process_raw(buf, False, False)
        try:
            if decoder.hyp().hypstr != '':
                print('Partial decoding result:', decoder.hyp().hypstr)
        except AttributeError:
            pass
        if decoder.get_in_speech():
            sys.stdout.write('.')
            sys.stdout.flush()
        if decoder.get_in_speech() != in_speech_bf:
            in_speech_bf = decoder.get_in_speech()
            if not in_speech_bf:
                decoder.end_utt()
                try:
                    if decoder.hyp().hypstr != '':
                        print('Stream decoding result:', decoder.hyp().hypstr)
                except AttributeError:
                    pass
                decoder.start_utt()
    else:
        break
decoder.end_utt()
print('An Error occured:', decoder.hyp().hypstr)