win32-loquendo 1.0.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Njc2MWYzOWJlYzhjNGQ4MGVmMjlkZDM1NzMyOTBlYzI5ZGJmZjYwNg==
5
+ data.tar.gz: !binary |-
6
+ YjYyM2Q2MWVmOWE5ZGU2MzA2MDUzNjBhYTg5YjNmMTY0ZjdlOTIzZQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NDhiZTUyM2U4OTg5NWU4NmEzNDU0MjA4NmJjMDYwNWY2NTcxNjJlYTFlYjI4
10
+ ODU5NTdlOTE1ZDMzZGRkNzY2MzU2ZGRmZjllM2VmNjdkMzMxNmJlNWE5MDUw
11
+ YjQ0NjE3OTVkYTZmMjg0YWFjMGI3Mzc5MzVlM2M3OGEzOGIzMGU=
12
+ data.tar.gz: !binary |-
13
+ NDgxMDBiMDM5YzdlZmIzNWY2ODFkOWU3MWFlZGRhNzE4M2Q1YzBiOTA2NTU2
14
+ NmM4Y2ZjYTQ2Y2ExYjg3NjdkY2ZmNGM4MWE0YzhiZmRiNzllNzBhZjNmNjQ0
15
+ ZTNhYmNkYWRmNWQxYTI0ZTRmMDFhOThhZTNlYjEyM2U0M2FmZjc=
@@ -0,0 +1,17 @@
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
@@ -0,0 +1,8 @@
1
+ --readme README.md
2
+ --default-return ""
3
+ --title "Win32-Loquendo Documentation"
4
+ --hide-void-return
5
+ --no-private
6
+ -
7
+ LICENSE.txt
8
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in win32-loquendo.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jonas Tingeborn
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.
@@ -0,0 +1,78 @@
1
+ # Win32::Loquendo
2
+
3
+ Ruby interface to the Loquendo speech synthesis (text to speech / TTS) program.
4
+
5
+ This gem only runs on Microsoft Windows as it relies both on the Win32 API as
6
+ well as the DLL files used by the Loquendo distribution. For that reason it
7
+ has been name spaced in the win32 module to make it abundantly clear which
8
+ platform it supports.
9
+
10
+ ## Prerequisites
11
+
12
+ * Must have Loquendo installed on the machine in order to use this gem.
13
+ * ruby ffi library, will be installed automatically through rubygems
14
+
15
+ ## Installation
16
+
17
+ $ gem install win32-loquendo
18
+
19
+ ## Usage
20
+
21
+ Basic example showing the three types of use
22
+
23
+ require 'win32/loquendo'
24
+
25
+ reader = Win32::Loquendo::Reader.new()
26
+
27
+ reader.say("Say it aloud") # Send the text to the sound card
28
+
29
+ reader.say("Give me the data") do |data|
30
+ # do stuff with the string of PCM WAVE bytes
31
+ end
32
+
33
+ reader.write("audio.wav", "Save the spoken text to a file")
34
+
35
+ Customize how the text is spoken
36
+
37
+ reader = Win32::Loquendo::Reader.new({
38
+ :sample_rate => 32000, # Pick a sample rate in Hz
39
+ :channels => 2, # Stereo or mono (1 or 2 audio channels)
40
+ :voice => "Elizabeth" # Specify the default voice to use
41
+ })
42
+
43
+ reader.say "Hi, this is Elizabeth speaking" # Speak with the default voice.
44
+ reader.say "and this is Simon", "Simon" # Override the default voice
45
+ # for this utterance.
46
+
47
+ reader.voices.each do |name| # List installed voices that can
48
+ reader.say "My name is #{name}", name # be used for speaking.
49
+ end
50
+
51
+ Note that you can customize a lot on the fly regarding how Loquendo speaks, by
52
+ simply adding commands as part of the text being spoken. For example:
53
+
54
+ * Trigger whatever pre-programmed demo phrase the voice used was shipped with.
55
+
56
+ reader.say("\\demosentence and I'm speaking through ruby win32-loquendo")
57
+
58
+ * Provide proper pronunciation for words using [X-SAMPA][*]
59
+
60
+ reader.say("Hello, or in Finnish; \SAMPA=;('t_de4ve)", "Dave")
61
+
62
+ Finally you can launch speech prompts in parallel, overlapping to the degree
63
+ you'd like by running reader instances in separate threads. This example
64
+ generates something eerily similar to Google's audio captchas, using 10
65
+ overlapping voices.
66
+
67
+ (0...40).to_a.shuffle.each_slice(4).map{|a| a.join(" ") }.map{|s|
68
+ Thread.new { Win32::Loquendo::Reader.new.say(s) }
69
+ }.each {|t|
70
+ t.join
71
+ }
72
+
73
+ A note of caution: Only ever interact with a reader from one and the same thread.
74
+ If used from different threads it will cause undefined behavior (errors,
75
+ hangs, crashes), since the library interact with C-code over FFI and such
76
+ interactions are not thread safe.
77
+
78
+ [*]: http://en.wikipedia.org/wiki/X-SAMPA
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "yard"
3
+
4
+ YARD::Rake::YardocTask.new do |t|
5
+ t.files = ['lib/*/*.rb']
6
+ end
@@ -0,0 +1,189 @@
1
+ require 'ffi'
2
+ require 'win32/registry'
3
+ require 'tempfile'
4
+
5
+ module Win32
6
+ module Loquendo
7
+
8
+ ###
9
+ # Reads text out loud or to file using the Loquendo TTS engine.
10
+ class Reader
11
+
12
+ ###
13
+ # @param [Hash] opts options to be used as default configuration.
14
+ # @option opts [Integer] :sample_rate (32000) in Hz.
15
+ # @option opts [Integer] :channels (2) denotes Stereo or mono, 2 or 1 channel.
16
+ # @option opts [String] :voice (Elisabeth) default voice to use unless
17
+ # overridden when calling {#say} or {#write}.
18
+ def initialize(opts={})
19
+ @opts = {
20
+ :sample_rate => 32000,
21
+ :channels => 2,
22
+ :voice => "Elizabeth"
23
+ }.merge(opts)
24
+ @speaking = false
25
+
26
+ # Sanity checking of input parameters
27
+ unless @opts[:sample_rate].kind_of?(Integer) && @opts[:sample_rate] > 0
28
+ raise LoquendoException, ":sample_rate must be an integer and larger than zero, but %s was specified" % @opts[:sample_rate].to_s
29
+ end
30
+ unless [1,2].include?( @opts[:channels] )
31
+ raise LoquendoException, "audio :channels must be either 1 or 2, but %s was specified" % @opts[:channels].to_s
32
+ end
33
+
34
+ # Instantiate the TTS reader
35
+ ptr = FFI::MemoryPointer.new :pointer
36
+
37
+ unless LoqTTS7.ttsNewReader(ptr,nil) == 0
38
+ LoqTTS7.ttsDeleteSession(nil)
39
+ raise LoquendoException, "Failed to create TTS reader"
40
+ end
41
+ @reader_ptr = ptr.read_pointer
42
+ @reader_ptr.freeze
43
+
44
+ # Register a callback for speaking so we know when speeches end, since
45
+ # we're interacting with the TTS engine asynchronously in order to avoid
46
+ # blocking the entire main thread while speaking is going on.
47
+ @callback = FFI::Function.new(:void, [:uint, :int, :pointer, :pointer]) do |speech_id, event, *ignore|
48
+ if event == 1
49
+ @speaking = false
50
+ info "End of speech ##{speech_id}"
51
+ end
52
+ end
53
+
54
+ unless LoqTTS7.ttsSetCallback(@reader_ptr, @callback, nil, 0) == 0
55
+ raise LoquendoException, "Failed to register TTS reading callback"
56
+ end
57
+
58
+ end # init
59
+
60
+ ###
61
+ # Writes +text+ spoken with +voice+ to +filename+.
62
+ # @param [String] filename to write the PCM WAV data to.
63
+ # @param [String,#read] text to be rendered to audio.
64
+ # @param [String] voice defaults to whatever voice was
65
+ # specified during the creation of the Reader object.
66
+ def write(filename, text, voice = @opts[:voice])
67
+ device = "LTTS7AudioFile"
68
+ load_voice(voice)
69
+ unless LoqTTS7.ttsSetAudio(@reader_ptr, device, filename, @opts[:sample_rate], 0, @opts[:channels], nil) == 0
70
+ raise LoquendoException, "Failed to prepare writing audio to file via #{device} library"
71
+ end
72
+ render_speech(text, device)
73
+ end
74
+
75
+ ###
76
+ # Speaks the provided +text+ using +voice+ through the sound card.
77
+ # If a block is provided, the spoken WAVE-data is handed as a string of
78
+ # bytes to the block instead of being sent to the sound card.
79
+ # @param [String,#read] text to be spoken.
80
+ # @param [String] voice uses whatever voice wasspecified during the
81
+ # creation of the Reader object unless overridden.
82
+ def say(text, voice = @opts[:voice])
83
+ if block_given?
84
+ data = nil
85
+ Dir.mktmpdir("loquendo_audio") do |dir|
86
+ file = File.join(dir,"spoken_text.wav")
87
+ write(file, text, voice)
88
+ data = open(file,'rb'){|f| f.read }
89
+ end
90
+ yield data
91
+ else
92
+ say_aloud(text, voice)
93
+ end
94
+ end
95
+
96
+ ###
97
+ # @return [Array<String>] a list of the installed voices, that can be
98
+ # used for speaking.
99
+ def voices
100
+ buff = FFI::MemoryPointer.new(:string, 1024)
101
+ unless LoqTTS7.ttsQuery(nil, 1, "Id", nil, buff, buff.size, false, false) == 0
102
+ raise LoquendoException, "Failed to query voices"
103
+ end
104
+ buff.read_string.split(";")
105
+ end
106
+
107
+ private #################################################################
108
+
109
+ def say_aloud(text, voice = @opts[:voice])
110
+ device = "LTTS7AudioBoard"
111
+ load_voice(voice)
112
+ unless LoqTTS7.ttsSetAudio(@reader_ptr, device, nil, @opts[:sample_rate], 0, @opts[:channels], nil) == 0
113
+ raise LoquendoException, "Failed to prepare playing audio via #{device} library"
114
+ end
115
+ render_speech(text, device)
116
+ end
117
+
118
+ def render_speech(text, device)
119
+ text = text.read if text.respond_to? :read
120
+ unless LoqTTS7.ttsRead(@reader_ptr, text, true, false, 0) == 0
121
+ raise LoquendoException, "Failed to playing audio via #{device} library"
122
+ end
123
+ @speaking = true # simulate synchronous behavior without making the program
124
+ while @speaking # "soft-block" for the speaking duration
125
+ sleep(0.01)
126
+ end
127
+ end
128
+
129
+ def load_voice(voice)
130
+ unless LoqTTS7.ttsLoadPersona(@reader_ptr, voice, nil, nil) == 0
131
+ LoqTTS7.ttsDeleteSession(nil)
132
+ raise LoquendoException, "Failed to load voice '#{voice}'"
133
+ end
134
+ end
135
+
136
+ def info(msg)
137
+ puts msg if $VERBOSE
138
+ end
139
+
140
+ end # Reader
141
+
142
+ # Custom exception used for this library
143
+ class LoquendoException < Exception
144
+ end
145
+
146
+ ###########################################################################
147
+ private ###################################################################
148
+
149
+ # Locate the installation path of the program and its DLLs
150
+ [ [ Win32::Registry::HKEY_LOCAL_MACHINE, "SOFTWARE\\Loquendo\\LTTS7\\Engine" ],
151
+ [ Win32::Registry::HKEY_CURRENT_USER, "SOFTWARE\\Loquendo\\LTTS7\\Engine" ]
152
+ ].each do |base,key|
153
+ begin
154
+ base.open(key) do |reg|
155
+ DLL_PATH ||= reg['DataPath']
156
+ end
157
+ rescue Win32::Registry::Error
158
+ end
159
+ end
160
+
161
+ raise LoquendoException, "Failed to find Loquendo TTS engine. Is the program installed?" unless defined?(DLL_PATH)
162
+
163
+ # @private
164
+ module LoqTTS7
165
+ extend FFI::Library
166
+ ffi_lib "#{DLL_PATH}bin\\LoqTTS7"
167
+ # reader ?
168
+ attach_function :ttsNewReader, [ :pointer, :pointer ], :int
169
+ # reader voice language ?
170
+ attach_function :ttsLoadPersona, [ :pointer, :string, :string, :string ], :int
171
+ # session
172
+ attach_function :ttsDeleteSession, [ :pointer ], :int
173
+ # reader device filename samplr ? chan ?
174
+ attach_function :ttsSetAudio, [ :pointer, :string, :string, :uint, :int, :int, :pointer ], :int
175
+ # reader text async ? ?
176
+ attach_function :ttsRead, [ :pointer, :string, :bool, :bool, :ulong ], :int
177
+ # nil 1 atts nil resbuff cbuff false false
178
+ attach_function :ttsQuery, [ :pointer, :int, :string, :string, :pointer, :uint, :bool, :bool ], :int
179
+ # reader callback nil 0
180
+ attach_function :ttsSetCallback, [ :pointer, :pointer, :pointer, :int ], :int
181
+ #
182
+ attach_function :ttsGetErrorMessage, [ :int ], :string
183
+ # reader
184
+ #attach_function :ttsStop, [ :pointer ], :int # Causes nasty hang in Ruby, probably GIL related..
185
+ end
186
+
187
+ end # Loquendo
188
+
189
+ end #Win32
@@ -0,0 +1,5 @@
1
+ module Win32
2
+ module Loquendo
3
+ VERSION = "1.0.1"
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'win32/loquendo/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "win32-loquendo"
8
+ spec.version = Win32::Loquendo::VERSION
9
+ spec.platform = Gem::Platform::CURRENT
10
+ spec.authors = ["Jonas Tingeborn"]
11
+ spec.email = ["tinjon@gmail.com"]
12
+ spec.description = %q{Ruby for the Win32 API of Loquendo speech synthesis programs}
13
+ spec.summary = %q{Ruby API for Loquendo speech synthesis}
14
+ spec.homepage = "https://github.com/jojje/win32-loquendo"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "ffi"
23
+
24
+ spec.rdoc_options += ['-m', 'README.md', '-x', 'lib/win32/(?!loquendo.rb).*',
25
+ 'lib/win32/loquendo.rb', 'LICENSE', 'README.md']
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.3"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "yard"
30
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: win32-loquendo
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: x86-mingw32
6
+ authors:
7
+ - Jonas Tingeborn
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Ruby for the Win32 API of Loquendo speech synthesis programs
70
+ email:
71
+ - tinjon@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - .yardopts
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - lib/win32/loquendo.rb
83
+ - lib/win32/loquendo/version.rb
84
+ - win32-loquendo.gemspec
85
+ homepage: https://github.com/jojje/win32-loquendo
86
+ licenses:
87
+ - MIT
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options:
91
+ - -m
92
+ - README.md
93
+ - -x
94
+ - lib/win32/(?!loquendo.rb).*
95
+ - lib/win32/loquendo.rb
96
+ - LICENSE
97
+ - README.md
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.0.6
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Ruby API for Loquendo speech synthesis
116
+ test_files: []
117
+ has_rdoc: