forked from: forked from: Text speech by Google API

by dimitris.1972g
Text speech by Google API
Google API を使った音声合成
@author Yasu
@see http://log.xingxx.com/2010/05/actionscript-30-6.html (KeadeAS)
♥0 | Line 112 | Modified 2012-02-25 00:52:35 | MIT License
play

ActionScript3 source code

/**
 * Copyright dimitris.1972g ( http://wonderfl.net/user/dimitris.1972g )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/h47J
 */

// forked from hacker_vbon7tr6's forked from: Text speech by Google API
// forked from clockmaker's Text speech by Google API
/**
 * Text speech by Google API
 * Google API を使った音声合成
 * @author Yasu
 * @see http://log.xingxx.com/2010/05/actionscript-30-6.html (KeadeAS)
 */
package {
    import flash.utils.ByteArray;
    import com.bit101.components.*;
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.net.*;

    public class Main extends Sprite {
        private var _input:InputText;
        private var snd:Sound;
        
        public function Main() {
            // Title
            var label:Label = new Label(this, 50, 180, "Speech by Google API - Porutuges BR");
            label.scaleX = label.scaleY = 2;
            
            // Text Input
            _input = new InputText(this, 50, 232, "ο γιάννης είναι καλό παιδί", null);
            _input.width = 200;
            _input.maxChars = 90;
            
            // Button
            new PushButton(this, 270, 230, "Speech!", onClick);
        }

        private function onClick(e:Event):void {
            
            var url:String = 
                "http://translate.google.com/translate_tts"
                + "?tl=el"
                + "&q=" + encodeURI(_input.text)
            ;
            
            var mp3:MP3Pitch = new MP3Pitch(url);
            mp3.rate = 1.16;
        }
    }
}
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.media.Sound;
import flash.events.Event;
import flash.events.SampleDataEvent;

class MP3Pitch 
{
    private const BLOCK_SIZE: int = 3072;
    
    private var _mp3: Sound;
    private var _sound: Sound;
    
    private var _target: ByteArray;
    
    private var _position: Number;
    private var _rate: Number;
    
    public function MP3Pitch( url: String )
    {
        _target = new ByteArray();

        _mp3 = new Sound();
        _mp3.addEventListener( Event.COMPLETE, complete );
        _mp3.load( new URLRequest( url ) );

        _position = 0.0;
        _rate = 1.0;

        _sound = new Sound();
        _sound.addEventListener( SampleDataEvent.SAMPLE_DATA, sampleData );
    }

    public function get rate(): Number
    {
        return _rate;
    }
    
    public function set rate( value: Number ): void
    {
        if( value < 0.0 )
            value = 0;

        _rate = value;
    }

    private function complete( event: Event ): void
    {
        _sound.play();
    }

    private function sampleData( event: SampleDataEvent ): void
    {
        //-- REUSE INSTEAD OF RECREATION
        _target.position = 0;
        
        //-- SHORTCUT
        var data: ByteArray = event.data;
        
        var scaledBlockSize: Number = BLOCK_SIZE * _rate;
        var positionInt: int = _position;
        var alpha: Number = _position - positionInt;

        var positionTargetNum: Number = alpha;
        var positionTargetInt: int = -1;

        //-- COMPUTE NUMBER OF SAMPLES NEED TO PROCESS BLOCK (+2 FOR INTERPOLATION)
        var need: int = Math.ceil( scaledBlockSize ) + 2;
        
        //-- EXTRACT SAMPLES
        var read: int = _mp3.extract( _target, need, positionInt );

        var n: int = read == need ? BLOCK_SIZE : read / _rate;

        var l0: Number;
        var r0: Number;
        var l1: Number;
        var r1: Number;

        for( var i: int = 0 ; i < n ; ++i )
        {
            //-- AVOID READING EQUAL SAMPLES, IF RATE < 1.0
            if( int( positionTargetNum ) != positionTargetInt )
            {
                positionTargetInt = positionTargetNum;
                
                //-- SET TARGET READ POSITION
                _target.position = positionTargetInt << 3;

                //-- READ TWO STEREO SAMPLES FOR LINEAR INTERPOLATION
                l0 = _target.readFloat();
                r0 = _target.readFloat();

                l1 = _target.readFloat();
                r1 = _target.readFloat();
            }
            
            //-- WRITE INTERPOLATED AMPLITUDES INTO STREAM
            data.writeFloat( l0 + alpha * ( l1 - l0 ) );
            data.writeFloat( r0 + alpha * ( r1 - r0 ) );
            
            //-- INCREASE TARGET POSITION
            positionTargetNum += _rate;
            
            //-- INCREASE FRACTION AND CLAMP BETWEEN 0 AND 1
            alpha += _rate;
            while( alpha >= 1.0 ) --alpha;
        }
        
        //-- FILL REST OF STREAM WITH ZEROs
        if( i < BLOCK_SIZE )
        {
            while( i < BLOCK_SIZE )
            {
                data.writeFloat( 0.0 );
                data.writeFloat( 0.0 );
                
                ++i;
            }
        }

        //-- INCREASE SOUND POSITION
        _position += scaledBlockSize;
    }
}