flite 0.0.3.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +97 -72
- data/bin/{saytime.rb → saytime} +19 -1
- data/bin/speaking-web-server +121 -0
- data/ext/flite/extconf.rb +40 -3
- data/ext/flite/rbflite.c +604 -83
- data/ext/flite/rbflite.h +10 -0
- data/ext/flite/win32_binary_gem.c +432 -0
- data/flite.gemspec +7 -3
- data/lib/flite.rb +45 -2
- data/lib/flite/version.rb +1 -1
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a1d5627fba26b34d2417f52876bdab6272624f8
|
4
|
+
data.tar.gz: fddcf4371388ef8258db15dc0a0aa2b8828924a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81961b439859672eec7b978c8e893a911e3ae44e68257debd20597cbbf8bddec898929541acc1b0d3496609f36941546fea049ea3e06a74253fa50265792a89c
|
7
|
+
data.tar.gz: 03370c926ff39c8fd461c8093bff07a8dafdcccd8934ce2e9895aa0466090681e019843912c2ba5328857218ebe18d790c7633df0fb9b0d7287fef1fbbce2cb3
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# Ruby Flite
|
2
2
|
|
3
|
-
Ruby
|
3
|
+
Ruby Flite is a small speech synthesis library for ruby using [CMU Flite](http://cmuflite.org).
|
4
4
|
|
5
5
|
CMU Flite (festival-lite) is a small, fast run-time synthesis engine developed
|
6
6
|
at CMU and primarily designed for small embedded machines and/or large
|
@@ -14,115 +14,140 @@ voices built using the [FestVox](http://festvox.org/) suite of voice building to
|
|
14
14
|
|
15
15
|
## Installation
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
```ruby
|
20
|
-
gem 'flite'
|
21
|
-
```
|
22
|
-
|
23
|
-
Install [CMU Flite](http://cmuflite.org):
|
17
|
+
Install [CMU Flite](http://cmuflite.org) and (optionally) [LAME](http://lame.sourceforge.net/).
|
24
18
|
|
25
19
|
```shell
|
26
20
|
# On ubuntu
|
27
21
|
sudo apt-get install flite1-dev
|
22
|
+
sudo apt-get install libmp3lame-dev # for mp3 support (optionally)
|
28
23
|
|
29
24
|
# On redhat
|
30
|
-
yum install flite
|
25
|
+
yum install flite-devel
|
26
|
+
yum install libmp3lame-devel # for mp3 support (optionally)
|
31
27
|
|
32
28
|
# On Windows
|
33
|
-
#
|
34
|
-
#
|
29
|
+
# You have no need to install CMU Flite and LAME if you use rubies distributed by
|
30
|
+
# rubyinstaller.org. Binary gems for the rubies include them.
|
31
|
+
|
32
|
+
# Others
|
33
|
+
# You need to install them by yourself.
|
35
34
|
```
|
36
35
|
|
37
36
|
And then execute:
|
38
37
|
|
39
|
-
$ bundle
|
40
|
-
|
41
|
-
Or install it yourself as:
|
42
|
-
|
43
38
|
$ gem install flite
|
44
39
|
|
45
|
-
Ruby
|
40
|
+
Ruby Flite tries to link with **all voices and languages**.
|
46
41
|
If you want to reduce dependent libraries, execute the followings
|
47
|
-
instead of above
|
48
|
-
|
49
|
-
$ bundle config --local build.flite --with-voices=kal --with-langs=eng
|
50
|
-
$ bundle
|
51
|
-
|
52
|
-
Or install it yourself as:
|
42
|
+
instead of above command.
|
53
43
|
|
54
44
|
$ gem install flite -- --with-voices=kal --with-langs=eng
|
55
45
|
|
56
|
-
##
|
46
|
+
## Examples
|
57
47
|
|
58
48
|
```ruby
|
59
49
|
require 'flite'
|
60
50
|
|
61
|
-
#
|
62
|
-
"Hello World!".
|
51
|
+
# Speak "Hello World!"
|
52
|
+
"Hello World!".speak
|
63
53
|
|
64
|
-
# save as
|
65
|
-
"Hello World!".to_speech
|
66
|
-
|
67
|
-
# write to an I/O object if it responds to 'write'.
|
68
|
-
File.open("hello_world.wave", "wb") do |f|
|
69
|
-
"Hello World!".to_speech(f)
|
70
|
-
end
|
71
|
-
```
|
72
|
-
## Advanced Usage
|
73
|
-
|
74
|
-
```ruby
|
75
|
-
require 'flite'
|
54
|
+
# Create a wav data and save as "hello_world.wav"
|
55
|
+
File.binwrite("hello_world.wav", "Hello World!".to_speech)
|
76
56
|
|
77
|
-
#
|
78
|
-
|
57
|
+
# Create a mp3 data and save as "hello_world.mp3"
|
58
|
+
# This works if mp3 support is enabled.
|
59
|
+
File.binwrite("hello_world.mp3", "Hello World!".to_speech(:mp3))
|
79
60
|
|
80
|
-
#
|
81
|
-
voice = Flite::Voice.new("slt")
|
82
|
-
|
83
|
-
# output to the speeker.
|
84
|
-
voice.speech("Hello World!")
|
85
|
-
|
86
|
-
# save as a WAVE file
|
87
|
-
voice.speech("Hello World!", "hello_world.wave")
|
88
|
-
|
89
|
-
# write to an I/O object if it responds to 'write'.
|
90
|
-
File.open("hello_world.wave", "wb") do |f|
|
91
|
-
voice.speech("Hello World!", f)
|
92
|
-
end
|
93
|
-
|
94
|
-
# Change the voice used for String#to_speech
|
61
|
+
# Change the voice used for String#speak and String#to_speech
|
95
62
|
Flite.default_voice = 'rms'
|
96
|
-
```
|
97
63
|
|
98
|
-
|
64
|
+
# Speak again
|
65
|
+
"Hello World!".speak
|
66
|
+
```
|
99
67
|
|
100
|
-
|
68
|
+
See:
|
69
|
+
|
70
|
+
* http://www.rubydoc.info/gems/flite/Flite/Voice
|
71
|
+
* http://www.rubydoc.info/gems/flite/String
|
72
|
+
|
73
|
+
## Sample Applications
|
74
|
+
|
75
|
+
### [saytime](https://github.com/kubo/ruby-flite/blob/master/bin/saytime) - talking clock
|
76
|
+
|
77
|
+
This is inspired by [saytime - talking clock for SPARCstations](http://acme.com/software/saytime/).
|
78
|
+
|
79
|
+
Example:
|
80
|
+
|
81
|
+
> Talk the current time once:
|
82
|
+
>
|
83
|
+
> ```shell
|
84
|
+
> saytime
|
85
|
+
> ```
|
86
|
+
>
|
87
|
+
> Talk the current time forever:
|
88
|
+
>
|
89
|
+
> ```shell
|
90
|
+
> saytime --loop
|
91
|
+
> ```
|
92
|
+
>
|
93
|
+
> Talk the current time 5 times
|
94
|
+
>
|
95
|
+
> ```shell
|
96
|
+
> saytime --loop 5
|
97
|
+
> ```
|
98
|
+
>
|
99
|
+
> Talk the current time 5 times with 10 second intervals
|
100
|
+
>
|
101
|
+
> ```shell
|
102
|
+
> saytime --loop 5 --interval 10
|
103
|
+
> ```
|
104
|
+
|
105
|
+
### [speaking-web-server](https://github.com/kubo/ruby-flite/blob/master/bin/speaking-web-server) - Web server replying synthesized speech
|
106
|
+
|
107
|
+
Usage:
|
108
|
+
|
109
|
+
> Start a web server:
|
110
|
+
>
|
111
|
+
> ```shell
|
112
|
+
> speaking-web-server
|
113
|
+
> ```
|
114
|
+
>
|
115
|
+
> Open a browser and access:
|
116
|
+
>
|
117
|
+
> http://HOSTNAME_OR_IP_ADDRESS:9080
|
118
|
+
> (Change HOSTNAME_OR_IP_ADDRESS.)
|
119
|
+
>
|
120
|
+
> Click 'Play' buttons.
|
101
121
|
|
102
122
|
## Restrictions
|
103
123
|
|
104
|
-
*
|
105
|
-
are not thread-safe. You need to create `Flite::Voice` objects for
|
106
|
-
each threads and use `Flite::Voice#speech`.
|
107
|
-
|
108
|
-
* `String#to_speech("play")` and `Flite::Voice#speech(text, "play")`
|
109
|
-
don't save wave data to the specified file `play`. They output speech
|
110
|
-
data to the speaker instead.
|
111
|
-
|
112
|
-
* `String#to_speech("stream")`, `String#to_speech("none")`,
|
113
|
-
`Flite::Voice#speech(text, "stream")` and `Flite::Voice#speech(text, "none")`
|
114
|
-
don't save wave data to the specified file `stream` or `none`. They
|
115
|
-
synthesize speech and discard the result.
|
124
|
+
* Ruby process doesn't terminate while talking.
|
116
125
|
|
117
126
|
* When an error occurs in CMU Flite, the error message is outputted to
|
118
127
|
the standard error.
|
119
128
|
|
129
|
+
* When a fatal error occurs in CMU Flite, the error message is outputted to
|
130
|
+
the standard error and the process is terminated. (CMU Flite calls `exit(-1)`...)
|
131
|
+
|
132
|
+
## NEWS
|
133
|
+
|
134
|
+
### 0.1.0
|
135
|
+
|
136
|
+
Almost methods were changed. Especially {String#to_speech} returns WAV
|
137
|
+
audio data instead of speaking. Use {String#speak} to speak a text.
|
138
|
+
|
120
139
|
## License
|
121
140
|
|
122
|
-
* Ruby
|
123
|
-
* CMU Flite is licensed under BSD-like license.
|
141
|
+
* Ruby Flite is licensed under 2-clause BSD-style license.
|
142
|
+
* CMU Flite bundled in Windows binary gems is licensed under BSD-like license.
|
124
143
|
See http://www.festvox.org/flite/download.html
|
144
|
+
* LAME bundled in Windows binary gems is licensed under LGPL.
|
145
|
+
|
146
|
+
## Related Works
|
125
147
|
|
148
|
+
* [flite4r](http://www.rubydoc.info/gems/flite4r/) - Flite for Ruby (GPL)
|
149
|
+
* [FestivalTTS4r](https://github.com/spejman/festivaltts4r) - Festival Text-To-Speech for Ruby
|
150
|
+
|
126
151
|
## Contributing
|
127
152
|
|
128
153
|
1. Fork it ( https://github.com/kubo/ruby-flite/fork )
|
data/bin/{saytime.rb → saytime}
RENAMED
@@ -1,5 +1,23 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
#
|
3
|
+
# saytime - talking clock
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# # Talk the current time once
|
7
|
+
# saytime
|
8
|
+
#
|
9
|
+
# # Talk the current time forever
|
10
|
+
# saytime --loop
|
11
|
+
#
|
12
|
+
# # Talk the current time 5 times
|
13
|
+
# saytime --loop 5
|
14
|
+
#
|
15
|
+
# # Talk the current time 5 times with 10 second intervals
|
16
|
+
# saytime --loop 5 --interval 10
|
17
|
+
#
|
18
|
+
# # Talk the current time with 'slt' and 'awb' voices
|
19
|
+
# saytime --voices=slt,awb
|
20
|
+
#
|
3
21
|
require 'flite'
|
4
22
|
require 'optparse'
|
5
23
|
|
@@ -40,7 +58,7 @@ def saytime(voice_name)
|
|
40
58
|
puts "voice: #{voice_name}"
|
41
59
|
|
42
60
|
voice = ($cached_voices[voice_name] ||= Flite::Voice.new(voice_name))
|
43
|
-
voice.
|
61
|
+
voice.speak(text)
|
44
62
|
end
|
45
63
|
|
46
64
|
voices = []
|
@@ -0,0 +1,121 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# speaking-web-server - Web server replying synthesized speech
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# 1. Start a Web server.
|
8
|
+
#
|
9
|
+
# speaking-web-server
|
10
|
+
#
|
11
|
+
# 2. Access to the web server.
|
12
|
+
#
|
13
|
+
# Open browser and access: http://HOSTNAME_OR_IP_ADDRESS:9080
|
14
|
+
# (Change HOSTNAME_OR_IP_ADDRESS.)
|
15
|
+
#
|
16
|
+
# 3. Click 'Play' buttons.
|
17
|
+
#
|
18
|
+
require 'webrick'
|
19
|
+
require 'flite'
|
20
|
+
|
21
|
+
def start_server(html_content)
|
22
|
+
srv = WEBrick::HTTPServer.new({:Port => 9080})
|
23
|
+
|
24
|
+
srv.mount_proc('/') do |req, res|
|
25
|
+
h = req.query
|
26
|
+
if h['text']
|
27
|
+
audio_type = if h['type'] == 'mp3'
|
28
|
+
:mp3
|
29
|
+
else
|
30
|
+
:wav
|
31
|
+
end
|
32
|
+
res['Content-type'] = "audio/#{audio_type}"
|
33
|
+
res['Content-Disposition'] = %Q{attachment; filename="audio.#{audio_type}"}
|
34
|
+
|
35
|
+
voice = Flite::Voice.new(h['voice'] || 'kal')
|
36
|
+
res.body = voice.to_speech(h['text'], audio_type)
|
37
|
+
else
|
38
|
+
res['Content-type'] = 'text/html'
|
39
|
+
res.body = html_content
|
40
|
+
end
|
41
|
+
end
|
42
|
+
trap("INT"){ srv.shutdown }
|
43
|
+
srv.start
|
44
|
+
end
|
45
|
+
|
46
|
+
html_content = <<EOS
|
47
|
+
<html>
|
48
|
+
<head>
|
49
|
+
<title>Flite CGI</title>
|
50
|
+
|
51
|
+
<script>
|
52
|
+
audio_type = 'wav';
|
53
|
+
|
54
|
+
function check_audio_type() {
|
55
|
+
var audio = new Audio;
|
56
|
+
if (audio.canPlayType('audio/wav') == '') {
|
57
|
+
if (#{Flite.supported_audio_types.include? :mp3} && audio.canPlayType('audio/mp3') != '') {
|
58
|
+
audio_type = 'mp3';
|
59
|
+
} else {
|
60
|
+
var text = document.getElementById('text');
|
61
|
+
text.disabled = true;
|
62
|
+
enable_buttons(false);
|
63
|
+
alert('Cannot play audio/wav in this browser.\\nUse Chrome, Firefox, Safari or Opera.');
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
function speak(voice) {
|
69
|
+
var text = document.getElementById('text');
|
70
|
+
if (text != '') {
|
71
|
+
var status = document.getElementById('status');
|
72
|
+
status.innerHTML = 'Playing'
|
73
|
+
enable_buttons(false);
|
74
|
+
var url = '/?voice=' + voice + '&type=' + audio_type + '&text=' + encodeURIComponent(text.value);
|
75
|
+
var audio = new Audio(url);
|
76
|
+
audio.onended = function() {
|
77
|
+
status.innerHTML = 'Finished'
|
78
|
+
enable_buttons(true);
|
79
|
+
};
|
80
|
+
audio.onabort = function() {
|
81
|
+
status.innerHTML = 'Abort'
|
82
|
+
enable_buttons(true);
|
83
|
+
};
|
84
|
+
audio.onerror = function() {
|
85
|
+
status.innerHTML = 'Error'
|
86
|
+
enable_buttons(true);
|
87
|
+
};
|
88
|
+
audio.play();
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
function enable_buttons(bval) {
|
93
|
+
var form = document.getElementById('speech_form');
|
94
|
+
var elements = form.elements;
|
95
|
+
for (var i = 0; i < elements.length; i++) {
|
96
|
+
var element = elements[i];
|
97
|
+
if (element.tagName == 'INPUT') {
|
98
|
+
element.disabled = !bval;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
</script>
|
103
|
+
|
104
|
+
</head>
|
105
|
+
<body onLoad="check_audio_type();">
|
106
|
+
|
107
|
+
<form id="speech_form">
|
108
|
+
<textarea id="text" name="text" cols=80 rows=4>Hello Flite World!</textarea>
|
109
|
+
<br />
|
110
|
+
<input type="button" value="Play(voice: kal)" onClick="speak('kal');">
|
111
|
+
<input type="button" value="Play(voice: kal16)" onClick="speak('kal16');">
|
112
|
+
<input type="button" value="Play(voice: awb)" onClick="speak('awb');">
|
113
|
+
<input type="button" value="Play(voice: rms)" onClick="speak('rms');">
|
114
|
+
<input type="button" value="Play(voice: slt)" onClick="speak('slt');">
|
115
|
+
</form>
|
116
|
+
Status: <span id="status" />
|
117
|
+
</body>
|
118
|
+
</html>
|
119
|
+
EOS
|
120
|
+
|
121
|
+
start_server(html_content)
|
data/ext/flite/extconf.rb
CHANGED
@@ -2,6 +2,8 @@ require "mkmf"
|
|
2
2
|
|
3
3
|
dir_config('flite')
|
4
4
|
|
5
|
+
libs_old = $libs
|
6
|
+
|
5
7
|
unless have_library('flite', 'flite_init')
|
6
8
|
saved_libs = $libs
|
7
9
|
puts "checkign for audio libraries depended by flite ..."
|
@@ -74,17 +76,52 @@ EOS
|
|
74
76
|
end
|
75
77
|
f.write <<EOS
|
76
78
|
|
77
|
-
|
79
|
+
#undef ENTRY
|
80
|
+
#ifdef RBFLITE_WIN32_BINARY_GEM
|
81
|
+
static cst_voice *dummy;
|
82
|
+
#define ENTRY(name, dll_name, func_name, var_name) {#name, func_name, &dummy, #dll_name, #func_name, #var_name}
|
83
|
+
#else
|
84
|
+
#define ENTRY(name, dll_name, func_name, var_name) {#name, func_name, &var_name}
|
85
|
+
const
|
86
|
+
#endif
|
87
|
+
|
88
|
+
rbflite_builtin_voice_t rbflite_builtin_voice_list[] = {
|
78
89
|
EOS
|
79
90
|
voices.each do |v|
|
80
|
-
f.puts(
|
91
|
+
f.puts(" ENTRY(#{v[0]}, flite_#{v[1]}.dll, register_#{v[1]}, #{v[2]}),")
|
81
92
|
end
|
82
93
|
f.write <<EOS
|
83
|
-
{NULL,
|
94
|
+
{NULL, },
|
84
95
|
};
|
96
|
+
|
97
|
+
#ifdef RBFLITE_WIN32_BINARY_GEM
|
98
|
+
EOS
|
99
|
+
voices.each_with_index do |v, idx|
|
100
|
+
f.write <<EOS
|
101
|
+
cst_voice *register_#{v[1]}(const char *voxdir)
|
102
|
+
{
|
103
|
+
return rbfile_call_voice_register_func(&rbflite_builtin_voice_list[#{idx}], voxdir);
|
104
|
+
}
|
105
|
+
EOS
|
106
|
+
end
|
107
|
+
f.write <<EOS
|
108
|
+
#endif
|
85
109
|
EOS
|
86
110
|
end
|
87
111
|
|
112
|
+
if have_library('mp3lame')
|
113
|
+
have_header('lame.h') || have_header('lame/lame.h')
|
114
|
+
end
|
115
|
+
|
88
116
|
RUBY_VERSION =~ /(\d+).(\d+)/
|
89
117
|
$defs << "-DInit_flite=Init_flite_#{$1}#{$2}0"
|
118
|
+
|
119
|
+
$objs = ['rbflite.o', 'rbflite_builtin_voice_list.o']
|
120
|
+
|
121
|
+
if with_config('win32-binary-gem')
|
122
|
+
$libs = libs_old
|
123
|
+
$defs << "-DRBFLITE_WIN32_BINARY_GEM"
|
124
|
+
$objs << 'win32_binary_gem.o'
|
125
|
+
end
|
126
|
+
|
90
127
|
create_makefile("flite_#{$1}#{$2}0")
|