I went with pocketsphinx_continuous and a $4 sound card.
To manage the fact that it needs to stop listening when using speech synth I used amixer to handle to input volume to the mic (this was recommended best practice by CMU as stop-starting engine will result in poorer recognition)
echo "SETTING MIC IN TO 15 (94%)" >> ./audio.log
amixer -c 1 set Mic 15 unmute 2>&1 >/dev/null
With a matching command to mute the listening when the speech synth plays
FILE: mute.sh
#!/bin/sh
sleep $1;
amixer -c 1 set Mic 0 unmute >/dev/null 2>&1 ;
echo "** MIC OFF **" >> /home/pi/PIXIE/audio.log
To calculate the right times to mute for I just run soxi via lua and then set the unmute.sh (opposite of the mute.sh) to run "x" seconds from the startup. There are no doubt lots of ways to handle this. I am happy with the results of this method.
LUA SNIPPET:
-- Begin parallel timing
-- MUTE UNTIL THE SOUNDCARD FREES UP
-- "filename" is a fully qualified path to a wav file
-- outputted by voice synth in previous operation
-- GET THE LENGTH
local sample_length = io.popen('soxi -D '..filename);
local total_length = sample_length:read("*a");
clean_length = string.gsub(total_length, "\n", "") +1;
sample_length:close();
-- EXAMPLE LOGGING OUTPUT...
--os.execute( 'echo LENGTH WAS "'.. clean_length .. '" Seconds >> ./audio.log');
-- we are about to play something...
-- MUTE, then schedule UNMUTE.sh in x seconds, then play synth output
-- (have unrolled mute.sh here for clarity)
os.execute( 'amixer -c 1 set Mic '..mic_level..' unmute 2>&1 >/dev/null ');
os.execute( 'echo "** MIC OFF **" >> ./audio.log ');
-- EXAMPLE LOGGING OUTPUT...
-- os.execute( 'echo PLAYING: "'.. filename..'" circa ' .. clean_length .. ' Seconds >> ./audio.log ');
os.execute( './unmute.sh "'.. clean_length ..'" &');
-- THEN PLAY THE THING WHILE THE OTHER PROCESS IS SLEEPING
os.execute( './sounds-uncached.sh '..filename..' 21000')
To actually grab the voice on the pi I use:
pocketsphinx_continuous -bestpath 0 -adcdev plughw:1 -samprate 20000 \
-nfft 512 -ds2 -topn2 -maxwpf 5 -kdtreefn 3000 -kdmaxdepth 7 -kdmaxbbi 15 \
-pl_window 10 -lm ./LANGUAGE/0892-min.lm -dict ./LANGUAGE/0892-min.dic 2>&1 \
| tee -i 2>/dev/null >( sed -u -n -e 's/^.\{9\}: //p' ) \
>( sed -u -n -e 's/^READY//p' \
-e 's/^Listening//p' -e 's/^FATAL_ERROR: \"continuous\.c\"\, //p') \
> /dev/null
Again, there are other ways, but I like my output this way.
For the synth I used Cepstrals fledgling pi solution, but it's not available online you have to contact them directly to arrange to buy it and it is around $30 to buy. The results are acceptable however the speech does create some nasty clicks and pops, the company have replied saying they no longer have a RaspPi and are unwilling to improve the product. YMMV
The voice recognition sits at around 12% CPU when "idle", and spikes briefly when doing a chunk of recognition.
The voice creation spikes at about 50-80% when rendering.
The play / sox weighs in pretty heavily but I do apply real-time effects to the rendered voices as I play them ;)
The pi is heavily stripped down using every guide I could find to stop un-required services and runs in complete CLI mode. 800mhz over-clocked (smallest).
scaling_governor set to: performance
When fully running: it runs at about 50ºC in direct sunlight and 38ºC in the shade. I have heat sinks fitted.
Last point: I actually run all this gear out to "internet driven" AI as a nice extra.
The pi handles all this seamlessly, And playing out any networked audio in real-time, And fully looped audio to any other Unix box. etc.
to handle the large speech CPU overhead burden I have implemented an md5sum based caching system so the same utterences are not rendered twice. (about 1000 files @ 220 mb total covers 70% of the utterences I generally get back from the AI) this really helps bring the total CPU load down overall.
In précis this is all totally doable. however the voice recognition will only be as good as the quality of your mics, your language model, how specifically close your subjects voices are to the original intended audience (I use a en_US model on en_UK children, not perfect) and other minutia of detail that with effort you can whittle down to a decent result.
And for the record, I already did all this once before on a kindle (and that worked too with cmu sphinx and flite). Hope this helps.