KATAKOTO
/**
* Copyright ikekou ( http://wonderfl.net/user/ikekou )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/tfRL
*/
// forked from ikekou's "Google Text To Speech" speak Japanese.
//googleTTSで無理やり日本語を喋らせてみる。カタコト。
//実際に喋ってるのはスペイン語。
//スペイン語はアルファベットをローマ字に非常に近く発音してくれることを学んだ!
//
//paqさんのVoiceChat(http://wonderfl.net/c/p2KD)とくっつけてみました
//http://wonderfl.net/c/w08s
//
package
{
import com.bit101.components.PushButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.ui.Keyboard;
[SWF(backgroundColor=0xeeeeee, width=465, height=465, frameRate=30)]
public class Main extends Sprite
{
private var tf:TextField;
private var isChanged:Boolean;
private var console:TextField;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
tf = new TextField();
tf.border = true;
tf.borderColor = 0x999999;
tf.background = true;
tf.backgroundColor = 0xffffff;
tf.multiline = false;
tf.width = 300;
tf.height = 19;
tf.type = TextFieldType.INPUT;
tf.x = 33;
tf.y = (stage.stageHeight - tf.height) / 2;
tf.multiline = false;
tf.restrict = "^ア-ン";
tf.text = 'かたことでしゃべります。';
//tf.text='あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほ';
addChild(tf);
isChanged = false;
tf.addEventListener(KeyboardEvent.KEY_DOWN, _onKeyDown);
tf.addEventListener(Event.CHANGE, _onChange);
var p:PushButton = new PushButton(this, 333, tf.y, "speak", _onSpeak);
//p.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
//debug
console = new TextField();
console.width=400;
addChild(console);
}
private function _onChange(e:Event):void
{
isChanged = true;
}
private function _onKeyDown(e:KeyboardEvent):void
{
if (e.keyCode == Keyboard.ENTER && isChanged)
{
isChanged = false;
_onSpeak(null);
}
}
private function _onSpeak(e:Event):void
{
if (!tf.text) return;
var p:Parser = new Parser();
p.addEventListener(Event.COMPLETE, _onComplete);
p.parse(tf.text);
tf.text = "";
isChanged = false;
stage.focus = tf;
}
private function _onComplete(e:Event):void
{
var c:ParsedXMLConverter = new ParsedXMLConverter();
var result:String = c.convert(Parser(e.target).data);
console.text = result;
var s:Speaker = new Speaker();
s.speak(result);
}
}
}
internal class Config
{
public static const URL_PROXY:String = "http://api.ikekou.jp/proxy.php";
public static const LANG:String = "es";
}
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLVariables;
internal class Parser extends EventDispatcher
{
public var data:XML;
public function parse(target:String, useProxy:Boolean = false ):void
{
if (!target) return;
var req:URLRequest = new URLRequest(Config.URL_PROXY);
var vars:URLVariables = new URLVariables();
req.data = vars;
vars.url = "http://jlp.yahooapis.jp/MAService/V1/parse?appid=0GIwpCyxg67plKeaS4vB4tJQVU8hQ9RTaAC4AlZibwtGU0tYbRB7SbLkFvgEs2Db&sentence=" + encodeURI(target);
var ul:URLLoader = new URLLoader();
ul.addEventListener(Event.COMPLETE, _onComplete);
ul.load(req);
}
private function _onComplete(e:Event):void
{
data = new XML(XMLUtil.deleteNameSpace(URLLoader(e.target).data));
dispatchEvent(new Event(Event.COMPLETE));
}
}
internal class XMLUtil
{
/**
*
* clockmakerさんのを拝借
*
* 名前空間を削除します
* @param オリジナルストリング(XML形式)
* @return namespace宣言を取り去ったXML
*/
public static function deleteNameSpace(xmlText:String):XML
{
// remove the namespaces from the string representation of the XML
xmlText = xmlText.replace(new RegExp("xmlns[^\"]*\"[^\"]*\"", "gi"), "");
xmlText = xmlText.replace(new RegExp("xsi[^\"]*\"[^\"]*\"", "gi"), "");
// set the string rep. of the XML back to real XML
return new XML(xmlText);
}
}
internal class ParsedXMLConverter
{
public function convert(parsedXml:XML):String
{
var converter:Converter = new Converter();
var words:XMLList = parsedXml..word;
var result:String = "";
//var n:int = words.length();
//for (var i:int = 0; i < n; i++)
//{
//result += converter.convert(words[i].reading, words[i].pos) + " ";
//}
//助詞以外は全部くっつけちゃったほうがいいかも
var buf:String = "";
var n:int = words.length();
for (var i:int = 0; i < n; i++)
{
if (words[i].pos == "助詞")
{
result += converter.convert(buf) + " ";
buf = "";
result += converter.convert(words[i].reading, words[i].pos) + " ";
}
else
{
buf += words[i].reading;
}
}
result += converter.convert(buf) + " ";
return result;
}
}
internal class Converter
{
public static const COLLECTION_BASIC:Array = [
["あ", "a"],
["い", "i"],
["う", "u"],
["え", "e"],
["お", "o"],
["ぁ", "a"],
["ぃ", "i"],
["ぅ", "u"],
["ぇ", "e"],
["ぉ", "o"],
["か", "ka"],
["き", "ki"],
["く", "ku"],
["け", "ke"],
["こ", "ko"],
["きゃ", "kya"],
["きゅ", "kyu"],
["きょ", "kyo"],
["さ", "sa"],
["し", "shi"],
["す", "su"],
["せ", "se"],
["そ", "so"],
["しゃ", "sha"],
["しゅ", "shu"],
["しょ", "sho"],
["た", "ta"],
["ち", "chi"],
["つ", "tsu"],
["て", "te"],
["と", "to"],
["ちゃ", "cha"],
["ちゅ", "chu"],
["ちょ", "cho"],
["な", "na"],
["に", "ni"],
["ぬ", "nu"],
["ね", "ne"],
["の", "no"],
["にゃ", "nya"],
["にゅ", "nyu"],
["にょ", "nyo"],
["は", "ha"],
["ひ", "hi"],
["ふ", "fu"],
["へ", "he"],
["ほ", "ho"],
["ひゃ", "hya"],
["ひゅ", "hyu"],
["ひょ", "hyo"],
["ま", "ma"],
["み", "mi"],
["む", "mu"],
["め", "me"],
["も", "mo"],
["みゃ", "mya"],
["みゅ", "myu"],
["みょ", "myo"],
["や", "ya"],
["ゆ", "yu"],
["よ", "yo"],
["ら", "ra"],
["り", "ri"],
["る", "ri"],
["れ", "re"],
["ろ", "ro"],
["りゃ", "rya"],
["りゅ", "ryu"],
["りょ", "ryo"],
["わ", "wa"],
["を", "o"],
["ん", "n"],
["が", "ga"],
["ぎ", "gi"],
["ぐ", "gu"],
["げ", "ge"],
["ご", "go"],
["ぎゃ", "gya"],
["ぎゅ", "gyu"],
["ぎょ", "gyo"],
["ざ", "za"],
["じ", "zi"],
["ず", "zu"],
["ぜ", "ze"],
["ぞ", "zo"],
["じゃ", "zya"],
["じゅ", "zyu"],
["じょ", "zyo"],
["だ", "da"],
["じ", "ji"],
["ず", "zu"],
["で", "de"],
["ど", "do"],
["じゃ", "zya"],
["じゅ", "zyu"],
["じょ", "zyo"],
["ば", "ba"],
["び", "bi"],
["ぶ", "bu"],
["べ", "be"],
["ぼ", "bo"],
["びゃ", "bya"],
["びゅ", "byu"],
["びょ", "byo"],
["ぱ", "pa"],
["ぴ", "pi"],
["ぷ", "pu"],
["ぺ", "pe"],
["ぽ", "po"],
["ぴゃ", "pya"],
["ぴゅ", "pyu"],
["ぴょ", "pyo"],
["、", "."],
["。", "."]
];
public static const COLLECTION_PARTICLE:Array = [
["あ", "a"],
["い", "i"],
["う", "u"],
["え", "e"],
["お", "o"],
["か", "ka"],
["き", "ki"],
["く", "ku"],
["け", "ke"],
["こ", "ko"],
["きゃ", "kya"],
["きゅ", "kyu"],
["きょ", "kyo"],
["さ", "sa"],
["し", "shi"],
["す", "su"],
["せ", "se"],
["そ", "so"],
["しゃ", "sha"],
["しゅ", "shu"],
["しょ", "sho"],
["た", "ta"],
["ち", "chi"],
["つ", "tsu"],
["て", "te"],
["と", "to"],
["ちゃ", "cha"],
["ちゅ", "chu"],
["ちょ", "cho"],
["な", "na"],
["に", "ni"],
["ぬ", "nu"],
["ね", "ne"],
["の", "no"],
["にゃ", "nya"],
["にゅ", "nyu"],
["にょ", "nyo"],
["は", "wa"],
["ひ", "hi"],
["ふ", "fu"],
["へ", "he"],
["ほ", "ho"],
["ひゃ", "hya"],
["ひゅ", "hyu"],
["ひょ", "hyo"],
["ま", "ma"],
["み", "mi"],
["む", "mu"],
["め", "me"],
["も", "mo"],
["みゃ", "mya"],
["みゅ", "myu"],
["みょ", "myo"],
["や", "ya"],
["ゆ", "yu"],
["よ", "yo"],
["ら", "ra"],
["り", "ri"],
["る", "ri"],
["れ", "re"],
["ろ", "ro"],
["りゃ", "rya"],
["りゅ", "ryu"],
["りょ", "ryo"],
["わ", "wa"],
["を", "o"],
["ん", "n"],
["が", "ga"],
["ぎ", "gi"],
["ぐ", "gu"],
["げ", "ge"],
["ご", "go"],
["ぎゃ", "gya"],
["ぎゅ", "gyu"],
["ぎょ", "gyo"],
["ざ", "za"],
["じ", "zi"],
["ず", "zu"],
["ぜ", "ze"],
["ぞ", "zo"],
["じゃ", "ja"],
["じゅ", "ju"],
["じょ", "jo"],
["だ", "da"],
["じ", "ji"],
["ず", "zu"],
["で", "de"],
["ど", "do"],
["じゃ", "ja"],
["じゅ", "ju"],
["じょ", "jo"],
["ば", "ba"],
["び", "bi"],
["ぶ", "bu"],
["べ", "be"],
["ぼ", "bo"],
["びゃ", "bya"],
["びゅ", "byu"],
["びょ", "byo"],
["ぱ", "pa"],
["ぴ", "pi"],
["ぷ", "pu"],
["ぺ", "pe"],
["ぽ", "po"],
["ぴゃ", "pya"],
["ぴゅ", "pyu"],
["ぴょ", "pyo"]
];
public function convert(target:String, pos:String="noun"):String
{
if ( !target) return "";
var collection:Array = COLLECTION_BASIC;
if (pos == POS.PARTICLE) collection = COLLECTION_PARTICLE;
var result:String = _convert(target, collection);
return result;
}
private function _convert(target:String, collection:Array):String
{
target = StringUtil.toHiragana(target);
var result:String = "";
var isPrevSmallTsu:Boolean = false;
var n:int = target.length;
for (var i:int = 0; i < n; i++)
{
result = __convert(
result,
target.charAt(i),
target.charAt(i - 1),
target.charAt(i + 1),
collection
);
}
return result;
}
private function __convert(result:String, current:String, prev:String, next:String, collection:Array):String
{
var tmp:String = current;
if (/[A-Za-z\.]/.test(current))
{
if (!/[a-zA-Z\.]/.test(prev))
{
result += " ";
}
result += tmp;
return result;
}
if (/[ゃゅょ]/.test(next))
{
tmp += next;
}
if (/[ゃゅょ]/.test(current) && result != "")
{
return result;
}
if (current == "っ")
{
return result;
}
if (result != "" &&
/ー/.test(current)
)
{
result = result + result.substr(result.length - 1, 1);
return result;
}
var converted:String = "";
var m:int = collection.length;
for (var j:int = 0; j < m; j++)
{
if (collection[j][0] == tmp)
{
converted = collection[j][1];
}
}
if (prev == "っ")
{
var fl:String = converted.charAt(0);
if (fl.indexOf("aiueo") == -1)
{
converted = fl + converted;
}
}
if (converted)
{
if (result) result += " ";
result += converted;
}
return result;
}
}
import flash.events.Event;
import flash.media.Sound;
import flash.net.URLRequest;
import flash.net.URLVariables;
internal class Speaker
{
public function speak(target:String):void
{
if (!target) return;
var req:URLRequest = new URLRequest(Config.URL_PROXY);
var vars:URLVariables = new URLVariables();
req.data = vars;
vars.url = "http://translate.google.com/translate_tts?tl="+Config.LANG+"&q=" + encodeURI(target);
var snd:Sound = new Sound();
snd.addEventListener(Event.COMPLETE, _onComplete);
snd.load(req);
}
private function _onComplete(e:Event):void
{
Sound(e.target).play();
}
}
internal class POS
{
public static const PARTICLE:String = "助詞";
}
internal class StringUtil
{
public static function toHiragana(target:String):String
{
var result:String = "";
var n:int = target.length;
for (var i:int = 0; i < n; i++)
{
var char:String = target.charAt(i);
if (/[ア-ン]/.test(char))
{
result += String.fromCharCode(char.charCodeAt() + (12354 - 12450));
}
//あとで
//else if (/[ア-ン]/.test(char))
//{
//result += String.fromCharCode(char.charCodeAt() + (12354 - 65393));
//}
else
{
result += char;
}
}
return result;
}
}