Create a AS3 MP3 Player with papervision3d spectrum display


As we’ve already promised you, here’s the tutorial about how to create a 3d spectrum display from a sound file with papervision3d and flash.
On this tutorial, we’ll focus on the 3d part. If you’re not comfortable with the SoundMixer.computeSpectrum method then you should read the previous tutorial.
So, let’s start with the fun.

Requirements

Adobe Flash CS3

Try / Buy

Source Files

Download

Getting Started

For this demo application, we’ve used the latest version of papervision3d with the code name GreatWhite. First of all, we need to include the papervision3d stuff.

import org.papervision3d.cameras.Camera3D;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.utils.MaterialsList;

These are all the classes we need for our application. The Camera3D class enables you to focus on a 3d object and zoom to it. Scene3D is a container that holds all 3d objects. The Viewport will be added to the main stage and is like a video screen that shows the result. Another important class is the BasicRenderEngine which renders all the objects from the scene with the current camera settings and outputs the result to the viewport. Papervision comes with different types of objects, but for our example we’ll only need the cube. And finally there are the materials which can be set to the objects. This is how papervision basically works.

Then we to set some constants for the sound channel

const CHANNELS_PER_DIRECTION:int= 256;
const CUBES_PER_CHANNEL:int		= 8;
const CHANNEL_STEPS:int			= Math.floor(CHANNELS_PER_DIRECTION / CUBES_PER_CHANNEL);

Next thing to do is to set the papervision variables

var viewport:Viewport3D;
var scene:Scene3D;
var camera:Camera3D;
var cube:Cube;
var renderer:BasicRenderEngine;

To keep a reference of each cube, we need to create 2 arrays. For each sound channel (left, right)

var cubesLeftChannel:Array		= new Array();
var cubesRightChannel:Array		= new Array();

At the end, we want to swing our camera from left to right and vice versa. To know in which direction we’re currently moving, we need to set a flag:

var bolAnimationForward:Boolean 	= true;

The next part is the same as in the previous tutorial. We create a new sound object and a url request for requesting the mp3 file. SndBytes will hold the current spectrum data.

var sndObject:Sound			= new Sound();
var reqObject:URLRequest 		= new URLRequest("so-deep.ram2000.mp3");
var sndBytes:ByteArray			= new ByteArray();

So, the next step will be the initializing of our 3d stuff, then loading the soundfile and finally creating the render loop. First of all, we create a new viewport and add it to the stage. The third parameter tells the viewport to use the whole width and height of the swf file for displaying the 3d objects.

viewport = new Viewport3D(0, 0, true);
addChild(viewport);

Then we create a new basic render engine and a scene which holds the 3d objects

renderer = new BasicRenderEngine();
scene = new Scene3D();

Our cubes will need a material. We create a blue one for cubes that are displaying the left channel and a green material for the other ones. You can easily change the colors for each side using hex values.

var blueMaterial:MaterialsList = new MaterialsList(
	{
		front:  new ColorMaterial(0x0066FF),
		back:   new ColorMaterial(0x0066FF),
		right:  new ColorMaterial(0x0046B0),
		left:   new ColorMaterial(0x0046B0),
		top:    new ColorMaterial(0x1171FF),
		bottom: new ColorMaterial(0x1171FF)
	}
);

var greenMaterial:MaterialsList = new MaterialsList(
	{
		front:  new ColorMaterial(0x00CC00),
		back:   new ColorMaterial(0x00CC00),
		right:  new ColorMaterial(0x009F00),
		left:   new ColorMaterial(0x009F00),
		top:    new ColorMaterial(0x00CC00),
		bottom: new ColorMaterial(0x00CC00)
	}
);

Now we need to create the cubes for the left channel, position them correctly on the x-axis, keep a reference in the array and add them to the scene

for(var i = 0; i < CUBES_PER_CHANNEL; i++) {
	cube = new Cube(blueMaterial, 12, 50, 400);
	cube.x = i * 50;
	cubesLeftChannel.push(cube);
	scene.addChild(cube);
}

The same procedure for the cubes standing for the right channel but with the green material and we place them between the green ones.

for(i = 0; i < CUBES_PER_CHANNEL; i++) {
	cube = new Cube(greenMaterial, 12, 50);
	cube.x = (i * 50) + 25;
	cubesRightChannel.push(cube);
	scene.addChild(cube);
}

Finally we create a new camera, set the target to the cube in the middle, adjust the zoom and move the start position a bit to the upper left

camera = new Camera3D();
camera.zoom = 11;
camera.target = cubesRightChannel[CUBES_PER_CHANNEL / 2 - 1] as Cube;
camera.x -= 400;
camera.y += 300;

Now we’re finished with creating all the necessary 3d stuff. Next thing to do is loading a sample mp3 file which is quite easy. We just load the url request we’ve created bevore and play the file.

sndObject.load(reqObject);
sndObject.play();

The only thing left to do is the render loop. This loop will be executed on enter frame, in our case 60 times per second. First, we compute the spectrum and put the result in the defined byte array.

SoundMixer.computeSpectrum(sndBytes);

Then we set the right position for the byte array pointer, read the float value and assign it to the current cube scaleY value. Like this, the cubes will be resized according to the spectrum. After the end of the first loop, we repeat the procedure for the right channel cubes

for(var i = 0; i < CUBES_PER_CHANNEL; i++) {
	var myCube:Cube = cubesLeftChannel[i] as Cube;
	sndBytes.position = CHANNEL_STEPS * 4 * i;
	myCube.scaleY =  sndBytes.readFloat();
}
for(i = 0; i < CUBES_PER_CHANNEL; i++) {
	myCube = cubesRightChannel[i] as Cube;
	sndBytes.position = 1024 + (CHANNEL_STEPS * 4 * i);
	myCube.scaleY = sndBytes.readFloat();
}

To swing our camera a bit, we increase and decrease it’s x value

if(bolAnimationForward) {
	camera.x += 4;
	if(camera.x > 800)
		bolAnimationForward = false;
} else {
	camera.x -= 4;
	if(camera.x < -400)
		bolAnimationForward = true;
}

And now we need to tell the render engine to render the current scene, camera and viewport

renderer.renderScene(scene, camera, viewport);

That was already the whole trick. You can also try rendering other materials and different objects. These were just the basics about papervision3d. We hope you enjoyed reading this tutorial. Any feedbacks and questions are welcome.

In the final you will get this:


Full code with comments

// Import Papervision3D
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.utils.MaterialsList;

// constants
const CHANNELS_PER_DIRECTION:int= 256;
const CUBES_PER_CHANNEL:int		= 8;
const CHANNEL_STEPS:int			= Math.floor(CHANNELS_PER_DIRECTION / CUBES_PER_CHANNEL);

// papervision vars
var viewport:Viewport3D;
var scene:Scene3D;
var camera:Camera3D;
var cube:Cube;
var renderer:BasicRenderEngine;

// arrays holding references to cubes for each channel
var cubesLeftChannel:Array		= new Array();
var cubesRightChannel:Array		= new Array();
// animation flag
var bolAnimationForward:Boolean = true;

// sound vars
var sndObject:Sound				= new Sound();
var reqObject:URLRequest 		= new URLRequest("so-deep.ram2000.mp3");
var sndBytes:ByteArray			= new ByteArray();

// INIT
function init():void {
	init3D();
	initSound();
	// add event listener for render loop
	addEventListener(Event.ENTER_FRAME, renderLoop);
}

// init3d
function init3D():void {
	// Create viewport
	viewport = new Viewport3D(0, 0, true);
	// add viewport to stage
	addChild(viewport);

	// create basic render engine
	renderer = new BasicRenderEngine();

	// Create scene
	scene = new Scene3D();

	// blue cube material
	var blueMaterial:MaterialsList = new MaterialsList(
		{
			front:  new ColorMaterial(0x0066FF),
			back:   new ColorMaterial(0x0066FF),
			right:  new ColorMaterial(0x0046B0),
			left:   new ColorMaterial(0x0046B0),
			top:    new ColorMaterial(0x1171FF),
			bottom: new ColorMaterial(0x1171FF)
		}
	);

	// green cube material
	var greenMaterial:MaterialsList = new MaterialsList(
		{
			front:  new ColorMaterial(0x00CC00),
			back:   new ColorMaterial(0x00CC00),
			right:  new ColorMaterial(0x009F00),
			left:   new ColorMaterial(0x009F00),
			top:    new ColorMaterial(0x00CC00),
			bottom: new ColorMaterial(0x00CC00)
		}
	);

	// create cubes for left channel
	for(var i = 0; i < CUBES_PER_CHANNEL; i++) {
		cube = new Cube(blueMaterial, 12, 50, 400);
		cube.x = i * 50;
		cubesLeftChannel.push(cube);
		scene.addChild(cube);
	}
	//create cubes for the right channel
	for(i = 0; i < CUBES_PER_CHANNEL; i++) {
		cube = new Cube(greenMaterial, 12, 50);
		cube.x = (i * 50) + 25;
		cubesRightChannel.push(cube);
		scene.addChild(cube);
	}

	// create camera
	camera = new Camera3D();
	// set camera zoom
	camera.zoom = 11;
	// set cube in the center as camera target
	camera.target = cubesRightChannel[CUBES_PER_CHANNEL / 2 - 1] as Cube;
	// camera start position
	camera.x -= 400;
	camera.y += 300;
}

function initSound():void {
	// load mp3 file and play it
	sndObject.load(reqObject);
	sndObject.play();
}

// render loop function
function renderLoop(e:Event):void
{
	// compute spectrum and put result in byte array
	SoundMixer.computeSpectrum(sndBytes);

	//
	// LEFT CHANNEL CUBES
	for(var i = 0; i < CUBES_PER_CHANNEL; i++) {
		var myCube:Cube = cubesLeftChannel[i] as Cube;
		// get the right positions for the byte array
		sndBytes.position = CHANNEL_STEPS * 4 * i;
		// resize current cube
		myCube.scaleY =  sndBytes.readFloat();
	}
	//
	// RIGHT CHANNEL CUBES
	for(i = 0; i < CUBES_PER_CHANNEL; i++) {
		myCube = cubesRightChannel[i] as Cube;
		// get the right positions for the byte array
		sndBytes.position = 1024 + (CHANNEL_STEPS * 4 * i);
		// resize current cube
		myCube.scaleY = sndBytes.readFloat();
	}

	// swing camera
	if(bolAnimationForward) {
		camera.x += 4;
		if(camera.x > 800)
			bolAnimationForward = false;
	} else {
		camera.x -= 4;
		if(camera.x < -400)
			bolAnimationForward = true;
	}

	// render current scene
	renderer.renderScene(scene, camera, viewport);
}

init();

Did you enjoy this article?
Share the love
Get free updates and win TTL prizes

Other Posts You Might Like

24 Responses to “Create a AS3 MP3 Player with papervision3d spectrum display”

  1. Ryoma says:

    Hi,

    I am having problem adding the sound spectrum in my mp3 player,
    any idea how to input in those code.

    How can i send my .FLA & .AS file here..

    Thanks,

  2. mel says:

    Hello, something goes wrong with the sample files.. publishing those i got 2 errors in TraingleMaterial.as. Easy but wrong solution would be by removing the line

    “override public function drawTriangle(face3D:Triangle3D, graphics:Graphics, renderSessionData:RenderSessionData):void ”

    in TraingleMaterial.as

    You probably know a better way of solving this

    thanks

  3. Rafael Nünlist says:

    Hey

    @ Ryoma: Please describe your problem a little bit more detailed. You can also send me your files. ( rafael.nuenlist [at] venox {dot} ch )

    @ mel: Did you change anything in the sample files? I tried to publish the fla on different computers and it worked out well.

  4. mel says:

    downloaded the files again and tried them om my other pc.. and all worked.. sorry should have tried that before posting

  5. Ryoma says:

    Rafael,

    Hi Rafael thanks for reply…

    i had send u the files please check your mail-thanks.

    Hope you can fixed my problem..

    Thanks,
    Ryoma

  6. Ryoma says:

    Hmmm.. i think Rafael,cant’ fixed my prob. here….. :(

    Any one of you could help me please….. and let me know..

    Thanks

    Regards,

    Leong

  7. gordee says:

    Great tutorial thanks!

    What would you need to do to have say spheres that jumped up and down?

  8. Billy says:

    Awesome stuff. Thanks.

  9. Great tips thanks a lot :)

  10. Doug says:

    Hey nice work Rafael!

    I’ve had a play with your source and posted an updated version on my blog here: http://deceptiveresolution.wordpress.com/2008/11/26/as3-mp3-with-papervision-20/

    If i get some more time i’ll try adding some cool new features like some of the other examples on my blog…

    peace and thanks

  11. george says:

    Thnxs! great package! this works really great, just one question how can i move the position of the bars, so i dont want that they be in the center of the stage
    thnxs again

  12. george says:

    I Got solved the problem! for position go to viewport3D.as, thats work for me, i hope be right

  13. Smiler says:

    Great job…!

  14. SetMidiya says:

    Great stuff! But I can’t understand this part:

    sndBytes.position = CHANNEL_STEPS * 4 * i;

    After the sixth “i” we get position at 640, but as far as I understood we have only 512 values in array. Can someone explaim me this?

  15. neil says:

    just awesome!

  16. Cory says:

    Rafael,

    I was wondering how can i apply this effect with out music? I just need the bar annimation.

    Thanks!

  17. ... says:

    good tutorial thanks

  18. Filipe says:

    Hi,

    I try to put a button for change the music (I wanna create a player of more than one music):


    button.addEventListener(MouseEvent.CLICK, onClic);

    function onClic(pEvt:Event):void
    {
    reqObject=URLRequest(“othersound.mp3″);
    init();
    }

    That don’t work and I get this error:

    Error: Error #2037: Vous avez appelé les fonctions dans un ordre incorrect ou un appel antérieur a échoué.
    at flash.media::Sound/_load()
    at flash.media::Sound/load()
    at pv3d_fla::MainTimeline/initSound()
    at pv3d_fla::MainTimeline/init()
    at pv3d_fla::MainTimeline/onClic()

    Sorry its in french…

    Do you know how I can do my stuff please??
    Thx

  19. Filipe says:

    Hi,
    Very nice, thx a lot!
    How can I use a button for change the music please?
    Just the function, I try this:

    reqObject=new URLRequest(“othersound.mp3″);
    init();

    But that do not work…

  20. gabriel says:

    Autoplay? Really? Off putting.

  21. Brad says:

    Great tut! I have but one question.

    How do you get this spectrum to work with an array? For example:

    var sndObject:Sound = new Sound();
    var reqObject:URLRequest = new URLRequest(“http://www.homepage.com/audio”+urlArray1[clickedIndex]+”.mp3″);
    var sndBytes:ByteArray = new ByteArray();

    This didn’t work.

  22. Enda Denby says:

    I was reading about some fresh tech ideas and found this on Yahoo! This is a very informative article! Really appreciate you for sharing this!

  23. i just wish that mp3 players could also have some 10 band equalizers and bass boost functions*`*

  24. KeithB says:

    That is fantastic! I Love it. Gonna include it in my splash page with a link back to this page and papervision3d. I can’t believe this is free. I really appreciate the code. Thanks for sharing.

Leave a Reply

TTL VIP
Become a TTL VIP Member & Get Notified of The Best Changes in Technology, Plus Win Prizes in Our VIP Only Contests...

Tech News Tech Tutorials Smartphone News Tablet News Gaming News Free Software Infographics Contact