ff: Sound Sphere
Impact
/**
* Copyright saharan ( http://wonderfl.net/user/saharan )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ipbb
*/
// forked from bkzen's Sound Sphere
package
{
import flash.display.Graphics;
import alternativ7.engine3d.alternativa3d;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.Vertex;
import alternativ7.engine3d.core.View;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.primitives.Sphere;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.media.SoundMixer;
import flash.media.SoundTransform;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.getTimer;
/**
* sound by AlainMikuni
* Alternativa3D を使って何か作ってみたかった。
* @author jc at bk-zen.com
*/
[SWF (backgroundColor = "0x000000", frameRate = "30", width = "465", height = "465")]
public class SoundSphere extends Sprite
{
private const radius: int = 200;
private const radius2: int = radius * 2;
private var rootContainer:Object3DContainer = new Object3DContainer();
private var camera:Camera3D;
private var sphere: Sphere;
private var length: uint;
private var startIndex:uint;
private var vertices:Vector.<Vertex>;
private var maxVertices:Vector.<Vertex>;
private var minVertices:Vector.<Vertex>;
private var sound:Sound;
private var bytes: ByteArray = new ByteArray();
public function SoundSphere()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// stage 初期化
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
// カメラを作成
camera = new Camera3D();
camera.rotationX = Math.PI;
camera.view = new View(stage.stageWidth, stage.stageHeight);
addChild(camera.view);
addChild(camera.diagram); // for debug
var s: int = 16;
sphere = new Sphere(radius, s, s);
var mat: FillMaterial = new FillMaterial(0xFF0000, 0.5, 0, 0xFF7777);
sphere.setMaterialToAllFaces(mat);
// 3D オブジェクトを追加
rootContainer.addChild(camera);
rootContainer.addChild(sphere);
// 必要なものをあらかじめ持っておく。
vertices = sphere.vertices;
length = vertices.length;
// 拡大縮小を行うために大き目の Sphere を作って、それを適応させる感じで。
var dummy: Sphere = new Sphere(radius + 400, s, s);
maxVertices = dummy.vertices;
dummy = sphere.clone() as Sphere;
minVertices = dummy.vertices;
stage.addEventListener(Event.RESIZE, onResize);
soundInit();
onResize();
}
/**
* リサイズハンドラ
* @param e
*/
private function onResize(e:Event = null):void
{
camera.view.width = stage.stageWidth;
camera.view.height = stage.stageHeight;
var g:Graphics = graphics;
g.clear();
g.beginFill(0);
g.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
}
/**
* サウンド準備
*/
private function soundInit():void
{
var url: String = "http://www.takasumi-nagai.com/soundfiles/sound007.mp3";
//var url: String = "http://www.takasumi-nagai.com/soundfiles/sound004.mp3";
sound = new Sound();
sound.addEventListener(Event.COMPLETE, onCompLoadSound);
sound.load(new URLRequest(url), new SoundLoaderContext(10, true));
}
/**
* サウンド読み込み完了。再生
* @param e
*/
private function onCompLoadSound(e:Event):void
{
sound.removeEventListener(Event.COMPLETE, onCompLoadSound);
var channel: SoundChannel = sound.play(0, 10, new SoundTransform(0.5));
addEventListener(Event.ENTER_FRAME, loop);
}
private function loop(e:Event):void
{
bytes.length = 0;
SoundMixer.computeSpectrum(bytes, true);
// カメラを動かしたり球を回転させたり。
var t: uint = getTimer();
sphere.rotationX = - t / 1700;
sphere.rotationY = - t / 1300;
camera.z = 1200 + 500 * Math.sin(t / 800);
// 上のほうが音が出やすいので上に集中させる
var i: uint = 0, v: Vertex, maxV: Vertex, minV: Vertex, p: Number,
n: uint = bytes.length >> 6;
var sum:Number = 0;
// 4つ飛ばしにしておく。
for (; i < length; i += 4)
{
v = vertices[i], maxV = maxVertices[i], minV = minVertices[i];
// z 座標を周波数とする
bytes.position = n * (minV.z + radius) / radius2 << 2;
p = bytes.readFloat();
bytes.position += 256;
p += bytes.readFloat();
sum += p * p * 8;
// apply some smoothing
v.x = (minV.x + maxV.x * p + v.x) * 0.5;
v.y = (minV.y + maxV.y * p + v.y) * 0.5;
v.z = (minV.z + maxV.z * p + v.z) * 0.5;
}
var scale:Number = 1 / (1 + sum / 0x200);
for (i = 0; i < length; i++)
{
if(i % 4 == 0) continue;
v = vertices[i], minV = minVertices[i];
// scaling
v.x = minV.x * scale;
v.y = minV.y * scale;
v.z = minV.z * scale;
}
// add effect
sum += 32;
if(sum > 0xFF) sum = 0xFF;
sphere.setMaterialToAllFaces(new FillMaterial(sum << 16, 0.5, 0, 0xFF7F7F));
// 裏側も描画する
sphere.calculateFacesNormals();
camera.render();
}
}
}