TTS(Text To Speech) powered by Google Translate
Googleの非公式APIを利用。
言語の切り替えには未対応(日本語出力のみ)。
再生中にもう一度[speak]ボタン(Enterキー)を押すと、大変なことになるかも…
package {
import com.bit101.components.PushButton;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.ui.Keyboard;
[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "0xFFFFFF")]
public class Main extends Sprite {
private var _loader:ImageLoader;
private var _input:TextField;
private var _droid:Sprite;
private var _tts:TTS;
private var _balloon:Balloon = null;
public function Main():void {
_loader = new ImageLoader();
_loader.addEventListener(Event.COMPLETE, _completed);
_loader.load();
}
private function _completed(e:Event = null):void {
_input = new TextField();
_input.border = true;
_input.borderColor = 0x999999;
_input.background = true;
_input.backgroundColor = 0xffffff;
_input.multiline = false;
_input.selectable = true;
_input.wordWrap = false;
// tf.autoSize = TextFieldAutoSize.LEFT;
_input.type = TextFieldType.INPUT;
_input.width = stage.stageWidth - 100;
_input.height = 20;
_input.x = 0;
_input.y = 0;
_input.text = "Flashから出力してみる";
_input.addEventListener(KeyboardEvent.KEY_DOWN, _onKeyDown);
addChild(_input);
var speakButton:PushButton = new PushButton(this, 0, 0, "speak", _pushed);
speakButton.setSize(100, 21);
speakButton.move(_input.x + _input.width, _input.y);
var bitmap:Bitmap = new Bitmap(_loader.images[0], "auto", true);
bitmap.smoothing = true;
// bitmap.x = bitmap.y = -SIZE / 2;
_droid = new Sprite();
_droid.addChild(bitmap);
_droid.x = stage.stageWidth - _droid.width;
_droid.y = stage.stageHeight - _droid.height;
addChild(_droid);
stage.focus = _input;
}
private function _onKeyDown(e:KeyboardEvent):void {
if (e.keyCode == Keyboard.ENTER) {
_pushed();
}
}
private function _pushed(e:Event = null):void {
if (!_input.text) {
return;
}
_tts = new TTS();
_tts.play(_input.text);
if (_balloon) {
removeChild(_balloon);
}
_balloon = new Balloon();
addChild(_balloon);
_balloon.create(_input.text);
_balloon.x = (stage.stageWidth - Balloon.WIDTH) * Math.random();
_balloon.y = _input.height + (stage.stageHeight - _input.height - _droid.height - _balloon.height) * Math.random();
_balloon.draw(_balloon.x, _balloon.y, _droid.x + 100, _droid.y + 100);
_balloon.tweet();
stage.focus = _input;
}
}
}
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.URLRequest;
import flash.system.LoaderContext;
/**
* 外部画像をBitmap化する(複数画像)
*/
class ImageLoader extends EventDispatcher {
// 画像ファイルのURL
private static const URL:Array = ["http://assets.wonderfl.net/images/related_images/7/7d/7d9f/7d9f19c5f2592b1482936caa3db93a2bc7aee1b2m"];
// BitmapDataの配列
private var _images:Vector.<BitmapData> = new Vector.<BitmapData>();
// 画像ファイルの数
private var _imagesNum:int;
private var _loadedA:int;
private var _loaderAList:Array;
private var _loadedB:int;
private var _loaderBList:Array;
public function ImageLoader():void {
}
public function load():void {
_imagesNum = URL.length;
_loadedA = _loadedB = 0;
_loaderAList = [];
_loaderBList = [];
for (var i:int = 0; i < _imagesNum; i++) {
var loader:Loader = new Loader();
_loaderAList[i] = loader;
loader.contentLoaderInfo.addEventListener(Event.INIT, loaderALoaded);
loader.load(new URLRequest(URL[i]), new LoaderContext(true));
}
}
private function loaderALoaded(e:Event):void {
e.target.removeEventListener(Event.INIT, loaderALoaded);
_loadedA++;
if (_loadedA == _imagesNum) {
for (var i:int = 0; i < _imagesNum; i++) {
var loader:Loader = new Loader();
_loaderBList[i] = loader;
loader.contentLoaderInfo.addEventListener(Event.INIT, loaderBLoaded);
loader.loadBytes(_loaderAList[i].contentLoaderInfo.bytes);
}
}
}
private function loaderBLoaded(e:Event):void {
e.target.removeEventListener(Event.INIT, loaderBLoaded);
_loadedB++;
if (_loadedB == _imagesNum) {
for (var i:int = 0; i < _imagesNum; i++) {
var bitmapData:BitmapData = new BitmapData(_loaderBList[i].width, _loaderBList[i].height);
bitmapData.draw(_loaderBList[i]);
_images.push(bitmapData);
}
// 読み込み完了イベント送出
dispatchEvent(new Event(Event.COMPLETE));
}
}
public function get images():Vector.<BitmapData> {
return this._images;
}
}
import flash.events.Event;
import flash.media.Sound;
import flash.net.URLRequest;
class TTS {
private var _sound:Sound;
public function TTS():void {
_sound = new Sound();
_sound.addEventListener(Event.COMPLETE, _completed);
}
public function play(text:String):void {
_sound.load(new URLRequest("http://service-maker2.appspot.com/tts?text=" + encodeURI(text)));
}
private function _completed(e:Event):void {
Sound(e.target).play();
}
}
import caurina.transitions.properties.DisplayShortcuts;
import caurina.transitions.Tweener;
import flash.display.Sprite;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
class Balloon extends Sprite {
public static const WIDTH:int = 200;
private static const PADDING:int = 10;
private static const FORMAT:TextFormat = new TextFormat('_ゴシック', 24, 0x000000, true, false);
private var _characters:Array = null;
private var _height:int = 0;
private var _tweetPos:Point;
public function Balloon():void {
// Tweenerの拡張機能を有効にする
DisplayShortcuts.init();
}
public function create(text:String):void {
var i:int;
if (_characters) {
for (i = 0; i < _characters.length; i++) {
removeChild(_characters[i]);
}
}
_characters = new Array(text.length);
var totalWidth:Number = 0;
var lines:int = 0;
var tf:TextField;
for (i = 0; i < text.length; i++) {
tf = new TextField();
tf.defaultTextFormat = FORMAT;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.multiline = false;
tf.selectable = false;
tf.wordWrap = false;
tf.text = text.charAt(i);
if (totalWidth + tf.width > WIDTH - (PADDING + 5)) {
totalWidth = 0;
lines += 1;
}
tf.x = PADDING + totalWidth;
tf.y = PADDING + tf.textHeight * lines;
totalWidth += tf.textWidth + 2;
_characters[i] = tf;
addChild(tf);
}
_height = PADDING * 2 + tf.textHeight * (lines + 1) + 2 * lines;
}
public function draw(balloonLeft:int, balloonTop:int, droidLeft:int, droidTop:int):void {
graphics.beginFill(0xFFFFFF * Math.random(), 0.5);
graphics.drawRoundRect(0, 0, WIDTH, _height, PADDING, PADDING);
graphics.drawTriangles(Vector.<Number>([WIDTH - PADDING, _height, WIDTH - PADDING - 50, _height, droidLeft - balloonLeft, droidTop - balloonTop]));
graphics.endFill();
_tweetPos = new Point(droidLeft - balloonLeft, droidTop - balloonTop);
}
public function tweet():void {
for (var i:int = 0; i < _characters.length; i++) {
var tf:TextField = _characters[i] as TextField;
var originalX:int = tf.x;
var originalY:int = tf.y;
tf.x = _tweetPos.x;
tf.y = _tweetPos.y;
tf.alpha = 0.0;
Tweener.addTween(tf, { _autoAlpha: 1.0, x: originalX, y: originalY, transition: 'easeOutBack', time: 0.5, delay: i * 0.20 } );
}
}
public override function get height():Number {
return _height;
}
}