Skip to content

Commit 6942d06

Browse files
committed
The synthesiser now downloads MP3 data concurrently. Massive speed
improvement for strings.
1 parent bfe5c35 commit 6942d06

File tree

1 file changed

+50
-4
lines changed

1 file changed

+50
-4
lines changed

src/com/darkprograms/speech/synthesiser/Synthesiser.java

+50-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@
22

33
import java.io.IOException;
44
import java.io.InputStream;
5+
import java.io.SequenceInputStream;
56
import java.net.URL;
67
import java.net.URLConnection;
78
import java.net.URLEncoder;
89
import java.util.ArrayList;
10+
import java.util.Collections;
11+
import java.util.LinkedHashSet;
912
import java.util.List;
13+
import java.util.Set;
14+
import java.util.concurrent.Callable;
15+
import java.util.concurrent.ExecutionException;
16+
import java.util.concurrent.ExecutorService;
17+
import java.util.concurrent.Executors;
18+
import java.util.concurrent.Future;
1019

1120
import com.darkprograms.speech.translator.GoogleTranslate;
1221

@@ -127,11 +136,29 @@ public InputStream getMP3Data(String synthText) throws IOException{
127136
* @throws IOException Throws exception if it cannot complete the request
128137
*/
129138
public InputStream getMP3Data(List<String> synthText) throws IOException{
130-
InputStream complete = getMP3Data(synthText.remove(0));
131-
for(String part: synthText){
132-
complete = new java.io.SequenceInputStream(complete, getMP3Data(part));//Concatenate with new MP3 Data
139+
//Uses an executor service pool for concurrency
140+
ExecutorService pool = Executors.newFixedThreadPool(synthText.size());
141+
//Stores the Future (Data that will be returned in the future)
142+
Set<Future<InputStream>> set = new LinkedHashSet<Future<InputStream>>();
143+
for(String part: synthText){ //Iterates through the list
144+
Callable<InputStream> callable = new MP3DataFetcher(part);//Creates Callable
145+
Future<InputStream> future = pool.submit(callable);//Begins to run Callable
146+
set.add(future);//Adds the response that will be returned to a set.
133147
}
134-
return complete;
148+
List<InputStream> inputStreams = new ArrayList<InputStream>(set.size());
149+
for(Future<InputStream> future: set){
150+
try {
151+
inputStreams.add(future.get());//Gets the returned data from the future.
152+
} catch (ExecutionException e) {//Thrown if the MP3DataFetcher encountered an error.
153+
Throwable ex = e.getCause();
154+
if(ex instanceof IOException){
155+
throw (IOException)ex;//Downcasts and rethrows it.
156+
}
157+
} catch (InterruptedException e){//Will probably never be called, but just in case...
158+
Thread.currentThread().interrupt();//Interrupts the thread since something went wrong.
159+
}
160+
}
161+
return new SequenceInputStream(Collections.enumeration(inputStreams));//Sequences the stream.
135162
}
136163

137164
/**
@@ -211,5 +238,24 @@ private boolean isEndingPunctuation(char input){
211238
public String detectLanguage(String text) throws IOException{
212239
return GoogleTranslate.detectLanguage(text);
213240
}
241+
242+
/**
243+
* This class is a callable.
244+
* A callable is like a runnable except that it can return data and throw exceptions.
245+
* Useful when using futures. Dramatically improves the speed of execution.
246+
* @author Aaron Gokaslan (Skylion)
247+
*/
248+
private class MP3DataFetcher implements Callable<InputStream>{
249+
private String synthText;
250+
251+
public MP3DataFetcher(String synthText){
252+
this.synthText = synthText;
253+
}
254+
255+
public InputStream call() throws IOException{
256+
return getMP3Data(synthText);
257+
}
258+
}
259+
214260
}
215261

0 commit comments

Comments
 (0)