Flash Actionscript 3 Waveform Generation Class

October 24th, 2008

In my last post, Plotting a Sound Wave in Flash AS3 I detailed a method to use when displaying audio data. The method itself works great, but due to Flash’s frame-based code execution and event processing the user looses input capabilities while the flash player chugs through millions of numbers adding, rounding and comparing. In order to make displaying an audio waveform easier on both the programmer and the user I wrote a class that analyzes a Sound object progressively, and dispatches a special event containing the analyzed data. The class will construct a left and right channel Vector, each containing one data point [a number between 0 and 1] for a given number of windows, between two positions in the sound. The left and right position are measured in samples and two types of analyzation are offered. Here is a demo of the class in action:

Screen Capture of Waveform Plot

Screen Capture of Waveform Plot


The calculated data can be reached incrementally through the WaveformEvent object which is dispatched every frame, or at the end of all analyzation in the Waveform object’s leftChannel and rightChannel properties. The details are listed in the documentation below.

Thanks to the Summit Projects Flash Blog and Thibault Imbert at ByteArray for their posts on the different techniques that went into my class.

Source
Here is the source for my TextMate project: Sources
Documentation: class and event

And here is a Flex version (made in windows): // Thanks dem!
Sources (Flex version)

Plotting a Sound Wave in Flash AS3

September 26th, 2008

I’ve always been really into wave editors. I used to make songs in Amadeus by piecing together samples from other songs. Tedious but very rewarding. In a post I made not a long time ago I detailed a little Theremin project which included some wave data visualization. In this post I”ll be going further into detail about plotting sound data.

Digital audio in it’s rawest form [PCM wave data] is a long list of numbers from 1 to -1, which represent the sound’s amplitude. Another way of thinking about this is that each number represents your speaker’s distance away from it’s rest position. At 1 the speaker is fully extended, blowing out your ears and scaring your cats, while at -1 it is fully retracted, blowing out your ears and scaring your cats. To make a meaningful visual out of this we just set up a graph where time is plotted on the horizontal axis and amplitude on the vertical. So at a really high resolution, that might look like this:
80's Oscilloscope
Okay, maybe it would look like that if you were living in the 80’s. Or if you were really into oscilloscopes. In reality with most popular songs being two to five minutes long, we’d be looking at HUGE graphs. One three minute song sampled at 44.1kHz/s comes out to be eight million samples per channel. Per channel. Since most modern music is in stereo, we’re looking at two graphs now. So how do we compress this data and view it in a meaningful way? We cheat a little. We kinda scrap the whole graph/function thing. Well kinda. Let’s say you have a window 1000 pixels wide and a sound 3 minutes long. We have to compress enough samples together in order to represent them using each pixel [about 7,938 samples per pixel]. Averaging doesn’t work because with values oscillating between -1 and 1 the mean is usually zero. We could take one sample every so often to represent an entire chunk and plot that, but that’s just resampling at a much lower resolution, which results in aliasing and all sorts of bogus stuff. Take this video for instance:

Just instead of helicopter blades not moving, it’ll be your data points. No, instead what we do is we scan every single sample and pick out the largest and the smallest numbers from the chunk, which in our case means running through every 7,938 samples and picking the biggest and smallest ones. Then we plot them on top of each other, maybe with a line connecting them. Flash gets a little slow working with lists and arrays this big, but I’m sure we’ll figure out some neat tricks to get this stuff working fast. That said, here’s a little demo. If you can figure out the song I’ll give you a million bucks. [Let it chug for a while, Flash is a slow beast]:

pcm wave data plotted in flash

pcm wave data plotted in flash

Project Source

ps – don’t cheat, guess the song before you download the source, goofball.

Formatting gcc, g++ Output Using PHP In TextMate

September 20th, 2008

While at ZendCon08 I saw a lot of people sharing the same love for TextMate as myself. I fricken love TextMate. Some of my friends laughed at me, saying “Bah, TM’s not an IDE, why do you want to write shell scripts to try to make it one?” And I’d be like, “I’m an ActionScript developer, there’s no point in using a sledge hammer to pound in nails.” This makes sense because my friends use Eclipse. I tried Eclipse but it’s so huge and the plugins are huge and the interface is cluttered and theming syntax-coloring is a pain. So when I got home from ZendCon, with my renewed love for PHP, and my continual quest to eventually be a good C programmer, I decided to write a gcc parser script that linked back into TextMate to go directly to my errors. I use a dark syntax theme, a slightly modded Amy, and the parser reflects that. Check out a picture of these gcc errors:

Picture of colored gcc output.

Picture of colored gcc output.


To do this you’ll need PHP installed on your machine. After that, the first step is to create a new command in TextMate’s C Bundle. Call it “Build, Format With PHP,” or anything else. Set it to save all files in the project when run [from the pull down at the top] now enter this into the text area:

export FILE=`basename ${TM_FILEPATH}`
export DIR=${TM_PROJECT_DIRECTORY}
~/Library/Application\ Support/TextMate/Support/bin/make_format_gcc.sh

Next select Output as “Show as HTML” so we can see our output. Now create a file called “make_format_gcc.sh” in the folder ~/Library/Application Support/TextMate/Support/bin/
Once you’ve created the file, use TM or vim to fill it with this:

make &> ${FILE}.mkout
php -f ~/Library/Application\ Support/TextMate/Support/bin/gcc_format.php ${FILE} ${DIR}

This bash script executes the make on the makefile and directs the standard and error output to the same file. Then the script calls php to parse and display the file. So now create a file named “gcc_format.php” in the same folder as make_format_gcc.sh and fill it with the meat of our parser:

<?php

    // get stdout and stderr then delete temp file
    $dir = $argv[2];
    $commandFile = $argv[1] . '.mkout';
    $commands = file_get_contents($commandFile);
   
    // break lines up by line ending
    $lines = explode("\n", $commands);
   
    // find errors and link them to pages and line number
    $errors = 0;
    for ($i=0; $i < count($lines); $i++)
    {
        $fnpos = strpos($lines[$i], ':');
        $filename = substr($lines[$i], 0, $fnpos);
        $lnpos = strpos($lines[$i], ': error:');
        $linestart = $lnpos - $fnpos - 1;
        if($linestart < 0) continue;
        $line = substr($lines[$i], $fnpos+1, $lnpos - $fnpos - 1);
        $link = "txmt://open/?url=file://$dir/$filename&line=$line&column=1";
        $lines[$i] = substr_replace( $lines[$i], '</a>', $lnpos, 0);
        $lines[$i] = "<a href=\"$link\">" . $lines[$i];
        $errors++;
    }
    $output = implode("<br />\n", $lines);
   
    echo '
    <html>
    <head>
        <style type="text/css">
        body    {background:#000000; color:#999999;}
        #comment{width:100%; background: #230021; color:#6060BF;}
        #fail   {width:100%; background:#3E0018; color:#9918B8;}
        #succ   {width:100%; background:#230021; color:#B0FFF0;}
        dslsh   {color:#A96AA9;}
        a:link  {color:#008080;}
        a:hover {color:#80A0FF;}
        </style>
    </head>
        <body>
            <div id="comment">
                <dslsh>//</dslsh> '
. $argv[1] .'\'s build results:
            </div>'
;
           
    echo $output . '<br />';
    if($errors > 0)
    {
        echo '<div id="fail">Build failed with '. $errors .' errors.</div>';
    }else
    {
        echo '<div id="succ">Build Succeeded!</div>';
    }
    echo'
        </body>
    </html>'
;
?>

This example assumes that you are working in a directory with a makefile, but I’m sure it can be easily modded to work with any build script. The colors reflect my favorite theme, but they should also be easily modded with lines 32-38 of the php script. Happy coding, peoples!

ZendCon 08

September 18th, 2008

I just got back from ZendCon 2008 and it was pretty fun. Much more fun than a typical work week. I got to learn a lot about the new features of PHP, some common and not so common security pitfalls and I met a lot of rad programmers. The highlight for me though, was the Yahoo party. Yahoo raffled off a Nintendo Wii, which I happened to win! When I went to pick it up from the rafflers the crowd of PHP developers started shouting “Speech! Speech!” So I stood up on a chair and told them I was an AS3 developer, and they promptly booed me down. I escaped unscathed, with the Wii.

Look at that happy lad! Time to get this thing ready for some homebrew apps.

I’ve moved servers!

September 2nd, 2008

After a little down time I’m back up in a much better situation! This blog is now hosted by 600RECORDS, which rocks. Tanks!

New Updated Tools/Classes For Actionscript 3

August 18th, 2008

Button
Calculating Frames Per Second [and memory usage]
MultiLoader
Example and Project Source

I’ve created a number of tools for people to use in the past, most of which I update regularly. In this post I’d like to revisit some of my old classes and post new updated code for those classes, as in their current form they don’t much represent my coding style. Please note that my class hierarchy has also changed, so make sure to update your includes if you are using these in your projects.

Button
I posted code for a button class here ->here about a year ago, since then I’ve changed things and really cleaned up that class. It’s simpler than before and faster. Given one to three images this class will create a clickable button that has the option to trigger up to four functions [on roll over, mouse down, mouse up and roll out]. Here is a snippet showing its use:

        var button:Button = new Button();
       
        // bitmapData of buttons "up" state
        var bmd_up:BitmapData = new BitmapData(50, 20, true, 0xFFBDE052);
        // bitmapData of buttons "over" state
        var bmd_over:BitmapData = new BitmapData(50, 20, true, 0xFF52C4E0);
        // bitmapData of buttons "down" state
        var bmd_down:BitmapData = new BitmapData(50, 20, true, 0xFFFFAF1A);
       
        button.x = 20;
        button.y = 20;
        // we pass our bitmapData to the button, one for each state. if only one bitmapData is supplied, it will be
        // copied to each state, after which each new bitmapData supplied will replace the first for the state
        // specified.
        button.up = bmd_up;
        button.over = bmd_over;
        button.down = bmd_down;
       
        // we supply functions to the buttons function references, if no functions are supplied, no functions will be called.
        button.overFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button over");};
        button.downFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button down");};
        button.upFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button up");};
        button.outFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button out");};
       
        addChild(button);
       
        // adding a label is as simple as creating a textfield and adding it to the button.
        var label:TextField = new TextField();
            label.textColor = 0xDDD4F7;
            label.mouseEnabled = false;
            label.text = "Button";
            label.autoSize = "left";
            label.x = button.width/2 - label.width/2;
            label.y = button.height/2 - label.height/2;
           
        button.addChild(label);

Calculating Frames Per Second
The next class I’d like to revisit is my FPS counter. It’s basically a textfield that displays an instantaneous fps count, and an averaged count. I have now removed the average frames per second and included a display of used memory in MB. Before I had used a timer to calculate the fps, which wasn’t quite accurate enough. Now the class uses flash.utils.getTimer() and is very precise and accurate. The class extends TextField so custom coloring, etc is very straightforward:

        var fps:FPSBox = new FPSBox();
        addChild(fps);

MultiLoader and MultiLoaderEvent
The next entry is a class created for downloading and importing files from your server or local file system into your flash application. It is what I use in place of my Multiple Bitmap Loader and my Bitmap Resource Handler. MultiLoader extends Loader to support multiple asynchronous downloads of images/swfs. They trigger specific (read “specially named”) ProgressEvents based on the names of entries supplied by you in their load functions. Alternatively, they also trigger a MultiLoaderEvent for every ProgressEvent or complete Event dispatched. One can access the bytesLoaded and bytesTotal for each event, as well as the entry name of the event (which matches the entry name given to MultiLoader). For example, to load a gif and listen to progress and complete events, code the following:

        var multiLoader:MultiLoader = new MultiLoader();
            multiLoader.load("http://www.efnx.com/images/experiment.gif", "efnx");
                       multiLoader.load("http://www.efnx.com/images/experiment.gif", "efnx", "Bitmap");
            multiLoader.addEventListener("efnx_Progress", efnxProgress, false, 0, true);// specially named
            multiLoader.addEventListener("efnx_Complete", efnxComplete, false, 0, true);// specially named
               multiLoader.addEventListener("progress", progress, false, 0, true);// will trigger a MultiLoaderEvent with an entry member for identification
               multiLoader.addEventListener("complete", complete, false, 0, true);

    private function efnxProgress(event:ProgressEvent):void
    {
        trace("UpdatedTools::efnxProgress()", (event.bytesLoaded/event.bytesTotal*100));
    }
    private function efnxComplete(event:ProgressEvent):void
    {
        trace("UpdatedTools::efnxComplete()");
    }
    private function progress(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::progress()", event.entry, (event.bytesLoaded/event.bytesTotal*100));
    }
    private function complete(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::complete()", event.entry);
    }

In this example my entry name is “efnx” and so MultiLoader triggers events of type “efnx_Progress” and “efnx_Complete”. By listening for these events, we can get updated information about our downloads. Another option is to listen for “progress” and “complete,” which will trigger an event of type MultiLoaderEvent, which extends ProgressEvent to include an “entry” member. The value of event.entry will be the name of the entry triggering the event, in this case “efnx.” Now to use our images we “get” the resource from MultiLoader, which has been storing it for us. A great feature of this class is being able to specify what the return type of your loaded object when calling the “get” function. Here I’m going to want to return a Bitmap object, so for the third parameter of the “load” function I’ll pass the string “Bitmap”. Here’s an example:

multiLoader.load("http://www.efnx.com/images/experiment.gif", "efnx", "Bitmap");

Now inside my efnxComplete function I’ll add the get function to get my Bitmap and display it.

        // if we are listening for "efnx_Complete"
    private function efnxComplete(event:Event):void
    {
        trace("UpdatedTools::efnxComplete()");
        var efnxBitmap:Bitmap = multiLoader.get("efnx");
            efnxBitmap.x = button.x + button.width + 10;
            efnxBitmap.y = button.y;
        addChild(efnxBitmap);
    }
        // or if we are listening for "complete"
    private function complete(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::complete()");
        var efnxBitmap:Bitmap = multiLoader.get(event.entry);
            efnxBitmap.x = button.x + button.width + 10;
            efnxBitmap.y = button.y;
        addChild(efnxBitmap);
    }

Using the third parameter of the load() function is optional and if omitted Multiloader will by default choose an appropriate return type, here is a list of the valid strings to pass as a return type:

MovieClip
Sprite
Bitmap
BitmapData

If no third parameter is supplied, MultiLoader will return a type it thinks is appropriate, given the extension of the loaded material. For example loading a .swf will return a MovieClip, where as loading a .jpeg, .png or .gif will return a BitmapData.

Example App and Project Source
Here is a project that shows all three updated classes being used:

package {

    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.text.TextField;
   
    import efnx.gui.Button;
    import efnx.time.FPSBox;
    import efnx.net.MultiLoader;
    import efnx.events.MultiLoaderEvent;
   
/**
 *  Application entry point for UpdatedTools post.
 *
 *  @langversion ActionScript 3.0
 *  @playerversion Flash 9.0
 *
 *  @author Schell Scivally
 *  @since 18.08.2008
 */

public class UpdatedTools extends Sprite {
   
    public static const testing:Boolean = false;
   
    public var button:Button = new Button();
    public var multiLoader:MultiLoader = new MultiLoader();
   
    /**
     *  @constructor
     */

    public function UpdatedTools()
    {
        super();

        stage.frameRate = 30;
        stage.scaleMode = "noScale";
        stage.align = "TL";
        stage.addEventListener("resize", resize, false, 0, true);
       
        // bitmapData of buttons "up" state
        var bmd_up:BitmapData = new BitmapData(50, 20, true, 0xFFBDE052);
        // bitmapData of buttons "over" state
        var bmd_over:BitmapData = new BitmapData(50, 20, true, 0xFF52C4E0);
        // bitmapData of buttons "down" state
        var bmd_down:BitmapData = new BitmapData(50, 20, true, 0xFFFFAF1A);
       
        button.x = 20;
        button.y = 20;
        // we pass our bitmapData to the button, one for each state. if only one bitmapData is supplied, it will be
        // copied to each state, after which each new bitmapData supplied will replace the first for the state
        // specified.
        button.up = bmd_up;
        button.over = bmd_over;
        button.down = bmd_down;
       
        // we supply functions to the buttons function references, if no functions are supplied, no functions will be called.
        button.overFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button over");};
        button.downFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button down");};
        button.upFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button up");};
        button.outFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button out");};
       
        addChild(button);
       
        // adding a label is as simple as creating a textfield and adding it to the button.
        var label:TextField = new TextField();
            label.textColor = 0xDDD4F7;
            label.mouseEnabled = false;
            label.text = "Button";
            label.autoSize = "left";
            label.x = button.width/2 - label.width/2;
            label.y = button.height/2 - label.height/2;
           
        button.addChild(label);
       
        var fps:FPSBox = new FPSBox();
        addChild(fps);
       
        MultiLoader.testing = true;
        MultiLoader.usingContext = true;
       
        multiLoader.load("http://www.efnx.com/images/experiment.gif", "efnx", "Bitmap");
        multiLoader.load("http://www.efnx.com/images/808.jpg", "808", "Sprite");
        multiLoader.addEventListener("progress", progress, false, 0, true);
        multiLoader.addEventListener("complete", complete, false, 0, true);
    }
   
    private function progress(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::progress()", event.entry, ": ", (event.bytesLoaded/event.bytesTotal*100));
    }
    private function complete(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::complete()");
        switch(event.entry)
        {
            case "efnx":
                var efnxBitmap:Bitmap = multiLoader.get("efnx");
                    efnxBitmap.x = button.x + button.width + 10;
                    efnxBitmap.y = button.y;
                addChild(efnxBitmap);
                break;
            case "808":
                var sprite808:Sprite = multiLoader.get("808");
                    sprite808.x = button.x;
                    sprite808.y = button.y + button.height + 20;
                addChild(sprite808);
                break;
            default:
        }
    }
   
    /**
     *  Resize stub.
     */

    private function resize(event:Event):void
    {
        if(testing) trace( "UpdatedTools::resize()" );
    }
   
}

}

And here is the source to my classes:
Example Project and Source [includes classes]

Here is a little example:
updatedExample

And as always you can find the classes by themselves [along with all my other classes] here efnx AS3 classes, as well as some limited documentation efnx Class Documentation

Actionscript 3 Browser Theremin / Wave Data Visualization

August 2nd, 2008

Yesterday I started fooling around with FP10’s sound generation capabilities and I got the idea to code a little Theremin. It came out pretty good, but was bland in aesthetics. I decided to try my hand at coding a visualization algorithm similar to the type of visualization one would see while using Amadeus or Digital Performer, etc. I wanted to plot the wave form on the stage. Taking a copy of the sound buffer and selecting equally spaced samples I plotted them on the bitmapData of a Bitmap object and drew lines between data points. This is what it looks like:
Theremin Wave Data

The mouse position in x controls the frequency of a sine wave [from 220Hz to 440Hz or A3 to A4], while the y position controls volume. There’s some tearing that occurs when modulating volume, I haven’t figured that out how to fix that yet. As you move your mouse the wave that is generated is plotted on the stage. The pink dots represent sampled data points [which correspond to speaker movement] while the purple lines are approximations of the in-betweens [just lines drawn from point to point]. After playing with that for a while I wrote a class that matches note names to frequencies and drew markers indicating where on the x-axis of the stage one would have to place the cursor to generate a given note between A3 and A4. This is just a small example of the possibilities of sound in flash, and one way to interact with it. I’m looking forward to building on the classes I made for this example. I’ve included my entire TextMate project and source below [which will be the foundation of many more experiments], you can chop it up and use it however you want, although I didn’t copy any license to it, but trust me I won’t sue.

src -> Theremin Project/Visualizing Wave Data

Flash 10 [Astro] Debug Install

July 30th, 2008

I had some problems installing the under-the-radar Flash 10 Debug version mentioned in a couple blogs in the past months. So here is my work around just in case anyone else can’t seem to get Flash 10 to trace to their flashlog.txt.

1. Download installer from Adobe’s svn repository and select your OS [the rest of these steps are for mac, mind you, but you'll get the idea].
2. Unarchive and mount “Install Flash Player 10 UB.dmg”
3. Here’s the funny part, I couldn’t install the package. I got an error saying “nothing to install”, so instead, right click on “Adobe Flash Player.pkg” and choose “Show Package Contents”. It should show two archives, a plist, pkginfo and a resources folder.
4. Unarchive “Archive.pax.gz” to your desktop.
5. Inside you’ll find “Flash Player.plugin,” “flashplayer.xpt” and “version.txt.” The version.txt file says the player is version 9.0.45.0, but after looking at the info for “Flash Player.plugin” you’ll see it’s version 10.0.0.525, which isn’t the newest, but it traces and that’s what I need it for.
6. Copy “Flash Player.plugin” and “flashplayer.xpt” to your internet plugin folder, on my machine that’s /Library/Internet Plug-Ins
7. Restart FireFox/Safari/whatever.

That’s it!

I’m sorry if this info is un-needed, I definitely needed it, maybe everyone else can simply install that package, but I couldn’t, so that’s the fix. Happy coding.

Blog Activity

July 8th, 2008

Hey guys, I’m not sure who reads this on a regular basis, but I’ve been super swamped with work lately and haven’t had a lot of time [or energy] for my own development. Hopefully I’ll be seeing things clear up soon and I’ll have some new classes and new projects to share with you. Thanks for sticking in there, tiger. In the meantime, here’s a rad video.

Merging Layered BitmapData in AS3

February 14th, 2008

This tutorial is for those of your who might have to write your own Photo-shop-a-like applications or anyone who has to merge [flatten] two BitmapData together at pixel-level, without using BitmapData.copyPixels or BitmapData.merge. Furthermore this tutorial deals with bitwise operations, which are super fast and rad for color computation. Boom. Color. If you’re not familiar with bitwise operators I suggest you check out Polygonal Labs’ Bitwise Gems: Fast Integer Math. Done? Great. Okay, on with our discussion. I hope this stuff makes sense because this is my first tutorial. Ever…. …so first let’s create some colored Bitmaps on the page.

var bmd1:BitmapData = new BitmapData(100, 100, true, 0xFF00FF00);
var bm1:Bitmap = new Bitmap(bmd1);
addChild(bm1);
var bmd2:BitmapData = new BitmapData(100, 100, true, 0xFFFF0000);
var bm2:Bitmap = new Bitmap(bmd2);
bm2.y = bm1.height;
addChild(bm2);
var bmd3:BitmapData = new BitmapData(100, 100, true, 0x7F0000FF);
var bm3:Bitmap = new Bitmap(bmd3);
bm3.x = bm1.width/2;
bm3.y = bm1.height/2;
addChild(bm3);

Building our project we should see somethin like this:
MergingLayeredBitmapDataStep1
As you can see we’ve created a super green bmd, a bloody red bmd and a half-hearted (half-opaque) blue bmd. When the half-opaque blue bitmap is placed over the green and red bitmaps it filters the green and red bitmaps, altering the percieved colors. Our goal is to be able to calculate those percieved colors given two 32 bit colors in order to merge them onto a new BitmapData.

Now let’s begin our pixel layering function. We can start by outlining what the function is going to do. Let’s give it two 32 bit colors, (like the red and blue or the green and blue) and let’s make it give us back a 32 bit color that represents the two colors layered on top of each other.

private function layerColor32(topColor:uint, bottomColor:uint):uint
{
}

Now let’s extract each color’s ARGB channels. Traditionally the method would look like this:

private function layerColor32(topColor:uint, bottomColor:uint):uint
{
    var aB:uint = bottomColor >>> 24;
    var rB:uint = bottomColor >>> 16 & 0xFF;
    var gB:uint = bottomColor >>> 8 & 0xFF;
    var bB:uint = bottomColor  & 0xFF;
    var aT:uint = topColor >>> 24;
    var rT:uint = topColor >>> 16 & 0xFF;
    var gT:uint = topColor >>> 8 & 0xFF;
    var bT:uint = topColor  & 0xFF;
}

But since we’re working with what the colors *should* look like when layered, we have to figure out how much each channel actually shows through, according to the alpha channel. To do this we’ll multiply each channel by the color’s alpha channel’s opacity. The opacity is simply the alpha channel value divided by 255. So 100% opacity (255 or 0xFF) would turn out as 1, and 1 times each channel means 100% of each channel will show. 50% opacity (127 or 0×7F-0×80) would turn out as .5 and .5 times each channel shows 50% of each channel. Thus:

private function layerColor32(topColor:uint, bottomColor:uint):uint
{
    var aB:uint = bottomColor >>> 24;
    var rB:uint = (bottomColor >>> 16 & 0xFF)*(aB/0xFF);
    var gB:uint = (bottomColor >>> 8 & 0xFF)*(aB/0xFF);
    var bB:uint = (bottomColor  & 0xFF)*(aB/0xFF);
    var aT:uint = topColor >>> 24;
    var rT:uint = (topColor >>> 16 & 0xFF)*(aT/0xFF);
    var gT:uint = (topColor >>> 8 & 0xFF)*(aT/0xFF);
    var bT:uint = (topColor  & 0xFF)*(aT/0xFF);
}

Now that we have our individual channel values we can begin to calculate our new color. Remember that the maximum color value is 255 (0xFF) so we’ll be constraining our channel additions to 255.

private function layerColor32(topColor:uint, bottomColor:uint):uint
{
    var aB:uint = bottomColor >>> 24;
    var rB:uint = (bottomColor >>> 16 & 0xFF)*(aB/0xFF);
    var gB:uint = (bottomColor >>> 8 & 0xFF)*(aB/0xFF);
    var bB:uint = (bottomColor  & 0xFF)*(aB/0xFF);

    var aT:uint = topColor >>> 24;
    var rT:uint = (topColor >>> 16 & 0xFF)*(aT/0xFF);
    var gT:uint = (topColor >>> 8 & 0xFF)*(aT/0xFF);
    var bT:uint = (topColor  & 0xFF)*(aT/0xFF);

    var aN:uint = Math.min(aB + aT, 0xFF);
    var rN:uint = Math.min(rB + rT, 0xFF);
    var gN:uint = Math.min(gB + gT, 0xFF);
    var bN:uint = Math.min(bB + bT, 0xFF);
}

If you combine our channels and return the new color you’ll get something much brighter than what we should see. We’re going to have to filter the bottom color through the top color to fix this. You might be saying “ah man, I’ll just use BitmapData.copyPixels,” but don’t worry, we’re almost done. It’ll be so much more satisfying to figure out this stuff in the end, believe me. You’ll be a color scientist. So, all we need to do is multiply each channel of the bottom color by a number that represents how much light penetrates the top layer. So, if our top layer alpha channel is 0×7F, our ’show through’ variable is going to be 50% (0×7F) and if our top alpha channel is 0×40 (25%) then 75% of the bottom channel will show through. To do this we’ll create our ’show through’ var and multiply the bottom channels by it.

private function layerColor32(topColor:uint, bottomColor:uint):uint
{
    var aB:uint = bottomColor >>> 24;
    var rB:uint = (bottomColor >>> 16 & 0xFF)*(aB/0xFF);
    var gB:uint = (bottomColor >>> 8 & 0xFF)*(aB/0xFF);
    var bB:uint = (bottomColor  & 0xFF)*(aB/0xFF);
    var aT:uint = topColor >>> 24;
    var rT:uint = (topColor >>> 16 & 0xFF)*(aT/0xFF);
    var gT:uint = (topColor >>> 8 & 0xFF)*(aT/0xFF);
    var bT:uint = (topColor  & 0xFF)*(aT/0xFF);
    /*this determines how much of our lower layer shows through*/
    var showThru:Number = (0xFF - aT)/0xFF;
    trace("laryerColor32:showThru: (255 - "+aT+")/255 = "+showThru);
    /**********************************************************************/
    var aN:uint = Math.min(aB + aT, 0xFF);
    var rN:uint = Math.min(rB*showThru + rT, 0xFF);
    var gN:uint = Math.min(gB*showThru + gT, 0xFF);
    var bN:uint = Math.min(bB*showThru + bT, 0xFF);
}

Now for the last bit. Let’s combine all our new channels and return that value.

private function layerColor32(topColor:uint, bottomColor:uint):uint
{
    var aB:uint = bottomColor >>> 24;
    var rB:uint = (bottomColor >>> 16 & 0xFF)*(aB/0xFF);
    var gB:uint = (bottomColor >>> 8 & 0xFF)*(aB/0xFF);
    var bB:uint = (bottomColor  & 0xFF)*(aB/0xFF);
    var aT:uint = topColor >>> 24;
    var rT:uint = (topColor >>> 16 & 0xFF)*(aT/0xFF);
    var gT:uint = (topColor >>> 8 & 0xFF)*(aT/0xFF);
    var bT:uint = (topColor  & 0xFF)*(aT/0xFF);
    /*this determines how much of our lower layer shows through*/
    var showThru:Number = (0xFF - aT)/0xFF;
    trace("laryerColor32:showThru: (255 - "+aT+")/255 = "+showThru);
    /**********************************************************************/
    var aN:uint = Math.min(aB + aT, 0xFF);
    var rN:uint = Math.min(rB*showThru + rT, 0xFF);
    var gN:uint = Math.min(gB*showThru + gT, 0xFF);
    var bN:uint = Math.min(bB*showThru + bT, 0xFF);
   
    return(aN << 24 | rN << 16 | gN << 8 | bN);
}

Awesome! Were done. Using this function, for loops and some creativity, you can compile any number of 32 bit BitmapData on top of each other. Boom. Color. So, let’s use this function and compare it to the blending that happens within DisplayObjectContainers with transparency! Let’s alter our first bitmap generating/placing code to use our new function:

var bmd1:BitmapData = new BitmapData(100, 100, true, 0xFF00FF00);
var bm1:Bitmap = new Bitmap(bmd1);
addChild(bm1);
var bmd2:BitmapData = new BitmapData(100, 100, true, 0xFFFF0000);
var bm2:Bitmap = new Bitmap(bmd2);
    bm2.y = bm1.height;
addChild(bm2);
var bmd3:BitmapData = new BitmapData(100, 100, true, 0x7F0000FF);
var bm3:Bitmap = new Bitmap(bmd3);
    bm3.x = bm1.width/2;
    bm3.y = bm1.height/2;
addChild(bm3);
var color1:uint = bmd1.getPixel32(0, 0);
var color2:uint = bmd3.getPixel32(0, 0);
var color3:uint = layerColor32(color2, color1);
var color4:uint = bmd2.getPixel32(0, 0);
var color5:uint = layerColor32(color2, color4);
var bmd4:BitmapData = new BitmapData(50, 50, true, color3);
var bm4:Bitmap = new Bitmap(bmd4);
    bm4.x = bm1.width;
addChild(bm4);
var bmd5:BitmapData = new BitmapData(50, 50, true, color5);
var bm5:Bitmap = new Bitmap(bmd5);
    bm5.x = bm1.width;
    bm5.y = bm1.height*1.5;
addChild(bm5);

Let’s take a look at it.
MergingLayeredBitmapDataStep2
Wow, I don’t believe. Well, there you have it. Bust out your color schemer (or equivalent) and check those hex codes. Exact are they not? I hope you enjoyed this! Yay color.