pocketsphinx-ruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.rspec +2 -0
- data/.travis.yml +25 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +96 -0
- data/Rakefile +9 -0
- data/examples/pocketsphinx_continuous.rb +13 -0
- data/examples/record_audio_file.rb +29 -0
- data/lib/pocketsphinx-ruby.rb +1 -0
- data/lib/pocketsphinx.rb +16 -0
- data/lib/pocketsphinx/api/pocketsphinx.rb +17 -0
- data/lib/pocketsphinx/api/sphinxad.rb +14 -0
- data/lib/pocketsphinx/api/sphinxbase.rb +26 -0
- data/lib/pocketsphinx/configuration.rb +65 -0
- data/lib/pocketsphinx/configuration/setting_definition.rb +40 -0
- data/lib/pocketsphinx/decoder.rb +64 -0
- data/lib/pocketsphinx/live_speech_recognizer.rb +48 -0
- data/lib/pocketsphinx/microphone.rb +65 -0
- data/lib/pocketsphinx/speech_recognizer.rb +9 -0
- data/lib/pocketsphinx/version.rb +3 -0
- data/pocketsphinx-ruby.gemspec +27 -0
- data/spec/configuration_spec.rb +47 -0
- data/spec/decoder_spec.rb +100 -0
- data/spec/microphone_spec.rb +102 -0
- data/spec/spec_helper.rb +38 -0
- metadata +144 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b67faaa7d60b0ff377d160f8fd88a28ebcc1eaa4
|
4
|
+
data.tar.gz: 163809adeed0af96f876f10bb2b2e93b4ebc8ba6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f7e109bae75aadd7a1ea053fb21cfd099e95c8e7476c08ea0d45d01991d84a93713e346e63d415e14981353f557d6c78fd11177cac726f1145ecbd1b80567f9f
|
7
|
+
data.tar.gz: a5b0af62adb929f617239f651d6929eb88b55861e5318970f14e46eaf81b49433fb1492bcfe2d176ea53f982843c3cd674d5cd7e63155ebe788618c0cbaa397b
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
.DS_Store
|
24
|
+
log
|
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.1.2
|
4
|
+
- 2.0.0
|
5
|
+
- 1.9.3
|
6
|
+
- rbx-2.2.9
|
7
|
+
- jruby-1.7.16
|
8
|
+
before_install:
|
9
|
+
- sudo apt-get update -qq
|
10
|
+
- sudo apt-get install -y swig
|
11
|
+
- git clone https://github.com/cmusphinx/sphinxbase.git
|
12
|
+
- cd sphinxbase
|
13
|
+
- ./autogen.sh
|
14
|
+
- ./configure
|
15
|
+
- make
|
16
|
+
- sudo make install
|
17
|
+
- cd ..
|
18
|
+
- git clone https://github.com/cmusphinx/pocketsphinx.git
|
19
|
+
- cd pocketsphinx
|
20
|
+
- ./autogen.sh
|
21
|
+
- ./configure
|
22
|
+
- make
|
23
|
+
- sudo make install
|
24
|
+
- cd ..
|
25
|
+
- sudo ldconfig
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Howard Wilson
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# pocketsphinx-ruby
|
2
|
+
|
3
|
+
[![Build Status](http://img.shields.io/travis/watsonbox/pocketsphinx-ruby.svg?style=flat)](https://travis-ci.org/watsonbox/pocketsphinx-ruby)
|
4
|
+
[![Code Climate](http://img.shields.io/codeclimate/github/watsonbox/pocketsphinx-ruby/badges/gpa.svg?style=flat)](https://codeclimate.com/github/watsonbox/pocketsphinx-ruby)
|
5
|
+
[![Coverage Status](https://img.shields.io/coveralls/watsonbox/pocketsphinx-ruby.svg?style=flat)](https://coveralls.io/r/watsonbox/pocketsphinx-ruby)
|
6
|
+
|
7
|
+
This gem provides Ruby [FFI](https://github.com/ffi/ffi) bindings for [Pocketsphinx](https://github.com/cmusphinx/pocketsphinx), a lightweight speech recognition engine, specifically tuned for handheld and mobile devices, though it works equally well on the desktop. Pocketsphinx is part of the [CMU Sphinx](http://cmusphinx.sourceforge.net/) Open Source Toolkit For Speech Recognition.
|
8
|
+
|
9
|
+
I had initially looked at using Pocketsphinx's [SWIG](http://www.swig.org/) interface for this gem, but decided in favor of FFI for many of the reasons outlined [here](https://github.com/ffi/ffi/wiki/Why-use-FFI), but most importantly ease of maintenance and JRuby support.
|
10
|
+
|
11
|
+
The goal of this project is to make it as easy as possible for the Ruby community to experiment with speech recognition. Please do contribute fixes and enhancements.
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
This gem depends on [Pocketsphinx](https://github.com/cmusphinx/pocketsphinx) (libpocketsphinx), and [Sphinxbase](https://github.com/cmusphinx/sphinxbase) (libsphinxbase and libsphinxad). The current stable versions (0.8) are from late 2012 and are now outdated. Build them manually from source, or on OSX the latest development (potentially unstable) versions can be installed using [Homebrew](http://brew.sh/) as follows ([more information here](https://github.com/watsonbox/homebrew-cmu-sphinx)).
|
17
|
+
|
18
|
+
Add the Homebrew tap:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
$ brew tap watsonbox/cmu-sphinx
|
22
|
+
```
|
23
|
+
|
24
|
+
You'll see some warnings as these formulae conflict with those in the main reponitory, but that's fine.
|
25
|
+
|
26
|
+
Install the libraries:
|
27
|
+
|
28
|
+
```bash
|
29
|
+
$ brew install --HEAD watsonbox/cmu-sphinx/cmu-sphinxbase
|
30
|
+
$ brew install --HEAD watsonbox/cmu-sphinx/cmu-sphinxtrain # optional
|
31
|
+
$ brew install --HEAD watsonbox/cmu-sphinx/cmu-pocketsphinx
|
32
|
+
```
|
33
|
+
|
34
|
+
You can test continuous recognition as follows:
|
35
|
+
|
36
|
+
```bash
|
37
|
+
$ pocketsphinx_continuous -inmic yes
|
38
|
+
```
|
39
|
+
|
40
|
+
Then add this line to your application's Gemfile:
|
41
|
+
|
42
|
+
gem 'pocketsphinx-ruby'
|
43
|
+
|
44
|
+
And then execute:
|
45
|
+
|
46
|
+
$ bundle
|
47
|
+
|
48
|
+
Or install it yourself as:
|
49
|
+
|
50
|
+
$ gem install pocketsphinx-ruby
|
51
|
+
|
52
|
+
|
53
|
+
## Basic Usage
|
54
|
+
|
55
|
+
The `LiveSpeechRecognizer` is modeled on the same class in [Sphinx4](http://cmusphinx.sourceforge.net/wiki/tutorialsphinx4). It uses the `Microphone` and `Decoder` classes internally to provide a simple, high-level recognition interface:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
require 'pocketsphinx-ruby'
|
59
|
+
|
60
|
+
Pocketsphinx::LiveSpeechRecognizer.new.recognize do |speech|
|
61
|
+
puts speech
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
|
66
|
+
## Microphone
|
67
|
+
|
68
|
+
The `Microphone` class uses Pocketsphinx's libsphinxad to record audio for speech recognition. For desktop applications this should normally be 16bit/16kHz raw PCM audio, so these are the default settings. The exact audio backend depends on [what was selected](https://github.com/cmusphinx/sphinxbase/blob/master/configure.in#L138) when libsphinxad was built. On OSX, OpenAL is [now supported](https://github.com/cmusphinx/sphinxbase/commit/5cc55c4721273681200e1f754ff0798ac073b950) and should work just fine.
|
69
|
+
|
70
|
+
For example, to record and save a 5 second raw audio file:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
microphone = Microphone.new
|
74
|
+
|
75
|
+
File.open("test.raw", "wb") do |file|
|
76
|
+
microphone.record do
|
77
|
+
FFI::MemoryPointer.new(:int16, 4096) do |buffer|
|
78
|
+
50.times do
|
79
|
+
sample_count = microphone.read_audio(buffer, 4096)
|
80
|
+
file.write buffer.get_bytes(0, sample_count * 2)
|
81
|
+
|
82
|
+
sleep 0.1
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
|
90
|
+
## Contributing
|
91
|
+
|
92
|
+
1. Fork it ( https://github.com/[my-github-username]/pocketsphinx-ruby/fork )
|
93
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
94
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
95
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
96
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "pocketsphinx-ruby"
|
5
|
+
|
6
|
+
include Pocketsphinx
|
7
|
+
|
8
|
+
configuration = Configuration.default
|
9
|
+
recognizer = LiveSpeechRecognizer.new(configuration)
|
10
|
+
|
11
|
+
recognizer.recognize do |speech|
|
12
|
+
puts speech
|
13
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "pocketsphinx-ruby"
|
5
|
+
|
6
|
+
include Pocketsphinx
|
7
|
+
|
8
|
+
MAX_SAMPLES = 4096
|
9
|
+
RECORDING_INTERVAL = 0.1
|
10
|
+
RECORDING_LENGTH = 5
|
11
|
+
|
12
|
+
puts "Recording #{RECORDING_LENGTH} seconds of audio..."
|
13
|
+
|
14
|
+
microphone = Microphone.new
|
15
|
+
|
16
|
+
File.open("test_write.raw", "wb") do |file|
|
17
|
+
microphone.record do
|
18
|
+
FFI::MemoryPointer.new(:int16, MAX_SAMPLES) do |buffer|
|
19
|
+
(RECORDING_LENGTH / RECORDING_INTERVAL).times do
|
20
|
+
sample_count = microphone.read_audio(buffer, MAX_SAMPLES)
|
21
|
+
|
22
|
+
# sample_count * 2 since this is length in bytes
|
23
|
+
file.write buffer.get_bytes(0, sample_count * 2)
|
24
|
+
|
25
|
+
sleep RECORDING_INTERVAL
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'pocketsphinx'
|
data/lib/pocketsphinx.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
require "pocketsphinx/version"
|
4
|
+
require "pocketsphinx/api/sphinxbase"
|
5
|
+
require "pocketsphinx/api/sphinxad"
|
6
|
+
require "pocketsphinx/api/pocketsphinx"
|
7
|
+
|
8
|
+
require "pocketsphinx/configuration"
|
9
|
+
require "pocketsphinx/microphone"
|
10
|
+
require "pocketsphinx/decoder"
|
11
|
+
require "pocketsphinx/speech_recognizer"
|
12
|
+
require "pocketsphinx/live_speech_recognizer"
|
13
|
+
|
14
|
+
module Pocketsphinx
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pocketsphinx
|
2
|
+
module API
|
3
|
+
module Pocketsphinx
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib "libpocketsphinx"
|
6
|
+
|
7
|
+
attach_function :ps_init, [:pointer], :pointer
|
8
|
+
attach_function :ps_default_search_args, [:pointer], :void
|
9
|
+
attach_function :ps_args, [], :pointer
|
10
|
+
attach_function :ps_process_raw, [:pointer, :pointer, :size_t, :int, :int], :int
|
11
|
+
attach_function :ps_start_utt, [:pointer, :string], :int
|
12
|
+
attach_function :ps_end_utt, [:pointer], :int
|
13
|
+
attach_function :ps_get_in_speech, [:pointer], :uint8
|
14
|
+
attach_function :ps_get_hyp, [:pointer, :pointer, :pointer], :string
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Pocketsphinx
|
2
|
+
module API
|
3
|
+
module SphinxAD
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib "libsphinxad"
|
6
|
+
|
7
|
+
attach_function :ad_open_dev, [:string, :int], :pointer
|
8
|
+
attach_function :ad_start_rec, [:pointer], :int32
|
9
|
+
attach_function :ad_stop_rec, [:pointer], :int32
|
10
|
+
attach_function :ad_read, [:pointer, :pointer, :int], :int
|
11
|
+
attach_function :ad_close, [:pointer], :void
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Pocketsphinx
|
2
|
+
module API
|
3
|
+
module Sphinxbase
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib "libsphinxbase"
|
6
|
+
|
7
|
+
class Argument < FFI::Struct
|
8
|
+
layout :name, :string,
|
9
|
+
:type, :int,
|
10
|
+
:deflt, :string,
|
11
|
+
:doc, :string
|
12
|
+
end
|
13
|
+
|
14
|
+
# TODO: Document on ruby side?
|
15
|
+
attach_function :cmd_ln_parse_r, [:pointer, :pointer, :int32, :pointer, :int], :pointer
|
16
|
+
attach_function :cmd_ln_float_r, [:pointer, :string], :double
|
17
|
+
attach_function :cmd_ln_set_float_r, [:pointer, :string, :double], :void
|
18
|
+
attach_function :cmd_ln_int_r, [:pointer, :string], :int
|
19
|
+
attach_function :cmd_ln_set_int_r, [:pointer, :string, :int], :void
|
20
|
+
attach_function :cmd_ln_str_r, [:pointer, :string], :string
|
21
|
+
attach_function :cmd_ln_set_str_r, [:pointer, :string, :string], :void
|
22
|
+
attach_function :err_set_debug_level, [:int], :int
|
23
|
+
attach_function :err_set_logfile, [:string], :int
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'pocketsphinx/configuration/setting_definition'
|
2
|
+
|
3
|
+
module Pocketsphinx
|
4
|
+
class Configuration
|
5
|
+
attr_reader :ps_config
|
6
|
+
|
7
|
+
private_class_method :new
|
8
|
+
|
9
|
+
def initialize(ps_arg_defs)
|
10
|
+
@ps_arg_defs = ps_arg_defs
|
11
|
+
@setting_definitions = SettingDefinition.from_arg_defs(ps_arg_defs)
|
12
|
+
|
13
|
+
# Sets default settings based on definitions
|
14
|
+
@ps_config = API::Sphinxbase.cmd_ln_parse_r(nil, ps_arg_defs, 0, nil, 1)
|
15
|
+
|
16
|
+
# Sets default grammar and language model if they are not set explicitly and
|
17
|
+
# are present in the default search path.
|
18
|
+
API::Pocketsphinx.ps_default_search_args(@ps_config)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.default
|
22
|
+
new(API::Pocketsphinx.ps_args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](name)
|
26
|
+
unless definition = @setting_definitions[name]
|
27
|
+
raise "Configuration setting '#{name}' does not exist"
|
28
|
+
end
|
29
|
+
|
30
|
+
case definition.type
|
31
|
+
when :integer
|
32
|
+
API::Sphinxbase.cmd_ln_int_r(@ps_config, "-#{name}")
|
33
|
+
when :float
|
34
|
+
API::Sphinxbase.cmd_ln_float_r(@ps_config, "-#{name}")
|
35
|
+
when :string
|
36
|
+
API::Sphinxbase.cmd_ln_str_r(@ps_config, "-#{name}")
|
37
|
+
when :boolean
|
38
|
+
API::Sphinxbase.cmd_ln_int_r(@ps_config, "-#{name}") != 0
|
39
|
+
when :string_list
|
40
|
+
raise NotImplementedException
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def []=(name, value)
|
45
|
+
unless definition = @setting_definitions[name]
|
46
|
+
raise "Configuration setting '#{name}' does not exist"
|
47
|
+
end
|
48
|
+
|
49
|
+
case definition.type
|
50
|
+
when :integer
|
51
|
+
raise "Configuration setting '#{name}' must be a Fixnum" unless value.respond_to?(:to_i)
|
52
|
+
API::Sphinxbase.cmd_ln_set_int_r(@ps_config, "-#{name}", value.to_i)
|
53
|
+
when :float
|
54
|
+
raise "Configuration setting '#{name}' must be a Float" unless value.respond_to?(:to_i)
|
55
|
+
API::Sphinxbase.cmd_ln_set_float_r(@ps_config, "-#{name}", value.to_f)
|
56
|
+
when :string
|
57
|
+
API::Sphinxbase.cmd_ln_set_str_r(@ps_config, "-#{name}", value.to_s)
|
58
|
+
when :boolean
|
59
|
+
API::Sphinxbase.cmd_ln_set_int_r(@ps_config, "-#{name}", value ? 1 : 0)
|
60
|
+
when :string_list
|
61
|
+
raise NotImplementedException
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Pocketsphinx
|
2
|
+
class Configuration
|
3
|
+
class SettingDefinition
|
4
|
+
TYPES = [:integer, :float, :string, :boolean, :string_list]
|
5
|
+
|
6
|
+
def initialize(name, type_code, default, doc)
|
7
|
+
@name, @type_code, @default, @doc = name, type_code, default, doc
|
8
|
+
end
|
9
|
+
|
10
|
+
def type
|
11
|
+
# Remove the required bit if it exists and find type from log2 of code
|
12
|
+
TYPES[Math.log2(@type_code - @type_code%2) - 1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def required?
|
16
|
+
@type_code % 2 == 1
|
17
|
+
end
|
18
|
+
|
19
|
+
# Build setting definitions from pocketsphinx argument definitions
|
20
|
+
#
|
21
|
+
# @param [FFI::Pointer] ps_arg_defs A pointer to the Pocketsphinx argument definitions
|
22
|
+
#
|
23
|
+
# @return [Hash] A hash of setting definitions (name -> definition)
|
24
|
+
def self.from_arg_defs(ps_arg_defs)
|
25
|
+
{}.tap do |setting_defs|
|
26
|
+
arg_array = FFI::Pointer.new(API::Sphinxbase::Argument, ps_arg_defs)
|
27
|
+
|
28
|
+
0.upto(Float::INFINITY) do |i|
|
29
|
+
arg = API::Sphinxbase::Argument.new(arg_array[i])
|
30
|
+
break if arg[:name].nil?
|
31
|
+
|
32
|
+
# Remove '-' from argument name
|
33
|
+
name = arg[:name][1..-1]
|
34
|
+
setting_defs[name] = new(name, arg[:type], arg[:deflt], arg[:doc])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Pocketsphinx
|
2
|
+
class Decoder
|
3
|
+
Error = Class.new(StandardError)
|
4
|
+
|
5
|
+
attr_reader :ps_decoder
|
6
|
+
attr_writer :ps_api
|
7
|
+
|
8
|
+
def initialize(configuration)
|
9
|
+
@configuration = configuration
|
10
|
+
@ps_decoder = ps_api.ps_init(configuration.ps_config)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Decode raw audio data.
|
14
|
+
#
|
15
|
+
# @param [Boolean] no_search If non-zero, perform feature extraction but don't do any
|
16
|
+
# recognition yet. This may be necessary if your processor has trouble doing recognition in
|
17
|
+
# real-time.
|
18
|
+
# @param [Boolean] full_utt If non-zero, this block of data is a full utterance
|
19
|
+
# worth of data. This may allow the recognizer to produce more accurate results.
|
20
|
+
# @return Number of frames of data searched
|
21
|
+
def process_raw(buffer, size, no_search = false, full_utt = false)
|
22
|
+
ps_api.ps_process_raw(@ps_decoder, buffer, size, no_search ? 1 : 0, full_utt ? 1 : 0).tap do |result|
|
23
|
+
raise Error, "Decoder#process_raw failed with error code #{result}" if result < 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Start utterance processing.
|
28
|
+
#
|
29
|
+
# This function should be called before any utterance data is passed
|
30
|
+
# to the decoder. It marks the start of a new utterance and
|
31
|
+
# reinitializes internal data structures.
|
32
|
+
#
|
33
|
+
# @param [String] name String uniquely identifying this utterance. If nil, one will be created.
|
34
|
+
def start_utterance(name = nil)
|
35
|
+
ps_api.ps_start_utt(@ps_decoder, name).tap do |result|
|
36
|
+
raise Error, "Decoder#start_utterance failed with error code #{result}" if result < 0
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# End utterance processing
|
41
|
+
def end_utterance
|
42
|
+
ps_api.ps_end_utt(@ps_decoder).tap do |result|
|
43
|
+
raise Error, "Decoder#end_utterance failed with error code #{result}" if result < 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Checks if the last feed audio buffer contained speech
|
48
|
+
def in_speech?
|
49
|
+
ps_api.ps_get_in_speech(@ps_decoder) != 0
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get hypothesis string and path score.
|
53
|
+
#
|
54
|
+
# @return [String] Hypothesis string
|
55
|
+
# @todo Expand to return path score and utterance ID
|
56
|
+
def hypothesis
|
57
|
+
ps_api.ps_get_hyp(@ps_decoder, nil, nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
def ps_api
|
61
|
+
@ps_api || API::Pocketsphinx
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Pocketsphinx
|
2
|
+
# High-level class for live speech recognition.
|
3
|
+
#
|
4
|
+
# Modeled on the LiveSpeechRecognizer from Sphinx4.
|
5
|
+
class LiveSpeechRecognizer < SpeechRecognizer
|
6
|
+
attr_writer :microphone
|
7
|
+
|
8
|
+
def microphone
|
9
|
+
@microphone ||= Microphone.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Recognize utterances and yield hypotheses in infinite loop
|
13
|
+
#
|
14
|
+
# @param [Float]
|
15
|
+
def recognize(recording_interval = 0.1, max_samples = 4096)
|
16
|
+
decoder.start_utterance
|
17
|
+
|
18
|
+
microphone.record do
|
19
|
+
FFI::MemoryPointer.new(:int16, max_samples) do |buffer|
|
20
|
+
loop do
|
21
|
+
if decoder.in_speech?
|
22
|
+
process_audio(buffer, max_samples, recording_interval) while decoder.in_speech?
|
23
|
+
yield get_hypothesis
|
24
|
+
else
|
25
|
+
process_audio(buffer, max_samples, recording_interval)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def process_audio(buffer, max_samples, delay)
|
35
|
+
sample_count = microphone.read_audio(buffer, max_samples)
|
36
|
+
decoder.process_raw(buffer, sample_count)
|
37
|
+
sleep delay
|
38
|
+
end
|
39
|
+
|
40
|
+
# Called on speech -> silence transition
|
41
|
+
def get_hypothesis
|
42
|
+
decoder.end_utterance
|
43
|
+
decoder.hypothesis.tap do
|
44
|
+
decoder.start_utterance
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Pocketsphinx
|
2
|
+
# Provides non-blocking audio recording using libsphinxad
|
3
|
+
class Microphone
|
4
|
+
Error = Class.new(StandardError)
|
5
|
+
|
6
|
+
attr_reader :ps_audio_device
|
7
|
+
attr_writer :ps_api
|
8
|
+
|
9
|
+
# Opens an audio device for recording
|
10
|
+
#
|
11
|
+
# The device is opened in non-blocking mode and placed in idle state.
|
12
|
+
#
|
13
|
+
# @param [Fixnum] sample_rate Samples per second for recording, e.g. 16000 for 16kHz
|
14
|
+
# @param [String] default_device The device name
|
15
|
+
# @param [Object] ps_api A SphinxAD API implementation to use, API::SphinxAD if not provided
|
16
|
+
def initialize(sample_rate = 16000, default_device = nil, ps_api = nil)
|
17
|
+
@ps_api = ps_api
|
18
|
+
@ps_audio_device = ps_api.ad_open_dev(default_device, sample_rate)
|
19
|
+
|
20
|
+
# Ensure that audio device is closed when object is garbage collected
|
21
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(ps_api, @ps_audio_device))
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.finalize(ps_api, ps_audio_device)
|
25
|
+
proc { ps_api.ad_close(ps_audio_device) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def record
|
29
|
+
start_recording
|
30
|
+
yield
|
31
|
+
stop_recording
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_recording
|
35
|
+
ps_api.ad_start_rec(@ps_audio_device).tap do |result|
|
36
|
+
raise Error, "Microphone#start_recording failed with error code #{result}" if result < 0
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def stop_recording
|
41
|
+
ps_api.ad_stop_rec(@ps_audio_device).tap do |result|
|
42
|
+
raise Error, "Microphone#stop_recording failed with error code #{result}" if result < 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Read next block of audio samples while recording; read upto max samples into buf.
|
47
|
+
#
|
48
|
+
# @param [FFI::Pointer] buffer 16bit buffer of at least max_samples in size
|
49
|
+
# @return [Fixnum] Samples actually read (could be 0 since non-blocking); -1 if not
|
50
|
+
# recording and no more samples remaining to be read from most recent recording.
|
51
|
+
def read_audio(buffer, max_samples = 4096)
|
52
|
+
ps_api.ad_read(@ps_audio_device, buffer, max_samples)
|
53
|
+
end
|
54
|
+
|
55
|
+
def close_device
|
56
|
+
ps_api.ad_close(@ps_audio_device).tap do |result|
|
57
|
+
raise Error, "Microphone#close_device failed with error code #{result}" if result < 0
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def ps_api
|
62
|
+
@ps_api || API::SphinxAD
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pocketsphinx/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "pocketsphinx-ruby"
|
8
|
+
spec.version = Pocketsphinx::VERSION
|
9
|
+
spec.authors = ["Howard Wilson"]
|
10
|
+
spec.email = ["howard@watsonbox.net"]
|
11
|
+
spec.summary = %q{Ruby FFI pocketsphinx bindings}
|
12
|
+
spec.description = %q{Ruby FFI pocketsphinx bindings}
|
13
|
+
spec.homepage = "https://github.com/watsonbox/pocketsphinx-ruby"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "ffi", ">= 1.9"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.1.0"
|
26
|
+
spec.add_development_dependency "coveralls"
|
27
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Configuration do
|
4
|
+
subject { Pocketsphinx::Configuration.default }
|
5
|
+
|
6
|
+
it "provides a default pocketsphinx configuration" do
|
7
|
+
expect(subject).to be_a(Pocketsphinx::Configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "supports integer settings" do
|
11
|
+
expect(subject['frate']).to eq(100)
|
12
|
+
expect(subject['frate']).to be_a(Fixnum)
|
13
|
+
|
14
|
+
subject['frate'] = 50
|
15
|
+
expect(subject['frate']).to eq(50)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "supports float settings" do
|
19
|
+
expect(subject['samprate']).to eq(16000)
|
20
|
+
expect(subject['samprate']).to be_a(Float)
|
21
|
+
|
22
|
+
subject['samprate'] = 8000
|
23
|
+
expect(subject['samprate']).to eq(8000)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "supports getting strings" do
|
27
|
+
expect(subject['warp_type']).to eq('inverse_linear')
|
28
|
+
|
29
|
+
subject['warp_type'] = 'different_type'
|
30
|
+
expect(subject['warp_type']).to eq('different_type')
|
31
|
+
end
|
32
|
+
|
33
|
+
it "supports getting booleans" do
|
34
|
+
expect(subject['smoothspec']).to eq(false)
|
35
|
+
|
36
|
+
subject['smoothspec'] = true
|
37
|
+
expect(subject['smoothspec']).to eq(true)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'raises exceptions when setting with incorrectly typed values' do
|
41
|
+
expect { subject['frate'] = true }.to raise_exception "Configuration setting 'frate' must be a Fixnum"
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'raises exceptions when a setting is unknown' do
|
45
|
+
expect { subject['unknown'] = true }.to raise_exception "Configuration setting 'unknown' does not exist"
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Decoder do
|
4
|
+
subject { @decoder }
|
5
|
+
let(:ps_api) { @decoder.ps_api = double }
|
6
|
+
|
7
|
+
# Share decoder across all examples for speed
|
8
|
+
before :all do
|
9
|
+
@decoder = Decoder.new(Configuration.default)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#process_raw' do
|
13
|
+
it 'calls libpocketsphinx' do
|
14
|
+
FFI::MemoryPointer.new(:int16, 4096) do |buffer|
|
15
|
+
expect(ps_api)
|
16
|
+
.to receive(:ps_process_raw)
|
17
|
+
.with(subject.ps_decoder, buffer, 4096, 0, 0)
|
18
|
+
.and_return(0)
|
19
|
+
|
20
|
+
subject.process_raw(buffer, 4096, false, false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'raises an exception on error' do
|
25
|
+
FFI::MemoryPointer.new(:int16, 4096) do |buffer|
|
26
|
+
expect(ps_api)
|
27
|
+
.to receive(:ps_process_raw)
|
28
|
+
.with(subject.ps_decoder, buffer, 4096, 0, 0)
|
29
|
+
.and_return(-1)
|
30
|
+
|
31
|
+
expect { subject.process_raw(buffer, 4096, false, false) }
|
32
|
+
.to raise_exception "Decoder#process_raw failed with error code -1"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#start_utterance' do
|
38
|
+
it 'calls libpocketsphinx' do
|
39
|
+
expect(ps_api)
|
40
|
+
.to receive(:ps_start_utt)
|
41
|
+
.with(subject.ps_decoder, "Utterance Name")
|
42
|
+
.and_return(0)
|
43
|
+
|
44
|
+
subject.start_utterance("Utterance Name")
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'raises an exception on error' do
|
48
|
+
expect(ps_api)
|
49
|
+
.to receive(:ps_start_utt)
|
50
|
+
.with(subject.ps_decoder, "Utterance Name")
|
51
|
+
.and_return(-1)
|
52
|
+
|
53
|
+
expect { subject.start_utterance("Utterance Name") }
|
54
|
+
.to raise_exception "Decoder#start_utterance failed with error code -1"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#end_utterance' do
|
59
|
+
it 'calls libpocketsphinx' do
|
60
|
+
expect(ps_api)
|
61
|
+
.to receive(:ps_end_utt)
|
62
|
+
.with(subject.ps_decoder)
|
63
|
+
.and_return(0)
|
64
|
+
|
65
|
+
subject.end_utterance
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'raises an exception on error' do
|
69
|
+
expect(ps_api)
|
70
|
+
.to receive(:ps_end_utt)
|
71
|
+
.with(subject.ps_decoder)
|
72
|
+
.and_return(-1)
|
73
|
+
|
74
|
+
expect { subject.end_utterance }
|
75
|
+
.to raise_exception "Decoder#end_utterance failed with error code -1"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#in_speech' do
|
80
|
+
it 'calls libpocketsphinx' do
|
81
|
+
expect(ps_api)
|
82
|
+
.to receive(:ps_get_in_speech)
|
83
|
+
.with(subject.ps_decoder)
|
84
|
+
.and_return(0)
|
85
|
+
|
86
|
+
expect(subject.in_speech?).to eq(false)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#hypothesis' do
|
91
|
+
it 'calls libpocketsphinx' do
|
92
|
+
expect(ps_api)
|
93
|
+
.to receive(:ps_get_hyp)
|
94
|
+
.with(subject.ps_decoder, nil, nil)
|
95
|
+
.and_return("Hypothesis")
|
96
|
+
|
97
|
+
expect(subject.hypothesis).to eq("Hypothesis")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Microphone do
|
4
|
+
module DummyAPI
|
5
|
+
def self.ad_open_dev(default_device, sample_rate)
|
6
|
+
:audio_device
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { @microphone }
|
11
|
+
let!(:ps_api) { @microphone.ps_api = double }
|
12
|
+
|
13
|
+
# Share microphone across all examples for speed
|
14
|
+
before :all do
|
15
|
+
# Don't open an audio device as there isn't one on Travis CI
|
16
|
+
@microphone = Microphone.new(16000, nil, DummyAPI)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#start_recording' do
|
20
|
+
it 'calls libsphinxad' do
|
21
|
+
expect(ps_api)
|
22
|
+
.to receive(:ad_start_rec)
|
23
|
+
.with(subject.ps_audio_device)
|
24
|
+
.and_return(0)
|
25
|
+
|
26
|
+
subject.start_recording
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'raises an exception on error' do
|
30
|
+
expect(ps_api)
|
31
|
+
.to receive(:ad_start_rec)
|
32
|
+
.with(subject.ps_audio_device)
|
33
|
+
.and_return(-1)
|
34
|
+
|
35
|
+
expect { subject.start_recording }
|
36
|
+
.to raise_exception "Microphone#start_recording failed with error code -1"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#stop_recording' do
|
41
|
+
it 'calls libsphinxad' do
|
42
|
+
expect(ps_api)
|
43
|
+
.to receive(:ad_stop_rec)
|
44
|
+
.with(subject.ps_audio_device)
|
45
|
+
.and_return(0)
|
46
|
+
|
47
|
+
subject.stop_recording
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raises an exception on error' do
|
51
|
+
expect(ps_api)
|
52
|
+
.to receive(:ad_stop_rec)
|
53
|
+
.with(subject.ps_audio_device)
|
54
|
+
.and_return(-1)
|
55
|
+
|
56
|
+
expect { subject.stop_recording }
|
57
|
+
.to raise_exception "Microphone#stop_recording failed with error code -1"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#record' do
|
62
|
+
it 'starts and stops recording, yielding control' do
|
63
|
+
expect(subject).to receive(:start_recording).ordered
|
64
|
+
|
65
|
+
subject.record do
|
66
|
+
expect(subject).to receive(:stop_recording).ordered
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#read_audio' do
|
72
|
+
it 'calls libsphinxad' do
|
73
|
+
expect(ps_api)
|
74
|
+
.to receive(:ad_read)
|
75
|
+
.with(subject.ps_audio_device, :buffer, 4096)
|
76
|
+
.and_return(0)
|
77
|
+
|
78
|
+
subject.read_audio(:buffer, 4096)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#close_device' do
|
83
|
+
it 'calls libsphinxad' do
|
84
|
+
expect(ps_api)
|
85
|
+
.to receive(:ad_close)
|
86
|
+
.with(subject.ps_audio_device)
|
87
|
+
.and_return(0)
|
88
|
+
|
89
|
+
subject.close_device
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'raises an exception on error' do
|
93
|
+
expect(ps_api)
|
94
|
+
.to receive(:ad_close)
|
95
|
+
.with(subject.ps_audio_device)
|
96
|
+
.and_return(-1)
|
97
|
+
|
98
|
+
expect { subject.close_device }
|
99
|
+
.to raise_exception "Microphone#close_device failed with error code -1"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'coveralls'
|
2
|
+
Coveralls.wear!
|
3
|
+
|
4
|
+
require 'pocketsphinx'
|
5
|
+
|
6
|
+
POCKETSPHINX_LOG_FILE = "./log/pocketsphinx_test.log"
|
7
|
+
|
8
|
+
# Set up pocketsphinx logging to a file rather than stdout
|
9
|
+
FileUtils.makedirs File.dirname(POCKETSPHINX_LOG_FILE)
|
10
|
+
FileUtils.touch POCKETSPHINX_LOG_FILE
|
11
|
+
Pocketsphinx::API::Sphinxbase.err_set_logfile POCKETSPHINX_LOG_FILE
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
include Pocketsphinx
|
15
|
+
|
16
|
+
# rspec-expectations config goes here. You can use an alternate
|
17
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
18
|
+
# assertions if you prefer.
|
19
|
+
config.expect_with :rspec do |expectations|
|
20
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
21
|
+
# and `failure_message` of custom matchers include text for helper methods
|
22
|
+
# defined using `chain`, e.g.:
|
23
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
24
|
+
# # => "be bigger than 2 and smaller than 4"
|
25
|
+
# ...rather than:
|
26
|
+
# # => "be bigger than 2"
|
27
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
28
|
+
end
|
29
|
+
|
30
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
31
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
32
|
+
config.mock_with :rspec do |mocks|
|
33
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
34
|
+
# a real object. This is generally recommended, and will default to
|
35
|
+
# `true` in RSpec 4.
|
36
|
+
mocks.verify_partial_doubles = true
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pocketsphinx-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Howard Wilson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.9'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.9'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.1.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.1.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: coveralls
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Ruby FFI pocketsphinx bindings
|
84
|
+
email:
|
85
|
+
- howard@watsonbox.net
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- examples/pocketsphinx_continuous.rb
|
98
|
+
- examples/record_audio_file.rb
|
99
|
+
- lib/pocketsphinx-ruby.rb
|
100
|
+
- lib/pocketsphinx.rb
|
101
|
+
- lib/pocketsphinx/api/pocketsphinx.rb
|
102
|
+
- lib/pocketsphinx/api/sphinxad.rb
|
103
|
+
- lib/pocketsphinx/api/sphinxbase.rb
|
104
|
+
- lib/pocketsphinx/configuration.rb
|
105
|
+
- lib/pocketsphinx/configuration/setting_definition.rb
|
106
|
+
- lib/pocketsphinx/decoder.rb
|
107
|
+
- lib/pocketsphinx/live_speech_recognizer.rb
|
108
|
+
- lib/pocketsphinx/microphone.rb
|
109
|
+
- lib/pocketsphinx/speech_recognizer.rb
|
110
|
+
- lib/pocketsphinx/version.rb
|
111
|
+
- pocketsphinx-ruby.gemspec
|
112
|
+
- spec/configuration_spec.rb
|
113
|
+
- spec/decoder_spec.rb
|
114
|
+
- spec/microphone_spec.rb
|
115
|
+
- spec/spec_helper.rb
|
116
|
+
homepage: https://github.com/watsonbox/pocketsphinx-ruby
|
117
|
+
licenses:
|
118
|
+
- MIT
|
119
|
+
metadata: {}
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 2.2.2
|
137
|
+
signing_key:
|
138
|
+
specification_version: 4
|
139
|
+
summary: Ruby FFI pocketsphinx bindings
|
140
|
+
test_files:
|
141
|
+
- spec/configuration_spec.rb
|
142
|
+
- spec/decoder_spec.rb
|
143
|
+
- spec/microphone_spec.rb
|
144
|
+
- spec/spec_helper.rb
|