tts-acapela 0.1.0

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,2 @@
1
+
2
+ = A client for the Acapela TTS server
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ gem 'rspec', '>= 2'
3
+ require 'rspec'
4
+ require 'rspec/core/rake_task'
5
+
6
+ namespace :gem do
7
+
8
+ desc "Builds the gem"
9
+ task :build do
10
+ system "gem build *.gemspec && mkdir -p pkg/ && mv *.gem pkg/"
11
+ end
12
+
13
+ desc "Builds and installs the gem"
14
+ task :install => :build do
15
+ system "gem install pkg/"
16
+ end
17
+
18
+ end
19
+
20
+ namespace :ext do
21
+
22
+ task :create_makefile do
23
+ chdir("ext") { ruby "extconf.rb" }
24
+ end
25
+
26
+ task :compile => :create_makefile do
27
+ chdir("ext") { sh "make" }
28
+ end
29
+
30
+ task :move_objects do
31
+ chdir("ext") do
32
+ mkdir_p "objs"
33
+ Dir["*.o"].each do |filename|
34
+ mv filename, "objs"
35
+ end
36
+ end
37
+ end
38
+
39
+ task :build => [ :compile, :move_objects ] do
40
+
41
+ end
42
+
43
+ end
44
+
45
+ desc "Run all specs in spec/lib directory"
46
+ RSpec::Core::RakeTask.new(:spec) do |task|
47
+ task.pattern = "spec/lib/**/*_spec.rb"
48
+ end
49
+
50
+ namespace :spec do
51
+
52
+ desc "Run all specs in spec/acceptance directory"
53
+ RSpec::Core::RakeTask.new(:acceptance => "ext:build") do |task|
54
+ task.pattern = "spec/acceptance/**/*_spec.rb"
55
+ end
56
+
57
+ end
@@ -0,0 +1,163 @@
1
+ #include "acapela.h"
2
+
3
+ // private functions
4
+
5
+ VALUE notConnectedErrorClass;
6
+ VALUE responseErrorClass;
7
+ VALUE valueErrorClass;
8
+
9
+ void checkConnection(const char* methodName, VALUE self) {
10
+ if (acapela_connected(self) == Qfalse)
11
+ rb_raise(notConnectedErrorClass, "method '%s' can just be executed with a open connection", methodName);
12
+ }
13
+
14
+ void checkResponse(const char* action, nscRESULT response) {
15
+ if (response != NSC_OK)
16
+ rb_raise(responseErrorClass, "error %d while performing action '%s'\n", response, action);
17
+ }
18
+
19
+ int callback_speech_data(
20
+ const unsigned char *data,
21
+ unsigned int dataSize,
22
+ PNSC_SOUND_DATA soundData,
23
+ void *instanceData
24
+ ) {
25
+ fwrite(data, dataSize, 1, (FILE*)instanceData);
26
+ return 0;
27
+ }
28
+
29
+ void initializeExecutionData(NSC_EXEC_DATA* executionData, FILE *file) {
30
+ executionData->pfnSpeechData = callback_speech_data;
31
+ executionData->pfnSpeechEvent = NULL;
32
+ executionData->ulEventFilter = NSC_EVTBIT_TEXT;
33
+ executionData->bEventSynchroReq = 1;
34
+ executionData->vsSoundData.uiSize = 0;
35
+ executionData->vsSoundData.pSoundBuffer = NULL;
36
+ executionData->pAppInstanceData = (void*)file;
37
+ }
38
+
39
+ // public functions
40
+
41
+ void Init_acapela() {
42
+ VALUE ttsModule = rb_define_module("TTS");
43
+ VALUE acapelaClass = rb_define_class_under(ttsModule, "Acapela", rb_cObject);
44
+ notConnectedErrorClass = rb_const_get(acapelaClass, rb_intern("NotConnectedError"));
45
+ responseErrorClass = rb_const_get(acapelaClass, rb_intern("ResponseError"));
46
+ valueErrorClass = rb_const_get(acapelaClass, rb_intern("ValueError"));
47
+
48
+ rb_define_method(acapelaClass, "connect", acapela_connect, 0);
49
+ rb_define_method(acapelaClass, "connected?", acapela_connected, 0);
50
+ rb_define_method(acapelaClass, "disconnect", acapela_disconnect, 0);
51
+ rb_define_method(acapelaClass, "voices", acapela_voices, 0);
52
+ rb_define_method(acapelaClass, "synthesize", acapela_synthesize, 1);
53
+ }
54
+
55
+ VALUE acapela_connect(VALUE self) {
56
+ nscHSRV *serverHandle;
57
+ nscHANDLE *dispatcherHandle;
58
+
59
+ if (acapela_connected(self) == Qtrue)
60
+ return Qfalse;
61
+
62
+ VALUE host = rb_ivar_get(self, rb_intern("@host"));
63
+ VALUE commandPort = rb_ivar_get(self, rb_intern("@command_port"));
64
+ VALUE dataPort = rb_ivar_get(self, rb_intern("@data_port"));
65
+
66
+ serverHandle = (nscHSRV*)malloc(sizeof(nscHSRV));
67
+ checkResponse("connecting", nscCreateServerContextEx(NSC_AF_INET, NUM2INT(commandPort), NUM2INT(dataPort), StringValuePtr(host), serverHandle));
68
+ rb_ivar_set(self, rb_intern("@connection"), (VALUE)serverHandle);
69
+
70
+ dispatcherHandle = (nscHANDLE*)malloc(sizeof(nscHANDLE));
71
+ checkResponse("creating dispatcher", nscCreateDispatcher(dispatcherHandle));
72
+ rb_ivar_set(self, rb_intern("@dispatcher"), (VALUE)dispatcherHandle);
73
+
74
+ return Qtrue;
75
+ }
76
+
77
+ VALUE acapela_connected(VALUE self) {
78
+ return rb_ivar_get(self, rb_intern("@connection")) == Qnil ? Qfalse : Qtrue;
79
+ }
80
+
81
+ VALUE acapela_disconnect(VALUE self) {
82
+ nscHSRV *serverHandle;
83
+ nscHANDLE *dispatcherHandle;
84
+
85
+ if (acapela_connected(self) == Qfalse)
86
+ return Qfalse;
87
+
88
+ dispatcherHandle = (nscHANDLE*)rb_ivar_get(self, rb_intern("@dispatcher"));
89
+ checkResponse("deleting dispatcher", nscDeleteDispatcher(*dispatcherHandle));
90
+ rb_ivar_set(self, rb_intern("@dispatcher"), Qnil);
91
+ free(dispatcherHandle);
92
+
93
+ serverHandle = (nscHSRV*)rb_ivar_get(self, rb_intern("@connection"));
94
+ checkResponse("disconnecting", nscReleaseServerContext(*serverHandle));
95
+ rb_ivar_set(self, rb_intern("@connection"), Qnil);
96
+ free(serverHandle);
97
+
98
+ return Qtrue;
99
+ }
100
+
101
+ VALUE acapela_voices(VALUE self) {
102
+ VALUE result;
103
+
104
+ nscRESULT response;
105
+ nscHSRV *serverHandle;
106
+
107
+ nscHANDLE voiceHandle;
108
+ NSC_FINDVOICE_DATA voice;
109
+
110
+ checkConnection("voices", self);
111
+
112
+ serverHandle = (nscHSRV*)rb_ivar_get(self, rb_intern("@connection"));
113
+
114
+ result = rb_ary_new();
115
+ response = nscFindFirstVoice(*serverHandle, NULL, 0, 0, 0, &voice, &voiceHandle);
116
+ while (response == NSC_OK) {
117
+ rb_ary_push(result, rb_str_new2(voice.cVoiceName));
118
+ response = nscFindNextVoice(voiceHandle, &voice);
119
+ }
120
+ nscCloseFindVoice(voiceHandle);
121
+
122
+ return result;
123
+ }
124
+
125
+ VALUE acapela_synthesize(VALUE self, VALUE text) {
126
+ VALUE result;
127
+
128
+ nscRESULT response;
129
+ nscHSRV* serverHandle;
130
+ nscHANDLE* dispatcherHandle;
131
+ VALUE voice;
132
+ int sampleFrequency;
133
+ nscHANDLE ttsHandle;
134
+ NSC_EXEC_DATA executionData;
135
+ char* filename;
136
+ FILE* file;
137
+ nscCHANID channelId;
138
+
139
+ checkConnection("synthesize", self);
140
+
141
+ serverHandle = (nscHSRV*)rb_ivar_get(self, rb_intern("@connection"));
142
+ dispatcherHandle = (nscHANDLE*)rb_ivar_get(self, rb_intern("@dispatcher"));
143
+ voice = rb_ivar_get(self, rb_intern("@voice"));
144
+ sampleFrequency = rb_ivar_get(self, rb_intern("@sample_frequency"));
145
+
146
+ checkResponse("opening channel", nscInitChannel(*serverHandle, StringValuePtr(voice), NUM2INT(sampleFrequency), 0, *dispatcherHandle, &channelId));
147
+ checkResponse("lock channel", nscLockChannel(*serverHandle, channelId, *dispatcherHandle, &ttsHandle));
148
+ checkResponse("add text", nscAddTextEx(ttsHandle, "UTF-8", StringValuePtr(text), strlen(StringValuePtr(text)), NULL));
149
+
150
+ filename = tmpnam(NULL);
151
+ file = fopen(filename, "w");
152
+ initializeExecutionData(&executionData, file);
153
+ checkResponse("execute channel", nscExecChannel(ttsHandle, &executionData));
154
+ fclose(file);
155
+
156
+ checkResponse("unlock channel", nscUnlockChannel(ttsHandle));
157
+ checkResponse("closing channel", nscCloseChannel(*serverHandle, channelId));
158
+
159
+ VALUE fileClass = rb_const_get(rb_cObject, rb_intern("File"));
160
+ result = rb_funcall(fileClass, rb_intern("new"), 1, rb_str_new2(filename));
161
+
162
+ return result;
163
+ }
@@ -0,0 +1,14 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+
5
+ #include "ruby.h"
6
+ #include "nscube.h"
7
+
8
+ void Init_acapela();
9
+
10
+ VALUE acapela_connect(VALUE self);
11
+ VALUE acapela_connected(VALUE self);
12
+ VALUE acapela_disconnect(VALUE self);
13
+ VALUE acapela_voices(VALUE self);
14
+ VALUE acapela_synthesize(VALUE self, VALUE text);
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ extension_name = "acapela"
4
+
5
+ dir_config extension_name, "/opt/Acapela/TelecomTTS/include"
6
+
7
+ found_nscube = find_library "nscube", "nscCreateServerContext", "/opt/Acapela/TelecomTTS/lib"
8
+
9
+ if found_nscube
10
+ create_makefile extension_name
11
+ else
12
+ puts "library 'nscube' is required, but wasn't found.\n"
13
+ exit 1
14
+ end
@@ -0,0 +1,7 @@
1
+
2
+ module TTS
3
+
4
+ autoload :Acapela, File.join(File.dirname(__FILE__), "tts", "acapela")
5
+ autoload :Cache, File.join(File.dirname(__FILE__), "tts", "cache")
6
+
7
+ end
@@ -0,0 +1,41 @@
1
+
2
+ module TTS
3
+
4
+ class Acapela
5
+
6
+ class Error < StandardError; end
7
+ class NotConnectedError < Error; end
8
+ class ResponseError < Error; end
9
+ class ValueError < Error; end
10
+ class VoiceNotSupportedError < Error; end
11
+
12
+ attr_accessor :host
13
+ attr_accessor :command_port
14
+ attr_accessor :data_port
15
+ attr_accessor :voice
16
+ attr_reader :sample_frequency
17
+ attr_accessor :cache_directory
18
+
19
+ def initialize(options = { })
20
+ self.host = options[:host] || "127.0.0.1"
21
+ self.command_port = options[:command_port] || 6666
22
+ self.data_port = options[:data_port] || 6665
23
+ self.voice = options[:voice]
24
+ self.sample_frequency = options[:sample_frequency] || 22050
25
+ self.cache_directory = options[:cache_directory] || "/tmp"
26
+ end
27
+
28
+ def sample_frequency=(value)
29
+ raise ValueError, "sample frequency #{value} is not supported. try 22050, 16000, 11025 or 8000." unless [ 22050, 16000, 11025, 8000 ].include?(value)
30
+ @sample_frequency = value
31
+ end
32
+
33
+ def settings_stamp
34
+ "#{@voice}#{@sample_frequency}"
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
41
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "ext", "acapela"))
@@ -0,0 +1,41 @@
1
+ require 'digest/md5'
2
+ require 'fileutils'
3
+
4
+ module TTS
5
+
6
+ class Cache
7
+
8
+ attr_accessor :tts
9
+ attr_accessor :cache_directory
10
+
11
+ def initialize(tts, cache_directory)
12
+ @tts, @cache_directory = tts, cache_directory
13
+ FileUtils.mkdir_p @cache_directory
14
+ end
15
+
16
+ def clear
17
+ FileUtils.rm Dir[File.join(@cache_directory, "*.pcm")]
18
+ end
19
+
20
+ def synthesize(text)
21
+ cache_filename = cache_path(text)
22
+ unless File.exists?(cache_filename)
23
+ file = @tts.synthesize text
24
+ FileUtils.mv file.path, cache_filename
25
+ end
26
+ File.new cache_filename
27
+ end
28
+
29
+ private
30
+
31
+ def cache_path(text)
32
+ File.join @cache_directory, cache_filename(text)
33
+ end
34
+
35
+ def cache_filename(text)
36
+ Digest::MD5.hexdigest("#{text}#{@tts.settings_stamp}") + ".pcm"
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,154 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
3
+
4
+ describe TTS::Acapela do
5
+
6
+ before :each do
7
+ @acapela = described_class.new :host => "46.51.190.56"
8
+ end
9
+
10
+ shared_examples_for "a method that need an open connection" do
11
+
12
+ it "should raise an #{TTS::Acapela::NotConnectedError} if disconnected" do
13
+ @acapela.disconnect
14
+ lambda do
15
+ do_call
16
+ end.should raise_error(TTS::Acapela::NotConnectedError);
17
+ end
18
+
19
+ end
20
+
21
+ describe "connect" do
22
+
23
+ after :each do
24
+ @acapela.disconnect
25
+ end
26
+
27
+ it "should change the state to connected" do
28
+ lambda do
29
+ @acapela.connect
30
+ end.should change(@acapela, :connected?).from(false).to(true)
31
+ end
32
+
33
+ it "should not raise an error if it's already connected" do
34
+ @acapela.connect
35
+ lambda do
36
+ @acapela.connect
37
+ end.should_not raise_error
38
+ end
39
+
40
+ end
41
+
42
+ describe "disconnect" do
43
+
44
+ before :each do
45
+ @acapela.connect
46
+ end
47
+
48
+ it "should change the state to disconnected" do
49
+ lambda do
50
+ @acapela.disconnect
51
+ end.should change(@acapela, :connected?).from(true).to(false)
52
+ end
53
+
54
+ it "should not raise an error if it's already disconnected" do
55
+ @acapela.disconnect
56
+ lambda do
57
+ @acapela.disconnect
58
+ end.should_not raise_error
59
+ end
60
+
61
+ end
62
+
63
+ describe "voices" do
64
+
65
+ before :each do
66
+ @acapela.connect
67
+ end
68
+
69
+ after :each do
70
+ @acapela.disconnect
71
+ end
72
+
73
+ def do_call
74
+ @acapela.voices
75
+ end
76
+
77
+ it_should_behave_like "a method that need an open connection"
78
+
79
+ it "should return an array of voices" do
80
+ voices = do_call
81
+ voices.should be_instance_of(Array)
82
+ voices.should == [
83
+ "julia22k", "klaus22k", "lucy22k", "bruno22k", "claire22k", "julie22k",
84
+ "peter22k", "sarah22k", "rachel22k", "justine22k", "graham22k", "alice22k"
85
+ ]
86
+ end
87
+
88
+ end
89
+
90
+ describe "synthesize" do
91
+
92
+ before :each do
93
+ @acapela.connect
94
+ @acapela.voice = "sarah22k"
95
+ end
96
+
97
+ after :each do
98
+ File.delete @file.path if @file
99
+ @acapela.disconnect
100
+ end
101
+
102
+ def do_call(text = "Hallo Welt")
103
+ @acapela.synthesize text
104
+ end
105
+
106
+ it_should_behave_like "a method that need an open connection"
107
+
108
+ it "should return a file with the synthesized text" do
109
+ @file = do_call
110
+ @file.should be_instance_of(File)
111
+ end
112
+
113
+ context "with voice 'julia22k'" do
114
+
115
+ before :each do
116
+ @acapela.voice = "julia22k"
117
+ end
118
+
119
+ it "should return the correct file" do
120
+ @file = do_call
121
+ md5 = Digest::MD5.hexdigest File.read(@file.path)
122
+ md5.should == "7e50b6c1666ec97be6c84b9dacf0ef89"
123
+ end
124
+
125
+ end
126
+
127
+ context "with voice 'lucy22k'" do
128
+
129
+ before :each do
130
+ @acapela.voice = "lucy22k"
131
+ end
132
+
133
+ it "should return the correct file" do
134
+ @file = do_call
135
+ md5 = Digest::MD5.hexdigest File.read(@file.path)
136
+ md5.should == "8288953a25090a2089b86ac324e582dc"
137
+ end
138
+
139
+ end
140
+
141
+ context "with a text with special characters" do
142
+
143
+ it "should return the correct file" do
144
+ @file = do_call "Schönhauser-Allee"
145
+ `cp #{@file.path} /home/phifty/Desktop/test.pcm`
146
+ md5 = Digest::MD5.hexdigest File.read(@file.path)
147
+ md5.should == "bf3ab75c5b55b4815e810ac6b0c83ee0"
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+
154
+ end
@@ -0,0 +1,63 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+
3
+ describe TTS::Cache do
4
+
5
+ before :each do
6
+ @acapela = TTS::Acapela.new :host => "46.51.190.56", :voice => "julia22k", :sample_frequency => 22050
7
+ @acapela.connect
8
+
9
+ @cache = described_class.new @acapela, "/tmp/cache"
10
+ end
11
+
12
+ after :each do
13
+ @cache.clear
14
+ @acapela.disconnect
15
+ end
16
+
17
+ describe "synthesize" do
18
+
19
+ before :each do
20
+ @cache_filename = "/tmp/cache/58bb7452ad8aaa2a25509ec076cc979d.pcm"
21
+ end
22
+
23
+ context "for a new request" do
24
+
25
+ before :each do
26
+ @cache.clear
27
+ end
28
+
29
+ it "should create a new cache file" do
30
+ File.exists?(@cache_filename).should be_false
31
+ @cache.synthesize "Hallo"
32
+ File.exists?(@cache_filename).should be_true
33
+ end
34
+
35
+ it "should return the right file" do
36
+ file = @cache.synthesize "Hallo"
37
+ file.path.should == @cache_filename
38
+ end
39
+
40
+ end
41
+
42
+ context "for a cached request" do
43
+
44
+ before :each do
45
+ @cache.synthesize "Hallo"
46
+ end
47
+
48
+ it "should not create a new cache file" do
49
+ File.exists?(@cache_filename).should be_true
50
+ @cache.synthesize "Hallo"
51
+ File.exists?(@cache_filename).should be_true
52
+ end
53
+
54
+ it "should return the right file" do
55
+ file = @cache.synthesize "Hallo"
56
+ file.path.should == @cache_filename
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
2
+
3
+ describe TTS::Acapela do
4
+
5
+ before :each do
6
+ @acapela = described_class.new :voice => "julia22k", :sample_frequency => 22050
7
+ end
8
+
9
+ describe "sample_frequency=" do
10
+
11
+ it "should set the sample frequency" do
12
+ @acapela.sample_frequency = 22050
13
+ @acapela.sample_frequency == 22050
14
+ end
15
+
16
+ it "should raise an #{TTS::Acapela::ValueError} on an invalid value" do
17
+ lambda do
18
+ @acapela.sample_frequency = 5
19
+ end.should raise_error(TTS::Acapela::ValueError)
20
+
21
+ lambda do
22
+ @acapela.sample_frequency = "invalid"
23
+ end.should raise_error(TTS::Acapela::ValueError)
24
+ end
25
+
26
+ end
27
+
28
+ describe "settings_stamp" do
29
+
30
+ it "should return a string with a snapshort of the synthesize-settings" do
31
+ @acapela.settings_stamp.should == "julia22k22050"
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,106 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
2
+
3
+ describe TTS::Cache do
4
+
5
+ before :each do
6
+ FileUtils.stub(:mkdir_p)
7
+
8
+ @acapela = mock TTS::Acapela, :settings_stamp => "julia22k22050"
9
+
10
+ @cache = described_class.new @acapela, "/tmp/cache"
11
+ end
12
+
13
+ describe "initialize" do
14
+
15
+ it "should try to create the cache directory" do
16
+ FileUtils.should_receive(:mkdir_p).with("/tmp/cache")
17
+ described_class.new @acapela, "/tmp/cache"
18
+ end
19
+
20
+ end
21
+
22
+ describe "clear" do
23
+
24
+ before :each do
25
+ FileUtils.stub(:rm)
26
+ end
27
+
28
+ it "should remove all *.pcm files from the cache directory" do
29
+ FileUtils.should_receive(:rm).with(Dir["/tmp/cache/*.pcm"])
30
+ @cache.clear
31
+ end
32
+
33
+ end
34
+
35
+ describe "synthesize" do
36
+
37
+ before :each do
38
+ @cache_filename = "/tmp/cache/58bb7452ad8aaa2a25509ec076cc979d.pcm"
39
+
40
+ @cached_file = mock File
41
+ File.stub(:new).and_return(@cached_file)
42
+
43
+ @file = mock File, :path => "/tmp/file"
44
+ @acapela.stub(:synthesize).and_return(@file)
45
+ end
46
+
47
+ def do_synthesize(text = "Hallo")
48
+ @cache.synthesize text
49
+ end
50
+
51
+ context "for a new request" do
52
+
53
+ before :each do
54
+ File.stub(:exists?).and_return(false)
55
+ FileUtils.stub(:mv)
56
+ end
57
+
58
+ it "should check the existance of the right file" do
59
+ File.should_receive(:exists?).with(@cache_filename).and_return(true)
60
+ do_synthesize
61
+ end
62
+
63
+ it "should synthesize a new file" do
64
+ @acapela.should_receive(:synthesize).with("Hallo").and_return(@file)
65
+ file = do_synthesize
66
+ file.should == @cached_file
67
+ end
68
+
69
+ it "should move the synthesized file to the cache" do
70
+ FileUtils.should_receive(:mv).with(@file.path, @cache_filename)
71
+ do_synthesize
72
+ end
73
+
74
+ it "should return the synthesized and cached file" do
75
+ file = do_synthesize
76
+ file.should == @cached_file
77
+ end
78
+
79
+ end
80
+
81
+ context "for a cached request" do
82
+
83
+ before :each do
84
+ File.stub(:exists?).and_return(true)
85
+ end
86
+
87
+ it "should check the existance of the right file" do
88
+ File.should_receive(:exists?).with(@cache_filename).and_return(true)
89
+ do_synthesize
90
+ end
91
+
92
+ it "should not synthesize a new file" do
93
+ @acapela.should_not_receive(:synthesize)
94
+ do_synthesize
95
+ end
96
+
97
+ it "should return the cached file" do
98
+ file = do_synthesize
99
+ file.should == @cached_file
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ gem 'rspec', '>= 2'
3
+ require 'rspec'
4
+
5
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "tts-acapela"))
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tts-acapela
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Philipp Brüll
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2010-12-03 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70207859994280 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '2'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70207859994280
25
+ description: It uses the native nscapi library to connect to the server.
26
+ email: b.phifty@gmail.com
27
+ executables: []
28
+ extensions:
29
+ - ext/extconf.rb
30
+ extra_rdoc_files:
31
+ - README.rdoc
32
+ files:
33
+ - README.rdoc
34
+ - Rakefile
35
+ - ext/acapela.c
36
+ - ext/acapela.h
37
+ - ext/extconf.rb
38
+ - lib/tts/acapela.rb
39
+ - lib/tts/cache.rb
40
+ - lib/tts-acapela.rb
41
+ - spec/acceptance/acapela_spec.rb
42
+ - spec/acceptance/cached_acapela_spec.rb
43
+ - spec/lib/tts/acapela_spec.rb
44
+ - spec/lib/tts/cache_spec.rb
45
+ - spec/spec_helper.rb
46
+ homepage:
47
+ licenses: []
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: 1.8.7
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project: tts-acapela
66
+ rubygems_version: 1.8.10
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: A client for the Acapela TTS server.
70
+ test_files:
71
+ - spec/acceptance/acapela_spec.rb
72
+ - spec/acceptance/cached_acapela_spec.rb
73
+ - spec/lib/tts/acapela_spec.rb
74
+ - spec/lib/tts/cache_spec.rb