In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

"Google Text To Speech" speak Japanese.

Google Text To Speechに日本語を喋ってもらいました。
/**
 * Copyright ikekou ( http://wonderfl.net/user/ikekou )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/faUk
 */

//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.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;
        
        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 = "今日は、いい天気ですね。焼肉が食べたいですね。";
            addChild(tf);
            
            isChanged = false;
            tf.addEventListener(KeyboardEvent.KEY_DOWN, _onKeyDown);
            tf.addEventListener(Event.CHANGE, _onChange);
            
            new PushButton(this, 333, tf.y, "speak", _onSpeak);
        }
        
        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);
            
            var s:Speaker = new Speaker();
            s.speak(result);
        }
        
    }
    
}

    internal class Config 
    {
        
        public static const URL_PROXY:String = "http://api.ikekou.jp/proxy.php";
        
    }

    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"],
            ["ん", "nn"],
            ["が", "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"],
            ["ん", "nn"],
            ["が", "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=es&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;
        }
        
    }