Nov 5, 2009
Hype/Papervision3D Demo
So after getting my hands on the new Hype framework, I wanted to put together a simple demo together that utilizes a combination of the SoundAnalyzer class and some 3D eye candy (via Papervision3D).
First off, I can say that I really like being able to play around with the sound spectrum using only a couple lines of code. I also used the Rythm class to run an enter frame method, which is very convenient in that I didn't need to manually set up an event and listener.
Lastly, I wanted to also utilize a tweening engine to smooth out the particle movement, but doing so cut the framerate by about 80% (a little better with TweenMax/TweenLite, but still not good enough). I also briefly played around with the Flint particle emitter, but I'm not familiar enough with Papervision/Flint to get it working how I wanted.
UPDATE - I decided to give a tween engine one more shot, and was able to use TweenMax while keeping the framerate at an acceptable level.
UPDATE 11/06/2009 - Updated code sample to reflect demo swf.
UPDATE 3/29/2010 - It's come to my attention that Wordpress tends to be a bit moody when it comes to code formatting in posts, especially in the case of vectors (which use the greater than/less than characters). That said, I've posted a couple pastebin examples:
Link --> Document class
Link --> ApplicationView class
Here's the demo in action-
..and here's the code-
Paper_Hype_Lab.as (this would be the document class in Flash):
First off, I can say that I really like being able to play around with the sound spectrum using only a couple lines of code. I also used the Rythm class to run an enter frame method, which is very convenient in that I didn't need to manually set up an event and listener.
Lastly, I wanted to also utilize a tweening engine to smooth out the particle movement, but doing so cut the framerate by about 80% (a little better with TweenMax/TweenLite, but still not good enough). I also briefly played around with the Flint particle emitter, but I'm not familiar enough with Papervision/Flint to get it working how I wanted.
UPDATE - I decided to give a tween engine one more shot, and was able to use TweenMax while keeping the framerate at an acceptable level.
UPDATE 11/06/2009 - Updated code sample to reflect demo swf.
UPDATE 3/29/2010 - It's come to my attention that Wordpress tends to be a bit moody when it comes to code formatting in posts, especially in the case of vectors (which use the greater than/less than characters). That said, I've posted a couple pastebin examples:
Link --> Document class
Link --> ApplicationView class
Here's the demo in action-
..and here's the code-
Paper_Hype_Lab.as (this would be the document class in Flash):
package {
import __AS3__.vec.Vector;
import com.almerblanklabs.view.ApplicationView;
import com.lifeztream.debug.FPS;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
import flash.external.ExternalInterface;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.media.SoundTransform;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.system.Security;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.utils.setTimeout;
import hype.framework.behavior.SimpleBehavior;
import hype.framework.core.TimeType;
import hype.framework.rhythm.SimpleRhythm;
import hype.framework.sound.SoundAnalyzer;
import org.papervision3d.objects.primitives.Sphere;
[SWF(width='580', height='580', backgroundColor='#000000')]
/**
*
* @author Nolan Butcher
*
* DISCLAIMER : This code sample is by no means an optimized example. It is a PROTOTYPE.
* Please keep this in mind when looking through this code.
*
*/
public class Paper_Hype_Lab extends Sprite
{
private static const ARTIST : String = "Trioptic of the Sound Scientists";
private static const AUDIO_PATH : String = 'http://flexgraphix.com/blog/wp-content/uploads/2009/11/';
private static const AUDIO_FILES : Array = [
{file:'evil_violin.mp3', title:'Evil Violin(Rich \'n Stingy)'},
{file:'am_i_going_to_die.mp3', title:'Am I Going to Die'},
{file:'going_pro.mp3', title:'Going Pro'},
{file:'life_is_easily_taken.mp3', title:'Life is Easily Taken'},
{file:'bubachu.mp3', title:'Bubachu'},
{file:'midi_in-out.mp3', title:'Midi In/Out'},
{file:'may_6.mp3', title:'May 6'},
{file:'slow_descent.mp3', title:'Slow Descent'},
{file:'nocens_sonitus.mp3', title:'Nocens Sonitus'},
{file:'remember.mp3', title:'Remember'},
{file:'soulful_east_coast.mp3', title:'Soulful East Coast'},
{file:'sunrise_on_the_highway.mp3', title:'Sunrise on the Highway'},
{file:'the_sad_truth_of_it_all.mp3', title:'The Sad Truth of it All'},
{file:'blueberry_haze.mp3', title:'Blueberry Haze'}
];
private static const VOLUME : Number = 1;
private var _view : ApplicationView;
private var _sphere : Sphere;
private var _music : Sound;
private var _sndChannel : SoundChannel;
private var _soundAnalyzer : SoundAnalyzer;
private var _freq : Vector. = new Vector.;
private var _rythm : SimpleRhythm;
private var _fps : FPS;
private var _audioIndex : int = 1;
private var _button : Sprite;
private var _hitArea : Sprite;
private var _textField : TextField;
private var _songText : TextField;
private var _rotationX : Number = 0.3;
private var _rotationY : Number = 0.3;
private var _cameraPitch : Number = 90;
private var _cameraYaw : Number = 270;
private var _xDist : Number;
private var _yDist : Number;
private var _mouseDown : Boolean = false;
public function Paper_Hype_Lab()
{
Security.allowDomain('*');
stage.frameRate = 60;
_sphere = new Sphere(null, 300, 24, 14);
_view = new ApplicationView();
_view.object3D = _sphere;
_view.startRendering();
addChild(_view);
_initRythm();
_initTextField();
_loadSound();
_initUI();
// Get the FPS widget @ www.lifeztream.com
_fps = new FPS();
addChild(_fps);
}
private function _handleMouseEvents(evt:MouseEvent):void
{
switch(String(evt.type))
{
case MouseEvent.MOUSE_DOWN:
_mouseDown = true;
break;
case MouseEvent.MOUSE_UP:
_mouseDown = false;
break;
}
}
private function _loadSound():void
{
var context : SoundLoaderContext = new SoundLoaderContext(1000, true);
var req : URLRequest = new URLRequest();
req.url = AUDIO_PATH + AUDIO_FILES[_audioIndex].file;
if (_rythm && _rythm.isRunning) _pauseRythm();
if (_sndChannel)
{
_sndChannel.stop();
try {
_music.close();
} catch(e:Error) {
trace ('cannot close sound stream');
}
}
_music = new Sound(req, context);
_music.addEventListener(IOErrorEvent.IO_ERROR, _handleIOErrorEvents, false, 0, true);
_sndChannel = _music.play(0, 1, new SoundTransform(VOLUME));
_sndChannel.addEventListener(Event.SOUND_COMPLETE, _onSoundDone, false, 0, true);
_soundAnalyzer = new SoundAnalyzer();
_soundAnalyzer.start();
_updateSongText();
if (_rythm) _initRythm();
}
private function _onSoundDone(evt:Event):void
{
_button.mouseEnabled = false;
setTimeout(_nextSong, 1000);
}
private function _nextSong():void
{
_button.mouseEnabled = true;
_button.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
private function _handleIOErrorEvents(evt:IOErrorEvent):void
{
if (ExternalInterface.available)
{
ExternalInterface.call("window.alert('" + AUDIO_FILES[_audioIndex].file + " cannot be loaded')");
}
}
private function _initUI():void
{
_hitArea = new Sprite();
_hitArea.graphics.beginFill(0x000,0);
_hitArea.graphics.drawRect(0,0,580,580);
_hitArea.graphics.endFill();
_hitArea.addEventListener(MouseEvent.MOUSE_DOWN, _handleMouseEvents, false, 0, true);
_hitArea.addEventListener(MouseEvent.MOUSE_UP, _handleMouseEvents, false, 0, true);
addChild(_hitArea);
_button = new Sprite();
_button.graphics.beginFill(0x666666);
_button.graphics.drawRect(0,0,100,30);
_button.graphics.endFill();
_button.x = 476;
_button.y = 4;
_button.buttonMode = true;
_button.mouseChildren = false;
_button.useHandCursor = true;
_button.addEventListener(MouseEvent.CLICK, _handleButtonEvents, false, 0, true);
var buttonFormat : TextFormat = new TextFormat(null, 14, 0xFFFFFF, true);
var buttonText : TextField = new TextField();
buttonText.defaultTextFormat = buttonFormat;
buttonText.text = "NEXT RIFF";
buttonText.height = 18;
buttonText.y = (_button.height - buttonText.textHeight) * .5;
buttonText.x = (_button.width - buttonText.textWidth) * .5;
addChild(_button);
_button.addChild(buttonText);
}
private function _pauseRythm():void
{
_rythm.stop();
}
private function _resumeRythm():void
{
_rythm.start();
}
private function _initRythm():void
{
_rythm = new SimpleRhythm(_trackRythm);
_rythm.start(TimeType.ENTER_FRAME);
}
private function _initTextField():void
{
var textFormat : TextFormat = new TextFormat();
textFormat.color = 0x666666;
textFormat.align = TextFormatAlign.CENTER;
textFormat.size = 14;
_songText = new TextField();
_songText.defaultTextFormat = textFormat;
_songText.width = 1;
_songText.text = "-- :: --";
_songText.autoSize = TextFieldAutoSize.CENTER;
_songText.y = (stage.stageHeight - _songText.textHeight) - 4;
_songText.x = (stage.stageWidth - _songText.width) * 0.5;
addChild(_songText);
var artistText : TextField = new TextField();
artistText.defaultTextFormat = textFormat;
artistText.width = 1;
artistText.text = "-- Artist :: " + ARTIST + " --";
artistText.x = (stage.stageWidth - artistText.width) * 0.5;
artistText.y = (_songText.y - artistText.textHeight) - 4;
artistText.autoSize = TextFieldAutoSize.CENTER;
addChild(artistText);
_textField = new TextField();
_textField.width = 1;
_textField.defaultTextFormat = textFormat;
_textField.text = "-- Click and drag to rotate sphere --";
_textField.x = (stage.stageWidth - _textField.width) * 0.5;
_textField.y = artistText.y - _textField.textHeight - 5;
_textField.autoSize = TextFieldAutoSize.CENTER;
addChild(_textField);
}
private function _updateSongText():void
{
_songText.text = "-- Song :: " + AUDIO_FILES[_audioIndex].title + " --";
_songText.x = (stage.stageWidth - _songText.width) * 0.5;
}
private function _handleButtonEvents(evt:MouseEvent):void
{
_sndChannel.removeEventListener(Event.SOUND_COMPLETE, _onSoundDone);
if (_audioIndex < AUDIO_FILES.length-2)
{
_audioIndex++;
} else {
_audioIndex = 0;
}
_loadSound();
}
private function _trackRythm(rythm : SimpleRhythm):void
{
for (var i:int = 1;i < _sphere.geometry.vertices.length + 1;++i)
{
_freq[i-1] = _soundAnalyzer.getFrequencyIndex(i, 400, 100);
}
_view.moveParticles(_freq);
// Rotates camera around sphere depending on mouse position
if (_mouseDown)
{
_xDist = mouseX - stage.stageWidth * 0.5;
_yDist = mouseY - stage.stageHeight * 0.5;
_cameraPitch = _yDist * _rotationX + 90;
_cameraYaw = _xDist * _rotationY + 270;
_view.camera.orbit(_cameraPitch, _cameraYaw);
}
}
}
}
ApplicationView.as (extends PV3D's BasicView class):
package com.almerblanklabs.view
{
import __AS3__.vec.Vector;
import com.greensock.OverwriteManager;
import com.greensock.TweenMax;
import com.greensock.easing.Elastic;
import com.greensock.plugins.MotionBlurPlugin;
import com.greensock.plugins.TweenPlugin;
import flash.events.Event;
import org.papervision3d.core.geom.Particles;
import org.papervision3d.core.geom.renderables.Particle;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.materials.special.ParticleMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Sphere;
import org.papervision3d.view.BasicView;
//import com.greensock.plugins.
public class ApplicationView extends BasicView
{
private var _object3D : DisplayObject3D;
private var _origVertices : Vector.
Enjoy ;)

Nice example.
I think ApplicationView may have some code missing though ?
I just noticed this comment, and added the missing code. However, the syntax highlighting isn't cooperating, so it's a bit hard to read (copy and paste into a text editor for best results).
One more comment:
The 'pre' code formatting seems to strip out some of my code. I've created a pastebin page with the ApplicationView code here : http://pastebin.com/uyk8gfnh