win32-loquendo 1.0.1-x86-mingw32

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.
@@ -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: