Sound with Footprint

by shohei909 forked from Instrument (diff: 407)
足跡に合わせて音が鳴ります。

クリック&ドラッグで休符を置けます。
♥14 | Line 336 | Modified 2015-11-19 01:29:56 | MIT License | (replaced)
play

Related images

ActionScript3 source code

/**
 * Copyright shohei909 ( http://wonderfl.net/user/shohei909 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/f2XK
 */

// forked from Event's Instrument
/* 10月のJAMの課題
「視覚的にも楽しめる楽器アプリをつくってください。」に挑戦。

Sound with footprint.
足跡に合わせて音が鳴ります。

クリック&ドラッグで休符を置けます。
*/

package {
    import flash.display.Loader;
    import flash.display.Sprite;
    import gs.*;
    [SWF(width="465",height="465",backgroundColor="0",frameRate="60")]
    public class FlashTest extends Sprite {
        private var loaders:Vector.<Loader>;
        private var data:Data;
        public function FlashTest() {
            loaders = Data.load();    //画像のロード開始
            var nowload:NowLoading = new NowLoading(stage,init);    //ロード画面の表示。ロード終了後init()を実行させる。
            for each(var loader:Loader in loaders){  nowload.addLoader(loader); }    //ロード画面と画像のロードの状態をリンクさせる
        }
        private function init():void{
            stage.removeChildAt(1);
            addChild( new DanceHole(465,465) )
        }
    }
}
import flash.filters.BlurFilter;
import flash.geom.*;
import flash.system.LoaderContext;
import flash.events.Event;
import flash.display.*;
import flash.net.*;
import frocessing.color.ColorHSV;

import org.si.sound.events.*;
import gs.*;
import com.greensock.easing.*;

class DanceHole extends Bitmap{ 
    private var black:BitmapData; 
    public var stop:Boolean = false; 
    public var count:int; 
    public var footCount:int = 0; 
    public var prints:Vector.<Print> = new Vector.<Print>;
    public var data:Data; 
    public var footX:int = 0;
    public var footY:int = 0;
    public var step:int = 60; //歩幅
    public var pace:int = 1;
    
    public var color:ColorHSV = new ColorHSV(0,0.9,1,0.1);
    public var filter:BlurFilter = new BlurFilter(2,2);
    
    private var isDown:Boolean = false
    
    function DanceHole(w:int,h:int){
        this.addEventListener("addedToStage",init);
        black = new BitmapData(w,h,true,0xFF000000);
        data = new Data();
        super( black.clone() );
    }
    
    private function init(e:Event):void{
        this.removeEventListener("addedToStage",init);
        this.addEventListener("exitFrame",onFrame);
        
        SiON.driver.dm.addEventListener(SoundObjectEvent.ENTER_FRAME ,onBeat);
            
        stage.addEventListener("mouseMove",onMove);
        stage.addEventListener("mouseDown",onDown);
        stage.addEventListener("mouseUp",onUp);
        footX = mouseX;
        footY = mouseY;
    }
    private function onFrame(e:Event):void{
        if(!stop){
            draw();
            SiON.driver.bpm = 100 + prints.length*3;
        }
    }
    
    private function onMove(e:Event):void{
        if(!stop){
            var dx:Number = mouseX - footX;
            var dy:Number = mouseY - footY;
            var r:Number = Math.sqrt(dx*dx+dy*dy);
            var dir:Number = Math.atan2(dy,dx);
            while( r > step){
                footX += step * Math.cos(dir);
                footY += step * Math.sin(dir);
                prints.push( new Print(footX,footY,dir,color,footCount++%2==0?"l":"r", isDown) );
                r -= step;
            }
        }
    }
    
    private function onUp(e:Event):void{isDown = false}
    private function onDown(e:Event):void{isDown = true;}
    private function onBeat(e:Event):void{
        if(!stop){
            count++;
            color.h += 10; 
            sequence();
        }
    }
    
    private function sequence():void{
        var s:Boolean = true
        if( count > pace ){ count = 0 }
        if( count < 1 ){
            if(s && prints.length > 0){
                prints.reverse();
                var p:Print = prints.pop();
                prints.reverse();
                
                
                var ct:ColorTransform = p.colorTransform;
                ct.alphaMultiplier = 1;
                ct.redOffset += 150;
                ct.greenOffset += 150;
                ct.blueOffset += 150; 
                data.draw(bitmapData,"foot",p.name,p.x,p.y,p.angle,p.colorTransform);
                if(!p.mute){ SiON.ar(p.x/465, p.y/465, p.color, p.name == "l");
                }else{ SiON.stop();} 
            }else{
               SiON.stop();
            }
        }
    }
    private function draw():void{
        var b:BitmapData = bitmapData;
        for each(var p:Print in prints){
            if(!p.mute){ data.draw(b,"foot",p.name,p.x,p.y,p.angle,p.colorTransform); }
        }
        b.unlock();
        b.lock();
        b.merge(black,b.rect,new Point,20,20,20,10);
        b.applyFilter(b,b.rect,new Point,filter);
    }
    
}

class Print{
    public var x:Number,y:Number,angle:Number;
    public var color:uint, colorTransform:ColorTransform, name:String, mute:Boolean;
    function Print(x:Number,y:Number,dir:Number,color:ColorHSV,name:String,mute:Boolean){
        this.x = x; this.y = y; this.angle = ( dir - Math.PI/2) ; 
        this.color = color.value;
        this.colorTransform= new ColorTransform(1,1,1,0.8,color.r,color.g,color.b,0);
        this.name = name;
        this.mute = mute
    }
}

class Data{
    static public const URL:Object = {
        "manFoot":"http://assets.wonderfl.net/images/related_images/4/4f/4fd0/4fd0652e356d7e09b373d8de9784a51732284d90"
    }
    static public const URL_NAME:Array=["manFoot"];
    
    static public const IMG_NAME:Object = {
        "foot":["l","r"]
    } 
    
    static public const cellWidth:int=27,cellHeight:int=27;
    //各オブジェクトに使うビットマップデータの設定
    public var MAP_SET:Object = { "foot":"manFoot" }
    
    //ビットマップを記録したオブジェクト。ロード後に使用可能
    static public var imageMap:Object = {};
    static public var imageCell:Object = {};
    static public var imageRect:Object = {};
    
    static private var loaders:Vector.<Loader> = new Vector.<Loader>();
    
    //画像をロード。ローダーの配列を作る。
    static public function load():Vector.<Loader>{
        for each(var url:String in URL){
            var loader:Loader = new Loader(); 
            loaders.push(loader);
        }
        loaders[0].load(new URLRequest(URL[URL_NAME[0]]), new LoaderContext(true));
        loaders[0].contentLoaderInfo.addEventListener("complete",onLoad,false,1000);
        return loaders;
    }
    //bitmapdataに画像を描画する
    public function draw(target:BitmapData,type:String,name:String,x:int,y:int,angle:Number,ct:ColorTransform):void{
        var map:String = MAP_SET[type];
        var b:BitmapData = imageCell[map][ IMG_NAME[type].indexOf(name) ];
        if(-1 < IMG_NAME[type].indexOf(name)){
            var mtr:Matrix = new Matrix(1,0,0,-1,-(b.width>>1),-(b.height>>1));
            mtr.rotate( angle );
            mtr.translate( x, y );
            target.draw( b, mtr, ct );
        }
    }
    
    
    
    static private var loadNum:int = 0;
    static private function onLoad(e:Event):void{
        e.currentTarget.removeEventListener("complete",onLoad);
        var rect:Rectangle = e.currentTarget.content.getRect(e.currentTarget.content);
        imageMap[URL_NAME[loadNum]]=new BitmapData(rect.width,rect.height,true,0x000000);
        imageMap[URL_NAME[loadNum]].draw( e.currentTarget.content );
        imageMap[URL_NAME[loadNum]].lock();
        setImageRect(URL_NAME[loadNum]);
        loadNum++;
        if(URL_NAME.length>loadNum){
            loaders[loadNum].load(new URLRequest(URL[URL_NAME[loadNum]]), new LoaderContext(true));
            loaders[loadNum].contentLoaderInfo.addEventListener("complete",onLoad,false,1000);
        }
    }
    
    static private function setImageRect(name:String):void{
        imageCell[name] = [];
        var map:BitmapData = imageMap[name];
        var lineColor:uint = map.getPixel32(map.width-1,map.height-1);
        var x:int = 0; var y:int=0; var height:int=0; var width:int=0; var count:int=0;
        while(true){
            width=0;height=0;
            if(lineColor != map.getPixel32(x,y) ){
                for(var i:int=1;i+x<map.width;i++){
                    if( lineColor == map.getPixel32(x+i,y) ){break;}
                }
                width=i;
                for(var j:int=1;j+y<map.width;j++){
                    if( lineColor == map.getPixel32(x,y+j) ){break;}
                }
                height=j;
                var rect:Rectangle = new Rectangle(x,y,width,height);
                var rect2:Rectangle = new Rectangle(0,0,width,height);
                
                var cell:BitmapData = new BitmapData(rect.width,rect.height,true,0x0)
                cell.setVector( rect2,map.getVector( rect ) );
                imageCell[name].push( cell );
            }
            x+=width+1;
            if(x>=map.width){ y+=height+1;x=0; }
            if(y>=map.height){ break; }
            count++;
        }
    }
}
class NowLoading extends Sprite{
    static public const COMPLETE:String = "complete";
    public var loaders:Vector.<Object> = new Vector.<Object>;
    public var bytesTotal:uint=0,bytesLoaded:uint=0;
    private var _loaderNum:uint=0,_completedNum:uint=0,_openNum:uint=0; //ローダーの数
    private var text:Bitmap, sprite:ProgressSprite;
    private var onLoaded:Function;
    private var LETTER:Object = {//文字
        "1":[[0,1,1],[0,0,1],[0,0,1],[0,0,1],[0,0,1]],"2":[[1,1,1],[0,0,1],[0,1,1],[1,0,0],[1,1,1]],"3":[[1,1,1],[0,0,1],[1,1,1],[0,0,1],[1,1,1]],"4":[[1,0,1],[1,0,1],[1,0,1],[1,1,1],[0,0,1]],"5":[[1,1,1],[1,0,0],[1,1,1],[0,0,1],[1,1,1]],
        "6":[[1,1,1],[1,0,0],[1,1,1],[1,0,1],[1,1,1]],"7":[[1,1,1],[0,0,1],[0,0,1],[0,0,1],[0,0,1]],"8":[[1,1,1],[1,0,1],[1,1,1],[1,0,1],[1,1,1]],"9":[[1,1,1],[1,0,1],[1,1,1],[0,0,1],[0,0,1]],"0":[[1,1,1],[1,0,1],[1,0,1],[1,0,1],[1,1,1]],
        ".":[[0],[0],[0],[0],[1]]," ":[[0],[0],[0],[0],[0]],"n":[[0,0,0],[0,0,0],[1,1,1],[1,0,1],[1,0,1]],"w":[[0,0,0,0,0],[0,0,0,0,0],[1,0,1,0,1],[1,0,1,0,1],[1,1,1,1,1]],"o":[[0,0,0],[0,0,0],[1,1,1],[1,0,1],[1,1,1]],
        "a":[[0,0,0],[0,0,1],[1,1,1],[1,0,1],[1,1,1]],"l":[[1],[1],[1],[1],[1]],"i":[[1],[0],[1],[1],[1]],"d":[[0,0,1],[0,0,1],[1,1,1],[1,0,1],[1,1,1]],"g":[[0,0,0],[0,0,0],[1,1,1],[1,0,1],[1,1,1],[0,0,1],[1,1,1]],
        "C":[[1,1,1],[1,0,0],[1,0,0],[1,0,0],[1,1,1]],"O":[[1,1,1],[1,0,1],[1,0,1],[1,0,1],[1,1,1]],"M":[[1,1,1,1,1],[1,0,1,0,1],[1,0,1,0,1],[1,0,1,0,1],[1,0,1,0,1]],"P":[[1,1,1],[1,0,1],[1,1,1],[1,0,0],[1,0,0]],
        "T":[[1,1,1],[0,1,0],[0,1,0],[0,1,0],[0,1,0]],"L":[[1,0,0],[1,0,0],[1,0,0],[1,0,0],[1,1,1]],"E":[[1,1,1],[1,0,0],[1,1,1],[1,0,0],[1,1,1]]
    }
    //ステージと関数を渡す
    public function NowLoading(stage:Stage, onLoaded:Function = null){
        if(onLoaded == null){ this.onLoaded=nullFunc }else{ this.onLoaded=onLoaded }
        sprite = new ProgressSprite(stage.stageWidth,stage.stageHeight);
        text = new Bitmap( new BitmapData(30*4,8,true,0x00000000 ) ); 
        stage.addChild(this); addChild(sprite); addChild(text);
        with(text){scaleX=scaleY=1; blendMode="invert"; x=stage.stageWidth-text.width; y=stage.stageHeight-text.height;}
    }
    //ローダーの追加
    public function addLoader(loader:Loader):Loader{ setListener(loader.contentLoaderInfo);_loaderNum++;return loader;}
    public function addURLLoader(loader:URLLoader):URLLoader{setListener(loader); _loaderNum++; return loader;}
    private function nullFunc():void{}
    private function setListener(loader:*):void{
        loader.addEventListener("open", onOpen);
        loader.addEventListener("complete", onComplete);
        loader.addEventListener("progress", update);
    }
    private function update(e:Event=null):void{
        bytesLoaded=0; bytesTotal=0;
        for each(var loadObj:Object in loaders){
            bytesLoaded += loadObj.bytesLoaded;
            bytesTotal += loadObj.bytesTotal;
        };
        sprite.progress(bytesLoaded/bytesTotal * _openNum/_loaderNum);
        if(bytesTotal!=0){ setText( "now loading... "+(bytesLoaded/bytesTotal* _openNum/_loaderNum*100).toFixed(1) ); }
    }
    private function onOpen(e:Event):void{ _openNum++;loaders.push(e.currentTarget); bytesTotal+=e.currentTarget.bytesTotal; }
    private function onComplete(e:Event):void{ _completedNum++;if(_loaderNum == _completedNum){ setText( "COMPLETE" );onLoaded(); } }
    private function setText(str:String):void{
        var b:BitmapData = text.bitmapData; var l:int = str.length; var position:int = b.width;
        b.lock();b.fillRect(b.rect,0x000000);
        for(var i:int=0;i<l;i++){
            var letterData:Array = LETTER[str.substr(l-i-1,1)];position-=letterData[0].length+1;
            for(var n:int=0;n<letterData.length;n++){ for(var m:int=0;m<letterData[n].length;m++){ 
                if(letterData[n][m]==1){b.setPixel32(m+position,n+1,0xFF000000);} 
            } }
        }
        b.unlock();
    }
}


//このスプライトを編集することでロード画面を変えることができる。
class ProgressSprite extends Sprite{
    private var mapData:BitmapData,sphereData:BitmapData,noizeData:BitmapData;
    private var bfRate:Number=0; //前の段階での進行度
    private var drawRate:Number=0;
    private var maxLevel:int = 5; 
    private var meter:Array = new Array();
    //コンストラクタ
    public function ProgressSprite(width:int,height:int):void{
        mapData = new BitmapData(width,height,true,0x00000000); 
        addChild(new Bitmap(mapData)).blendMode="invert";
        for(var i:int=0;i<maxLevel;i++){
            meter[i]=0;
        }
        addEventListener("enterFrame",onFrame);
    }
    //ロードが進行したときに呼び出される。 rateはロードの進行度で0-1
    public function progress(rate:Number):void{ bfRate = rate; }
    //ロードの進行度に合わせて、描画。
    private function draw(rate:Number, level:int=0):void{
        var thick:int = mapData.height*(0.61803)/1.61803;
        var floor:int = 0;
        for(var i:int=1;i<level+1;i++){
            thick*=(0.61803)/1.61803;
            floor+=thick;
        }
        mapData.fillRect( new Rectangle(0,mapData.height-floor,mapData.width*rate,thick), 0x1000000*int(0xFF*(maxLevel-level+1)/(maxLevel)));
    }
    private function onFrame(e:Event):void{
        for(var i:int=0;i<maxLevel;i++){
            var n:int = Math.pow(2,i+2);
            meter[i]=(bfRate+ meter[i]*(n-1))/n;
            draw(meter[i],i);
        }
    }  
}


//ライブラリ
//SiON-音声全般 http://www.libspark.org/wiki/keim/SiON
//サンプルコード:http://wonderfl.net/search?q=org.si.sion
import org.si.sion.*;
import org.si.sion.effector.*;
import org.si.sound.*;
import org.si.sound.synthesizers.*;
class MyDriver extends SiONDriver {
    public var waveTableSynth:WaveTableSynth;
    public var dm:DrumMachine = new DrumMachine(3, 8, 3, 2, 2, 2);
    public var ar:Arpeggiator = new Arpeggiator();
    public var fill:SiONData;
    function MyDriver():void{
        super();
        volume = 1;
        play(); 
        bpm = 240;
        
        dm.volume = 0.0;
        dm.snareVolume = 0.6;
        dm.bassVolume = 0.8;
        dm.play();
        
        
        ar.volume = 0.8;
        ar.noteLength = 1;
        ar.gateTime = 1; 
        ar.effectSend1 = ar.volume * 0.4;
        ar.effectSend2 = ar.volume * 0.5; 
        ar.effectors = [new SiEffectStereoDelay()];
        
        
        waveTableSynth = new WaveTableSynth();
        waveTableSynth.color = 0x1203acff;
        waveTableSynth.releaseTime = 0.2;
        ar.synthesizer = waveTableSynth;
        
        ar.play();
    }
}

class SiON{
    //SiONDriverは一つしか作れないので、staticで作る。
    static public var driver:MyDriver = new MyDriver();
    static public function ar(x:Number,y:Number,color:int,left:Boolean):void{
        driver.ar.pattern = left ? [0,-8] : [-8, 0];
        driver.pan = x*2.4 - 1.2;
        driver.ar.scaleIndex = - y * 20 + 10;
        driver.waveTableSynth.color = color >> 4;
        TweenLite.to(driver.ar, 0, {volume:0.8} );
    }
    static public function stop():void{
        TweenLite.to(driver.ar, 4, {volume:0,ease:Expo.easeOut} );
    }
}

Forked