Un servizio TextToSpeech con FreeTTS

www.beanizer.org
Un servizio TextToSpeech con FreeTTS
Un semplice server text to speech interrogabile via http
Introduzione
Una delle tecnologie che più stimolano il mio lato fanciullesco è la domotica. Non posso permettermi un forno con dentro
Java, ma con alcuni adattatori x10 mi sono recentemente divertito a costruire un sistema in cui una Midlet sul mio
cellulare periodicamente comunica al mio server casalingo la propria cella GSM, così il mio forno elettrico può venir acceso
quando mi dirigo verso casa. Lo so, è kitsch ( e costoso,a seconda del provider gprs), ma vado matto per questo genere
di inutilità.
Il mese scorso mi ha riaggredito un vecchio sogno; un sistema parlante in casa. Facile da fare oggi!! Sono piuttosto
ossessionato da web service e integrazione di sistemi, per cui volevo un sorta di blackbox parlante, direttamente esposta
a tutti i miei sistemi casalinghi(desktop, portatile e cellulare), per cui per questa volta ho optato per un semplice
approccio http, niente SOAP, xml-rpc o socket.
Poi dovevo scegliere il motore di sintesi vocale. Avevo già messo le mani su FreeTTS, un sintetizzatore vocale scritto
interamente in JavaTM, e ne ero rimasto soddisfatto.
Era anche una buona occasione per usare la classe com.sun.net.httpserver.HttpServer del jdk per implementare il
semplice server http di cui avevo bisogno.
A questo punto avevo tutto per costruire la mia "macchina parlante". Da sottolineare il fatto che FreTTS include negli
esempi una soluzione client/server con scopi però differenti da quella esposta in questo articolo. Nel nostro caso abbiamo
un server che possegga anche scheda audio e casse acustiche, mentre nell'esempio client/server di FreeTTS, il server
produce l'audio che però viene "suonato" dal client.
Panoramica
Ho usato jdk 1.5 e FreeTTS 1.2 . Naturalmete i jars di FreeTTS dovranno essere nel classpath. Non è richiesto
nient'altro e, essendo il motore tts 100% java, è anche utilizzabile su qualsiasi piattaforma Java.
Con sole 2 classi, il nostro motore parlante sarà pronto. Non entrerò nei dettagli di com.sun.net.httpserver.HttpServer,
l'unica cosa che ci serve sapere è che possiamo associare un contesto ad un handler. Il codice chiarirà tutto questo.
Immaginiamo di volere un servizio in ascolto sulla porta 8000, con un contesto http tipo "/ttsserver/say", che "vocalizzerà"
il testo della URI che si trova dopo il punto interrogativo.
Una tipica chiamata sarà qualcosa del genere:
"http://localhost:8000/ttsserver/say?Che tempo fa oggi"
Il codice
Scriviamo il codice della prima classe. Dovrà semplicemente inizializzare e far partire il server http. Ecco il codice:
package org.beanizer.ttsserver;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
public class Server {
private HttpServer server=null;
public void start(){
try {
server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/ttsserver/say", new VoiceHandler());
server.setExecutor(null);
server.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static void main(String args[]){
Server s=new Server();
s.start();
}
}
Il metodo main crea un'istanza della classe e ne chiama il metodo start.
Analizziamo il codice racchiuso nel blocco try/catch in start:
1) viene creato un server http in ascolto sulla porta tcp 8000.
http://www.beanizer.org/site
Realizzata con Joomla!
Generata: 9 June, 2017, 16:50
www.beanizer.org
2) Il contesto "/ttsserver/say" sarà gestito da VoiceHandler, che è la seconda classe che scriveremo.
3) Creiamo un esecutore di default (un oggetto che esegue processi Runnable, in questo caso le singole chiamate http).
4) Alla fine il server http viene fatto partire.
Abbiamo bisogno solo di una ulteriore semplice classe per la gestione delle richieste http ricevute sul contesto creato.
La vediamo alla prossime pagina.
package org.beanizer.ttsserver;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.sun.speech.freetts.Voice;
import com.sun.speech.freetts.VoiceManager;
import com.sun.speech.freetts.util.Utilities;
public class VoiceHandler implements HttpHandler{
private Voice voice;
public VoiceHandler() {
try {
voice = VoiceManager.getInstance().getVoice(
Utilities.getProperty("voice16kName", "kevin16"));
voice.allocate();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void handle(HttpExchange t) throws IOException {
voice.speak(t.getRequestURI().getQuery());
String response = "Ok";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
La nostra classe VoiceHandler estende com.sun.net.httpserver.HttpHandler, in particolare il metodo handle per gestire
le richieste in arrivo.
Nel costruttore otteniamo una istanza di VoiceManager, da questo otteniamo una Voice utilizzando la classe Utilities, e
allochiamo la voce. A questo punto la voce è pronta per essere usata con una semplce chiamata speak(String).
Una nota sulla selezione della voce. FreeTTS include alcune voci: una di qualità 8k, una 16k(quella che stiamo
utilizzando noi) e una di miglior qualità ma limitata al dominio di tempo/data. In rete è possibile trovare altre voci, anche
per lingue diverse dall'inglese e anche produrne di proprie(anche se la procedura è complessa). Qui ci sono informazioni
al riguardo.
Torniamo alla nostra classe. Il metodo handle: 1) "vocalizza" ciò che arriva con la chiamata http (tutto quello che segue
"?" nella URI)
2) invia un "Ok" al chiamante.
Per far partire il servizio assicurarsi che i jar di FreeTTS siano nel classpath e lanciare la classe
org.beanizer.ttsserver.Server con java.
Conclusioni
Questo è più o meno tutto. é possibile estendere la struttura per controllare gli accessi, parametrizzare la voce da
utilizzare etc., ma semplicemente con le 2 classi proposte ogni dispositivo in grado di fare chiamate http( ad es. un
http://www.beanizer.org/site
Realizzata con Joomla!
Generata: 9 June, 2017, 16:50
www.beanizer.org
browser) può far parlare il nostro accrocchio.
A casa lo utilizzo per le più disparate fesserie, ed è veramente divertente. Alcuni usi:
1) Alcuni messaggi di log (opportunamente filtrati per evitare "spam")
2) Odio le suonerie telefoniche, per cui ho istruito il mio server asterisk a far dire al server tts chi mi chiama, usando il
nome al posto del numero in caso di persone note.
Al momento stò lavorando su un servizio simile per il riconoscimento vocale, ma questa è una bestia totalmente
diversa.....
Hasta la proxima.
http://www.beanizer.org/site
Realizzata con Joomla!
Generata: 9 June, 2017, 16:50