Game session Sound Playback / Recording - actionscript-3

So I'm making a simple flash game. Basically I have a turntable that goes on for 30 seconds with a couple of sample music that adds up together in multiple layers of sound to form a final song.
Now I would like to be able to record and play the sounds at the end of the game.
I've created a SoundFx class that takes mp3 audio and turns it into byteArrays with the hope to mix the audios in to the same Sound channel.
Now I've reached a certain impass since I cannot properly mix the bytearrays. I'm starting to think it's not possible to encode the byte Arrays as you add the channels to the mix.
I'd love to be guided in the right direction. I'm not sure if the best way to proceed from here, even just the playback would be nice. Creating a button log would probably fix the playback and mixing the audio in a second run to go straight to the file. but it sure seems like a long path to achieve this.
Many thanks and apologies for my crappy english in advance
David R.
some code on the matter:
private var srcSound:Sound;
private var sound1:Sound;
private var sound2:Sound;
private var soundChannel:SoundChannel;
private var bytes:ByteArray;
private var incbytes:ByteArray;
private var mixedBytes:ByteArray;
public var pitchShiftFactor:Number;
public var position:Number;
public var AddSound:Boolean = false;
public var incremental:Number;
public var left1:Number;
public var left2:Number;
public var right1:Number;
public var right2:Number;
public var mixedBytes1:Number;
public var mixedBytes2:Number;
public function SoundFx() {
}
public function playFx(srcSound:Sound):void{
this.srcSound = srcSound;
position = 0;
var morphedSound:Sound = new Sound();
morphedSound.addEventListener(SampleDataEvent.SAMPLE_DATA, sampleDataHandler);
soundChannel = morphedSound.play();
}
public function addSound(sound1:Sound , sound2:Sound):void{
this.sound1 = sound1;
this.sound2 = sound2;
sound1.addEventListener(SampleDataEvent.SAMPLE_DATA, addSampleData);
position = 0;
soundChannel = sound1.play();
soundChannel = sound2.play();
AddSound = true;
}
private function addSampleData(event:SampleDataEvent):void{
position = 0;
var incbytes:ByteArray = new ByteArray();
position += sound1.extract(incbytes, 4096, position);
var bytes:ByteArray = new ByteArray();
position += sound2.extract(bytes, 4096, position);
event.data.writeBytes(mixBytes(bytes, incbytes));
}
private function sampleDataHandler(event:SampleDataEvent):void
{
var bytes:ByteArray = new ByteArray();
position += srcSound.extract(bytes, 4096, position);
event.data.writeBytes(editBytes(bytes));
}
private function mixBytes(bytes1:ByteArray , bytes2:ByteArray ):ByteArray{
bytes.position = 0;
incbytes.position = 0;
var returnBytes:ByteArray = new ByteArray();
while(bytes1.bytesAvailable > 0)
{
left1 = bytes1.readFloat();
left2 = bytes2.readFloat();
right1 = bytes1.readFloat();
right2 = bytes2.readFloat();
mixedBytes1 = left1 + left2;
mixedBytes2 = right1 + right1;
mixedBytes.writeFloat(mixedBytes1);
mixedBytes.writeFloat(mixedBytes2);
}
return mixedBytes;
}
private function editBytes(bytes:ByteArray):ByteArray{
//var skipCount:Number = 0;
var returnBytes:ByteArray = new ByteArray();
bytes.position = 0;
while(bytes.bytesAvailable > 0)
{
//skipCount++;
returnBytes.writeFloat(bytes.readFloat());
returnBytes.writeFloat(bytes.readFloat());
}
return returnBytes;
}
}

i think i get your idea,hope i did.
You should try to pass all of your SoundChannel classes (sound layers being added) to a SoundMixer class (there is plenty of info on this in adobe site),like a funnel,and then add a SAMPLEDATA event listener to that soundmixer, and capture the byte array of that sound mixer,it is like getting the byte array of the final mixdown...then encode those bytes to wav or mp3 .
Sorry i can not write that code down for you,i am not very good with the code yet, but im good at mixing sounds.
Here is an example form adobe site itself:
function loaded(event:Event):void
{
outputSnd.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound);
outputSnd.play();
}
Useful link:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html
soundmixer class link:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/SoundMixer.html

experimenting with stratus (cirrus) internet radio i used SoundMixer.computeSpectrum() on the server side and passed that data to the client side with NetStream.send() for drawing and playback.
It worked, but was very ram hungry with client and server on one computer (and with several songs loaded and converted to raw audio data :)
so, try computeSpectrum(), it seems perfect for creating an "audio log"

Related

How do I unload an external ".swf" file to load another?

I am a student who's working for months on a game and now I've got stuck on a problem.
I am new to actionscript 3 but i learn fast.
I can load my menu screen ("startScreen.swf") into my game (firstgame) automatically and everything works fine when I click play or storyScreen or instructionsScreen. But the problem is that I want to return after pressing ESC button. I have tried many code but nothing works exactly how I want.
Example: I click on story and the swf (storyScreen.swf) loads and I can read the story and when I am finished, I want to press ESC to reload my swf (startScreen.swf) and all the functions in it. Like play and instructions.
You can find my code and empty space in the function (esc).
I know it is maybe easy to solve but I really don't know how. :(
public class FirstGame extends MovieClip
{
public var Player:MovieClip
private var leftKeyIsDown:Boolean;
private var RightKeyIsDown:Boolean;
private var aMissileArray:Array;
private var aEnemyArray:Array;
public var scoreTxt:TextField;
public var ammoTxt:TextField;
public var MenuEnd:EndGameScreen;
public var menuAgain:EndGameScreen;
private var MenuStart:mcStartGameScreen;
private var MenuStory:mcStartGameScreen;
private var MenuInstructions:mcStartGameScreen;
private var nScore:Number;
private var nAmmo:Number;
private var tEnemyTimer:Timer;
public function FirstGame()
{
//Create a loader object
var startLoader:Loader = new Loader();
//add event listener to listen for the complete event
startLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, startLoaded);
//load our loader object
startLoader.load(new URLRequest("startScreen.swf"));
}
public function startLoaded(e:Event):void
{
MenuEnd.hideScreen();
Player.visible = false;
scoreTxt.visible = false;
ammoTxt.visible = false;
//get a reference to the loaded movieclip
MenuStart = e.target.content as mcStartGameScreen;
//listen for start game event
MenuStart.addEventListener("START_GAME", playGameAgain);
//add it to the stage
addChild(MenuStart);
//get a reference to the loaded movieclip
MenuStory = e.target.content as mcStartGameScreen;
//listen for start game event
MenuStory.addEventListener("SHOW_STORY", storyGameScreen);
//add it to the stage
addChild(MenuStory);
//get a reference to the loaded movieclip
MenuInstructions = e.target.content as mcStartGameScreen;
//listen for start game event
MenuInstructions.addEventListener("SHOW_INSTRUCTIONS", instructionsGameScreen);
//add it to the stage
addChild(MenuInstructions);
}
private function instructionsGameScreen(e:Event):void
{
var instructionsLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("instructionsScreen.swf");
instructionsLoader.load(url);
addChild(instructionsLoader);
stage.addEventListener(KeyboardEvent.KEY_UP, esc);
}
private function storyGameScreen(e:Event):void
{
var storyLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("storyScreen.swf");
storyLoader.load(url);
addChild(storyLoader);
stage.addEventListener(KeyboardEvent.KEY_UP, esc);
}
private function esc(e:KeyboardEvent):void
{
if (e.keyCode == 27)
{
//fscommand("quit");
/////////test//////////////////(new URLRequest(stage.loaderInfo.url), "FirstGame.swf");
}
}
private function playGameAgain(e:Event):void
{
//initialize variables
aMissileArray = new Array();
aEnemyArray = new Array();
nScore = 0;
nAmmo = 20;
Player.x = 262,95
Player.y = 323,30
Player.visible = true;
scoreTxt.visible = true;
ammoTxt.visible = true;
MenuStart.hideScreen();
MenuEnd.addEventListener("PLAY_AGAIN", playGameAgain);
MenuEnd.hideScreen();
updateScoreText();
updateAmmoText();
//trace("First Game Loaded");
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
stage.addEventListener(Event.ENTER_FRAME, gameLoop)
//creat an timer object
tEnemyTimer = new Timer(1000)
//listen for the timer ticks/intervals
tEnemyTimer.addEventListener(TimerEvent.TIMER, addEnemy)
//start our timer
tEnemyTimer.start();
}
I believe you should be able to start a new request on the same loader object. Either way, you're dealing with object creation + cleanup. The crux of the solution I'm offering is that you reuse your loaders.
Your current code is somewhat repetitious, so I've modified it slightly to demonstrate how you could simplify the code. Some thoughts while reviewing your code:
You're adding the same object to the stage multiple times (ie.,
MenuStart, MenuStory, MenuInstructions); these are all pointers to
the same root swf you loaded (a.k.a., startLoader).
You've registered events the stage at multiple locations. Best
practice is to place these in your constructor as they are
persistent.
Because you want to reuse your loaders at a later point, keeping a
table with them makes it easier to reference.
Any time you find yourself programming the same code in similar ways,
it's a good indication that you can simplify with a single function
(simply change the arguments).
Give this a try:
public var Player:MovieClip
private var leftKeyIsDown:Boolean;
private var RightKeyIsDown:Boolean;
private var aMissileArray:Array;
private var aEnemyArray:Array;
public var scoreTxt:TextField;
public var ammoTxt:TextField;
public var MenuEnd:EndGameScreen;
public var menuAgain:EndGameScreen;
private var MenuStart:mcStartGameScreen;
private var MenuStory:mcStartGameScreen;
private var MenuInstructions:mcStartGameScreen;
private var nScore:Number;
private var nAmmo:Number;
private var tEnemyTimer:Timer;
private var screens:Object = {
"SHOW_INSTRUCTIONS":{
"loader":new Loader(),
"url":new URLRequest("instructionsScreen.swf")
},
"SHOW_STORY":{
"loader":new Loader(),
"url":new URLRequest("storyScreen.swf")
},
"START_GAME":{
"loader":new Loader(),
"url":new URLRequest("startScreen.swf")
}
}
public function FirstGame() {
var startLoader:Loader = loadScreen({"type":"START_GAME"});
//Register our event listeners
startLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, startLoaded);
stage.addEventListener(KeyboardEvent.KEY_UP, esc);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
stage.addEventListener(Event.ENTER_FRAME, gameLoop)
}
private function loadScreen(e:Object):Loader {
screens[e.type].loader.load(screens[e.type].url);
addChild(screens[e.type].loader);
return screens[e.type].loader;
}
public function startLoaded(e:Event):void {
//initialize variables
aMissileArray = new Array();
aEnemyArray = new Array();
nScore = 0;
nAmmo = 20;
Player.x = 262, 95
Player.y = 323, 30
Player.visible = true;
scoreTxt.visible = true;
ammoTxt.visible = true;
MenuEnd.addEventListener("PLAY_AGAIN", playGameAgain);
MenuEnd.hideScreen();
updateScoreText();
updateAmmoText();
//creat an timer object
tEnemyTimer = new Timer(1000)
tEnemyTimer.addEventListener(TimerEvent.TIMER, addEnemy)
tEnemyTimer.start();
var swfRoot = screens.START_GAME.loader["content"];
swfRoot.addEventListener("START_GAME", loadScreen);
swfRoot.addEventListener("SHOW_STORY", loadScreen);
swfRoot.addEventListener("SHOW_INSTRUCTIONS", loadScreen);
}
private function esc(e:KeyboardEvent):void {
if (e.keyCode == 27) {
//fscommand("quit");
// Loop through our loaders, and reset them all.
for each (var entry:Object in screens) {
entry.loader.unloadAndStop();
removeChild(entry.loader);
}
// Reload the start screen
var startLoader:Loader = loadScreen({"type":"START_GAME"});
startLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, startLoaded);
}
}
The last thing I want to be guilty of is telling you how to run your project, however, I think you may be taking the wrong approach, here.
Instead of setting up the story and the game as separate swf files, what you would probably need to do is set up the story as a MovieClip, and the game as a MovieClip. (Yes, MovieClips can contain other symbols, including other MovieClips.) Then, you'll want to hide/show or add/remove these MovieClips from your stage using code.
If you need to know how to do this, let me give you the age-old admonishment: RTD (Read the Documentation). These are basic tasks that are covered both in the online Adobe Flash documentation, and across numerous tutorials online.
I hope that helps!

trouble resetting a flash game

I'm trying to build a simple flash game in which I need to be able to restart the game if the user dies. However resetting all of the variables doesn't seem to be accomplishing anything. All of my game elements are stored in arrays and I thought that maybe setting each of them to the array constructor wasn't deleting the objects that they were pointing to and that they were left on the screen as a result. Does anyone know of a way to delete those elements (since I can't iterate over the list to delete them for obvious reasons) or does anyone know of a better way to reset a game in flash? For reference, here's the init function and the variable declarations at the top of my program that are supposed to start/reset the game.
public class Main extends MovieClip {
//put field variables here
static var hudLayer:Sprite; //layer used to represent HUD elements
static var gameLayer:Sprite; //layer used to represent objects in the game space
static var uiTextLayer:Sprite; //layer used to represent text that should appear ON TOP of the HUD
static var backgroundLayer:Sprite; //layer used to display the background image
static var players: Array; //array of all the player objects for reference
static var backgrounds:Array; //array of all the background objects
static var lines: Array; //array of all the lines
static var powerUps:Array; //array of all the powerups
static var enemies:Array; //array of all the enemies
static var miscellaneousObjects:Array; //array of miscellaneous objects that I'd like to be able to keep track of
var xCoords:Array, yCoords:Array; //Used to temporarily hold x and y coordinates when making new drawings
static var grav:Number; //coefficient representing the force of gravity
static var isPaused:Boolean; //manages pausing mechanic
static var timer:Timer; //used for time delayed updating of game elements
var pt:Point; //variable used by collision detection
var asteroidTiming:Number; //used to properly delay creating of asteroids on the screen
static var asteroidDelay:Number; //current delay between when asteroids are deployed, changes over course of execution
static var score:Number; //this should be self-explanatory
var scoreField:TextField; //used to display the score
static var myTextFormat:TextFormat; //used to format the text in the scoreField
static var inGameOver:Boolean; //used to determine if we're at the game over screen
[Frame(factoryClass="Preloader")]
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
//set up the Sprite Layers
backgroundLayer = new Sprite();
gameLayer = new Sprite();
hudLayer = new Sprite();
uiTextLayer = new Sprite();
addChild(backgroundLayer);
addChild(gameLayer);
addChild(hudLayer);
addChild(uiTextLayer);
//instantiate important variables
xCoords = new Array();
yCoords = new Array();
players = new Array();
backgrounds = new Array();
enemies = new Array();
powerUps = new Array();
miscellaneousObjects = new Array();
grav = .04;
addBackGround();
addPlayer(400, 50);
isPaused = false;
lines = new Array();
score = 0;
inGameOver = false;
//instantiate text fields
scoreField = new TextField();
scoreField.text = "Score: " + score;
hudLayer.addChild(scoreField);
scoreField.x = 20;
scoreField.y = 20;
scoreField.textColor = 0xFFFFFF;
myTextFormat = new TextFormat();
myTextFormat.size = 15;
scoreField.setTextFormat(myTextFormat);
//set up timer
timer = new Timer(5);
timer.addEventListener(TimerEvent.TIMER, function():void { update()});
timer.start()
asteroidTiming = 0;
asteroidDelay = 150;
//set up mouse listener
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownEvent);
//set up key listener
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyEvent);
//tests
}
Since I can't see all your code, I will guess that you are not using removechild() to get rid of display objects off the stage.
To create a object:
var object:DisplayObject = new DisplayObject();
To make it visible on the display list:
parent.addChild(object);
To remove it from the display list:
parent.removeChild(object);
To erase its memory:
object=null;
(These four things must be done in this order, for this to work properly. IF you make something null without removing it from the display list, you leave it there, still visible, with no way of referencing it. It like lost in your application.
You have to make sure you always use removeChild() before making a variable null, or overwriting the variable.

actionscript 3.0 function calling using button click

im creating a simple flash playlist using buttons, in my stage i have 4 buttons which is button for song1,song2, stop and play. i have a working code for this one, but i decided to revise it because my previous code is like, per song they have each stop and play button,so i created this one to have a dynamic stop and play, i created a function for each song, the function will change the filename of the song to be loaded,
heres the catch, so i first pick a song, (either song1 or song2) then i click stop, then when i select a new song this error appears
Error: Error #2037: Functions called in incorrect sequence, or earlier call was unsuccessful.
at flash.media::Sound/_load()
at flash.media::Sound/load()
at playlist_fla::MainTimeline/songSelect1()
i think its not calling the second function because i cant see the trace i put inside it,anyway heres my code, sorry for the long post,
THANKS IN ADVANCE
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
var myTransform = new SoundTransform();
var lastPosition:Number = 0;
var song;
song1.addEventListener(MouseEvent.CLICK,songSelect1);
function songSelect1(e:MouseEvent):void{
song = "<filenameofthe1stsong>";
mySound.load(new URLRequest(song));
myTransform.volume = 0.5;
myChannel.soundTransform = myTransform;
lastPosition=0;
trace(1);
}
song2.addEventListener(MouseEvent.CLICK,songSelect2);
function songSelect2(e:MouseEvent):void{
song = "<filenameofthe2ndsong>";
mySound.load(new URLRequest(song));
myTransform.volume = 0.5;
myChannel.soundTransform = myTransform;
lastPosition=0;
trace(2);
}
btnStop.addEventListener(MouseEvent.CLICK,onClickStop);
function onClickStop(e:MouseEvent):void{
lastPosition = myChannel.position;
myChannel.stop();
}
btnPlay.addEventListener(MouseEvent.CLICK,onClickPlay);
function onClickPlay(e:MouseEvent):void{
myChannel = mySound.play(lastPosition);
myChannel.soundTransform = myTransform();
}
Correction:
According to Adobe:
Once load() is called on a Sound object, you can't later load a
different sound file into that Sound object. To load a different sound
file, create a new Sound object.
So, creating a new sound object would be the only way to fix it.
- - - Original Post - - -
If you enable debugging in your flash settings, it'd be easier to determine exactly what line is causing issues. That said, your code doesn't look incorrect apart from defining your sound transform twice. Try this:
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
var myTransform = new SoundTransform();
myChannel.soundTransform = myTransform;
var lastPosition:Number = 0;
var song;
song1.addEventListener(MouseEvent.CLICK,songHandler);
song2.addEventListener(MouseEvent.CLICK,songHandler);
btnStop.addEventListener(MouseEvent.CLICK,onClickStop);
btnPlay.addEventListener(MouseEvent.CLICK,onClickPlay);
function songHandler(e:MouseEvent):void {
switch (e.currentTarget.name) {
case "song1":
songSelect("<filenameofthe1stsong>")
break;
case "song2":
songSelect("<filenameofthe2ndsong>")
break;
}
}
function songSelect(songPath:String):void {
mySound.load(new URLRequest(songPath));
myChannel.soundTransform.volume = 0.5;
lastPosition = 0;
trace("Loading " + songPath);
}
function onClickStop(e:MouseEvent):void {
lastPosition = myChannel.position;
myChannel.stop();
}
function onClickPlay(e:MouseEvent):void {
myChannel = mySound.play(lastPosition);
myChannel.soundTransform = myTransform();
}

Details about as3 Sound.extract() format?

Using the sound object .extract() method, it's possible to retrieve the uncompressed sound data as a ByteArray. What is the format of the extracted sound data? Custom internal format, or established format? Endian type?
I would like to be able to load sounddata directly into a byteArray and feed sound playback from this data (bypassing step 1 below).
Here are my experiments so far:
Step 1. Here I load a sound, extract the data content and save it to disc:
private var sound:Sound;
private var byteArray:ByteArray;
// loading a sound...
private function init():void {
sound = new Sound();
sound.addEventListener(Event.COMPLETE, onComplete);
sound.load(new URLRequest('short.mp3'));
}
// saving it to disc...
private function onComplete(e:Event):void {
byteArray = new ByteArray();
sound.extract(byteArray, 100000000);
byteArray.position = 0;
var file:FileReference = new FileReference();
file.save(byteArray, 'short.data');
}
Step 2. Here I load the data from disc and feed the playback of a new sound object with this data:
private var sound:Sound;
private var byteArray:ByteArray;
// loading a sound...
private function init():void {
file = new FileReference();
file.addEventListener(Event.COMPLETE, onLoaded);
file.addEventListener(Event.SELECT, onSelected);
file.browse();
}
private function onSelected(e:Event):void {
file.load();
}
private function onLoaded(e:Event):void {
trace('loaded');
trace(file.data.length);
byteArray = file.data;
sound2 = new Sound();
sound2.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
sound2.play();
}
private function onSampleData(e:SampleDataEvent):void {
trace(e.position);
for (var i:int = 0; i < 2048; i++) {
var left:Number = byteArray.readFloat();
var right:Number = byteArray.readFloat();
e.data.writeFloat(left * 0.2);
e.data.writeFloat(right * 0.2);
}
}
I would like to be able of accomplishing this second step (loading data from disc and feeding a sound object playback) by using an external converter utility (sox or something).
/ Jonas
It should be standard 32bit floats, one per channel per sample. So I would try -e floating-point for sox, I haven't tried though but I would do it with a certain level of confidence... :) Floats are endian-independent, I believe...

Fast or asynchronous AS3 JPEG encoding

I'm currently using the JPGEncoder from the AS3 core lib to encode a bitmap to JPEG
var enc:JPGEncoder = new JPGEncoder(90);
var jpg:ByteArray = enc.encode(bitmap);
Because the bitmap is rather large (3000 x 2000) the encoding takes a long while (about 20 seconds), causing the application to seemingly freeze while encoding. To solve this, I need either:
An asynchronous encoder so I can keep updating the screen (with a progress bar or something) while encoding
An alternative encoder which is simply faster
Is either possible, and how can I do it?
I found an asynchronous encoder:
http://www.switchonthecode.com/tutorials/flex-tutorial-an-asynchronous-jpeg-encoder
Setting up the encoder to be asynchronous would likely be your best bet.
Here are two examples from Adobe
This example is with actionscript/flex, but its the same idea.
You can do it much faster with Alchemy:
http://www.websector.de/blog/2009/06/21/speed-up-jpeg-encoding-using-alchemy/
http://segfaultlabs.com/devlogs/alchemy-asynchronous-jpeg-encoding-2
You can use the alchemy encoder. It is really fast and you can encode images asynchronously. You can use this class to abstract it.
public class JPGAlchemyEncoder {
private static var alchemyWrapper:Object;
private var quality:Number;
public function JPGAlchemyEncoder(quality:Number) {
this.quality = quality;
if (!alchemyWrapper){
var loader:CLibInit = new CLibInit;
alchemyWrapper = loader.init();
}
}
public function encode(bitmapData:BitmapData):ByteArray{
var data: ByteArray = bitmapData.clone().getPixels( bitmapData.rect );
data.position = 0;
return alchemyWrapper.write_jpeg_file(data, bitmapData.width, bitmapData.height, 3, 2, quality);
}
public function encodeAsync(bitmapData:BitmapData, completeHandler:Function):void{
var encodedData:ByteArray = new ByteArray();
var data: ByteArray = bitmapData.clone().getPixels(bitmapData.rect);
data.position = 0;
var encodeComplete:Function = function():void{
completeHandler(encodedData);
};
alchemyWrapper.encodeAsync(encodeComplete, data, encodedData, bitmapData.width, bitmapData.height, quality);
}
}
}
asynchronous decode the png picture in separate thread ,supported by new version ...
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_LOAD;
var loader:Loader = new Loader();
loader.load(new URLRequest("...png"),loaderContext);
addChild(loader);
that's official.