freetts 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ ...