freetts 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ # emacs
2
+ *~
3
+ \#*\#
4
+
5
+ # Ruby / Rubygems
6
+ *.gem
7
+
data/.rvmrc.example ADDED
@@ -0,0 +1 @@
1
+ rvm --create jruby-X.Y.Z@freetts
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # Integration Exercise: Java Library Wrapper
2
+
3
+ ## Exercise Summary
4
+
5
+ - You should create a gem using JRuby that wraps an existing Java library.
6
+ - Your gem should work with a Java library that doesn't already have
7
+ a good wrapper.
8
+ - You should make the API for your library look and feel like Ruby, not Java.
9
+
10
+
11
+ ## A JRuby wrapper for FreeTTS
12
+ FreeTTS is a speech synthesis system written entirely in the JavaTM programming
13
+ language. It is based upon Flite: a small run-time speech synthesis engine
14
+ developed at Carnegie Mellon University. Flite is derived from the Festival
15
+ Speech Synthesis System from the University of Edinburgh and the FestVox project
16
+ from Carnegie Mellon University.
17
+
18
+ This wrapper exposes the most essential functionality required for processing
19
+ text-to-speech requests.
20
+
21
+
22
+ ### Sample Code
23
+ It's easy enough to pass a String to FreeTTS:
24
+
25
+ ```ruby
26
+ require "lib/freetts"
27
+
28
+ FreeTTS.speak "hello world"
29
+ ```
30
+
31
+ With a little bit of manipulation, FreeTTS can read the news to you:
32
+
33
+ ```ruby
34
+ require "uri"
35
+ require "rss"
36
+ require "lib/freetts"
37
+
38
+ uri = URI.parse("http://feeds.feedburner.com/RubyInside")
39
+ feed_items = RSS::Parser.parse(uri.read, false).items.first(5)
40
+ feed_items.each do |item|
41
+ puts item.title.content
42
+ FreeTTS.speak item.title.content
43
+ end
44
+ ```
45
+
46
+ You can change the currently selected voice and make modifications that
47
+ will affect pitch, rate of speech, and so on.
48
+
49
+ ```ruby
50
+ voice = FreeTTS::Voice.for_name("alan")
51
+ voice.pitch *= 1.25
52
+ voice.rate += 20
53
+ ```
54
+
55
+ Feel free to run any of the sample programs in the `examples/` directory
56
+ to see the library in action.
57
+
58
+ ```bash
59
+ examples/hello_world.rb
60
+ examples/rss_reader.rb
61
+ examples/voice_play.rb
62
+ ```
63
+
64
+
65
+ ## Future Enhancements
66
+ - An adapter for plugging IO objects directly into the speech synthesizer
67
+ - Whack out a gem version of the library
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ require "lib/freetts"
4
+
5
+ FreeTTS.speak("hello world")
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env jruby
2
+
3
+
4
+ $:.unshift File.join(File.dirname(__FILE__), "../lib")
5
+ require "uri"
6
+ require "rss"
7
+ require "freetts"
8
+
9
+
10
+ feed_url = "http://feeds.feedburner.com/RailsInside"
11
+
12
+ uri = URI.parse(feed_url)
13
+
14
+ feed_items = RSS::Parser.parse(uri.read, false).items.first(5)
15
+
16
+ feed_items.each do |item|
17
+ title = item.title.content
18
+ puts title
19
+ FreeTTS.speak(title)
20
+ end
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env jruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), "..")
4
+ require "lib/freetts"
5
+
6
+
7
+ # A summary of the available commands
8
+ HELP_MESSAGE = "Enter one of the following commands:\n" +
9
+ " v select a voice\n" +
10
+ " i view information for currently selected voice\n" +
11
+ " c change a setting for currently selected voice\n" +
12
+ " s speak a phrase\n" +
13
+ " h/? view this help message\n" +
14
+ " q/x quit"
15
+
16
+
17
+ # Display a summary of the available commands.
18
+ def display_help_message
19
+ puts HELP_MESSAGE
20
+ end
21
+
22
+
23
+ # Prompt the user to enter a command and return his input.
24
+ def prompt_for_input(prompt_string="Command")
25
+ $stdout.write("#{ prompt_string }:>> ")
26
+ $stdin.gets.chomp
27
+ end
28
+
29
+
30
+ # Allow the user to select a new current_voice from a list of options.
31
+ def select_voice
32
+ voices = FreeTTS::Voice.all
33
+ options_with_indices = voices.each_with_index.map { |v, i| "(#{ i }) #{ v }" }
34
+ puts "Select a voice by entering the appropriate number:"
35
+ puts " #{ options_with_indices.join(" ") }"
36
+
37
+ user_input = prompt_for_input("Selection")
38
+
39
+ if user_input =~ /\A\d+\Z/ and
40
+ (selected_name = voices[user_input.to_i] rescue nil)
41
+ FreeTTS.current_voice = FreeTTS::Voice.for_name(selected_name)
42
+ puts "Voice \"#{ selected_name }\" has been selected."
43
+ else
44
+ puts "Sorry, but that is not a valid selection."
45
+ end
46
+ end
47
+
48
+
49
+ # Display attribute values for the currently selected voice.
50
+ def show_voice_info
51
+ attributes = %w(age description domain duration_stretch gender locale)
52
+ attributes += %w(organization pitch pitch_range pitch_shift rate style volume)
53
+
54
+ voice = FreeTTS.current_voice
55
+ puts "Current settings for voice \"#{ voice.name } \":"
56
+ attributes.each do |attribute|
57
+ puts " #{ attribute.ljust(20) }#{ voice.send(attribute.to_sym) }"
58
+ end
59
+ end
60
+
61
+ # Change an attribute for the currently selected voice.
62
+ def change_voice_setting
63
+ update_attributes = %w( duration_stretch pitch pitch_range pitch_shift )
64
+ update_attributes += %w( rate volume )
65
+
66
+ options_with_indices = update_attributes.each_with_index.
67
+ map { |v, i| "(#{ i }) #{ v }" }
68
+ puts "Select an attribute to update by entering the appropriate number:"
69
+ puts " #{ options_with_indices.join(" ") }"
70
+
71
+ user_input = prompt_for_input("Selection")
72
+
73
+ if user_input =~ /\A\d+\Z/ and
74
+ (0..update_attributes.size).include?(user_input.to_i)
75
+ selected_attribute = update_attributes[user_input.to_i]
76
+ current_value = FreeTTS.current_voice.send(selected_attribute.to_sym)
77
+
78
+ user_input = prompt_for_input("New value (current: #{ current_value })")
79
+
80
+ #begin
81
+ new_value = Float(user_input)
82
+ FreeTTS.current_voice.send((selected_attribute + "=").to_sym, new_value)
83
+ puts "Set \"selected_attribute\" to value #{ new_value }"
84
+ #rescue Exception => e
85
+ #puts e
86
+ #puts "Illegal argument: requested value may be out of range for this attribute"
87
+ #end
88
+ else
89
+ puts "Sorry, but that is not a valid selection."
90
+ end
91
+ end
92
+
93
+ # Prompt the user to enter text to speak, and pass it to FreeTTS.
94
+ def prompt_for_speakable
95
+ puts "Enter text to be spoken:>> "
96
+ user_input = $stdin.gets.chomp
97
+ FreeTTS.speak(user_input)
98
+ end
99
+
100
+
101
+ def unknown_command(command)
102
+ puts "Sorry, I don't know how to '#{ command }'."
103
+ end
104
+
105
+
106
+ display_help_message
107
+
108
+ loop do
109
+ entered_command = prompt_for_input
110
+
111
+ case entered_command.downcase.chars.to_a[0]
112
+ when "v"
113
+ select_voice
114
+ when "i"
115
+ show_voice_info
116
+ when "c"
117
+ change_voice_setting
118
+ when "s"
119
+ prompt_for_speakable
120
+ when "h", "?"
121
+ display_help_message
122
+ when "q", "x"
123
+ break
124
+ else
125
+ unknown_command(entered_command)
126
+ end
127
+ end
128
+
129
+
130
+
131
+
132
+
133
+
data/lib/freetts.rb ADDED
@@ -0,0 +1,18 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require "java"
4
+ require "vendor/freetts.jar"
5
+
6
+ require "freetts/voice"
7
+ require "freetts/version"
8
+
9
+
10
+ module FreeTTS
11
+ @current_voice = Voice.for_name(Voice::DEFAULT_NAME)
12
+ class << self; attr_accessor :current_voice; end
13
+
14
+
15
+ def self.speak(speakable)
16
+ self.current_voice.speak(speakable)
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module FreeTTS
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,47 @@
1
+ module FreeTTS
2
+ class Voice
3
+ DEFAULT_NAME = "kevin16"
4
+
5
+ @voice_manager = com.sun.speech.freetts.VoiceManager.get_instance
6
+ class << self; attr_reader :voice_manager; end
7
+
8
+
9
+ def initialize(voice)
10
+ @voice_impl = voice
11
+ end
12
+
13
+ def speak(saying)
14
+ @voice_impl.speak(saying)
15
+ end
16
+
17
+ def method_missing(method, *args, &block)
18
+ method = method.to_s
19
+ java_method_name = case method
20
+ when /\A(.*)=\Z/
21
+ "set_#{ $1 }"
22
+ when /\A(.*)\Z/
23
+ "get_#{ $1 }"
24
+ end
25
+
26
+ if java_method_name and @voice_impl.respond_to?(java_method_name.to_sym)
27
+ return @voice_impl.send(java_method_name.to_sym, *args)
28
+ else
29
+ error_message = "undefined method #{ method } for #{ self }:Voice"
30
+ raise NoMethodError.new(error_message)
31
+ end
32
+ end
33
+
34
+ def self.all
35
+ voice_manager.get_voices.map { |voice| voice.get_name }
36
+ end
37
+
38
+ def self.for_name(voice_name)
39
+ if voice = voice_manager.get_voice(voice_name)
40
+ voice.allocate
41
+ Voice.new(voice)
42
+ else
43
+ raise "no voice found for name \"#{ voice_name }\""
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "../lib")
2
+
3
+ require "freetts"
4
+ require "test/unit"
5
+
6
+
7
+ class FreeTTSTest < Test::Unit::TestCase
8
+ def test_setting_current_voice
9
+ start_voice = FreeTTS.current_voice
10
+ all_voices = FreeTTS::Voice.all
11
+
12
+ new_voice_name = all_voices.reject { |name| name == start_voice.name }.first
13
+ FreeTTS.current_voice = FreeTTS::Voice.for_name(new_voice_name)
14
+ new_voice = FreeTTS.current_voice
15
+
16
+ assert_not_nil(new_voice)
17
+ assert_equal(new_voice_name, new_voice.name)
18
+ end
19
+ end
@@ -0,0 +1,64 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "../lib")
2
+
3
+ require "freetts"
4
+ require "test/unit"
5
+
6
+
7
+ class VoiceTest < Test::Unit::TestCase
8
+ def valid_voice
9
+ FreeTTS.current_voice
10
+ end
11
+
12
+ # Calling valid accessor methods should result in a successful invocation.
13
+ def test_valid_accessor_methods
14
+ valid_accessors = %w( description gender locale pitch rate style )
15
+ valid_accessors.each do |method|
16
+ assert_nothing_raised do
17
+ valid_voice.send(method.to_sym)
18
+ end
19
+ end
20
+ end
21
+
22
+ # Calling unknown accessor methods should raise a NoMethodException.
23
+ def test_invalid_accessor_methods
24
+ invalid_accessors = %w( something voice wallaby wombat parakeet )
25
+ invalid_accessors.each do |method|
26
+ assert_raises(NoMethodError) do
27
+ valid_voice.send(method.to_sym)
28
+ end
29
+ end
30
+ end
31
+
32
+ # A request for all voices should get an array of names.
33
+ def test_fetch_voices
34
+ voice_names = FreeTTS::Voice.all
35
+ assert_instance_of(Array, voice_names)
36
+
37
+ voice_names.each do |voice_name|
38
+ assert_instance_of(String, voice_name)
39
+ end
40
+ end
41
+
42
+ # Requesting an available voice by name should return the relevant voice.
43
+ def test_fetch_any_single_valid_voice
44
+ voice_names = FreeTTS::Voice.all
45
+
46
+ voice_names.each do |voice_name|
47
+ assert_nothing_raised do
48
+ voice = FreeTTS::Voice.for_name(voice_name)
49
+ assert_instance_of(FreeTTS::Voice, voice)
50
+ assert_equal(voice_name, voice.name)
51
+ end
52
+ end
53
+ end
54
+
55
+ # Attempting to fetch a non-existent voice should raise an exception.
56
+ def test_cannot_fetch_fake_voices
57
+ fake_voices = ["Ed McMahon", "Casey Kasem", "Rick Dees", "Frank Sinatra"]
58
+ fake_voices.each do |voice_name|
59
+ assert_raises(RuntimeError) do
60
+ FreeTTS::Voice.for_name(voice_name)
61
+ end
62
+ end
63
+ end
64
+ end
Binary file
Binary file
Binary file
data/vendor/cmulex.jar ADDED
Binary file
Binary file
data/vendor/en_us.jar ADDED
Binary file
Binary file
data/vendor/voices.txt ADDED
@@ -0,0 +1,13 @@
1
+ # This file lists the voice directories avialable to FreeTTs.
2
+ # To get the name of a voice directory from a voice jar file,
3
+ # type "java -jar voicefile.jar".
4
+ #
5
+ # Entries should look like:
6
+ #com.sun.speech.freetts.en.us.cmu_time_awb.AlanVoiceDirectory
7
+ #com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory
8
+
9
+ com.sun.speech.freetts.en.us.cmu_time_awb.AlanVoiceDirectory
10
+ com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory
11
+
12
+ # Uncomment to allow MBROLA voices:
13
+ #de.dfki.lt.freetts.en.us.MbrolaVoiceDirectory
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: freetts
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Chris kottom
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-19 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+ description: FreeTTS provides a simple wrapper around the Java library of the same name in order to expose a voice synthesis API.
16
+ email: chris@chriskottom.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - .rvmrc.example
23
+ - README.md
24
+ - examples/hello_world.rb
25
+ - examples/rss_reader.rb
26
+ - examples/voice_play.rb
27
+ - lib/freetts.rb
28
+ - lib/freetts/version.rb
29
+ - lib/freetts/voice.rb
30
+ - test/freetts_test.rb
31
+ - test/voice_test.rb
32
+ - vendor/cmu_time_awb.jar
33
+ - vendor/cmu_us_kal.jar
34
+ - vendor/cmudict04.jar
35
+ - vendor/cmulex.jar
36
+ - vendor/cmutimelex.jar
37
+ - vendor/en_us.jar
38
+ - vendor/freetts.jar
39
+ - vendor/voices.txt
40
+ has_rdoc: true
41
+ homepage: ''
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ none: false
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ none: false
59
+ requirements: []
60
+ rubyforge_project: freetts
61
+ rubygems_version: 1.5.1
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: A voice synthesizer in JRuby
65
+ test_files: []
66
+ ...