├── .gitignore ├── .rspec ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin └── sphinxtrain-ruby ├── lib ├── sphinxtrain-ruby.rb ├── sphinxtrain.rb └── sphinxtrain │ ├── acoustic_model.rb │ ├── analyser.rb │ ├── map_adapter.rb │ ├── trainer.rb │ ├── training_decoder.rb │ └── version.rb ├── spec └── spec_helper.rb └── sphinxtrain-ruby.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | *.bundle 19 | *.so 20 | *.o 21 | *.a 22 | mkmf.log 23 | .DS_Store 24 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1.2 4 | - 2.0.0 5 | - 1.9.3 6 | - rbx-2.2.9 7 | - jruby-1.7.16 8 | before_install: 9 | - sudo apt-get update -qq 10 | - sudo apt-get install -y swig 11 | - git clone https://github.com/cmusphinx/sphinxbase.git 12 | - cd sphinxbase 13 | - ./autogen.sh 14 | - ./configure 15 | - make 16 | - sudo make install 17 | - cd .. 18 | - git clone https://github.com/cmusphinx/pocketsphinx.git 19 | - cd pocketsphinx 20 | - ./autogen.sh 21 | - ./configure 22 | - make 23 | - sudo make install 24 | - cd .. 25 | - git clone https://github.com/cmusphinx/sphinxtrain.git 26 | - cd sphinxtrain 27 | - ./autogen.sh 28 | - ./configure 29 | - sudo make install 30 | - cd .. 31 | - sudo ldconfig -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in sphinxtrain-ruby.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Howard Wilson 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sphinxtrain-ruby 2 | 3 | [![Build Status](http://img.shields.io/travis/watsonbox/sphinxtrain-ruby.svg?style=flat)](https://travis-ci.org/watsonbox/sphinxtrain-ruby) 4 | 5 | Toolkit for training/adapting CMU Sphinx acoustic models. 6 | 7 | The main goal is to help with [adapting existing acoustic models](http://cmusphinx.sourceforge.net/wiki/tutorialadapt) to a specific speaker/accent. Currently only the English [Voxforge](http://voxforge.org/) model is supported as a base - in fact [an adapted one](http://grasch.net/node/21) created by Peter Grasch in 2013 using the most up to date training data available at that time. I can confirm his results of a few percent performance increase over Voxforge 0.4 for my accent at least (British English). 8 | 9 | 10 | ## Installation 11 | 12 | Please note that Ruby >= 2.1 is required for this gem. 13 | 14 | Add this line to your application's Gemfile: 15 | 16 | ```ruby 17 | gem 'sphinxtrain-ruby' 18 | ``` 19 | 20 | And then execute: 21 | 22 | ```bash 23 | $ bundle 24 | ``` 25 | 26 | Or install it yourself as: 27 | 28 | ```bash 29 | $ gem install sphinxtrain-ruby 30 | ``` 31 | 32 | 33 | ## Usage 34 | 35 | Run `sphinxtrain-ruby` from the command line and follow the instructions. It will: 36 | 37 | 1. Download and extract the Grasch Voxforge English 0.4 acoustic model (on first run) 38 | 2. Download the CMU ARCTIC example sentences (on first run) 39 | 3. Record the 20 example sentences. Press enter to record, speak sentence, then wait. 40 | 4. Decode the sentences using the base acoustic model, giving an overall score. 41 | 5. Duplicate and adapt the base acoustic model using the recorded sentences. 42 | 6. Decode the sentences using the adapted acoustic model, giving an overall score. 43 | 44 | See some example output [here](https://github.com/watsonbox/sphinxtrain-ruby/wiki/Example-Output). All data is saved in `~/.sphinxtrain-ruby`. 45 | 46 | 47 | ## To Do 48 | 49 | - [ ] Add support for different data sets, not just the example from CPU Sphinx 50 | - [ ] Allow re-recording when mistakes are made 51 | - [ ] Re-factor code and add specs 52 | - [ ] Consider using actual libs rather than command line tools for adapting model 53 | - [ ] Make command line wget downloads less verbose 54 | 55 | 56 | ## Contributing 57 | 58 | 1. Fork it ( https://github.com/watsonbox/sphinxtrain-ruby/fork ) 59 | 2. Create your feature branch (`git checkout -b my-new-feature`) 60 | 3. Commit your changes (`git commit -am 'Add some feature'`) 61 | 4. Push to the branch (`git push origin my-new-feature`) 62 | 5. Create a new Pull Request 63 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require 'rake/clean' 3 | 4 | begin 5 | require 'rspec/core/rake_task' 6 | RSpec::Core::RakeTask.new(:spec) 7 | task :default => [:spec] 8 | rescue LoadError 9 | end 10 | -------------------------------------------------------------------------------- /bin/sphinxtrain-ruby: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'sphinxtrain-ruby' 4 | 5 | Sphinxtrain::Trainer.new.train 6 | -------------------------------------------------------------------------------- /lib/sphinxtrain-ruby.rb: -------------------------------------------------------------------------------- 1 | require 'sphinxtrain' -------------------------------------------------------------------------------- /lib/sphinxtrain.rb: -------------------------------------------------------------------------------- 1 | require "pocketsphinx-ruby" 2 | require "colorize" 3 | require "word_aligner" 4 | 5 | require "sphinxtrain/version" 6 | require "sphinxtrain/analyser" 7 | require "sphinxtrain/map_adapter" 8 | require "sphinxtrain/acoustic_model" 9 | require "sphinxtrain/training_decoder" 10 | require "sphinxtrain/trainer" 11 | 12 | module Sphinxtrain 13 | def self.base_dir 14 | File.join(Dir.home, '.sphinxtrain-ruby') 15 | end 16 | 17 | def self.recordings_dir 18 | File.join(base_dir, 'recordings') 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/sphinxtrain/acoustic_model.rb: -------------------------------------------------------------------------------- 1 | module Sphinxtrain 2 | class AcousticModel < Struct.new(:url) 3 | MODEL_URLS = { 4 | voxforge_grasch: "http://files.kde.org/accessibility/Simon/am/voxforge_en_sphinx.cd_cont_5000.tar.gz" 5 | } 6 | 7 | MODEL_DESCRIPTIONS = { 8 | voxforge_grasch: "Grasch Voxforge English 0.4" 9 | } 10 | 11 | def self.voxforge_grasch 12 | new MODEL_URLS[:voxforge_grasch] 13 | end 14 | 15 | def description 16 | MODEL_DESCRIPTIONS[MODEL_URLS.invert[url]] || url 17 | end 18 | 19 | def downloaded? 20 | File.exist?(downloaded_filename) 21 | end 22 | 23 | def downloaded_filename 24 | File.basename(url) 25 | end 26 | 27 | def folder 28 | File.basename(downloaded_filename, '.tar.gz') 29 | end 30 | 31 | def adapted_folder 32 | folder + "_adapted" 33 | end 34 | 35 | def download! 36 | `wget #{url}` 37 | `tar xfz #{downloaded_filename}` 38 | end 39 | 40 | def duplicate! 41 | FileUtils.rm_rf(adapted_folder) if Dir.exist?(adapted_folder) 42 | FileUtils.cp_r(folder, adapted_folder) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/sphinxtrain/analyser.rb: -------------------------------------------------------------------------------- 1 | module Sphinxtrain 2 | class Analyser 3 | def initialize(model) 4 | configuration['hmm'] = model 5 | configuration['seed'] = 1 # Ensure deterministic results 6 | end 7 | 8 | def analyse(sentences_file, recordings_dir) 9 | total = 0 10 | first_decoding = true 11 | 12 | File.open(sentences_file).each_line.with_index do |transcription, index| 13 | transcription = transcription.downcase.gsub(/[,\.]/, '') 14 | file_path = File.join(recordings_dir, "arctic_#{(index + 1).to_s.rjust(4, "0")}.raw") 15 | decoder.decode file_path 16 | 17 | # Repeat the first decoding after CMN estimations are calculated 18 | # See https://github.com/watsonbox/pocketsphinx-ruby/issues/10 19 | if first_decoding 20 | first_decoding = false 21 | redo 22 | end 23 | 24 | hypothesis = decoder.hypothesis 25 | error_rate = WordAligner.align(transcription, hypothesis) 26 | total += error_rate.percentage_accurate 27 | 28 | if block_given? 29 | yield transcription, hypothesis, error_rate.percentage_accurate 30 | end 31 | end 32 | 33 | total / 20 34 | end 35 | 36 | private 37 | 38 | def configuration 39 | @configuration ||= Pocketsphinx::Configuration.default 40 | end 41 | 42 | def decoder 43 | @decoder ||= Pocketsphinx::Decoder.new(configuration) 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/sphinxtrain/map_adapter.rb: -------------------------------------------------------------------------------- 1 | module Sphinxtrain 2 | class MapAdapter 3 | SPHINX_FE_COMMAND = "sphinx_fe" 4 | BW_COMMAND = "/usr/local/Cellar/cmu-sphinxtrain/HEAD/libexec/sphinxtrain/bw" 5 | MAP_ADAPT_COMMAND = "/usr/local/Cellar/cmu-sphinxtrain/HEAD/libexec/sphinxtrain/map_adapt" 6 | 7 | attr_accessor :old_model, :new_model, :recordings_dir, :sentences_transcription, :sentences_files, :sentences_dict 8 | 9 | def initialize(old_model:, new_model:, recordings_dir:, sentences_transcription:, sentences_files:, sentences_dict:) 10 | self.old_model = old_model 11 | self.new_model = new_model 12 | self.recordings_dir = recordings_dir 13 | self.sentences_transcription = sentences_transcription 14 | self.sentences_files = sentences_files 15 | self.sentences_dict = sentences_dict 16 | end 17 | 18 | def adapt 19 | `#{SPHINX_FE_COMMAND} \ 20 | -argfile #{new_model_file 'feat.params'} \ 21 | -samprate 16000 \ 22 | -c #{sentences_files} \ 23 | -di #{recordings_dir} \ 24 | -do #{recordings_dir} \ 25 | -ei raw \ 26 | -eo mfc \ 27 | -seed 1 > /dev/null 2>&1` 28 | 29 | `#{BW_COMMAND} \ 30 | -hmmdir #{new_model} \ 31 | -moddeffn #{new_model_file 'mdef'} \ 32 | -ts2cbfn ".cont." \ 33 | -feat 1s_c_d_dd \ 34 | -cmn current \ 35 | -agc none \ 36 | -dictfn #{sentences_dict} \ 37 | -ctlfn #{sentences_files} \ 38 | -lsnfn #{sentences_transcription} \ 39 | -accumdir #{recordings_dir} \ 40 | -lda #{new_model_file 'feature_transform'} \ 41 | -cepdir #{recordings_dir} > /dev/null 2>&1` 42 | 43 | `#{MAP_ADAPT_COMMAND} \ 44 | -meanfn #{old_model_file 'means'} \ 45 | -varfn #{old_model_file 'variances'} \ 46 | -mixwfn #{old_model_file 'mixture_weights'} \ 47 | -tmatfn #{old_model_file 'transition_matrices'} \ 48 | -accumdir #{recordings_dir} \ 49 | -mapmeanfn #{new_model_file 'means'} \ 50 | -mapvarfn #{new_model_file 'variances'} \ 51 | -mapmixwfn #{new_model_file 'mixture_weights'} \ 52 | -maptmatfn #{new_model_file 'transition_matrices'} > /dev/null 2>&1` 53 | end 54 | 55 | private 56 | 57 | def old_model_file(file) 58 | File.join(old_model, file) 59 | end 60 | 61 | def new_model_file(file) 62 | File.join(new_model, file) 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lib/sphinxtrain/trainer.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | module Sphinxtrain 4 | class Trainer 5 | def acoustic_model 6 | @acoustic_model ||= AcousticModel.voxforge_grasch 7 | end 8 | 9 | def train 10 | Pocketsphinx.disable_logging 11 | 12 | Dir.mkdir Sphinxtrain.base_dir rescue Errno::EEXIST 13 | Dir.chdir Sphinxtrain.base_dir do 14 | if acoustic_model.downloaded? 15 | log "=> Using existing acoustic model #{acoustic_model.description}", :yellow 16 | else 17 | log "=> Downloading #{acoustic_model.description}..." 18 | acoustic_model.download! 19 | end 20 | 21 | download_assets unless arctic_file(:txt, :listoffiles, :transcription, :dic).all? { |f| File.exist? f } 22 | 23 | if Dir.exist?(Sphinxtrain.recordings_dir) 24 | log "=> Using sentences recorded in #{Sphinxtrain.recordings_dir}", :yellow 25 | else 26 | record_sentences 27 | end 28 | 29 | result = analyse_model 30 | 31 | duplicate_model 32 | adapt_model 33 | 34 | adapted_result = analyse_model acoustic_model.adapted_folder 35 | 36 | improvement = ((adapted_result/result)-1)*100 37 | 38 | log "=> Adapted acoustic model improved by #{improvement}%. Test this model with:" 39 | log "=> pocketsphinx_continuous -hmm #{File.join(Sphinxtrain.base_dir, acoustic_model.adapted_folder)} -inmic yes" 40 | end 41 | end 42 | 43 | private 44 | 45 | def download_assets 46 | log "=> Downloading CMU ARCTIC Example Sentences..." 47 | 48 | arctic_file(:txt, :listoffiles, :transcription, :dic).each do |file| 49 | `wget http://www.speech.cs.cmu.edu/cmusphinx/moindocs/#{file} -O #{file}` 50 | end 51 | end 52 | 53 | def arctic_file(*keys) 54 | keys.length == 1 ? "arctic20.#{keys.first}" : keys.map { |k| arctic_file k } 55 | end 56 | 57 | def record_sentences 58 | log "=> Recording sentences..." 59 | Dir.mkdir Sphinxtrain.recordings_dir unless Dir.exist?(Sphinxtrain.recordings_dir) 60 | 61 | recognizer = Pocketsphinx::LiveSpeechRecognizer.new 62 | decoder = TrainingDecoder.new(recognizer.decoder) 63 | recognizer.decoder = decoder 64 | 65 | # Initialize the decoder and microphone 66 | recognizer.decoder.ps_decoder 67 | recognizer.recordable 68 | 69 | File.open(arctic_file(:txt), 'r').lines.each_with_index do |sentence, index| 70 | puts "SAY: #{sentence}" 71 | puts "Press ENTER to continue" 72 | gets 73 | 74 | # Small delay to avoid capturing audio connected with keypress 75 | sleep 0.2 76 | 77 | # Record a single utterance captured by TrainingDecoder 78 | recognizer.recognize do |speech| 79 | save_audio decoder.last_utterance, index 80 | break 81 | end 82 | 83 | puts "Saved audio\n\n" 84 | end 85 | end 86 | 87 | def save_audio(data, sentence_index) 88 | raise "Can't save empty audio data" if data.nil? || data.empty? 89 | 90 | File.open(File.join(Sphinxtrain.recordings_dir, "arctic_#{(sentence_index + 1).to_s.rjust(4, "0")}.raw"), "wb") do |file| 91 | file.write data 92 | end 93 | end 94 | 95 | def analyse_model(model_folder = acoustic_model.folder) 96 | log "=> Analysing acoustic model...\n" 97 | 98 | result = Analyser.new(model_folder).analyse(arctic_file(:txt), Sphinxtrain.recordings_dir) do |transcription, hypothesis, accuracy| 99 | puts " ACTUAL: #{transcription}" 100 | puts " RECORD: #{hypothesis}" 101 | puts " RESULT: #{accuracy}\n\n" 102 | end 103 | 104 | puts " OVERALL: #{result}\n\n" 105 | result 106 | end 107 | 108 | def duplicate_model 109 | log "=> Duplicating Voxforge acoustic model..." 110 | acoustic_model.duplicate! 111 | end 112 | 113 | # Follows process described here: http://cmusphinx.sourceforge.net/wiki/tutorialadapt 114 | def adapt_model 115 | log "=> Adapting Voxforge acoustic model..." 116 | 117 | MapAdapter.new( 118 | old_model: acoustic_model.folder, 119 | new_model: acoustic_model.adapted_folder, 120 | recordings_dir: Sphinxtrain.recordings_dir, 121 | sentences_transcription: arctic_file(:transcription), 122 | sentences_files: arctic_file(:listoffiles), 123 | sentences_dict: arctic_file(:dic) 124 | ).adapt 125 | end 126 | 127 | def log(message, color = :green) 128 | puts message.colorize(color) 129 | end 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /lib/sphinxtrain/training_decoder.rb: -------------------------------------------------------------------------------- 1 | module Sphinxtrain 2 | # Wrap a decoder to save the last utterance 3 | class TrainingDecoder < SimpleDelegator 4 | attr_accessor :data 5 | attr_accessor :last_utterance 6 | 7 | def start_utterance(*args) 8 | self.data = "" 9 | super 10 | end 11 | 12 | def end_utterance(*args) 13 | self.last_utterance = data 14 | super 15 | end 16 | 17 | def process_raw(buffer, size, *args) 18 | super 19 | self.data << buffer.get_bytes(0, size * 2) 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/sphinxtrain/version.rb: -------------------------------------------------------------------------------- 1 | module Sphinxtrain 2 | VERSION = "0.0.3" 3 | end 4 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rspec --init` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause this 4 | # file to always be loaded, without a need to explicitly require it in any files. 5 | # 6 | # Given that it is always loaded, you are encouraged to keep this file as 7 | # light-weight as possible. Requiring heavyweight dependencies from this file 8 | # will add to the boot time of your test suite on EVERY test run, even for an 9 | # individual file that may not need all of that loaded. Instead, consider making 10 | # a separate helper file that requires the additional dependencies and performs 11 | # the additional setup, and require it from the spec files that actually need it. 12 | # 13 | # The `.rspec` file also contains a few flags that are not defaults but that 14 | # users commonly want. 15 | # 16 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 17 | RSpec.configure do |config| 18 | # rspec-expectations config goes here. You can use an alternate 19 | # assertion/expectation library such as wrong or the stdlib/minitest 20 | # assertions if you prefer. 21 | config.expect_with :rspec do |expectations| 22 | # This option will default to `true` in RSpec 4. It makes the `description` 23 | # and `failure_message` of custom matchers include text for helper methods 24 | # defined using `chain`, e.g.: 25 | # be_bigger_than(2).and_smaller_than(4).description 26 | # # => "be bigger than 2 and smaller than 4" 27 | # ...rather than: 28 | # # => "be bigger than 2" 29 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 30 | end 31 | 32 | # rspec-mocks config goes here. You can use an alternate test double 33 | # library (such as bogus or mocha) by changing the `mock_with` option here. 34 | config.mock_with :rspec do |mocks| 35 | # Prevents you from mocking or stubbing a method that does not exist on 36 | # a real object. This is generally recommended, and will default to 37 | # `true` in RSpec 4. 38 | mocks.verify_partial_doubles = true 39 | end 40 | 41 | # The settings below are suggested to provide a good initial experience 42 | # with RSpec, but feel free to customize to your heart's content. 43 | =begin 44 | # These two settings work together to allow you to limit a spec run 45 | # to individual examples or groups you care about by tagging them with 46 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 47 | # get run. 48 | config.filter_run :focus 49 | config.run_all_when_everything_filtered = true 50 | 51 | # Limits the available syntax to the non-monkey patched syntax that is recommended. 52 | # For more details, see: 53 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 54 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 55 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 56 | config.disable_monkey_patching! 57 | 58 | # This setting enables warnings. It's recommended, but in some cases may 59 | # be too noisy due to issues in dependencies. 60 | config.warnings = true 61 | 62 | # Many RSpec users commonly either run the entire suite or an individual 63 | # file, and it's useful to allow more verbose output when running an 64 | # individual spec file. 65 | if config.files_to_run.one? 66 | # Use the documentation formatter for detailed output, 67 | # unless a formatter has already been configured 68 | # (e.g. via a command-line flag). 69 | config.default_formatter = 'doc' 70 | end 71 | 72 | # Print the 10 slowest examples and example groups at the 73 | # end of the spec run, to help surface which specs are running 74 | # particularly slow. 75 | config.profile_examples = 10 76 | 77 | # Run specs in random order to surface order dependencies. If you find an 78 | # order dependency and want to debug it, you can fix the order by providing 79 | # the seed, which is printed after each run. 80 | # --seed 1234 81 | config.order = :random 82 | 83 | # Seed global randomization in this process using the `--seed` CLI option. 84 | # Setting this allows you to use `--seed` to deterministically reproduce 85 | # test failures related to randomization by passing the same `--seed` value 86 | # as the one that triggered the failure. 87 | Kernel.srand config.seed 88 | =end 89 | end 90 | -------------------------------------------------------------------------------- /sphinxtrain-ruby.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'sphinxtrain/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "sphinxtrain-ruby" 8 | spec.version = Sphinxtrain::VERSION 9 | spec.authors = ["Howard Wilson"] 10 | spec.email = ["howard@watsonbox.net"] 11 | spec.summary = %q{Toolkit for training/adapting CMU Sphinx acoustic models.} 12 | spec.description = %q{Toolkit for training/adapting CMU Sphinx acoustic models.} 13 | spec.homepage = "" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files -z`.split("\x0") 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | spec.required_ruby_version = '>= 2.1.0' 21 | 22 | spec.add_dependency "pocketsphinx-ruby", "~> 0.3.0" 23 | spec.add_dependency "word_aligner", "~> 0.1.2" 24 | spec.add_dependency "colorize", "~> 0.7.3" 25 | 26 | spec.add_development_dependency "bundler", "~> 1.6" 27 | spec.add_development_dependency "rspec", "~> 3.1.0" 28 | spec.add_development_dependency "rake" 29 | end 30 | --------------------------------------------------------------------------------