tts-acapela 0.1.0

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