forked from: forked from: forked from: GoogleText2Speech
http://jp.techcrunch.com/archives/20091214the-unofficial-google-text-to-speech-api/
// forked from Geo877's forked from: forked from: GoogleText2Speech
// forked from ongaeshi's forked from: GoogleText2Speech
// forked from miyaoka's GoogleText2Speech
// forked from TheCoolMuseum's mp3 可変速再生
package
{
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.utils.ByteArray;
import caurina.transitions.Tweener;
import flash.utils.Timer;
import com.bit101.components.HUISlider;
import com.bit101.components.PushButton;
/**
* http://jp.techcrunch.com/archives/20091214the-unofficial-google-text-to-speech-api/
*/
[SWF(width = "465", height = "465", backgroundColor = 0xFFFFFF, frameRate = "60")]
public class Text2Speech
extends Sprite
{
private const REQ_URL_BASE:String = "http://translate.google.com/translate_tts?tl=en&q=";
private var _outputSnd:Sound = new Sound();
private var _sampleTable:ByteArray;
private var bufferLength:int = 2048;
private var speed:Number = 1.3;
private var vol:Number = 0.5;
private var rowDelay:Number = 100;
private var rowIndex:int = 0;
private var tfd:TextField = new TextField();
public function Text2Speech()
{
// スライダーの設定
var spdSlider:HUISlider = new HUISlider(this, 50, 420, "speed", function ():void
{
speed = spdSlider.value;
});
spdSlider.minimum = 0.2;
spdSlider.maximum = 3.0;
spdSlider.value = speed;
spdSlider.width = 400;
// 読み上げテキスト表示の設定
tfd.autoSize = TextFieldAutoSize.LEFT;
tfd.wordWrap = true;
tfd.width = 400;
addChild(tfd);
tfd.x = 20;
tfd.defaultTextFormat = new TextFormat("OCRB", 24);
// サウンド設定
_outputSnd.addEventListener(SampleDataEvent.SAMPLE_DATA, player);
// 初期化
init();
// 読み上げ開始
speachNext();
}
private function init():void
{
rowIndex = 0;
tfd.text = "";
tfd.y = 350;
}
private function speachNext():void
{
if (rowIndex >= lyrics.length)
{
return;
init();
}
var text:String = lyrics[rowIndex]
rowIndex++;
var timer:Timer = new Timer(rowDelay, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, function ():void
{
// arguments.calee → 現在実行中の関数への参照
timer.removeEventListener(TimerEvent.TIMER_COMPLETE, arguments.callee);
speach(text + "\n");
});
timer.start();
}
private function appendChar(char:String):void
{
var lastHeight:Number = tfd.textHeight;
tfd.appendText(char);
tfd.y -= tfd.textHeight - lastHeight;
}
// 実際に音声を再生する
private function speach(text:String):void
{
var sourceSnd:Sound = new Sound();
sourceSnd.addEventListener(Event.COMPLETE, function (event:Event):void
{
var txtLen:int = text.length;
var charTime:Number = sourceSnd.length / speed / txtLen;
var timers:Array = [];
for (var i:int = 0; i < txtLen; i++)
{
timers.push(new Timer(charTime * i, 1));
}
timers.forEach(function(timer:Timer, index:int, arr:Array):void {
var char:String = text.substr(index, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, function ():void
{
timer.removeEventListener(TimerEvent.TIMER_COMPLETE, arguments.callee);
appendChar(char);
});
timer.start();
});
_sampleTable = new ByteArray();
sourceSnd.extract(_sampleTable, sourceSnd.length / 1000 * 44100, 0);
_sampleTable.position = 0;
_outputSnd.play();
});
sourceSnd.load(new URLRequest(REQ_URL_BASE + encodeURI(text)));
}
private function player(event:SampleDataEvent):void {
var pos:Number = _sampleTable.position / 6;
var length:Number = _sampleTable.length / 8;
for (var i:int = 0; i < bufferLength; i++ ) {
pos += speed;
if (pos > length-1)
{
speachNext();
break;
}
_sampleTable.position = Math.round(pos) * 8;
event.data.writeFloat(_sampleTable.readFloat() * vol);
event.data.writeFloat(_sampleTable.readFloat() * vol);
}
}
private var lyrics:Array = [
"Hello.",
"My name is George.",
];
}
}