pocketsphinx-ruby 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|