pocketsphinx-ruby 0.0.3 → 0.1.0
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/README.md +45 -7
 - data/lib/pocketsphinx.rb +7 -1
 - data/lib/pocketsphinx/api/call_helpers.rb +16 -0
 - data/lib/pocketsphinx/api/pocketsphinx.rb +4 -0
 - data/lib/pocketsphinx/configuration/default.rb +10 -0
 - data/lib/pocketsphinx/configuration/grammar.rb +21 -0
 - data/lib/pocketsphinx/decoder.rb +58 -15
 - data/lib/pocketsphinx/grammar/jsgf.rb +37 -0
 - data/lib/pocketsphinx/grammar/jsgf_builder.rb +27 -0
 - data/lib/pocketsphinx/microphone.rb +4 -10
 - data/lib/pocketsphinx/version.rb +1 -1
 - data/spec/assets/grammars/goforward.gram +15 -0
 - data/spec/assets/grammars/invalid.gram +1 -0
 - data/spec/assets/grammars/sentences.gram +5 -0
 - data/spec/configuration_spec.rb +9 -5
 - data/spec/decoder_spec.rb +77 -1
 - data/spec/grammar_spec.rb +43 -0
 - data/spec/integration/default_recognition_spec.rb +21 -0
 - data/spec/integration/{speech_recognizer_spec.rb → grammar_recognition_spec.rb} +4 -3
 - metadata +18 -4
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: d3479a20de1bf075e2a4d2efcf8721c05a650751
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: a3ea68aaf9e0dc60149c2992dd8316233d8568f3
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: e732d04275721ed223776c7d90b97894e8a778e73e334a036561715efbf868b65e8b20809730013fcaf020f21ab5de2fa646af6b7bc7aeb2f467345b6492f33e
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: a6670826d281b272ea29d4d609805328d2da8af4753d66349e78f222c5c99eaf05a7dde19faad8ac070b57e03aacab20396c5686c8b7365e4d586591bc958add
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -56,7 +56,7 @@ Or install it yourself as: 
     | 
|
| 
       56 
56 
     | 
    
         
             
            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:
         
     | 
| 
       57 
57 
     | 
    
         | 
| 
       58 
58 
     | 
    
         
             
            ```ruby
         
     | 
| 
       59 
     | 
    
         
            -
            require 'pocketsphinx-ruby'
         
     | 
| 
      
 59 
     | 
    
         
            +
            require 'pocketsphinx-ruby' # Omitted in subsequent examples
         
     | 
| 
       60 
60 
     | 
    
         | 
| 
       61 
61 
     | 
    
         
             
            Pocketsphinx::LiveSpeechRecognizer.new.recognize do |speech|
         
     | 
| 
       62 
62 
     | 
    
         
             
              puts speech
         
     | 
| 
         @@ -106,7 +106,7 @@ The `Microphone` class uses Pocketsphinx's libsphinxad to record audio for speec 
     | 
|
| 
       106 
106 
     | 
    
         
             
            For example, to record and save a 5 second raw audio file:
         
     | 
| 
       107 
107 
     | 
    
         | 
| 
       108 
108 
     | 
    
         
             
            ```ruby
         
     | 
| 
       109 
     | 
    
         
            -
            microphone = Microphone.new
         
     | 
| 
      
 109 
     | 
    
         
            +
            microphone = Pocketsphinx::Microphone.new
         
     | 
| 
       110 
110 
     | 
    
         | 
| 
       111 
111 
     | 
    
         
             
            File.open("test.raw", "wb") do |file|
         
     | 
| 
       112 
112 
     | 
    
         
             
              microphone.record do
         
     | 
| 
         @@ -130,7 +130,7 @@ To open this audio file take a look at [this wiki page](https://github.com/watso 
     | 
|
| 
       130 
130 
     | 
    
         
             
            The `Decoder` class uses Pocketsphinx's libpocketsphinx to decode audio data into text. For example to decode a single utterance:
         
     | 
| 
       131 
131 
     | 
    
         | 
| 
       132 
132 
     | 
    
         
             
            ```ruby
         
     | 
| 
       133 
     | 
    
         
            -
            decoder = Decoder.new(Configuration.default)
         
     | 
| 
      
 133 
     | 
    
         
            +
            decoder = Pocketsphinx::Decoder.new(Pocketsphinx::Configuration.default)
         
     | 
| 
       134 
134 
     | 
    
         
             
            decoder.decode 'spec/assets/audio/goforward.raw'
         
     | 
| 
       135 
135 
     | 
    
         | 
| 
       136 
136 
     | 
    
         
             
            puts decoder.hypothesis # => "go forward ten years"
         
     | 
| 
         @@ -142,16 +142,54 @@ puts decoder.hypothesis # => "go forward ten years" 
     | 
|
| 
       142 
142 
     | 
    
         
             
            Keyword spotting is another feature that is not in the current stable (0.8) releases of Pocketsphinx, having been [merged into trunk](https://github.com/cmusphinx/pocketsphinx/commit/f562f9356cc7f1ade4941ebdde0c377642a023e3) early in 2014. In can be useful for detecting an activation keyword in a command and control application, while ignoring all other speech. Set up a recognizer as follows:
         
     | 
| 
       143 
143 
     | 
    
         | 
| 
       144 
144 
     | 
    
         
             
            ```ruby
         
     | 
| 
       145 
     | 
    
         
            -
            configuration = Configuration::KeywordSpotting.new('Okay computer')
         
     | 
| 
       146 
     | 
    
         
            -
            recognizer = LiveSpeechRecognizer.new(configuration)
         
     | 
| 
      
 145 
     | 
    
         
            +
            configuration = Pocketsphinx::Configuration::KeywordSpotting.new('Okay computer')
         
     | 
| 
      
 146 
     | 
    
         
            +
            recognizer = Pocketsphinx::LiveSpeechRecognizer.new(configuration)
         
     | 
| 
       147 
147 
     | 
    
         
             
            ```
         
     | 
| 
       148 
148 
     | 
    
         | 
| 
       149 
     | 
    
         
            -
            The `KeywordSpotting` configuration accepts a second argument for adjusting the sensitivity of the keyword detection. Note that this is just a wrapper which sets the `keyphrase` and `kws_threshold` settings on the default configuration 
     | 
| 
      
 149 
     | 
    
         
            +
            The `KeywordSpotting` configuration accepts a second argument for adjusting the sensitivity of the keyword detection. Note that this is just a wrapper which sets the `keyphrase` and `kws_threshold` settings on the default configuration:
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 152 
     | 
    
         
            +
            Pocketsphinx::Configuration::KeywordSpotting.new('keyword', 2).changes
         
     | 
| 
      
 153 
     | 
    
         
            +
            # => [
         
     | 
| 
      
 154 
     | 
    
         
            +
            #   { :name => "keyphrase", :type => :string, :default => nil, :required => false, :value => "keyword", :info => "Keyphrase to spot" },
         
     | 
| 
      
 155 
     | 
    
         
            +
            #   { :name => "kws_threshold", :type => :float, :default => 1.0, :required => false, :value => 2.0, :info => "Threshold for p(hyp)/p(alternatives) ratio" },
         
     | 
| 
      
 156 
     | 
    
         
            +
            #   { :name => "lm", :type => :string, :default => "/usr/local/Cellar/cmu-pocketsphinx/HEAD/share/pocketsphinx/model/lm/en_US/hub4.5000.DMP", :required => false, :value => nil, :info => "Word trigram language model input file" }
         
     | 
| 
      
 157 
     | 
    
         
            +
            # ]
         
     | 
| 
      
 158 
     | 
    
         
            +
            ```
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
            ### Grammars
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
            Another way of configuring Pocketsphinx is with a grammar, which is normally used to describe very simple types of languages for command and control. Restricting the set of possible utterances in this way can greatly improve recognition accuracy for these types of application.
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
            Load a [JSGF](http://www.w3.org/TR/jsgf/) grammar from a file:
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 168 
     | 
    
         
            +
            configuration = Pocketsphinx::Configuration::Grammar.new('sentences.gram')
         
     | 
| 
      
 169 
     | 
    
         
            +
            ```
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            Or build one dynamically with this simple DSL (currently only supports sentence lists):
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 174 
     | 
    
         
            +
            configuration = Pocketsphinx::Configuration::Grammar.new do
         
     | 
| 
      
 175 
     | 
    
         
            +
              sentence "Go forward ten meters"
         
     | 
| 
      
 176 
     | 
    
         
            +
              sentence "Go backward ten meters"
         
     | 
| 
      
 177 
     | 
    
         
            +
            end
         
     | 
| 
      
 178 
     | 
    
         
            +
            ```
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
            ## Troubleshooting
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
            This gem has been tested with a manual Pocketsphinx installation on Ubuntu 14.04 and a Homebrew Pocketsphinx installation on OSX 10.9.4 Mavericks. Take a look at the following common problems before opening an issue.
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
            **`attach_function': Function 'ps_default_search_args' not found in [libpocketsphinx.so] (FFI::NotFoundError)**
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
            An error like this probably means that you have an old version of the Pocketsphinx libraries installed. If necessary, replace them with a recent development version which supports the features available in this gem.
         
     | 
| 
       150 
188 
     | 
    
         | 
| 
       151 
189 
     | 
    
         | 
| 
       152 
190 
     | 
    
         
             
            ## Contributing
         
     | 
| 
       153 
191 
     | 
    
         | 
| 
       154 
     | 
    
         
            -
            1. Fork it ( https://github.com/ 
     | 
| 
      
 192 
     | 
    
         
            +
            1. Fork it ( https://github.com/watsonbox/pocketsphinx-ruby/fork )
         
     | 
| 
       155 
193 
     | 
    
         
             
            2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
       156 
194 
     | 
    
         
             
            3. Commit your changes (`git commit -am 'Add some feature'`)
         
     | 
| 
       157 
195 
     | 
    
         
             
            4. Push to the branch (`git push origin my-new-feature`)
         
     | 
    
        data/lib/pocketsphinx.rb
    CHANGED
    
    | 
         @@ -6,12 +6,18 @@ require "pocketsphinx/version" 
     | 
|
| 
       6 
6 
     | 
    
         
             
            require "pocketsphinx/api/sphinxbase"
         
     | 
| 
       7 
7 
     | 
    
         
             
            require "pocketsphinx/api/sphinxad"
         
     | 
| 
       8 
8 
     | 
    
         
             
            require "pocketsphinx/api/pocketsphinx"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require "pocketsphinx/api/call_helpers"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            # Grammar
         
     | 
| 
      
 12 
     | 
    
         
            +
            require "pocketsphinx/grammar/jsgf"
         
     | 
| 
      
 13 
     | 
    
         
            +
            require "pocketsphinx/grammar/jsgf_builder"
         
     | 
| 
       9 
14 
     | 
    
         | 
| 
       10 
15 
     | 
    
         
             
            # Configuration
         
     | 
| 
       11 
     | 
    
         
            -
            require  
     | 
| 
      
 16 
     | 
    
         
            +
            require "pocketsphinx/configuration/setting_definition"
         
     | 
| 
       12 
17 
     | 
    
         
             
            require "pocketsphinx/configuration/base"
         
     | 
| 
       13 
18 
     | 
    
         
             
            require "pocketsphinx/configuration/default"
         
     | 
| 
       14 
19 
     | 
    
         
             
            require "pocketsphinx/configuration/keyword_spotting"
         
     | 
| 
      
 20 
     | 
    
         
            +
            require "pocketsphinx/configuration/grammar"
         
     | 
| 
       15 
21 
     | 
    
         | 
| 
       16 
22 
     | 
    
         
             
            require "pocketsphinx/audio_file"
         
     | 
| 
       17 
23 
     | 
    
         
             
            require "pocketsphinx/microphone"
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Pocketsphinx
         
     | 
| 
      
 2 
     | 
    
         
            +
              module API
         
     | 
| 
      
 3 
     | 
    
         
            +
                Error = Class.new(StandardError)
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                module CallHelpers
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def api_call(method, *args)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    calling_method = caller[0][/`.*'/][1..-2]
         
     | 
| 
      
 8 
     | 
    
         
            +
                    ps_api.send(method, *args).tap do |result|
         
     | 
| 
      
 9 
     | 
    
         
            +
                      if result < 0
         
     | 
| 
      
 10 
     | 
    
         
            +
                        raise Error, "#{self.class.to_s.split('::').last}##{calling_method} failed with error code #{result}"
         
     | 
| 
      
 11 
     | 
    
         
            +
                      end
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -17,6 +17,10 @@ module Pocketsphinx 
     | 
|
| 
       17 
17 
     | 
    
         
             
                  attach_function :ps_end_utt, [:decoder], :int
         
     | 
| 
       18 
18 
     | 
    
         
             
                  attach_function :ps_get_in_speech, [:decoder], :uint8
         
     | 
| 
       19 
19 
     | 
    
         
             
                  attach_function :ps_get_hyp, [:decoder, :pointer, :pointer], :string
         
     | 
| 
      
 20 
     | 
    
         
            +
                  attach_function :ps_set_jsgf_string, [:decoder, :string, :string], :int
         
     | 
| 
      
 21 
     | 
    
         
            +
                  attach_function :ps_unset_search, [:decoder, :string], :int
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attach_function :ps_get_search, [:decoder], :string
         
     | 
| 
      
 23 
     | 
    
         
            +
                  attach_function :ps_set_search, [:decoder, :string], :int
         
     | 
| 
       20 
24 
     | 
    
         
             
                end
         
     | 
| 
       21 
25 
     | 
    
         
             
              end
         
     | 
| 
       22 
26 
     | 
    
         
             
            end
         
     | 
| 
         @@ -7,6 +7,16 @@ module Pocketsphinx 
     | 
|
| 
       7 
7 
     | 
    
         
             
                    # Sets default grammar and language model if they are not set explicitly and
         
     | 
| 
       8 
8 
     | 
    
         
             
                    # are present in the default search path.
         
     | 
| 
       9 
9 
     | 
    
         
             
                    API::Pocketsphinx.ps_default_search_args(@ps_config)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    # Treat ps_default_search_args settings as defaults
         
     | 
| 
      
 12 
     | 
    
         
            +
                    changes.each do |details|
         
     | 
| 
      
 13 
     | 
    
         
            +
                      setting_definitions[details[:name]].deflt = details[:value]
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  # Show details for settings which don't match Pocketsphinx defaults
         
     | 
| 
      
 18 
     | 
    
         
            +
                  def changes
         
     | 
| 
      
 19 
     | 
    
         
            +
                    details.reject { |d| d[:default] == d[:value] }
         
     | 
| 
       10 
20 
     | 
    
         
             
                  end
         
     | 
| 
       11 
21 
     | 
    
         
             
                end
         
     | 
| 
       12 
22 
     | 
    
         | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Pocketsphinx
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Configuration
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Grammar < Default
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :grammar
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(*args, &block)#(grammar_path = nil)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    super()
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    @grammar = ::Grammar::Jsgf.new(*args, &block)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  # Since JSGF strings are not supported in Pocketsphinx configuration (only files),
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # we use the post_init_decoder hook to configure the JSGF
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def post_init_decoder(decoder)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    decoder.unset_search
         
     | 
| 
      
 16 
     | 
    
         
            +
                    decoder.set_jsgf_string(grammar.raw)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    decoder.set_search
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/pocketsphinx/decoder.rb
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Pocketsphinx
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Decoder < Struct.new(:configuration)
         
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
      
 3 
     | 
    
         
            +
                include API::CallHelpers
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
                attr_writer :ps_api
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
         @@ -13,10 +13,7 @@ module Pocketsphinx 
     | 
|
| 
       13 
13 
     | 
    
         
             
                #   nil, the previous configuration will be reloaded, with any changes applied.
         
     | 
| 
       14 
14 
     | 
    
         
             
                def reconfigure(configuration = nil)
         
     | 
| 
       15 
15 
     | 
    
         
             
                  self.configuration = configuration if configuration
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                  ps_api.ps_reinit(ps_decoder, self.configuration.ps_config).tap do |result|
         
     | 
| 
       18 
     | 
    
         
            -
                    raise Error, "Decoder#reconfigure failed with error code #{result}" if result < 0
         
     | 
| 
       19 
     | 
    
         
            -
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  reinit_decoder
         
     | 
| 
       20 
17 
     | 
    
         
             
                end
         
     | 
| 
       21 
18 
     | 
    
         | 
| 
       22 
19 
     | 
    
         
             
                # Decode a raw audio stream as a single utterance, opening a file if path given
         
     | 
| 
         @@ -64,9 +61,7 @@ module Pocketsphinx 
     | 
|
| 
       64 
61 
     | 
    
         
             
                #   worth of data.  This may allow the recognizer to produce more accurate results.
         
     | 
| 
       65 
62 
     | 
    
         
             
                # @return Number of frames of data searched
         
     | 
| 
       66 
63 
     | 
    
         
             
                def process_raw(buffer, size, no_search = false, full_utt = false)
         
     | 
| 
       67 
     | 
    
         
            -
                   
     | 
| 
       68 
     | 
    
         
            -
                    raise Error, "Decoder#process_raw failed with error code #{result}" if result < 0
         
     | 
| 
       69 
     | 
    
         
            -
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                  api_call :ps_process_raw, ps_decoder, buffer, size, no_search ? 1 : 0, full_utt ? 1 : 0
         
     | 
| 
       70 
65 
     | 
    
         
             
                end
         
     | 
| 
       71 
66 
     | 
    
         | 
| 
       72 
67 
     | 
    
         
             
                # Start utterance processing.
         
     | 
| 
         @@ -77,16 +72,12 @@ module Pocketsphinx 
     | 
|
| 
       77 
72 
     | 
    
         
             
                #
         
     | 
| 
       78 
73 
     | 
    
         
             
                # @param [String] name String uniquely identifying this utterance. If nil, one will be created.
         
     | 
| 
       79 
74 
     | 
    
         
             
                def start_utterance(name = nil)
         
     | 
| 
       80 
     | 
    
         
            -
                   
     | 
| 
       81 
     | 
    
         
            -
                    raise Error, "Decoder#start_utterance failed with error code #{result}" if result < 0
         
     | 
| 
       82 
     | 
    
         
            -
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                  api_call :ps_start_utt, ps_decoder, name
         
     | 
| 
       83 
76 
     | 
    
         
             
                end
         
     | 
| 
       84 
77 
     | 
    
         | 
| 
       85 
78 
     | 
    
         
             
                # End utterance processing
         
     | 
| 
       86 
79 
     | 
    
         
             
                def end_utterance
         
     | 
| 
       87 
     | 
    
         
            -
                   
     | 
| 
       88 
     | 
    
         
            -
                    raise Error, "Decoder#end_utterance failed with error code #{result}" if result < 0
         
     | 
| 
       89 
     | 
    
         
            -
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  api_call :ps_end_utt, ps_decoder
         
     | 
| 
       90 
81 
     | 
    
         
             
                end
         
     | 
| 
       91 
82 
     | 
    
         | 
| 
       92 
83 
     | 
    
         
             
                # Checks if the last feed audio buffer contained speech
         
     | 
| 
         @@ -102,12 +93,64 @@ module Pocketsphinx 
     | 
|
| 
       102 
93 
     | 
    
         
             
                  ps_api.ps_get_hyp(ps_decoder, nil, nil)
         
     | 
| 
       103 
94 
     | 
    
         
             
                end
         
     | 
| 
       104 
95 
     | 
    
         | 
| 
      
 96 
     | 
    
         
            +
                # Adds new search using JSGF model.
         
     | 
| 
      
 97 
     | 
    
         
            +
                #
         
     | 
| 
      
 98 
     | 
    
         
            +
                # Convenience method to parse JSGF model from string and create a search.
         
     | 
| 
      
 99 
     | 
    
         
            +
                #
         
     | 
| 
      
 100 
     | 
    
         
            +
                # @param [String] jsgf_string The JSGF grammar
         
     | 
| 
      
 101 
     | 
    
         
            +
                # @param [String] name The search name
         
     | 
| 
      
 102 
     | 
    
         
            +
                def set_jsgf_string(jsgf_string, name = 'default')
         
     | 
| 
      
 103 
     | 
    
         
            +
                  api_call :ps_set_jsgf_string, ps_decoder, name, jsgf_string
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                # Returns name of curent search in decoder
         
     | 
| 
      
 107 
     | 
    
         
            +
                def get_search
         
     | 
| 
      
 108 
     | 
    
         
            +
                  ps_api.ps_get_search(ps_decoder)
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                # Actives search with the provided name.
         
     | 
| 
      
 112 
     | 
    
         
            +
                #
         
     | 
| 
      
 113 
     | 
    
         
            +
                # Activates search with the provided name. The search must be added before
         
     | 
| 
      
 114 
     | 
    
         
            +
                # using either ps_set_fsg(), ps_set_lm() or ps_set_kws().
         
     | 
| 
      
 115 
     | 
    
         
            +
                def set_search(name = 'default')
         
     | 
| 
      
 116 
     | 
    
         
            +
                  api_call :ps_set_search, ps_decoder, name
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                # Unsets the search and releases related resources.
         
     | 
| 
      
 120 
     | 
    
         
            +
                #
         
     | 
| 
      
 121 
     | 
    
         
            +
                # Unsets the search previously added with
         
     | 
| 
      
 122 
     | 
    
         
            +
                # using either ps_set_fsg(), ps_set_lm() or ps_set_kws().
         
     | 
| 
      
 123 
     | 
    
         
            +
                def unset_search(name = 'default')
         
     | 
| 
      
 124 
     | 
    
         
            +
                  api_call :ps_unset_search, ps_decoder, name
         
     | 
| 
      
 125 
     | 
    
         
            +
                end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
       105 
127 
     | 
    
         
             
                def ps_api
         
     | 
| 
       106 
128 
     | 
    
         
             
                  @ps_api || API::Pocketsphinx
         
     | 
| 
       107 
129 
     | 
    
         
             
                end
         
     | 
| 
       108 
130 
     | 
    
         | 
| 
       109 
131 
     | 
    
         
             
                def ps_decoder
         
     | 
| 
       110 
     | 
    
         
            -
                  @ps_decoder 
     | 
| 
      
 132 
     | 
    
         
            +
                  init_decoder if @ps_decoder.nil?
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @ps_decoder
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                private
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                def init_decoder
         
     | 
| 
      
 139 
     | 
    
         
            +
                  @ps_decoder = ps_api.ps_init(configuration.ps_config)
         
     | 
| 
      
 140 
     | 
    
         
            +
                  post_init_decoder
         
     | 
| 
      
 141 
     | 
    
         
            +
                end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                def reinit_decoder
         
     | 
| 
      
 144 
     | 
    
         
            +
                  ps_api.ps_reinit(ps_decoder, configuration.ps_config).tap do |result|
         
     | 
| 
      
 145 
     | 
    
         
            +
                    raise API::Error, "Decoder#reconfigure failed with error code #{result}" if result < 0
         
     | 
| 
      
 146 
     | 
    
         
            +
                    post_init_decoder
         
     | 
| 
      
 147 
     | 
    
         
            +
                  end
         
     | 
| 
      
 148 
     | 
    
         
            +
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                def post_init_decoder
         
     | 
| 
      
 151 
     | 
    
         
            +
                  if configuration.respond_to?(:post_init_decoder)
         
     | 
| 
      
 152 
     | 
    
         
            +
                    configuration.post_init_decoder(self)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  end
         
     | 
| 
       111 
154 
     | 
    
         
             
                end
         
     | 
| 
       112 
155 
     | 
    
         
             
              end
         
     | 
| 
       113 
156 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Pocketsphinx
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Grammar
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Jsgf
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_reader :raw
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(path = nil, &block)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    if path.nil? && !block_given?
         
     | 
| 
      
 8 
     | 
    
         
            +
                      raise "Either a path or block is required to create a JSGF grammar"
         
     | 
| 
      
 9 
     | 
    
         
            +
                    end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    if block_given?
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @raw = grammar_from_block(&block)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    else
         
     | 
| 
      
 14 
     | 
    
         
            +
                      @raw = grammar_from_file(path)
         
     | 
| 
      
 15 
     | 
    
         
            +
                      check_grammar
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def grammar_from_file(path)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    File.read path
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def grammar_from_block(&block)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    builder = JsgfBuilder.new
         
     | 
| 
      
 25 
     | 
    
         
            +
                    builder.instance_eval(&block)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    builder.jsgf
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  private
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def check_grammar
         
     | 
| 
      
 32 
     | 
    
         
            +
                    # Simple header check for now
         
     | 
| 
      
 33 
     | 
    
         
            +
                    raise 'Invalid JSGF grammar' unless raw.lines.first.strip == "#JSGF V1.0;"
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Pocketsphinx
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Grammar
         
     | 
| 
      
 3 
     | 
    
         
            +
                class JsgfBuilder
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 5 
     | 
    
         
            +
                    @sentences = []
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def sentence(sentence)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @sentences << sentence
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def jsgf
         
     | 
| 
      
 13 
     | 
    
         
            +
                    header + sentences_rule
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  private
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def header
         
     | 
| 
      
 19 
     | 
    
         
            +
                    "#JSGF V1.0;\n\ngrammar default;\n\n"
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def sentences_rule
         
     | 
| 
      
 23 
     | 
    
         
            +
                    "public <sentence> = #{@sentences.map(&:downcase).join(' | ')};"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -3,7 +3,7 @@ module Pocketsphinx 
     | 
|
| 
       3 
3 
     | 
    
         
             
              #
         
     | 
| 
       4 
4 
     | 
    
         
             
              # Implements Recordable interface (#record and #read_audio)
         
     | 
| 
       5 
5 
     | 
    
         
             
              class Microphone
         
     | 
| 
       6 
     | 
    
         
            -
                 
     | 
| 
      
 6 
     | 
    
         
            +
                include API::CallHelpers
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                attr_reader :ps_audio_device
         
     | 
| 
       9 
9 
     | 
    
         
             
                attr_writer :ps_api
         
     | 
| 
         @@ -36,15 +36,11 @@ module Pocketsphinx 
     | 
|
| 
       36 
36 
     | 
    
         
             
                end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
                def start_recording
         
     | 
| 
       39 
     | 
    
         
            -
                   
     | 
| 
       40 
     | 
    
         
            -
                    raise Error, "Microphone#start_recording failed with error code #{result}" if result < 0
         
     | 
| 
       41 
     | 
    
         
            -
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
                  api_call :ad_start_rec, @ps_audio_device
         
     | 
| 
       42 
40 
     | 
    
         
             
                end
         
     | 
| 
       43 
41 
     | 
    
         | 
| 
       44 
42 
     | 
    
         
             
                def stop_recording
         
     | 
| 
       45 
     | 
    
         
            -
                   
     | 
| 
       46 
     | 
    
         
            -
                    raise Error, "Microphone#stop_recording failed with error code #{result}" if result < 0
         
     | 
| 
       47 
     | 
    
         
            -
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  api_call :ad_stop_rec, @ps_audio_device
         
     | 
| 
       48 
44 
     | 
    
         
             
                end
         
     | 
| 
       49 
45 
     | 
    
         | 
| 
       50 
46 
     | 
    
         
             
                # Read next block of audio samples while recording; read upto max samples into buf.
         
     | 
| 
         @@ -69,9 +65,7 @@ module Pocketsphinx 
     | 
|
| 
       69 
65 
     | 
    
         
             
                end
         
     | 
| 
       70 
66 
     | 
    
         | 
| 
       71 
67 
     | 
    
         
             
                def close_device
         
     | 
| 
       72 
     | 
    
         
            -
                   
     | 
| 
       73 
     | 
    
         
            -
                    raise Error, "Microphone#close_device failed with error code #{result}" if result < 0
         
     | 
| 
       74 
     | 
    
         
            -
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  api_call :ad_close, @ps_audio_device
         
     | 
| 
       75 
69 
     | 
    
         
             
                end
         
     | 
| 
       76 
70 
     | 
    
         | 
| 
       77 
71 
     | 
    
         
             
                def ps_api
         
     | 
    
        data/lib/pocketsphinx/version.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #JSGF V1.0;
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            /**
         
     | 
| 
      
 4 
     | 
    
         
            +
             * JSGF Grammar for Turtle example
         
     | 
| 
      
 5 
     | 
    
         
            +
             */
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            grammar goforward;
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            public <move> = go forward ten meters;
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            public <move2> = go <direction> <distance> [meter | meters];
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            <direction> = forward | backward;
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            <distance> = one | two | three | four | five | six | seven | eight | nine | ten;
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            This isn't a valid grammar
         
     | 
    
        data/spec/configuration_spec.rb
    CHANGED
    
    | 
         @@ -90,12 +90,16 @@ describe Configuration do 
     | 
|
| 
       90 
90 
     | 
    
         
             
              context 'keyword spotting configuration' do
         
     | 
| 
       91 
91 
     | 
    
         
             
                subject { Configuration::KeywordSpotting.new('Okay computer') }
         
     | 
| 
       92 
92 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
                it ' 
     | 
| 
       94 
     | 
    
         
            -
                   
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
      
 93 
     | 
    
         
            +
                it 'modifies the default configuration keyphrase and language model' do
         
     | 
| 
      
 94 
     | 
    
         
            +
                  changes = subject.changes
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  expect(changes.count).to be(2)
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  expect(changes[0][:name]).to eq('keyphrase')
         
     | 
| 
      
 99 
     | 
    
         
            +
                  expect(changes[0][:value]).to eq('okay computer')
         
     | 
| 
       96 
100 
     | 
    
         | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
                  expect( 
     | 
| 
      
 101 
     | 
    
         
            +
                  expect(changes[1][:name]).to eq('lm')
         
     | 
| 
      
 102 
     | 
    
         
            +
                  expect(changes[1][:value]).to be_nil
         
     | 
| 
       99 
103 
     | 
    
         
             
                end
         
     | 
| 
       100 
104 
     | 
    
         | 
| 
       101 
105 
     | 
    
         
             
                it 'exposes the keyphrase setting as #keyword' do
         
     | 
    
        data/spec/decoder_spec.rb
    CHANGED
    
    | 
         @@ -12,12 +12,18 @@ describe Decoder do 
     | 
|
| 
       12 
12 
     | 
    
         
             
              end
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
              describe '#reconfigure' do
         
     | 
| 
       15 
     | 
    
         
            -
                it 'calls libpocketsphinx' do
         
     | 
| 
      
 15 
     | 
    
         
            +
                it 'calls libpocketsphinx and the configuration post initialize hook' do
         
     | 
| 
       16 
16 
     | 
    
         
             
                  expect(ps_api)
         
     | 
| 
       17 
17 
     | 
    
         
             
                    .to receive(:ps_reinit)
         
     | 
| 
       18 
18 
     | 
    
         
             
                    .with(subject.ps_decoder, configuration.ps_config)
         
     | 
| 
       19 
19 
     | 
    
         
             
                    .and_return(0)
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
      
 21 
     | 
    
         
            +
                  configuration.define_singleton_method(:post_init_decoder) { |decoder| }
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  expect(configuration)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    .to receive(:post_init_decoder)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    .with(subject)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
       21 
27 
     | 
    
         
             
                  subject.reconfigure
         
     | 
| 
       22 
28 
     | 
    
         
             
                end
         
     | 
| 
       23 
29 
     | 
    
         | 
| 
         @@ -133,4 +139,74 @@ describe Decoder do 
     | 
|
| 
       133 
139 
     | 
    
         
             
                  expect(subject.hypothesis).to eq("Hypothesis")
         
     | 
| 
       134 
140 
     | 
    
         
             
                end
         
     | 
| 
       135 
141 
     | 
    
         
             
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
              describe '#set_jsgf_string' do
         
     | 
| 
      
 144 
     | 
    
         
            +
                it 'calls libpocketsphinx' do
         
     | 
| 
      
 145 
     | 
    
         
            +
                  expect(ps_api)
         
     | 
| 
      
 146 
     | 
    
         
            +
                    .to receive(:ps_set_jsgf_string)
         
     | 
| 
      
 147 
     | 
    
         
            +
                    .with(subject.ps_decoder, 'default', 'JSGF')
         
     | 
| 
      
 148 
     | 
    
         
            +
                    .and_return(0)
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                  subject.set_jsgf_string('JSGF')
         
     | 
| 
      
 151 
     | 
    
         
            +
                end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                it 'raises an exception on error' do
         
     | 
| 
      
 154 
     | 
    
         
            +
                  expect(ps_api)
         
     | 
| 
      
 155 
     | 
    
         
            +
                    .to receive(:ps_set_jsgf_string)
         
     | 
| 
      
 156 
     | 
    
         
            +
                    .and_return(-1)
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                  expect { subject.set_jsgf_string('JSGF') }
         
     | 
| 
      
 159 
     | 
    
         
            +
                    .to raise_exception "Decoder#set_jsgf_string failed with error code -1"
         
     | 
| 
      
 160 
     | 
    
         
            +
                end
         
     | 
| 
      
 161 
     | 
    
         
            +
              end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
              describe '#set_search' do
         
     | 
| 
      
 164 
     | 
    
         
            +
                it 'calls libpocketsphinx' do
         
     | 
| 
      
 165 
     | 
    
         
            +
                  expect(ps_api)
         
     | 
| 
      
 166 
     | 
    
         
            +
                    .to receive(:ps_set_search)
         
     | 
| 
      
 167 
     | 
    
         
            +
                    .with(subject.ps_decoder, 'search')
         
     | 
| 
      
 168 
     | 
    
         
            +
                    .and_return(0)
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                  subject.set_search('search')
         
     | 
| 
      
 171 
     | 
    
         
            +
                end
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                it 'raises an exception on error' do
         
     | 
| 
      
 174 
     | 
    
         
            +
                  expect(ps_api)
         
     | 
| 
      
 175 
     | 
    
         
            +
                    .to receive(:ps_set_search)
         
     | 
| 
      
 176 
     | 
    
         
            +
                    .and_return(-1)
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  expect { subject.set_search('search') }
         
     | 
| 
      
 179 
     | 
    
         
            +
                    .to raise_exception "Decoder#set_search failed with error code -1"
         
     | 
| 
      
 180 
     | 
    
         
            +
                end
         
     | 
| 
      
 181 
     | 
    
         
            +
              end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
              describe '#unset_search' do
         
     | 
| 
      
 184 
     | 
    
         
            +
                it 'calls libpocketsphinx' do
         
     | 
| 
      
 185 
     | 
    
         
            +
                  expect(ps_api)
         
     | 
| 
      
 186 
     | 
    
         
            +
                    .to receive(:ps_unset_search)
         
     | 
| 
      
 187 
     | 
    
         
            +
                    .with(subject.ps_decoder, 'search')
         
     | 
| 
      
 188 
     | 
    
         
            +
                    .and_return(0)
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                  subject.unset_search('search')
         
     | 
| 
      
 191 
     | 
    
         
            +
                end
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                it 'raises an exception on error' do
         
     | 
| 
      
 194 
     | 
    
         
            +
                  expect(ps_api)
         
     | 
| 
      
 195 
     | 
    
         
            +
                    .to receive(:ps_unset_search)
         
     | 
| 
      
 196 
     | 
    
         
            +
                    .and_return(-1)
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                  expect { subject.unset_search('search') }
         
     | 
| 
      
 199 
     | 
    
         
            +
                    .to raise_exception "Decoder#unset_search failed with error code -1"
         
     | 
| 
      
 200 
     | 
    
         
            +
                end
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
              describe '#get_search' do
         
     | 
| 
      
 204 
     | 
    
         
            +
                it 'calls libpocketsphinx' do
         
     | 
| 
      
 205 
     | 
    
         
            +
                  expect(ps_api)
         
     | 
| 
      
 206 
     | 
    
         
            +
                    .to receive(:ps_get_search)
         
     | 
| 
      
 207 
     | 
    
         
            +
                    .and_return(:search)
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                  expect(subject.get_search).to eq(:search)
         
     | 
| 
      
 210 
     | 
    
         
            +
                end
         
     | 
| 
      
 211 
     | 
    
         
            +
              end
         
     | 
| 
       136 
212 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Grammar::Jsgf do
         
     | 
| 
      
 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"
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              context "reading a grammar from a file" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                let(:grammar_path) { grammar :goforward }
         
     | 
| 
      
 10 
     | 
    
         
            +
                subject { Grammar::Jsgf.new(grammar_path) }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                it "reads a grammar from a file" do
         
     | 
| 
      
 13 
     | 
    
         
            +
                  expect(subject.raw.lines.count).to eq(15)
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                context "the grammar file is invalid" do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  let(:grammar_path) { grammar :invalid }
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  it "raises an exception" do
         
     | 
| 
      
 20 
     | 
    
         
            +
                    expect { subject }.to raise_exception "Invalid JSGF grammar"
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              context "building a grammer from a block" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                subject do
         
     | 
| 
      
 27 
     | 
    
         
            +
                  Grammar::Jsgf.new do
         
     | 
| 
      
 28 
     | 
    
         
            +
                    sentence "Go forward ten meters"
         
     | 
| 
      
 29 
     | 
    
         
            +
                    sentence "Go backward ten meters"
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                it "builds a grammar from a block" do
         
     | 
| 
      
 34 
     | 
    
         
            +
                  expect(subject.raw).to eq(File.read grammar(:sentences))
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              private
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              def grammar(name)
         
     | 
| 
      
 41 
     | 
    
         
            +
                "spec/assets/grammars/#{name}.gram"
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe 'speech recognition with default configuration' do
         
     | 
| 
      
 4 
     | 
    
         
            +
              subject do
         
     | 
| 
      
 5 
     | 
    
         
            +
                AudioFileSpeechRecognizer.new.tap do |speech_recognizer|
         
     | 
| 
      
 6 
     | 
    
         
            +
                  speech_recognizer.decoder = @decoder
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              # Share decoder across all examples for speed
         
     | 
| 
      
 11 
     | 
    
         
            +
              before :all do
         
     | 
| 
      
 12 
     | 
    
         
            +
                @decoder = Decoder.new(Configuration.default)
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              describe '#recognize' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                it 'should decode speech in raw audio' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  expect { |b| subject.recognize('spec/assets/audio/goforward.raw', 4096, &b) }.
         
     | 
| 
      
 18 
     | 
    
         
            +
                    to yield_with_args("go forward ten years")
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'spec_helper'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            describe  
     | 
| 
      
 3 
     | 
    
         
            +
            describe 'speech recognition with a grammar' do
         
     | 
| 
       4 
4 
     | 
    
         
             
              let(:recordable) { AudioFile.new('spec/assets/audio/goforward.raw') }
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
              subject do
         
     | 
| 
         @@ -12,12 +12,13 @@ describe SpeechRecognizer do 
     | 
|
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
              # Share decoder across all examples for speed
         
     | 
| 
       14 
14 
     | 
    
         
             
              before :all do
         
     | 
| 
       15 
     | 
    
         
            -
                @ 
     | 
| 
      
 15 
     | 
    
         
            +
                @configuration = Configuration::Grammar.new('spec/assets/grammars/goforward.gram')
         
     | 
| 
      
 16 
     | 
    
         
            +
                @decoder = Decoder.new(@configuration)
         
     | 
| 
       16 
17 
     | 
    
         
             
              end
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
19 
     | 
    
         
             
              describe '#recognize' do
         
     | 
| 
       19 
20 
     | 
    
         
             
                it 'should decode speech in raw audio' do
         
     | 
| 
       20 
     | 
    
         
            -
                  expect { |b| subject.recognize(4096, &b) }.to yield_with_args("go forward ten  
     | 
| 
      
 21 
     | 
    
         
            +
                  expect { |b| subject.recognize(4096, &b) }.to yield_with_args("go forward ten meters")
         
     | 
| 
       21 
22 
     | 
    
         
             
                end
         
     | 
| 
       22 
23 
     | 
    
         
             
              end
         
     | 
| 
       23 
24 
     | 
    
         
             
            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.0 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0
         
     | 
| 
       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-24 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: ffi
         
     | 
| 
         @@ -100,6 +100,7 @@ files: 
     | 
|
| 
       100 
100 
     | 
    
         
             
            - examples/record_audio_file.rb
         
     | 
| 
       101 
101 
     | 
    
         
             
            - lib/pocketsphinx-ruby.rb
         
     | 
| 
       102 
102 
     | 
    
         
             
            - lib/pocketsphinx.rb
         
     | 
| 
      
 103 
     | 
    
         
            +
            - lib/pocketsphinx/api/call_helpers.rb
         
     | 
| 
       103 
104 
     | 
    
         
             
            - lib/pocketsphinx/api/pocketsphinx.rb
         
     | 
| 
       104 
105 
     | 
    
         
             
            - lib/pocketsphinx/api/sphinxad.rb
         
     | 
| 
       105 
106 
     | 
    
         
             
            - lib/pocketsphinx/api/sphinxbase.rb
         
     | 
| 
         @@ -107,19 +108,27 @@ files: 
     | 
|
| 
       107 
108 
     | 
    
         
             
            - lib/pocketsphinx/audio_file_speech_recognizer.rb
         
     | 
| 
       108 
109 
     | 
    
         
             
            - lib/pocketsphinx/configuration/base.rb
         
     | 
| 
       109 
110 
     | 
    
         
             
            - lib/pocketsphinx/configuration/default.rb
         
     | 
| 
      
 111 
     | 
    
         
            +
            - lib/pocketsphinx/configuration/grammar.rb
         
     | 
| 
       110 
112 
     | 
    
         
             
            - lib/pocketsphinx/configuration/keyword_spotting.rb
         
     | 
| 
       111 
113 
     | 
    
         
             
            - lib/pocketsphinx/configuration/setting_definition.rb
         
     | 
| 
       112 
114 
     | 
    
         
             
            - lib/pocketsphinx/decoder.rb
         
     | 
| 
      
 115 
     | 
    
         
            +
            - lib/pocketsphinx/grammar/jsgf.rb
         
     | 
| 
      
 116 
     | 
    
         
            +
            - lib/pocketsphinx/grammar/jsgf_builder.rb
         
     | 
| 
       113 
117 
     | 
    
         
             
            - lib/pocketsphinx/live_speech_recognizer.rb
         
     | 
| 
       114 
118 
     | 
    
         
             
            - lib/pocketsphinx/microphone.rb
         
     | 
| 
       115 
119 
     | 
    
         
             
            - lib/pocketsphinx/speech_recognizer.rb
         
     | 
| 
       116 
120 
     | 
    
         
             
            - lib/pocketsphinx/version.rb
         
     | 
| 
       117 
121 
     | 
    
         
             
            - pocketsphinx-ruby.gemspec
         
     | 
| 
       118 
122 
     | 
    
         
             
            - spec/assets/audio/goforward.raw
         
     | 
| 
      
 123 
     | 
    
         
            +
            - spec/assets/grammars/goforward.gram
         
     | 
| 
      
 124 
     | 
    
         
            +
            - spec/assets/grammars/invalid.gram
         
     | 
| 
      
 125 
     | 
    
         
            +
            - spec/assets/grammars/sentences.gram
         
     | 
| 
       119 
126 
     | 
    
         
             
            - spec/configuration_spec.rb
         
     | 
| 
       120 
127 
     | 
    
         
             
            - spec/decoder_spec.rb
         
     | 
| 
      
 128 
     | 
    
         
            +
            - spec/grammar_spec.rb
         
     | 
| 
       121 
129 
     | 
    
         
             
            - spec/integration/decoder_spec.rb
         
     | 
| 
       122 
     | 
    
         
            -
            - spec/integration/ 
     | 
| 
      
 130 
     | 
    
         
            +
            - spec/integration/default_recognition_spec.rb
         
     | 
| 
      
 131 
     | 
    
         
            +
            - spec/integration/grammar_recognition_spec.rb
         
     | 
| 
       123 
132 
     | 
    
         
             
            - spec/microphone_spec.rb
         
     | 
| 
       124 
133 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
       125 
134 
     | 
    
         
             
            - spec/speech_recognizer_spec.rb
         
     | 
| 
         @@ -149,10 +158,15 @@ specification_version: 4 
     | 
|
| 
       149 
158 
     | 
    
         
             
            summary: Ruby FFI pocketsphinx bindings
         
     | 
| 
       150 
159 
     | 
    
         
             
            test_files:
         
     | 
| 
       151 
160 
     | 
    
         
             
            - spec/assets/audio/goforward.raw
         
     | 
| 
      
 161 
     | 
    
         
            +
            - spec/assets/grammars/goforward.gram
         
     | 
| 
      
 162 
     | 
    
         
            +
            - spec/assets/grammars/invalid.gram
         
     | 
| 
      
 163 
     | 
    
         
            +
            - spec/assets/grammars/sentences.gram
         
     | 
| 
       152 
164 
     | 
    
         
             
            - spec/configuration_spec.rb
         
     | 
| 
       153 
165 
     | 
    
         
             
            - spec/decoder_spec.rb
         
     | 
| 
      
 166 
     | 
    
         
            +
            - spec/grammar_spec.rb
         
     | 
| 
       154 
167 
     | 
    
         
             
            - spec/integration/decoder_spec.rb
         
     | 
| 
       155 
     | 
    
         
            -
            - spec/integration/ 
     | 
| 
      
 168 
     | 
    
         
            +
            - spec/integration/default_recognition_spec.rb
         
     | 
| 
      
 169 
     | 
    
         
            +
            - spec/integration/grammar_recognition_spec.rb
         
     | 
| 
       156 
170 
     | 
    
         
             
            - spec/microphone_spec.rb
         
     | 
| 
       157 
171 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
       158 
172 
     | 
    
         
             
            - spec/speech_recognizer_spec.rb
         
     |