RSS

Create a AS3 MP3 Player with papervision3d spectrum display

Sun, Jul 6, 2008

3D, Flash, Latest, Sound

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:

Create a AS3 MP3 Player with papervision3d spectrum display

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();

Share/Save/Bookmark

, , , , , ,

This post was written by:

Rafael Nuenlist - who has written 5 posts on The Tech Labs.

Rafael Nünlist is currently working at orange8 as a Richmedia Developer. He will complete his apprenticeship with a swiss federal vocational diploma in information technology this summer. His strengths are Flash, Flex, Actionscript, Php/MySQL and AIR. He is also a member of the dreaminginflash team.

8 Comments For This Post

  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.

2 Trackbacks For This Post

  1. Player de MP3 con AS3 y PaperVision 3D | Fausto Carrera Says:

    [...] Links al tutorial en TheTechLabs.com [...]

  2. 利用PaperVision3D和Flash创建基于声音文件波谱显示的AS3 MP3 Player的教程 - 全文检索博客 Says:

    [...] http://www.thetechlabs.com/3d/create-a-as3-mp3-player-with-papervision3d-spectrum-display/ 本文链接地址:http://blog.minidx.com/2008/07/09/1060.html [...]

Leave a Reply