Controlling Sound Pitch With Actionscript 3.0?
Asked Answered
R

2

5

after browsing the documentation for the sound classes, it seems there is no way to control sound pitch with Actionscript 3.0. there is only the ability to control volume and pan. why is there no pitch property? it's the only sound property missing for the ability to create a full featured sound engine in Actionscript?

i hope i'm misinformed, but in case i'm not are there any alternatives / workarounds to control pitch in AS3?

Rainwater answered 27/2, 2010 at 0:3 Comment(0)
P
8

Andre Michelle has a great article on Pitch control with actionscript 3.0

For reference, here is Andre's sample code:

package components
{
    import flash.events.Event;
    import flash.events.SampleDataEvent;
    import flash.media.Sound;
    import flash.net.URLRequest;
    import flash.utils.ByteArray;

    /**
     * @author Andre Michelle ([email protected])
     */
    public 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;
        }
    }
}

Basic usage would be something like:

//create an MP3Pitch instance and load a sound
var mp3:MP3Pitch = new MP3Pitch("/path/to/your/file.mp3");
//change the pitch via rate setter
mp3.rate += 0.5
Premium answered 27/2, 2010 at 0:35 Comment(3)
glad it helps. Initally Lee Brimelow(theflashblog.com/?p=1129) had a post on that, but Sound is Andre Michelle's area of expertise.Premium
-1 because the articles are broken links. Thus we see the importance of at least putting some modicum of an answer as your "answer", not just links.Blockbuster
@NealDavis Thanks for pointing that out as I haven't revisited this answer in a few years. I've updated the answer now to include updated links and code samples.Premium
B
0

Extract a bytearray from the sound object, and then manipulate the byte data, returning a new bytearray.

Here is the actual example from the API Reference Doc

var sourceSnd:Sound = new Sound(); 
var outputSnd:Sound = new Sound(); 
var urlReq:URLRequest = new URLRequest("test.mp3");

sourceSnd.load(urlReq); sourceSnd.addEventListener(Event.COMPLETE, loaded);

function loaded(event:Event):void {
    outputSnd.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound);
    outputSnd.play(); }

function processSound(event:SampleDataEvent):void {
    var bytes:ByteArray = new ByteArray();
    sourceSnd.extract(bytes, 4096);
    event.data.writeBytes(upOctave(bytes)); }

function upOctave(bytes:ByteArray):ByteArray {
    var returnBytes:ByteArray = new ByteArray();
    bytes.position = 0;
    while(bytes.bytesAvailable > 0)
    {
        returnBytes.writeFloat(bytes.readFloat());
        returnBytes.writeFloat(bytes.readFloat());
        if (bytes.bytesAvailable > 0)
        {
            bytes.position += 8;
        }
    }
    return returnBytes;
}
Blockbuster answered 18/11, 2016 at 5:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.