Flexで音声合成
Flex勉強会(まいど!〜)でお話しした内容の一部です。
Flexで、入力した文字を音声で読み上げる。
マイコミジャーナルの記事が面白そうだったのと、gainerでFlashからローカルjavaにアクセスするアイデアが意外で面白かったので、
組み合わせてやってまえ!ということで作りました。
つまり、Flexでローカルjavaにソケット接続して、FreeTTSで音声を読み上げる方法です。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="connect();"> <mx:VBox horizontalAlign="center" horizontalCenter="0"> <mx:Spacer width="100%" height="100"/> <mx:HBox width="100%" horizontalAlign="center"> <mx:TextInput id="txtMessage" horizontalCenter="0" width="294"/> <mx:Button label="Speech" click="speech();"/> </mx:HBox> </mx:VBox> <mx:Script> <![CDATA[ private var socket:Socket; private function speech():void{ socket.writeUTFBytes(txtMessage.text); socket.writeUTFBytes('\n'); socket.flush(); } private function connect():void{ socket = new Socket(); socket.addEventListener("connect", socket_connect); socket.addEventListener("ioError", socket_ioError); socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); socket.connect("localhost", uint(10164)); } private function socket_connect(event:Event):void {} private function socket_ioError(event:IOErrorEvent):void {} private function socketDataHandler(event:ProgressEvent):void {} ]]> </mx:Script> </mx:Application>
package jp.co.genephics.example.speech; public class SpeechServer { public static void main(String[] args){ int arg = 10164; if( args.length > 0 ){ arg = Integer.parseInt(args[0]); } SpeechSocketServer server = new SpeechSocketServer(); try{ server.startServer(arg); }catch(Exception e){ e.printStackTrace(); } } }
■javaサーバーソケット(SpeechSocketServer.java)
package jp.co.genephics.example.speech; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class SpeechSocketServer { public void startServer(int port)throws Exception{ ServerSocket server = null; try{ server = new ServerSocket(port,200); while(true){ Socket socket = server.accept(); socket.setSoTimeout( 1000*60 ); // スレッド生成 SpeechThread thread = new SpeechThread(socket); thread.start(); } }catch(Exception e){ e.printStackTrace(); }finally{ if(server != null){ try{ server.close(); }catch(IOException ioe){ ioe.printStackTrace(); } } } } }
package jp.co.genephics.example.speech; import java.net.Socket; public class SpeechThread extends Thread { private Socket socket; public SpeechThread(Socket socket){ this.socket = socket; } @Override public void run(){ SpeechChild child = new SpeechChild(this.socket); child.execute(); } }
■Socketのメッセージを読んでSpeechクラスにわたすjava(SpeechChild.java)
package jp.co.genephics.example.speech; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; public class SpeechChild { private Socket socket; public SpeechChild(Socket socket){ this.socket = socket; } public void execute(){ try{ BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); StringBuffer sb = new StringBuffer(); // textAreaとか複数行を拾うならこうかな // while(true){ String str = reader.readLine(); // if(str.endsWith("\n"))break; // sb.append( str ); // } // Speechの実行 // String str = sb.toString(); Speech speech = new Speech(); speech.speak(str); speech.deallocateSynthesizer(); }catch(IOException e){ e.printStackTrace(); } } }
■FreeTTSでSpeechするjava(Speech.java)
// マイコミジャーナルの記事のままですよ // あと、ユーザーディレクトリにspeech.propertiesを置く事。 package jp.co.genephics.example.speech; import java.beans.PropertyVetoException; import java.util.Locale; import javax.speech.AudioException; import javax.speech.Central; import javax.speech.EngineException; import javax.speech.synthesis.Synthesizer; import javax.speech.synthesis.SynthesizerModeDesc; import javax.speech.synthesis.Voice; public class Speech { private Synthesizer synthesizer = null; public Speech() { // シンセザイザのモードを指定 SynthesizerModeDesc desc = new SynthesizerModeDesc (null, "general", Locale.US, Boolean.FALSE, null); try { // シンセザイザを作成 synthesizer = Central.createSynthesizer(desc); if (synthesizer == null) { System.err.println("ERROR! シンセザイザが見つかりません。"); System.exit(1); } // ボイスを作成 String voiceName = "kevin16"; Voice voice = new Voice(voiceName, Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, null); if (voice == null) { System.err.println( "ERROR! シンセザイザがボイス " + voiceName + " をサポートしていません。"); System.exit(1); } // リソースの割り当て synthesizer.allocate(); synthesizer.resume(); // ボイスの設定 synthesizer.getSynthesizerProperties().setVoice(voice); } catch (EngineException ex) { ex.printStackTrace(); } catch (PropertyVetoException ex) { ex.printStackTrace(); } catch (AudioException ex) { ex.printStackTrace(); } } public void speak(String message) { try { // テキストの読み上げ synthesizer.speakPlainText(message, null); synthesizer.waitEngineState(Synthesizer.QUEUE_EMPTY); } catch (InterruptedException ex) { ex.printStackTrace(); } } public void deallocateSynthesizer() { try { // リソースの開放 synthesizer.deallocate(); } catch (EngineException ex) { ex.printStackTrace(); } } }
こんなところでしょうか。
しっかり読み上げてくれますけど、ちゃんと作り込んでないんで、
もし参考にする場合は、ちゃんと書いて下さいね(笑)。
僕はここでやめましたが、
このノリで作ってけば、なんか面白いの作れます?