FONT DANCE
音に反応するフォント FontDance
音が出るので注意して下さい
http://linkalink.jp/enok/?p=650
/**
* Copyright linktale ( http://wonderfl.net/user/linktale )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/7qCm
*/
// forked from enok's DON forked from: Saqoosha challenge for professionals
// 音に反応するフォント FontDance
// 音が出るので注意して下さい
// http://linktale.net/
package {
import flash.display.Sprite;
import flash.display.StageQuality;
import com.flashdynamix.utils.SWFProfiler;
[SWF(backgroundColor="0xffffff", frameRate="30")]
public class FontDanceController extends Sprite {
public function FontDanceController():void {
//SWFProfiler.init(stage, this);
stage.quality = StageQuality.HIGH;
//背景をしく
graphics.beginFill(0x151515);
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
graphics.endFill();
//配置
var trick:FontDance = new FontDance(this);
addChild(trick);
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObjectContainer;
import flash.display.GradientType;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.ConvolutionFilter;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.media.SoundMixer;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.utils.ByteArray;
class FontDance extends Sprite {
//この2つを設定すると色々な文字で同じ演出が可能
protected const TARGET_TEXT:String = "WONDERFL";
protected const SCALE:Number = 0.7; //文字大きさ(調整用)
//protected const TARGET_TEXT:String = "DON";
//protected const SCALE:Number = 1.0; //文字大きさ(調整用)
protected var _s:DisplayObjectContainer;
protected var _centerX:Number; //中心X
protected var _centerY:Number; //中心Y
protected var _soundM:soundManager;
protected var _view:Sprite = new Sprite();
protected var _pointList:Vector.<Point> = new Vector.<Point>(); //文字のアウトラインのポイント
protected var _distList:Vector.<Number> = new Vector.<Number>(); //ポイントの真ん中からの距離
protected var _radiusList:Vector.<Number> = new Vector.<Number>(); //ポイントの半径の長さ
protected var _colorList:Vector.<uint> = new Vector.<uint>(); //ポイントの色
protected var _colorPattern:Vector.<uint> = new Vector.<uint>(); //色パターン
protected var _pointViewList:Vector.<Sprite> = new Vector.<Sprite>(); //各ポイントのビュー
public function FontDance(s:DisplayObjectContainer):void {
_s = s;
//中点
_centerX = s.stage.stageWidth / 2;
_centerY = s.stage.stageHeight / 2;
init();
}
protected function init():void {
setColor(); //色初期化
setPoint(); //文字アウトラインポイント初期化
_soundM = new soundManager(false, true);
//addChild(_view);
_soundM.addEventListener(soundManager.SAMPLE_DATA, processSound);
_soundM.addEventListener(soundManager.COMPLETE, complete);
addEventListener(Event.ENTER_FRAME, update);
}
protected function setColor():void {
//色設定
_colorPattern.push(0x444444);
_colorPattern.push(0x555555);
_colorPattern.push(0x666666);
}
protected function setPoint():void {
//テキスト設置
var txt:TextField = new TextField();
var tf:TextFormat = new TextFormat("_sans", 100);
txt.defaultTextFormat = tf;
txt.autoSize = TextFieldAutoSize.LEFT;
txt.text = TARGET_TEXT;
//ビットマップ設置
var txtBmpData:BitmapData = new BitmapData( txt.width, txt.height, true, 0xffffffff);
txtBmpData.draw(txt);
//文字のエッジ検出
var cf : ConvolutionFilter = new ConvolutionFilter(3, 3, [-1, -1, -1, -1, 8, -1, -1, -1, -1]);
txtBmpData.applyFilter(txtBmpData, txtBmpData.rect, new Point(), cf);
var txtBmp:Bitmap = new Bitmap(txtBmpData);
//addChild(txtBmp);
//ポイント設置
var offset:Point = new Point(_centerX - txt.textWidth / 2, _centerY - txt.textHeight / 2);
var p:Point, sp:Sprite;
for ( var i:int = 0; i < txtBmpData.width; i++ ) {
for ( var j:int = 0; j < txtBmpData.height; j++ ) {
if (txtBmpData.getPixel(i, j) == 0xffffff) {
//初期化
_pointList.push(new Point(i, j).add(offset));
}
}
}
//ランダムに減らす
var tmpList:Vector.<Point> = new Vector.<Point>();
while (_pointList.length>512) {
i = Math.floor(Math.random() * _pointList.length);
tmpList = _pointList.slice(0, i);
tmpList = tmpList.concat(_pointList.slice(i+1));
_pointList = tmpList.slice();
}
for each(p in _pointList) {
_distList.push(0.0);
_radiusList.push(3.0);
_colorList.push(_colorPattern[Math.floor(Math.random() * _colorPattern.length)]);
sp = new Sprite();
sp.blendMode = BlendMode.ADD; //ブレンドモードオン
_pointViewList.push(addChild(sp) as Sprite);
}
}
protected function processSound(e:Event):void {
setSoundData();
}
private function setSoundData():void {
var bytes:ByteArray = new ByteArray();
const CHANNEL_LENGTH:int = 256;
//stretchFactor高めに設定
SoundMixer.computeSpectrum(bytes, true, 64);
//左チャンネル
for (var i:int = 0; i < CHANNEL_LENGTH; i++) {
var val:Number = bytes.readFloat();
_distList[i] = val * 0.01; //距離設定
_radiusList[i] = val * 8 + 2; //半径設定
}
//右チャンネル
for (i = CHANNEL_LENGTH; i > 0; i--) {
val = bytes.readFloat();
_distList[255 + i] = val * 0.01; //距離設定
_radiusList[255 + i] = val * 8 + 2; //半径設定
}
}
protected function complete(e:Event):void {
trace("complete");
_soundM.removeEventListener(soundManager.SAMPLE_DATA, processSound);
removeEventListener(Event.ENTER_FRAME, update);
}
protected function update(e:Event):void {
var xx:Number, yy:Number;
var p:Point, mat:Matrix = new Matrix();;
//_view.graphics.clear();
for (var i:int=0; i < _pointList.length; i++ ) {
p = _pointList[i];
xx = (p.x - _centerX) * SCALE + _centerX;
yy = (p.y - _centerY) * SCALE + _centerY;
xx = (p.x - _centerX) * SCALE + _centerX;
yy = (p.y - _centerY) * SCALE + _centerY;
xx - _centerX > 0 ? xx += Math.pow(xx - _centerX, 2) * _distList[i] : xx -= Math.pow(xx - _centerX, 2) * _distList[i];
yy - _centerY > 0 ? yy += Math.pow(yy - _centerY, 2) * _distList[i] * 2 : yy -= Math.pow(yy - _centerY, 2) * _distList[i] * 2;
xx = xx - _radiusList[i] / 2;
yy = yy - _radiusList[i] / 2;
mat.createGradientBox(_radiusList[i] * 2, _radiusList[i] * 2, 0, -_radiusList[i], -_radiusList[i]);
_pointViewList[i].graphics.clear();
//見た目の演出
_pointViewList[i].graphics.beginGradientFill(
GradientType.RADIAL, [_colorList[i] , 0x222222], [1, 0.1], [0xAA, 0xFF], mat, SpreadMethod.REFLECT);
_pointViewList[i].graphics.drawCircle(xx, yy, _radiusList[i]);
//_view.graphics.drawCircle(xx, yy, _radiusList[i]);
}
}
}
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.media.SoundMixer;
import flash.net.URLRequest;
import flash.utils.ByteArray;
class soundManager extends EventDispatcher {
public static const COMPLETE:String = "COMPLETE";
public static const SAMPLE_DATA:String = "SAMPLE_DATA"; //ディスパッチャ用
private const TYPE:uint = 1;
private const SOUND_SAMPLING_RATE:Number = 44.1; //サンプリングレート
private const SOUND_BUFFER_LENGTH:Number = 2048; //サウンドの取得バッフャ数
private var _sourceSnd:Sound; //元音源
private var _outputSnd:Sound; //コピー音源
private var _urlReq:URLRequest = new URLRequest("http://linkalink.jp/enok/wonderfl/font_dance/1.mp3");
//private var _urlReq:URLRequest = new URLRequest("http://techno.to/sound/COR020-2/1.mp3");
private var _soundBytes:ByteArray;
private var _soundBytesPosition:uint;
private var _soundBytesTotal:uint;
private var _repeat:Boolean;
private var _useFFTMode:Boolean;
public function soundManager(repeat:Boolean = true, useFFTMode:Boolean=false):void {
_repeat = repeat;
_useFFTMode = useFFTMode;
init();
}
private function init():void {
_sourceSnd = new Sound();
_outputSnd = new Sound();
_sourceSnd.load(_urlReq);
_sourceSnd.addEventListener(Event.COMPLETE, loadSoundComplete);
}
private function loadSoundComplete(e:Event):void {
_sourceSnd.removeEventListener(Event.COMPLETE, loadSoundComplete);
//trace(_sourceSnd.length, _sourceSnd.length * SOUND_SAMPLING_RATE, _sourceSnd.length * SOUND_SAMPLING_RATE * 8);
if (TYPE == 1) {
//音の全データを一括で取得 extractなしでもいけるけど、テストも兼ねて
_soundBytes = new ByteArray();
_sourceSnd.extract(_soundBytes, _sourceSnd.length * SOUND_SAMPLING_RATE * 8);
_soundBytesTotal = _soundBytes.length;
_soundBytesPosition = 0;
}
_outputSnd = new Sound();
_outputSnd.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound);
_outputSnd.play();
}
private function processSound(e:SampleDataEvent):void {
var end:Boolean = false;
if (TYPE == 1) {
for (var i:uint = 0; i < SOUND_BUFFER_LENGTH; ++i) {
if(_soundBytesPosition > _soundBytesTotal - 8){
if (_repeat) {
_soundBytesPosition -= _soundBytesTotal;
}else {
_outputSnd.removeEventListener(SampleDataEvent.SAMPLE_DATA, processSound);
end = true;
dispatchEvent(new Event(COMPLETE));
break;
}
}
if(!end){
_soundBytes.position = _soundBytesPosition;
e.data.writeFloat( _soundBytes.readFloat() / 8 );
e.data.writeFloat( _soundBytes.readFloat() / 8 );
_soundBytesPosition += 8;
}
}
}else if (TYPE == 2) {
//現在の音を取得するパターン、何故かビットレートが早くなってしまう extractなしでもいけるけど、テストも兼ねて
var bytes:ByteArray = new ByteArray();
_sourceSnd.extract(bytes, 512 * 8);
bytes.position = 0;
var cnt:uint = 0;
while (bytes.bytesAvailable > 0) {
e.data.writeFloat(bytes.readFloat());
e.data.writeFloat(bytes.readFloat());
if (bytes.bytesAvailable > 0){
bytes.position += 8;
}
cnt++;
}
}
dispatchEvent(new Event(SAMPLE_DATA));
}
}