pocketsphinx-ruby 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/lib/pocketsphinx.rb +3 -1
- data/lib/pocketsphinx/api/sphinxbase.rb +1 -0
- data/lib/pocketsphinx/audio_file.rb +13 -10
- data/lib/pocketsphinx/configuration/base.rb +2 -2
- data/lib/pocketsphinx/configuration/grammar.rb +1 -1
- data/lib/pocketsphinx/configuration/keyword_spotting.rb +5 -0
- data/lib/pocketsphinx/decoder.rb +23 -4
- data/lib/pocketsphinx/microphone.rb +1 -1
- data/lib/pocketsphinx/speech_recognizer.rb +82 -34
- data/lib/pocketsphinx/version.rb +1 -1
- data/pocketsphinx-ruby.gemspec +2 -2
- data/spec/configuration_spec.rb +11 -2
- data/spec/decoder_spec.rb +18 -7
- data/spec/grammar_spec.rb +4 -4
- data/spec/integration/decoder_spec.rb +3 -3
- data/spec/integration/default_recognition_spec.rb +2 -2
- data/spec/integration/grammar_recognition_spec.rb +4 -4
- data/spec/integration/keyword_recognition_spec.rb +25 -0
- data/spec/live_speech_recognizer_spec.rb +8 -0
- data/spec/microphone_spec.rb +2 -2
- data/spec/spec_helper.rb +0 -2
- data/spec/speech_recognizer_spec.rb +9 -5
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0129cb6b05e984d481f79c27fd085cb119eb195f
|
4
|
+
data.tar.gz: 9a6e6c3750992d6a1d3c7b8d80005b03e7d01b5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef774d606a2c53df8c88e42fb9593cada5347993feb0bf7b044362faf8b5ba28cc8728674732125bef1cd7b7cc78ee8a9ed81d092c4d08b626758e6d93929754
|
7
|
+
data.tar.gz: 656a27d5578fc665116afaa1b63a76ae81e7616cf6f1af49fa65dffca6f01a5e9e5941df2a6b6e9ac825c48e9b9854e77d70cf0eae4b4011b24a5fed3baa4dc1
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
**v0.1.1 - 29/10/14**
|
4
|
+
|
5
|
+
* Allow logging to be disabled
|
6
|
+
* Recognizer can now be paused (during TTS reply for example)
|
7
|
+
* Spot keywords immediately by not using speech -> silence transitions
|
8
|
+
* Return path_score and utterance_id with hypothesis
|
9
|
+
* Fix namespacing bug in Configuration::Grammar
|
10
|
+
* Improve test coverage
|
11
|
+
|
12
|
+
|
13
|
+
**v0.1.0 - 24/10/14**
|
14
|
+
|
15
|
+
* Support for JSGF grammars + very simple sentences DSL
|
16
|
+
|
17
|
+
|
18
|
+
**v0.0.3 - 21/10/14**
|
19
|
+
|
20
|
+
* Support for keyword spotting configuration
|
21
|
+
* Support reconfiguring of Decoder / Recognizer
|
22
|
+
* Fix CPU usage bug in `Microphone#read_audio_delay`
|
23
|
+
* Fix bug in `Configuration` float value type checking
|
24
|
+
|
25
|
+
|
26
|
+
**v0.0.2 - 20/10/14**
|
27
|
+
|
28
|
+
* Support for decoding raw audio files as well as live audio
|
29
|
+
|
30
|
+
|
31
|
+
**v0.0.1**
|
32
|
+
|
33
|
+
Initial release
|
data/lib/pocketsphinx.rb
CHANGED
@@ -21,6 +21,7 @@ module Pocketsphinx
|
|
21
21
|
attach_function :cmd_ln_set_str_r, [:pointer, :string, :string], :void
|
22
22
|
attach_function :err_set_debug_level, [:int], :int
|
23
23
|
attach_function :err_set_logfile, [:string], :int
|
24
|
+
attach_function :err_set_logfp, [:pointer], :void
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
@@ -1,14 +1,6 @@
|
|
1
1
|
module Pocketsphinx
|
2
|
-
# Implements Recordable interface (#
|
2
|
+
# Implements Recordable interface (#start_recording, #stop_recording and #read_audio)
|
3
3
|
class AudioFile < Struct.new(:file_path)
|
4
|
-
def record
|
5
|
-
File.open(file_path, 'rb') do |file|
|
6
|
-
self.file = file
|
7
|
-
yield
|
8
|
-
self.file = nil
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
4
|
# Read next block of audio samples from file; up to max samples into buffer.
|
13
5
|
#
|
14
6
|
# @param [FFI::Pointer] buffer 16bit buffer of at least max_samples in size
|
@@ -16,7 +8,7 @@ module Pocketsphinx
|
|
16
8
|
# @return [Fixnum] Samples actually read; nil if EOF
|
17
9
|
def read_audio(buffer, max_samples = 4096)
|
18
10
|
if file.nil?
|
19
|
-
raise "Can't read audio: use AudioFile#
|
11
|
+
raise "Can't read audio: use AudioFile#start_recording to open the file first"
|
20
12
|
end
|
21
13
|
|
22
14
|
if data = file.read(max_samples * 2)
|
@@ -25,6 +17,17 @@ module Pocketsphinx
|
|
25
17
|
end
|
26
18
|
end
|
27
19
|
|
20
|
+
def start_recording
|
21
|
+
self.file = File.open(file_path, 'rb')
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop_recording
|
25
|
+
if file
|
26
|
+
file.close
|
27
|
+
self.file = nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
28
31
|
private
|
29
32
|
|
30
33
|
attr_accessor :file
|
@@ -48,7 +48,7 @@ module Pocketsphinx
|
|
48
48
|
when :boolean
|
49
49
|
API::Sphinxbase.cmd_ln_int_r(ps_config, "-#{name}") != 0
|
50
50
|
when :string_list
|
51
|
-
raise
|
51
|
+
raise NotImplementedError
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -66,7 +66,7 @@ module Pocketsphinx
|
|
66
66
|
when :boolean
|
67
67
|
API::Sphinxbase.cmd_ln_set_int_r(ps_config, "-#{name}", value ? 1 : 0)
|
68
68
|
when :string_list
|
69
|
-
raise
|
69
|
+
raise NotImplementedError
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -6,7 +6,7 @@ module Pocketsphinx
|
|
6
6
|
def initialize(*args, &block)#(grammar_path = nil)
|
7
7
|
super()
|
8
8
|
|
9
|
-
@grammar = ::Grammar::Jsgf.new(*args, &block)
|
9
|
+
@grammar = Pocketsphinx::Grammar::Jsgf.new(*args, &block)
|
10
10
|
end
|
11
11
|
|
12
12
|
# Since JSGF strings are not supported in Pocketsphinx configuration (only files),
|
data/lib/pocketsphinx/decoder.rb
CHANGED
@@ -1,7 +1,18 @@
|
|
1
1
|
module Pocketsphinx
|
2
2
|
class Decoder < Struct.new(:configuration)
|
3
|
+
require 'delegate'
|
4
|
+
|
3
5
|
include API::CallHelpers
|
4
6
|
|
7
|
+
class Hypothesis < SimpleDelegator
|
8
|
+
attr_accessor :path_score, :utterance_id
|
9
|
+
|
10
|
+
def initialize(string, path_score, utterance_id)
|
11
|
+
@path_score, @utterance_id = path_score, utterance_id
|
12
|
+
super(string)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
5
16
|
attr_writer :ps_api
|
6
17
|
|
7
18
|
# Reinitialize the decoder with updated configuration.
|
@@ -85,12 +96,20 @@ module Pocketsphinx
|
|
85
96
|
ps_api.ps_get_in_speech(ps_decoder) != 0
|
86
97
|
end
|
87
98
|
|
88
|
-
# Get hypothesis string and
|
99
|
+
# Get hypothesis string (with #path_score and #utterance_id).
|
89
100
|
#
|
90
|
-
# @return [
|
91
|
-
# @todo Expand to return path score and utterance ID
|
101
|
+
# @return [Hypothesis] Hypothesis (behaves like a string)
|
92
102
|
def hypothesis
|
93
|
-
|
103
|
+
mp_path_score = FFI::MemoryPointer.new(:int32, 1)
|
104
|
+
mp_utterance_id = FFI::MemoryPointer.new(:pointer, 1)
|
105
|
+
|
106
|
+
hypothesis = ps_api.ps_get_hyp(ps_decoder, mp_path_score, mp_utterance_id)
|
107
|
+
|
108
|
+
hypothesis.nil? ? nil : Hypothesis.new(
|
109
|
+
hypothesis,
|
110
|
+
mp_path_score.get_int32(0),
|
111
|
+
mp_utterance_id.read_pointer.read_string.force_encoding('UTF-8')
|
112
|
+
)
|
94
113
|
end
|
95
114
|
|
96
115
|
# Adds new search using JSGF model.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Pocketsphinx
|
2
2
|
# Provides non-blocking live audio recording using libsphinxad
|
3
3
|
#
|
4
|
-
# Implements Recordable interface (#
|
4
|
+
# Implements Recordable interface (#start_recording, #stop_recording and #read_audio)
|
5
5
|
class Microphone
|
6
6
|
include API::CallHelpers
|
7
7
|
|
@@ -3,11 +3,13 @@ module Pocketsphinx
|
|
3
3
|
#
|
4
4
|
# Essentially orchestrates interaction between Recordable and Decoder, and detects new utterances.
|
5
5
|
class SpeechRecognizer
|
6
|
-
# Recordable interface must implement #
|
6
|
+
# Recordable interface must implement #start_recording, #stop_recording and #read_audio
|
7
7
|
attr_writer :recordable
|
8
8
|
attr_writer :decoder
|
9
9
|
attr_writer :configuration
|
10
10
|
|
11
|
+
ALGORITHMS = [:after_speech, :continuous]
|
12
|
+
|
11
13
|
def initialize(configuration = nil)
|
12
14
|
@configuration = configuration
|
13
15
|
end
|
@@ -33,39 +35,28 @@ module Pocketsphinx
|
|
33
35
|
def reconfigure(configuration = nil)
|
34
36
|
self.configuration = configuration if configuration
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
+
pause do
|
39
|
+
decoder.reconfigure(configuration)
|
40
|
+
end
|
38
41
|
end
|
39
42
|
|
40
|
-
# Recognize
|
41
|
-
#
|
42
|
-
# Splits speech into utterances by detecting silence between them.
|
43
|
-
# By default this uses Pocketsphinx's internal Voice Activity Detection (VAD) which can be
|
44
|
-
# configured by adjusting the `vad_postspeech`, `vad_prespeech`, and `vad_threshold` settings.
|
43
|
+
# Recognize speech and yield hypotheses in infinite loop
|
45
44
|
#
|
46
45
|
# @param [Fixnum] max_samples Number of samples to process at a time
|
47
|
-
def recognize(max_samples = 4096)
|
48
|
-
|
49
|
-
|
46
|
+
def recognize(max_samples = 4096, &b)
|
47
|
+
unless ALGORITHMS.include?(algorithm)
|
48
|
+
raise NotImplementedError, "Unknown speech recognition algorithm: #{algorithm}"
|
49
|
+
end
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
process_audio(buffer, max_samples) or break
|
57
|
-
end
|
58
|
-
|
59
|
-
hypothesis = get_hypothesis
|
60
|
-
yield hypothesis if hypothesis
|
61
|
-
else
|
62
|
-
process_audio(buffer, max_samples) or break
|
63
|
-
end
|
64
|
-
end
|
51
|
+
start unless recognizing?
|
52
|
+
|
53
|
+
FFI::MemoryPointer.new(:int16, max_samples) do |buffer|
|
54
|
+
loop do
|
55
|
+
send("recognize_#{algorithm}", max_samples, buffer, &b) or break
|
65
56
|
end
|
66
57
|
end
|
67
58
|
ensure
|
68
|
-
|
59
|
+
stop
|
69
60
|
end
|
70
61
|
|
71
62
|
def in_speech?
|
@@ -77,8 +68,73 @@ module Pocketsphinx
|
|
77
68
|
@recognizing == true
|
78
69
|
end
|
79
70
|
|
71
|
+
def pause
|
72
|
+
recognizing?.tap do |was_recognizing|
|
73
|
+
stop if was_recognizing
|
74
|
+
yield
|
75
|
+
start if was_recognizing
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def start
|
80
|
+
recordable.start_recording
|
81
|
+
decoder.start_utterance
|
82
|
+
@recognizing = true
|
83
|
+
end
|
84
|
+
|
85
|
+
def stop
|
86
|
+
decoder.end_utterance
|
87
|
+
recordable.stop_recording
|
88
|
+
@recognizing = false
|
89
|
+
end
|
90
|
+
|
91
|
+
# Determine which algorithm to use for co-ordinating speech recognition
|
92
|
+
#
|
93
|
+
# @return [Symbol] :continuous or :after_speech
|
94
|
+
# :continuous yields as soon as any hypothesis is available
|
95
|
+
# :after_speech yields hypothesis on speech -> silence transition if one exists
|
96
|
+
# Default is :after_speech
|
97
|
+
def algorithm
|
98
|
+
if configuration.respond_to?(:recognition_algorithm)
|
99
|
+
configuration.recognition_algorithm
|
100
|
+
else
|
101
|
+
ALGORITHMS.first
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
80
105
|
private
|
81
106
|
|
107
|
+
# Yields as soon as any hypothesis is available
|
108
|
+
def recognize_continuous(max_samples, buffer)
|
109
|
+
process_audio(buffer, max_samples).tap do
|
110
|
+
if hypothesis = decoder.hypothesis
|
111
|
+
yield hypothesis
|
112
|
+
|
113
|
+
decoder.end_utterance
|
114
|
+
decoder.start_utterance
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Splits speech into utterances by detecting silence between them.
|
120
|
+
# By default this uses Pocketsphinx's internal Voice Activity Detection (VAD) which can be
|
121
|
+
# configured by adjusting the `vad_postspeech`, `vad_prespeech`, and `vad_threshold` settings.
|
122
|
+
def recognize_after_speech(max_samples, buffer)
|
123
|
+
if in_speech?
|
124
|
+
while in_speech?
|
125
|
+
process_audio(buffer, max_samples) or break
|
126
|
+
end
|
127
|
+
|
128
|
+
decoder.end_utterance
|
129
|
+
hypothesis = decoder.hypothesis
|
130
|
+
decoder.start_utterance
|
131
|
+
|
132
|
+
yield hypothesis if hypothesis
|
133
|
+
end
|
134
|
+
|
135
|
+
process_audio(buffer, max_samples)
|
136
|
+
end
|
137
|
+
|
82
138
|
def process_audio(buffer, max_samples)
|
83
139
|
sample_count = recordable.read_audio(buffer, max_samples)
|
84
140
|
|
@@ -93,13 +149,5 @@ module Pocketsphinx
|
|
93
149
|
|
94
150
|
sample_count
|
95
151
|
end
|
96
|
-
|
97
|
-
# Called on speech -> silence transition
|
98
|
-
def get_hypothesis
|
99
|
-
decoder.end_utterance
|
100
|
-
decoder.hypothesis.tap do
|
101
|
-
decoder.start_utterance
|
102
|
-
end
|
103
|
-
end
|
104
152
|
end
|
105
153
|
end
|
data/lib/pocketsphinx/version.rb
CHANGED
data/pocketsphinx-ruby.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Pocketsphinx::VERSION
|
9
9
|
spec.authors = ["Howard Wilson"]
|
10
10
|
spec.email = ["howard@watsonbox.net"]
|
11
|
-
spec.summary = %q{Ruby
|
12
|
-
spec.description = %q{Ruby FFI
|
11
|
+
spec.summary = %q{Ruby speech recognition with Pocketsphinx}
|
12
|
+
spec.description = %q{Provides Ruby FFI bindings for Pocketsphinx, a lightweight speech recognition engine.}
|
13
13
|
spec.homepage = "https://github.com/watsonbox/pocketsphinx-ruby"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
data/spec/configuration_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Configuration do
|
3
|
+
describe Pocketsphinx::Configuration do
|
4
4
|
subject { Pocketsphinx::Configuration.default }
|
5
5
|
|
6
6
|
it "provides a default pocketsphinx configuration" do
|
@@ -46,6 +46,15 @@ describe Configuration do
|
|
46
46
|
expect { subject['smoothspec'] = nil }.to raise_exception "Only string settings can be set to nil"
|
47
47
|
end
|
48
48
|
|
49
|
+
it "does not support string lists" do
|
50
|
+
subject.setting_definitions['string_list_setting'] = Pocketsphinx::Configuration::SettingDefinition.new(
|
51
|
+
'string_list_setting', 32, nil, nil
|
52
|
+
)
|
53
|
+
|
54
|
+
expect { subject['string_list_setting'] }.to raise_exception NotImplementedError
|
55
|
+
expect { subject['string_list_setting'] = 'value' }.to raise_exception NotImplementedError
|
56
|
+
end
|
57
|
+
|
49
58
|
it 'raises exceptions when setting with incorrectly typed values' do
|
50
59
|
expect { subject['frate'] = true }.to raise_exception "Configuration setting 'frate' must be of type Integer"
|
51
60
|
end
|
@@ -88,7 +97,7 @@ describe Configuration do
|
|
88
97
|
end
|
89
98
|
|
90
99
|
context 'keyword spotting configuration' do
|
91
|
-
subject { Configuration::KeywordSpotting.new('Okay computer') }
|
100
|
+
subject { Pocketsphinx::Configuration::KeywordSpotting.new('Okay computer') }
|
92
101
|
|
93
102
|
it 'modifies the default configuration keyphrase and language model' do
|
94
103
|
changes = subject.changes
|
data/spec/decoder_spec.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Decoder do
|
4
|
-
subject { Decoder.new(configuration) }
|
3
|
+
describe Pocketsphinx::Decoder do
|
4
|
+
subject { Pocketsphinx::Decoder.new(configuration) }
|
5
5
|
let(:ps_api) { subject.ps_api }
|
6
6
|
let(:ps_decoder) { double }
|
7
|
-
let(:configuration) { Configuration.default }
|
7
|
+
let(:configuration) { Pocketsphinx::Configuration.default }
|
8
8
|
|
9
9
|
before do
|
10
10
|
subject.ps_api = double
|
@@ -132,11 +132,22 @@ describe Decoder do
|
|
132
132
|
describe '#hypothesis' do
|
133
133
|
it 'calls libpocketsphinx' do
|
134
134
|
expect(ps_api)
|
135
|
-
.to receive(:ps_get_hyp)
|
136
|
-
|
137
|
-
|
135
|
+
.to receive(:ps_get_hyp) do |ps_decoder, mp_path_score, mp_utterance_id|
|
136
|
+
expect(ps_decoder).to eq(subject.ps_decoder)
|
137
|
+
expect(mp_path_score).to be_a(FFI::MemoryPointer)
|
138
|
+
expect(mp_utterance_id).to be_a(FFI::MemoryPointer)
|
138
139
|
|
139
|
-
|
140
|
+
mp_path_score.put_int32(0, 20)
|
141
|
+
mp_utterance_id.write_pointer(FFI::MemoryPointer.from_string("Utterance"))
|
142
|
+
|
143
|
+
"Hypothesis"
|
144
|
+
end
|
145
|
+
|
146
|
+
hypothesis = subject.hypothesis
|
147
|
+
|
148
|
+
expect(hypothesis).to eq("Hypothesis")
|
149
|
+
expect(hypothesis.path_score).to eq(20)
|
150
|
+
expect(hypothesis.utterance_id).to eq("Utterance")
|
140
151
|
end
|
141
152
|
end
|
142
153
|
|
data/spec/grammar_spec.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Grammar::Jsgf do
|
3
|
+
describe Pocketsphinx::Grammar::Jsgf do
|
4
4
|
it "raises an exception when neither a file or block are given" do
|
5
|
-
expect { Grammar::Jsgf.new }.to raise_exception "Either a path or block is required to create a JSGF grammar"
|
5
|
+
expect { Pocketsphinx::Grammar::Jsgf.new }.to raise_exception "Either a path or block is required to create a JSGF grammar"
|
6
6
|
end
|
7
7
|
|
8
8
|
context "reading a grammar from a file" do
|
9
9
|
let(:grammar_path) { grammar :goforward }
|
10
|
-
subject { Grammar::Jsgf.new(grammar_path) }
|
10
|
+
subject { Pocketsphinx::Grammar::Jsgf.new(grammar_path) }
|
11
11
|
|
12
12
|
it "reads a grammar from a file" do
|
13
13
|
expect(subject.raw.lines.count).to eq(15)
|
@@ -24,7 +24,7 @@ describe Grammar::Jsgf do
|
|
24
24
|
|
25
25
|
context "building a grammer from a block" do
|
26
26
|
subject do
|
27
|
-
Grammar::Jsgf.new do
|
27
|
+
Pocketsphinx::Grammar::Jsgf.new do
|
28
28
|
sentence "Go forward ten meters"
|
29
29
|
sentence "Go backward ten meters"
|
30
30
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Decoder do
|
3
|
+
describe Pocketsphinx::Decoder do
|
4
4
|
subject { @decoder }
|
5
5
|
let(:configuration) { @configuration }
|
6
6
|
|
7
7
|
# Share decoder across all examples for speed
|
8
8
|
before :all do
|
9
|
-
@configuration = Configuration.default
|
10
|
-
@decoder = Decoder.new(@configuration)
|
9
|
+
@configuration = Pocketsphinx::Configuration.default
|
10
|
+
@decoder = Pocketsphinx::Decoder.new(@configuration)
|
11
11
|
end
|
12
12
|
|
13
13
|
describe '#decode' do
|
@@ -2,14 +2,14 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe 'speech recognition with default configuration' do
|
4
4
|
subject do
|
5
|
-
AudioFileSpeechRecognizer.new.tap do |speech_recognizer|
|
5
|
+
Pocketsphinx::AudioFileSpeechRecognizer.new.tap do |speech_recognizer|
|
6
6
|
speech_recognizer.decoder = @decoder
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
# Share decoder across all examples for speed
|
11
11
|
before :all do
|
12
|
-
@decoder = Decoder.new(Configuration.default)
|
12
|
+
@decoder = Pocketsphinx::Decoder.new(Pocketsphinx::Configuration.default)
|
13
13
|
end
|
14
14
|
|
15
15
|
describe '#recognize' do
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'speech recognition with a grammar' do
|
4
|
-
let(:recordable) { AudioFile.new('spec/assets/audio/goforward.raw') }
|
4
|
+
let(:recordable) { Pocketsphinx::AudioFile.new('spec/assets/audio/goforward.raw') }
|
5
5
|
|
6
6
|
subject do
|
7
|
-
SpeechRecognizer.new.tap do |speech_recognizer|
|
7
|
+
Pocketsphinx::SpeechRecognizer.new(@configuration).tap do |speech_recognizer|
|
8
8
|
speech_recognizer.recordable = recordable
|
9
9
|
speech_recognizer.decoder = @decoder
|
10
10
|
end
|
@@ -12,8 +12,8 @@ describe 'speech recognition with a grammar' do
|
|
12
12
|
|
13
13
|
# Share decoder across all examples for speed
|
14
14
|
before :all do
|
15
|
-
@configuration = Configuration::Grammar.new('spec/assets/grammars/goforward.gram')
|
16
|
-
@decoder = Decoder.new(@configuration)
|
15
|
+
@configuration = Pocketsphinx::Configuration::Grammar.new('spec/assets/grammars/goforward.gram')
|
16
|
+
@decoder = Pocketsphinx::Decoder.new(@configuration)
|
17
17
|
end
|
18
18
|
|
19
19
|
describe '#recognize' do
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Keyword spotting recognizes keywords mid-speech, not only after a speech -> silence transition
|
4
|
+
describe 'keyword spotting' do
|
5
|
+
let(:recordable) { Pocketsphinx::AudioFile.new('spec/assets/audio/goforward.raw') }
|
6
|
+
|
7
|
+
subject do
|
8
|
+
Pocketsphinx::SpeechRecognizer.new(@configuration).tap do |speech_recognizer|
|
9
|
+
speech_recognizer.recordable = recordable
|
10
|
+
speech_recognizer.decoder = @decoder
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Share decoder across all examples for speed
|
15
|
+
before :all do
|
16
|
+
@configuration = Pocketsphinx::Configuration::KeywordSpotting.new('forward')
|
17
|
+
@decoder = Pocketsphinx::Decoder.new(@configuration)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#recognize' do
|
21
|
+
it 'should decode speech in raw audio' do
|
22
|
+
expect { |b| subject.recognize(4096, &b) }.to yield_with_args('forward')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Pocketsphinx::LiveSpeechRecognizer do
|
4
|
+
it 'uses the microphone for audio input' do
|
5
|
+
expect(Pocketsphinx::Microphone).to receive(:new).and_return(:microphone)
|
6
|
+
expect(Pocketsphinx::LiveSpeechRecognizer.new.recordable).to eq(:microphone)
|
7
|
+
end
|
8
|
+
end
|
data/spec/microphone_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Microphone do
|
3
|
+
describe Pocketsphinx::Microphone do
|
4
4
|
module DummyAPI
|
5
5
|
def self.ad_open_dev(default_device, sample_rate)
|
6
6
|
:audio_device
|
@@ -13,7 +13,7 @@ describe Microphone do
|
|
13
13
|
# Share microphone across all examples for speed
|
14
14
|
before :all do
|
15
15
|
# Don't open an audio device as there isn't one on Travis CI
|
16
|
-
@microphone = Microphone.new(16000, nil, DummyAPI)
|
16
|
+
@microphone = Pocketsphinx::Microphone.new(16000, nil, DummyAPI)
|
17
17
|
end
|
18
18
|
|
19
19
|
describe '#start_recording' do
|
data/spec/spec_helper.rb
CHANGED
@@ -11,8 +11,6 @@ FileUtils.touch POCKETSPHINX_LOG_FILE
|
|
11
11
|
Pocketsphinx::API::Sphinxbase.err_set_logfile POCKETSPHINX_LOG_FILE
|
12
12
|
|
13
13
|
RSpec.configure do |config|
|
14
|
-
include Pocketsphinx
|
15
|
-
|
16
14
|
# rspec-expectations config goes here. You can use an alternate
|
17
15
|
# assertion/expectation library such as wrong or the stdlib/minitest
|
18
16
|
# assertions if you prefer.
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe SpeechRecognizer do
|
3
|
+
describe Pocketsphinx::SpeechRecognizer do
|
4
4
|
let(:configuration) { double }
|
5
5
|
let(:recordable) { double }
|
6
6
|
let(:decoder) { double }
|
7
|
-
subject { SpeechRecognizer.new(configuration) }
|
7
|
+
subject { Pocketsphinx::SpeechRecognizer.new(configuration) }
|
8
8
|
|
9
9
|
before do
|
10
10
|
subject.decoder = decoder
|
@@ -30,9 +30,13 @@ describe SpeechRecognizer do
|
|
30
30
|
subject.reconfigure(:new_configuration)
|
31
31
|
end
|
32
32
|
|
33
|
-
it 'restarts
|
34
|
-
|
35
|
-
|
33
|
+
it 'restarts recognition if it was interrupted' do
|
34
|
+
allow(subject).to receive(:recognizing?).and_return(true)
|
35
|
+
|
36
|
+
expect(decoder).to receive(:end_utterance).ordered
|
37
|
+
expect(recordable).to receive(:stop_recording).ordered
|
38
|
+
expect(recordable).to receive(:start_recording).ordered
|
39
|
+
expect(decoder).to receive(:start_utterance).ordered
|
36
40
|
|
37
41
|
subject.reconfigure
|
38
42
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pocketsphinx-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Howard Wilson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -80,7 +80,8 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
description: Ruby FFI
|
83
|
+
description: Provides Ruby FFI bindings for Pocketsphinx, a lightweight speech recognition
|
84
|
+
engine.
|
84
85
|
email:
|
85
86
|
- howard@watsonbox.net
|
86
87
|
executables: []
|
@@ -90,6 +91,7 @@ files:
|
|
90
91
|
- ".gitignore"
|
91
92
|
- ".rspec"
|
92
93
|
- ".travis.yml"
|
94
|
+
- CHANGELOG.md
|
93
95
|
- Gemfile
|
94
96
|
- LICENSE.txt
|
95
97
|
- README.md
|
@@ -129,6 +131,8 @@ files:
|
|
129
131
|
- spec/integration/decoder_spec.rb
|
130
132
|
- spec/integration/default_recognition_spec.rb
|
131
133
|
- spec/integration/grammar_recognition_spec.rb
|
134
|
+
- spec/integration/keyword_recognition_spec.rb
|
135
|
+
- spec/live_speech_recognizer_spec.rb
|
132
136
|
- spec/microphone_spec.rb
|
133
137
|
- spec/spec_helper.rb
|
134
138
|
- spec/speech_recognizer_spec.rb
|
@@ -155,7 +159,7 @@ rubyforge_project:
|
|
155
159
|
rubygems_version: 2.2.2
|
156
160
|
signing_key:
|
157
161
|
specification_version: 4
|
158
|
-
summary: Ruby
|
162
|
+
summary: Ruby speech recognition with Pocketsphinx
|
159
163
|
test_files:
|
160
164
|
- spec/assets/audio/goforward.raw
|
161
165
|
- spec/assets/grammars/goforward.gram
|
@@ -167,6 +171,8 @@ test_files:
|
|
167
171
|
- spec/integration/decoder_spec.rb
|
168
172
|
- spec/integration/default_recognition_spec.rb
|
169
173
|
- spec/integration/grammar_recognition_spec.rb
|
174
|
+
- spec/integration/keyword_recognition_spec.rb
|
175
|
+
- spec/live_speech_recognizer_spec.rb
|
170
176
|
- spec/microphone_spec.rb
|
171
177
|
- spec/spec_helper.rb
|
172
178
|
- spec/speech_recognizer_spec.rb
|