きまぐれ作曲機 - forked from: Instrument
細胞たちが適当に作曲してくれます。
マウスで細胞たちにきっかけを与えるとうにょうにょ動き出します。
/**
* Copyright AtuyL ( http://wonderfl.net/user/AtuyL )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/jNX1
*/
// forked from Event's Instrument
/*
* 細胞さんたちが勝手に作曲してくれるよ(´・ω・)
* 細胞さんたちは適当に結婚して落ち着くけど、
* マウスで新しい出会いを与えてあげるとまた婚活をはじめるからね(´・ω・)
*
* ある意味人生の縮図だね(´・ω・)
*/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.PixelSnapping;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import frocessing.color.ColorHSV;
import org.si.sion.events.SiONTrackEvent;
import org.si.sion.sequencer.SiMMLTrack;
import org.si.sion.SiONDriver;
import org.si.sion.SiONVoice;
import org.si.sion.utils.SiONPresetVoice;
import org.si.sound.DrumMachine;
[SWF(width=465,height=465,frameRate=30,backgroundColor=0xFFFFFF)]
public class LifeGame extends Sprite {
public var driver:SiONDriver = new SiONDriver();
public var presetVoice:SiONPresetVoice = new SiONPresetVoice();
// forked from keim_at_Si's "SiON TENORION for v0.57"
// http://wonderfl.net/c/qf4b
public var voices:Vector.<SiONVoice> = new Vector.<SiONVoice>(16);
public var notes :Vector.<int> = Vector.<int>([36,48,60,72, 43,48,55,60, 65,67,70,72, 77,79,82,84]);
public var length:Vector.<int> = Vector.<int>([ 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4]);
private var bitmapWidth:int = 64;
private var bitmapHeight:int = 64;
private var bitmapData:BitmapData;
private var bitmap:Bitmap;
private var beatmapData:BitmapData;
private var beatmap:Bitmap;
private var colors:Vector.<uint>;
private var field:Field;
public function LifeGame() {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
// forked from keim_at_Si's "SiON TENORION for v0.57"
// http://wonderfl.net/c/qf4b
var i:int;
for (i=0; i<4; i++) voices[i] = presetVoice["triangle8"];
for (i=4; i<8; i++) voices[i] = presetVoice["valsound.bass18"];
for (i=8; i<16; i++) voices[i] = presetVoice["valsound.piano11"];
field = new Field(bitmapWidth,bitmapHeight);
bitmapData = new BitmapData(bitmapWidth,bitmapHeight,true,0x00FFFFFF);
bitmap = new Bitmap(bitmapData,PixelSnapping.NEVER,false);
bitmap.scaleX = stage.stageWidth / bitmapWidth;
bitmap.scaleY = stage.stageHeight / bitmapHeight;
addChild(bitmap);
beatmapData = new BitmapData(bitmapWidth,bitmapHeight,true,0x0);
beatmap = new Bitmap(beatmapData,PixelSnapping.NEVER,false);
beatmap.scaleX = stage.stageWidth / bitmapWidth;
beatmap.scaleY = stage.stageHeight / bitmapHeight;
addChild(beatmap);
// forked from ton's "ライフゲーム「グライダー銃」 Game of Life「Glider gun」"
// http://wonderfl.net/c/8TxM
var color:ColorHSV = new ColorHSV();
colors = new Vector.<uint>(bitmapWidth * bitmapHeight, true);
for (i = 0; i < bitmapHeight; i++) {
for (var j:int = 0; j < bitmapWidth; j++) {
color.h = (i + j) * 4;
colors[bitmapWidth * i + j] = color.value32;
}
}
driver.setBeatCallbackInterval(1);
driver.addEventListener(SiONTrackEvent.BEAT,beat);
driver.setTimerInterruption(1,interruption);
driver.addEventListener(SiONTrackEvent.BEAT,beat);
stage.addEventListener(Event.ENTER_FRAME,enter_frame);
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouse_down);
stage.addEventListener(MouseEvent.MOUSE_MOVE,mouse_move);
stage.addEventListener(MouseEvent.MOUSE_UP,mouse_up);
driver.bpm = 96;
driver.play();
var drum:DrumMachine = new DrumMachine(0,0,8,1,0,0);
drum.bassVoiceNumber = 5;
drum.hihatVoiceNumber = 2;
drum.snareVoiceNumber = 1;
drum.play();
}
private function beat(event:SiONTrackEvent):void{
for each (var trk:SiMMLTrack in driver.sequencer.tracks) trk.keyOff();
}
private var beatCounter:int;
private function interruption() : void{
var x:int = beatCounter & bitmapWidth - 1;
beatmap.bitmapData.colorTransform(beatmapData.rect,new ColorTransform(1.0,1.0,1.0,0.9));
beatmap.bitmapData.fillRect(new Rectangle(x,0,1,bitmapHeight),0x10000000);
for(var y:int = 0;y < bitmapHeight; y++) {
var node:Node = field.getNode(x,y);
if(node.status){
noteOn(node.x,node.y);
}
}
beatCounter++;
}
private var keyFlag:int;
private function noteOn(x:int,y:int):void{
var i:int = x % 16;
var note:int = notes[i];
var len:int = length[i];
var v:int = y / 4;
trace(v);
var voice:SiONVoice = voices[v];
this.driver.noteOn(note,voice,len);
}
private var isDown:Boolean;
private function mouse_down(e:MouseEvent):void {
isDown = true;
}
private function mouse_move(e:MouseEvent):void {
if(!isDown) return;
var x:int = bitmap.mouseX >> 0;
var y:int = bitmap.mouseY >> 0;
x = x < 0 ? 0 : x >= bitmapWidth - 1 ? bitmapWidth - 1 : x;
y = y < 0 ? 0 : y >= bitmapHeight - 1 ? bitmapHeight - 1 : y;
var node:Node = field.getNode(x,y);
for(var i:int = 0,iLength:int = node.relationNodes.length;i < iLength;i++){
node.relationNodes[i].status = true;
}
}
private function mouse_up(e:MouseEvent):void {
isDown = false;
}
private function enter_frame(event:Event):void{
field.update();
bitmapData.lock();
bitmapData.colorTransform(bitmapData.rect,new ColorTransform(1.0,1.0,1.0,0.9));
for(var i:int = 0;i < field.length;i++){
var node:Node = field.nodes[i];
if(node.status){
var color:uint = (0xFF << 24) + colors[node.y * bitmapWidth + node.x];
bitmapData.setPixel32(node.x,node.y,color);
}
}
bitmapData.unlock();
}
}
}
internal class Field{
public var length:int;
public var nodes:Vector.<Node>;
private var indices:Vector.<Vector.<int>>;
public function getNode(x:int,y:int):Node{
return nodes[indices[y][x]];
}
public function Field(w:int,h:int){
length = w * h;
nodes = new Vector.<Node>(length);
buffer = new Vector.<Boolean>(length);
indices = new Vector.<Vector.<int>>(h);
var i:int;
// create nodes
var x:int,y:int;
for(i = 0;i < length;i++){
x = i % w;
y = i / h;
nodes[i] = new Node(x,y);
indices[y] ||= new Vector.<int>(w);
indices[y][x] = i;
}
// attach relation nodes ( link list
var t:int,b:int;
var l:int,r:int;
for(i = 0;i < length;i++){
x = i % w;
y = i / h;
l = x - 1;
l = l < 0 ? w - 1 : l;
r = x + 1;
r = r >= w ? 0 : r;
t = y - 1;
t = t < 0 ? h - 1 : t;
b = y + 1;
b = b >= h ? 0 : b;
//trace(l,x,r);
//trace(t,y,b);
nodes[i].relationNodes[0] = nodes[indices[t][l]];// top left
nodes[i].relationNodes[1] = nodes[indices[t][x]];// top center
nodes[i].relationNodes[2] = nodes[indices[t][r]];// top right
nodes[i].relationNodes[3] = nodes[indices[y][l]];// middle left
//nodes[i].relationNodes[0] = nodes[indices[y][x]];// middle-center is current node
nodes[i].relationNodes[4] = nodes[indices[y][r]];// middle right
nodes[i].relationNodes[5] = nodes[indices[b][l]];// bottom left
nodes[i].relationNodes[6] = nodes[indices[b][x]];// bottom center
nodes[i].relationNodes[7] = nodes[indices[b][r]];// bottom right
}
}
private var buffer:Vector.<Boolean>;
public function update():void{
var i:int = 0,node:Node;
for(i = 0;i < length;i++){
node = nodes[i];
var count:int = node.getCount();
// high life
var status:Boolean =
node.status && count <= 1 ? false
:node.status && count <= 3 ? true
:!node.status && count == 3 ? true
:!node.status && count == 6 ? true
:node.status && count >= 4 ? false : false;
buffer[i] = status;
}
for(i = 0;i < length;i++){
nodes[i].status = buffer[i];
}
}
}
internal class Node{
public var x:int;
public var y:int;
public var relationNodes:Vector.<Node>;
public function Node(x:int,y:int){
this.x = x;
this.y = y;
this.relationNodes = new Vector.<Node>;
this.status = Math.random() < 0.1;
}
public var status:Boolean;
public function getCount():int{
var count:int = 0;
for(var i:int = 0,iLength:int = this.relationNodes.length;i < iLength;i++){
var node:Node = this.relationNodes[i];
count += node.status ? 1 : 0;
}
return count;
}
}