forked from: playing streamed chunks of mp3s

by hacker_mx_95scj forked from playing streamed chunks of mp3s (diff: 1)
♥0 | Line 417 | Modified 2012-02-03 13:30:50 | MIT License
play

ActionScript3 source code

/**
 * Copyright hacker_mx_95scj ( http://wonderfl.net/user/hacker_mx_95scj )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/3y9W
 */

// forked from seikimaiii's playing streamed chunks of mp3s
package
{
    import flash.geom.*;
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.utils.ByteArray;
    import flash.utils.Timer;
    import flash.net.URLRequest;
    import flash.text.TextField;
    import flash.external.ExternalInterface;
    import flash.system.Security;
    
    [SWF(frameRate="30",width=400,height=400,backgroundColor=0)]
    
    /**
    *
    * @author SeikimaIII
    * v1.0
    *
    * Music Class
    * Container for all the individual player elements.
    *
    */
    public class Music extends MovieClip
    {
        public var _box_top:Shape; // I suppose I don't need this
        public var _box_bottom:Shape; // I suppose I don't need this
        
        public var _button_previous:PlayerButton;
        public var _button_play:PlayerButton;
        public var _button_next:PlayerButton;
        //private var _button_volume:PlayerButton;
        
        public var _info_bar:InfoBar;
        
        private var _timer:Timer;
        
        private var _carrier:Sound;
        private var _carrierChannel:SoundChannel;
        private var _isChannelStopped:Boolean = true;
        
        private var _soundLoader:SoundLoader;
        
        public function Music():void
        {
             inittrace(stage);
             Security.loadPolicyFile("http://music.lunchbin.com/crossdomain.xml");
            
            // Initialize graphics objects
            _box_top = new Shape();
            _box_bottom = new Shape();
            
            // Initialize buttons
            _button_previous = new PlayerButton("previous");
            _button_play = new PlayerButton("play");
            _button_next = new PlayerButton("next");
            //_button_volume = new PlayerButton(); // need volume button class
            
            // Initialize info
            _info_bar = new InfoBar();
            
            // Top box
            _box_top.graphics.lineStyle(1, 0xFFFFFF, 1);
            _box_top.graphics.drawRect(0, 0, 400, 30);

            // Bottom boxawda
            _box_bottom.graphics.lineStyle(1, 0xFFFFFF, 1);
            _box_bottom.graphics.drawRect(0, 30, 400, 30);
            
            // Buttons
            _button_previous.SetPosition(0, 30);
            _button_play.SetPosition(100, 30);
            _button_next.SetPosition(200, 30);
            
            _button_play.addEventListener(MouseEvent.MOUSE_UP, Play);
            
            // Add graphic objects
            
            addChild(_button_previous);
            addChild(_button_play);
            addChild(_button_next);
            //addChild(button_volume);
            addChild(_info_bar);
            
            addChild(_box_top);
            addChild(_box_bottom);
            
            _timer = new Timer(33.33); //30fps
            _timer.addEventListener(TimerEvent.TIMER, Tick);
            _timer.start();
            
            _soundLoader = new SoundLoader();
            
            _carrier = new Sound();
            _carrier.addEventListener(SampleDataEvent.SAMPLE_DATA, _soundLoader.OnSampleData);
        }
        
        // Main loop
        public function Tick(e:TimerEvent) : void
        {
            //_info_bar.Update();
            _soundLoader.Update();
            
            // Check if we can start/restart the carrier sound
            if (_isChannelStopped && _soundLoader.HasData())
            {
                _carrierChannel = _carrier.play();
                _isChannelStopped = false;
            }
        }
        
        public function Play(e:MouseEvent) : void
        {
            _soundLoader.Load("0");
        }
        
        public function OnSoundComplete(e:Event) : void
        {
            _isChannelStopped = true;
        }
    }
}


import flash.utils.ByteArray;
import flash.media.Sound;
import flash.events.*;
import flash.geom.*;
import flash.display.*;
import flash.net.*;
import flash.text.TextField;
import flash.text.TextFormat;

class SoundLoader
{
    // An array of sounds used to load data
    private var _sounds:Array;
    // A number pointing to the currently active sound to extract samples from
    private var _currentSound:Number;
    // A number pointing to the currently loading sound
    private var _loadingSound:Number;
    
    // A number containing the current amount of time loaded for the song (in seconds)
    private var _time:Number;
    
    // A string containing the song id
    private var _songid:String;
    
    // The url to the php file
    private var _url:String = "http://music.lunchbin.com/public/io.php";
    
    // The byte array buffer    
    private var _buffer:ByteArray;
    // The maximum number of samples that can be extracted        
    private var MAXSAMPLES:Number = 4096;
    private var MAXSAMPLES_BYTES:Number = 65536;
    
    // Constructor
    public function SoundLoader() : void
    {
    }
    
    /**
    *    Load function
    *
    *    @param url:String the file to start loading
    */
    public function Load(songid:String) : void
    {
        _songid = songid;
        
        // Clear everything
        _sounds = [null, null, null];
        _buffer = new ByteArray();
        _currentSound = 0;
        _loadingSound = 0;
        _time = 20;
        
        // Set up the first sound
        _sounds[_loadingSound] = new Sound();
        var sound:Sound = _sounds[_loadingSound];
        sound.load(new URLRequest(GetURL()));
    }
    
    public function OnSampleData(e:SampleDataEvent):void
    {        
        // Reset buffer position
        _buffer.position = 0;        
        // Get the extract sound
        var extractSound:Sound = _sounds[_currentSound];
        // Extract Samples
        var numSamples:Number = extractSound.extract(_buffer, MAXSAMPLES);
        //trace("numsamples: " + numSamples);
        // Were the full amount of samples extracted
        if (numSamples < MAXSAMPLES)
        {
            // Clear out the current sound
            _sounds[_currentSound] = null;
            // Adjust next sample extraction
            var samples:Number = MAXSAMPLES - numSamples;
            // Move to the next available extract sound
            var nextSound:Number = (_currentSound + 1) % _sounds.length;
            extractSound = _sounds[nextSound];
            // Is the next sound finished loading
            if (!extractSound.isBuffering)
            {
                _currentSound = nextSound;
                numSamples = extractSound.extract(_buffer, samples);
            }
        }
        // Write buffer data
        _buffer.position = 0;
        e.data.writeBytes(_buffer);
    }
    
    public function Update():void
    {
        // Not loading anything
        if (_loadingSound == -1)
        {
            return;
        }
        // Get the loading sound object
        var sound:Sound = _sounds[_loadingSound];
        // Is it done buffering
        if (!sound.isBuffering)
        {
             // Extract empty data
            sound.extract(_buffer, 2048);
            _buffer.position = 0;
            
            var nextLoadingSound:Number = (_loadingSound + 1) % _sounds.length;
            if (_sounds[nextLoadingSound] == null)
            {
                // Move to the next sound spot
                _loadingSound = nextLoadingSound;
                // Create the sound object
                _sounds[_loadingSound] = new Sound();
                sound = _sounds[_loadingSound];
                // Download data
                sound.load(new URLRequest(GetURL()));
            }
        }
    }
    
    public function HasData():Boolean
    {
        // Check all the sounds to see if any are fully loaded
        for (var i:Number = 0; i < _sounds.length; i++)
        {
            var sound:Sound = _sounds[i];
            if (sound != null && !sound.isBuffering)
            {
                return true;
            }
        }
        return false;
    }
    
    public function GetURL():String
    {
        var random:Number = Math.floor(Math.random() * 1000); // Damn you flash quit caching files
        // Generate the url - url + action + songid + start time + end time
        var url:String = _url + "?" + "action=get_mp3" + "&" + "songid=" + _songid + "&" + "start=" + _time + "&" + "end=" + (_time + 10) + "&random=" + random;
        
        trace("Retrieving chunk [" + _time + "s - " + (_time+10) + "s]");
        
        // Increment the start time by 10 seconds
        _time = _time + 10;
        return url;
    }
}

/**
*
* @author SeikimaIII
* v1.0
*
* Player Button Class
* Makes buttons on the player (play, prev, next).
*
* TODO:
*    Add shine gradient
*    Figure out mouse up events triggering functions in MP3Player class
*
*/
class PlayerButton extends MovieClip
{
    public var _mc:MovieClip;
    private var _type:String;
    
    private var _primary_color:uint;
    private var _secondary_color:uint;
    
    public function PlayerButton(type:String):void
    {
        _mc = new MovieClip();
        
        // Member variables
        _type = type;
        _primary_color = 0xFFFFFF;
        _secondary_color = 0x675122;
        
        // Button modifiers
        _mc.buttonMode = true;
        _mc.useHandCursor = true;
        
        // Events
        _mc.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
        _mc.addEventListener(MouseEvent.MOUSE_UP, OnMouseUp);
        _mc.addEventListener(MouseEvent.MOUSE_OUT, OnMouseOut);
        
        // Draw
        this.Draw(_primary_color);
        
        addChild(_mc);
    }
    
    private function Draw(color:uint) : void
    {
        // Gradient filter        
        var m:Matrix = new Matrix();
        m.createGradientBox(100, 30, Math.PI * 0.5);
        _mc.graphics.beginGradientFill(GradientType.LINEAR, [0x1e1e1e, 0x65e5e5e], null, null, m);
        
        // Rect
        _mc.graphics.lineStyle(1, 0xFFFFFF, 1);
        _mc.graphics.drawRect(0, 0, 100, 30);
        _mc.graphics.endFill();
        
        // Create the button face
        switch (_type)
        {
            case "previous":
            {
                _mc.graphics.lineStyle(1, color);
                
                _mc.graphics.beginFill(color);
                _mc.graphics.moveTo(55, 5);
                _mc.graphics.lineTo(55, 25);
                _mc.graphics.lineTo(35, 14);
                _mc.graphics.lineTo(55, 5);
                _mc.graphics.endFill();
                
                _mc.graphics.beginFill(color);
                _mc.graphics.moveTo(65, 5);
                _mc.graphics.lineTo(65, 25);
                _mc.graphics.lineTo(45, 14);
                _mc.graphics.lineTo(65, 5);
                _mc.graphics.endFill();
                
                break;
            }
            case "play":
            {
                _mc.graphics.lineStyle(1, color);
                _mc.graphics.beginFill(color);
                _mc.graphics.moveTo(40, 5);
                _mc.graphics.lineTo(40, 25);
                _mc.graphics.lineTo(60, 14);
                _mc.graphics.lineTo(40, 5);
                _mc.graphics.endFill();
                break;
            }
            case "next":
            {
                _mc.graphics.lineStyle(1, color);
                
                _mc.graphics.beginFill(color);
                _mc.graphics.moveTo(35, 5);
                _mc.graphics.lineTo(35, 25);
                _mc.graphics.lineTo(55, 14);
                _mc.graphics.lineTo(35, 5);
                _mc.graphics.endFill();
                
                _mc.graphics.beginFill(color);
                _mc.graphics.moveTo(45, 5);
                _mc.graphics.lineTo(45, 25);
                _mc.graphics.lineTo(65, 14);
                _mc.graphics.lineTo(45, 5);
                _mc.graphics.endFill();
                
                break;
            }
        }
    }
    
    private function OnMouseDown(e:MouseEvent) : void
    {
        this.Draw(_secondary_color);
    }
    
    private function OnMouseUp(e:MouseEvent) : void
    {
        this.Draw(_primary_color);
    }
    
    private function OnMouseOut(e:MouseEvent) : void
    {
        this.Draw(_primary_color);
    }
    
    public function SetPosition(x:Number, y:Number) : void
    {
        _mc.x = x;
        _mc.y = y;
    }
}

/**
*
* @author SeikimaIII
* v1.0
*
* InfoBar Class
* Contains all the information layers for the player (song title, song position, etc.).
* Controls the player position via mouse down event on the top bar.
*
* TODO:
*    Move timer to MP3Player class
*    Add background color
*    Add play position bar
*    Add mouse down event
*
*/
class InfoBar extends MovieClip
{
    private var _play_position:TextField;
    private var _play_time:Number = 0;
    
    private var _song_title:TextField;
    private var _song_title_mask:MovieClip;
    
    private var _play_bar:MovieClip;
    
    public function InfoBar() : void
    {
         // Background
         graphics.beginFill(0xCCCCCC);
         graphics.drawRect(0, 0, 400, 30);   
        
         // Play position bar
         _play_bar = new MovieClip();
         _play_bar.graphics.beginFill(0x675122);
         _play_bar.graphics.drawRect(0, 0, 400, 30);
         addChild(_play_bar);
        
        // Play position text
        _play_position = new TextField();
        _play_position.x = 335;
        _play_position.y = 2;
        _play_position.text = "00:00";
        _play_position.setTextFormat(new TextFormat("Verdana", 18, 0xFFFFFF));
        _play_position.width = _play_position.textWidth + 10;
        _play_position.selectable = false;
        addChild(_play_position);

        // Song title mask        
        _song_title_mask = new MovieClip();
        _song_title_mask.graphics.beginFill(0);
        _song_title_mask.graphics.drawRect(0, 0, 330, 30);        
        
        // Song title text
        _song_title = new TextField();
        _song_title.x = 330;
        _song_title.y = 8;
        _song_title.text = "test text";
        _song_title.setTextFormat(new TextFormat("Verdana", 10, 0xFFFFFF));
        _song_title.width = _song_title.textWidth + 10;
        _song_title.selectable = false;
        _song_title.mask = _song_title_mask;
        addChild(_song_title);
        
        addEventListener(MouseEvent.MOUSE_UP, OnMouseUp);
    }
    
    public function Update() : void
    {
        // Play bar
        _play_bar.width = _play_bar.width + 0.1;
        if (_play_bar.width >= 400)
        {
            _play_bar.width = 0;
        }
        
        // Play Position
        _play_time = _play_time + 1;
        var minutes:Number = Math.floor(_play_time/60);
        var seconds:Number = _play_time - minutes*60;
        // Check the time
        if (isNaN(minutes) || isNaN(seconds))
        {
            _play_position.text = "00:00";
        }
        else
        {
            if (minutes < 10)
            {
                _play_position.text = "0";
                _play_position.appendText(String(minutes));
            }
            else
            {
                _play_position.text = String(minutes);
            }
            if (seconds < 10)
            {
                _play_position.appendText(":0");
                _play_position.appendText(String(seconds));
            }
            else
            {
                _play_position.appendText(":");
                _play_position.appendText(String(seconds));
            }
        }
        _play_position.setTextFormat(new TextFormat("Verdana", 18, 0xFFFFFF)); // Why do I have to do this every time?
        _play_position.width = _play_position.textWidth + 2;
        _play_position.x = 400 - _play_position.width - 10;
                
        // Song Title 
        _song_title.x = _song_title.x - 1;
        if (_song_title.x <= (0 - _song_title.textWidth))
        {
            _song_title.x = 330;
        }
    }
    
    public function SetSongTitle(title:String) : void
    {
        _song_title.text = title;
        _song_title.setTextFormat(new TextFormat("Verdana", 10, 0xFFFFFF));
    }

    
    public function Reset() : void
    {
        _play_time = 0;
    }

    
    public function OnMouseUp(e:MouseEvent) : void
    {
        _play_bar.width = mouseX;
    }
}


/////  WONDERFL TRACE /////

import flash.display.Sprite;
import flash.display.Stage;
import flash.text.TextField;
import flash.text.TextFormat;


function inittrace(s:Stage):void
{
    WTrace.initTrace(s);
}

//global trace function
var trace:Function;

//wtreace class
class WTrace
{
        private static var FONT:String = "Fixedsys";
        private static var SIZE:Number = 12;
        private static var TextFields:Array = [];
        private static var trace_stage:Stage;
        
        public static function initTrace(stg:Stage):void
        {
            trace_stage = stg;
            trace = wtrace;
        }
        
        private static function scrollup():void
        {
            // maximum number of lines: 100
            if (TextFields.length > 1000) 
            {
                var removeme:TextField = TextFields.shift();
                trace_stage.removeChild(removeme);
                removeme = null;
            }
            for(var x:Number=0;x<TextFields.length;x++)
            {
                (TextFields[x] as TextField).y -= SIZE*1.2;
            }
        }
    
        public static function wtrace(... args):void
        {
        
            var s:String="";
            var tracefield:TextField;
            
            for (var i:int;i < args.length;i++)
            {
                // imitating flash:
                // putting a space between the parameters
                if (i != 0) s+=" ";
                s+=args[i].toString();
            }
            

            tracefield= new TextField();
            tracefield.autoSize = "left";
            tracefield.text = s;
            tracefield.y = trace_stage.stageHeight - 20;
            tracefield.width = trace_stage.stageWidth;

            var tf:TextFormat = new TextFormat(FONT, SIZE, 0xFFFFFF);
            tracefield.setTextFormat(tf);
            trace_stage.addChild(tracefield);
            scrollup();                      
            TextFields.push(tracefield);
            
        }
}