forked from: 万華鏡+mp3再生
kaleidoscope + sound spectrum
* 万華鏡 + サウンドスペクトル表示
*
* 左がオレンジ、右が青
* 重い・・・。要軽量化
*
* ♪使用音楽素材について♪
* 音楽素材/魔王魂(http://maoudamashii.jokersounds.com/)の素材を使わせていただきました。
* ありがとうございます。
*
/**
* Copyright takishiki ( http://wonderfl.net/user/takishiki )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/1Do1
*/
// forked from takishiki's 万華鏡+mp3再生
/*
* kaleidoscope + sound spectrum
* 万華鏡 + サウンドスペクトル表示
*
* 左がオレンジ、右が青
* 重い・・・。要軽量化
*
* ♪使用音楽素材について♪
* 音楽素材/魔王魂(http://maoudamashii.jokersounds.com/)の素材を使わせていただきました。
* ありがとうございます。
*
*/
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.display.BlendMode;
import flash.display.Graphics;
import flash.filters.GlowFilter;
import flash.system.Security;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.media.SoundTransform;
import flash.media.SoundMixer;
import flash.net.URLRequest;
import flash.utils.ByteArray;
[SWF(width = 465, height = 465, frameRate = 30, backgroundColor = 0x000000)]
public class Main extends MovieClip
{
// 定数
private const FFT_MODE :Boolean = false;
private const POLY_R :int = 50;
// 変数
private var _sp:Sprite;
private var _bmp:Bitmap;
private var _bmpd:BitmapData;
private var _deg:Number = 0;
private var _bgSp:Sprite;
private var _canvas:Sprite;
private var _mainSp:Sprite;
private var _end:Boolean;
private var _chips:Array;
private var _cnt:int;
// constructor
public function Main():void {
stage.frameRate = 30;
_cnt = 0;
_end = false;
_chips = [];
_mainSp = new Sprite();
_canvas = new Sprite(); // 星描画用
_mainSp.addChild(_canvas);
var g:Graphics;
// 三角形描画
var sp:Sprite = new Sprite();
g = sp.graphics;
g.beginFill(0x000000, 1.0);
g.drawRect(0, 0, POLY_R * 2, POLY_R * 2);
drawPoly(sp, 3, POLY_R, POLY_R, POLY_R, 30);
g.endFill();
_mainSp.addChild(sp);
_bmpd = new BitmapData(stage.stageWidth * 2, stage.stageHeight * 2, false, 0x000000);
_bmp = new Bitmap(_bmpd);
_bmp.x = -(stage.stageWidth * 2) / 2;
_bmp.y = -(stage.stageHeight * 2) / 2;
_sp = new Sprite();
_sp.addChild(_bmp);
_sp.x = stage.stageWidth / 2;
_sp.y = stage.stageHeight / 2;
this.addChild(_sp);
// mp3
var snd:Sound = new Sound();
Security.loadPolicyFile("http://mutast.heteml.jp/crossdomain.xml");
var req:URLRequest;
req = new URLRequest("http://vaindog.raindrop.jp/wonderfl/sound/bgm_maoudamashii_cyber06.mp3");
var context:SoundLoaderContext = new SoundLoaderContext(10, true);
snd.load(req,context);
var channel:SoundChannel;
channel = snd.play();
var transform:SoundTransform = new SoundTransform();
transform.volume = 0.5;
transform.pan = 0.0;
channel.soundTransform = transform;
channel.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
// 多角形描画
private function drawPoly(sp:Sprite, num:int, x:int, y:int, r:int, deg:Number):void {
/*
* sp:対象Sprite
* num:頂点の数
* x:中心のx座標
* y:中心のy座標
* r:半径
* deg:回転角度(度)
*/
var g:Graphics = sp.graphics;
var rad:Number;
var i:int;
var step:Number = 360 / num;
// 描画スタート位置に移動
rad = deg2rad(0 + deg);
g.moveTo(x + r * Math.cos(rad), y + r * Math.sin(rad));
for (i = 0; i < num; i++) {
rad = deg2rad((i + 1) * step + deg);
g.lineTo(x + r * Math.cos(rad), y + r * Math.sin(rad));
}
}
//
private function onPlaybackComplete(event:Event):void {
_end = true;
//removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
// フレーム処理
private function onEnterFrame(event:Event):void {
_sp.rotation += 1;
// 万華鏡画像作成
makeImage(_bmpd);
_cnt++;
if(_cnt<10) {
return;
}
_cnt = 0;
// sound
var bytes:ByteArray = new ByteArray();
const CHANNEL_LENGTH:int = 256;
SoundMixer.computeSpectrum(bytes, FFT_MODE, 0);
var maxL:Number = 0;
var maxR:Number = 0;
var chip:Chip;
var i:int;
// L
for (i = 0; i < CHANNEL_LENGTH; i++) {
maxL = Math.max(bytes.readFloat(), maxL);
}
chip = new Chip(POLY_R, -30, 1 * Math.cos(Math.PI / 6 * (1 - maxL)), 1 * Math.sin(Math.PI / 6 * (1 - maxL)), 20 * maxL, randRange(0, 359), hsv2rgb(30, 1, 1));
_canvas.addChild(chip);
_chips.push(chip);
// R
for (i = CHANNEL_LENGTH; i > 0; i--) {
maxR = Math.max(bytes.readFloat(), maxR);
}
chip = new Chip(POLY_R, -30, 1 * Math.cos(Math.PI / 6 * (1 - maxR)), -1 * Math.sin(Math.PI / 6 * (1 - maxR)), 20 * maxR, randRange(0, 359), hsv2rgb(200, 1, 1));
_canvas.addChild(chip);
_chips.push(chip);
// チップ生存チェック
var end_y:Number = POLY_R * 2 + 30;
var len:int = _chips.length;
for (i = 0; i < len; i++) {;
if (_chips[i].y >= end_y) {
_canvas.removeChild(_chips[i]);
_chips.splice(i, 1);
len = len - 1;
}
}
if ((_end) && (_chips.length==0)) {
this.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
// 万華鏡画像作成
private function makeImage(target:BitmapData):void {
var h:int = POLY_R * 3 / 2;
var r3:Number = Math.sqrt(3);
// ステージ用
var bmpd:BitmapData = new BitmapData(POLY_R * 2, POLY_R * 2, false, 0x000000);
// 元の三角形用
var bmpdTri:BitmapData = new BitmapData(POLY_R * 2, POLY_R * 2, false, 0x000000);
// 一行描画用
var bmpdRow:BitmapData = new BitmapData(target.width, Math.ceil(h), false, 0x000000);
// ステージ描画
bmpd.lock();
bmpd.draw(_mainSp);
bmpd.unlock();
var rect:Rectangle = new Rectangle();
rect.x = 0;
rect.y = 0;
rect.width = POLY_R * 2;
rect.height = POLY_R * 2;
// 三角形部分を切り取り
bmpdTri.copyPixels(bmpd, rect, new Point());
var matrix:Matrix = new Matrix();
var matrix2:Matrix = new Matrix();
var rad:Number = Math.PI * 2 / 3; // 120°
var num:int;
var i:int;
// 行作成
bmpdRow.lock();
num = Math.ceil(target.width / POLY_R) + 2;
for (i = 0; i < num; i++) {
matrix = new Matrix();
// 中央に平行移動
matrix2 = new Matrix();
matrix2.translate( -POLY_R, -POLY_R);
matrix.concat(matrix2);
if (i % 2 == 0) {
// 偶数
// 回転
matrix2 = new Matrix();
matrix2.rotate(-rad * i);
matrix.concat(matrix2);
}else {
// 奇数
// 反転
matrix2 = new Matrix();
matrix2.scale(1, -1);
matrix.concat(matrix2);
// 回転
matrix2 = new Matrix();
matrix2.rotate(-rad * int(i / 2) + rad);
matrix.concat(matrix2);
// y軸平行移動
matrix2 = new Matrix();
matrix2.translate(0, -POLY_R / 2);
matrix.concat(matrix2);
}
// x軸平行移動
matrix2 = new Matrix();
matrix2.translate(Math.floor(i * POLY_R / 2 * r3), 0);
matrix.concat(matrix2);
// 基準位置まで平行移動
matrix2 = new Matrix();
matrix2.translate(0, POLY_R);
matrix.concat(matrix2);
// 描画
bmpdRow.draw(bmpdTri, matrix, new ColorTransform(), BlendMode.LIGHTEN);
}
bmpdRow.unlock();
// 行のbmpdを反転しながら列方向に描画
target.lock();
// 背景色で塗りつぶし
target.fillRect(target.rect, 0x000000);
num = Math.ceil(target.height / POLY_R);
for (i = 0; i < num; i++) {
matrix = new Matrix();
// 中央に平行移動
matrix2 = new Matrix();
matrix2.translate(0, -Math.round(h / 2));
matrix.concat(matrix2);
if (i % 2 == 1) {
// 奇数
// 反転
matrix2 = new Matrix();
matrix2.scale(1, -1);
matrix.concat(matrix2);
}
// 平行移動
matrix2 = new Matrix();
matrix2.translate(0, Math.floor(h * i));
matrix.concat(matrix2);
// 基準位置まで平行移動
matrix2 = new Matrix();
matrix2.translate(0, Math.round(h / 2));
matrix.concat(matrix2);
// 描画
target.draw(bmpdRow, matrix, new ColorTransform(), BlendMode.LIGHTEN);
}
target.unlock();
bmpdTri.dispose();
bmpdRow.dispose();
}
// HSV -> RGB(uint)
private function hsv2rgb(h:Number, s:Number, v:Number):uint {
var r:Number = 0;
var g:Number = 0;
var b:Number = 0;
if (s == 0) {
r = g = b = v;
}else {
var hTemp:Number = (h + 360) % 360;
hTemp /= 60;
var i:Number = Math.floor(hTemp); // 整数部
var f:Number = hTemp - i; // 小数部
var p:Number = v * (1.0 - s);
var q:Number = v * (1.0 - (s * f));
var t:Number = v * (1.0 - (s * (1.0 - f)));
switch(i) {
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
}
}
return rgb2hex(r * 255, g * 255, b * 255);
}
// R, G, B -> hex color value
private function rgb2hex(r:Number = 0, g:Number = 0, b:Number = 0):uint {
r = Math.round(r);
g = Math.round(g);
b = Math.round(b);
return 0xff000000 + r * 0x10000 + g * 0x100 + b;
}
// degree -> radian
private function deg2rad(deg:Number):Number {
deg %= 360;
return deg / 180 * Math.PI;
}
// a-bの乱数生成
private function randRange(min:Number = 0, max:Number = 1):Number {
var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}
}
}
// Chip
import flash.display.*;
import flash.events.Event;
import flash.filters.GlowFilter;
class Chip extends Sprite {
private var _vx:Number;
private var _vy:Number;
private var _r:Number;
private var _deg:Number;
private var _color:uint;
//
public function Chip(x:Number, y:Number, vy:Number, vx:Number, r:Number, deg:Number, color:uint):void {
this.x = x;
this.y = y;
this.rotation = deg;
_vy = vy;
_vx = vx;
_r = r;
_color = color;
_deg = randRange(0, 20) - 10;
var alpha:Number = randRange(0, 100) / 100;
var g:Graphics = this.graphics;
g.lineStyle(1, _color, 1.0);
//g.beginFill(_color, alpha);
drawStar(this, 5, 0, 0, _r, _r * 0.5, 0);
g.endFill();
this.filters = [new GlowFilter(_color, 0.8, 10, 10, 2, 2, true, false), new GlowFilter(_color, 0.6, 20, 20, 4, 2, false, false)];
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
//
private function onEnterFrame(event:Event):void {
this.y += _vy;
this.x += _vx;
this.rotation += _deg;
}
// draw star shape
private function drawStar(sp:Sprite, num:int, x:int, y:int, r1:int, r2:int, deg:Number):void {
/*
* sp:対象Sprite
* num:頂点の数
* x:中心のx座標
* y:中心のy座標
* r1:外側(山)の半径
* r2:内側(谷)の半径
* deg:回転角度(度)
*/
var g:Graphics = sp.graphics;
var rad:Number;
var i:int;
var step:Number = 360 / num;
// 描画スタート位置に移動
rad = deg2rad(0 + deg);
g.moveTo(x + r1 * Math.cos(rad), y + r1 * Math.sin(rad));
// 谷 -> 山 -> 谷 の順番で線を描画
for (i = 0; i < num; i++) {
rad = deg2rad(i * step + deg + step / 2);
g.lineTo(x + r2 * Math.cos(rad), y + r2 * Math.sin(rad));
rad = deg2rad((i + 1) * step + deg);
g.lineTo(x + r1 * Math.cos(rad), y + r1 * Math.sin(rad));
}
}
// a-bの乱数生成
private function randRange(min:Number = 0, max:Number = 1):Number {
var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}
// degree -> radian
private function deg2rad(deg:Number):Number {
deg %= 360;
return deg / 180 * Math.PI;
}
}