package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.text.TextField;
import mx.utils.StringUtil;
public class Main extends Sprite
{
private const oplist:Array = [
[ 10, 10, "OP1" ],
[ 110, 10, "OP2" ],
[ 10, 110, "OP3" ],
[ 110, 110, "OP4" ],
[ 210, 60, "Output" ],
];
private const algoinp:Array = [
[ 0x0, 0x1, 0x2, 0x4, 0x8 ],
[ 0x0, 0x0, 0x3, 0x4, 0x8 ],
[ 0x0, 0x0, 0x2, 0x5, 0x8 ],
[ 0x0, 0x1, 0x0, 0x6, 0x8 ],
[ 0x0, 0x1, 0x0, 0x4, 0xa ],
[ 0x0, 0x1, 0x1, 0x1, 0xe ],
[ 0x0, 0x1, 0x0, 0x0, 0xe ],
[ 0x0, 0x0, 0x0, 0x0, 0xf ],
];
private const PI2:Number = Math.PI * 2;
private const SR:int = 44100; // sampling rate
private const BGCOLOR:uint = 0xffffc0;
private const WIDTH:int = 500;
private const HEIGHT:int = 50;
private var freq:Number = 440; // 周波数
private var wavesplist:Array = new Array;
private var playtf:TextField;
private var play:Boolean = false;
private var masktflist:Array = new Array;
private var masklist:Array = new Array;
private var multflist:Array = new Array;
private var mullist:Array = new Array;
private var algoSprite:Sprite = new Sprite;
private var algotflist:Array = new Array;
private var algorithm:int = 0;
private var whlist:Array = new Array(5); // wave height
private var sound:Sound = new Sound;
private var soundChannel:SoundChannel = null;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
initWaveForm();
initPlay();
initOpMask();
//OP1 Feedback
initMultiple();
initAlgorithm();
drawWaveForm();
drawPlay();
drawMask();
for (var r:int = 0; r < 4; r++)
{
drawMultiple(r);
}
drawAlgorithm();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
}
private function initWaveForm():void
{
for (var r:int = 0; r < 5; r++)
{
var tf:TextField = new TextField;
tf.x = 10;
tf.y = 10 + (HEIGHT * 2 + 10) * r;
tf.width = 100;
tf.height = HEIGHT * 2;
tf.border = true;
tf.selectable = false;
tf.text = oplist[r][2];
addChild(tf);
var sp:Sprite = new Sprite;
sp.x = 120;
sp.y = tf.y;
addChild(sp);
wavesplist[r] = sp;
}
}
private function initPlay():void
{
var tf:TextField = new TextField;
tf.x = 10;
tf.y = 600;
tf.width = 100;
tf.height = 50;
tf.text = "Play";
tf.border = true;
tf.selectable = false;
tf.background = true;
tf.name = "p";
tf.addEventListener(MouseEvent.CLICK, onClick);
addChild(tf);
playtf = tf;
}
private function initOpMask():void
{
var tf:TextField = new TextField;
tf.x = 120;
tf.y = 570;
tf.text = "Op. mask:";
addChild(tf);
for (var r:int = 0; r < 4; r++)
{
tf = new TextField;
tf.x = 120;
tf.y = 600 + 30 * r;
tf.width = 40;
tf.height = 20;
tf.text = oplist[r][2];
tf.border = true;
tf.selectable = false;
tf.background = true;
tf.name = StringUtil.substitute("o {0}", r);
tf.addEventListener(MouseEvent.CLICK, onClick);
addChild(tf);
masktflist.push(tf);
masklist.push(true);
}
}
private function initMultiple():void
{
var tf:TextField = new TextField;
tf.x = 200;
tf.y = 570;
tf.text = "Multiple:";
addChild(tf);
for (var r:int = 0; r < 4; r++)
{
var y:Number = 600 + 30 * r;
multflist[r] = new Array;
mullist[r] = 1;
for (var i:int = 0; i < 16; i++)
{
tf = new TextField;
tf.x = 200 + 30 * i;
tf.y = y;
tf.width = 30;
tf.height = 20;
tf.text = i.toString();
tf.border = true;
tf.selectable = false;
tf.background = true;
tf.name = StringUtil.substitute("m {0} {1}", r, i);
tf.addEventListener(MouseEvent.CLICK, onClick);
addChild(tf);
multflist[r][i] = tf;
}
}
}
private function initAlgorithm():void
{
var tf:TextField = new TextField;
tf.x = 640;
tf.y = 10;
tf.text = "Algorithm:";
addChild(tf);
for (var r:int = 0; r < 8; r++)
{
tf = new TextField;
tf.x = 640;
tf.y = 40 + 30 * r;
tf.width = 30;
tf.height = 20;
tf.text = r.toString();
tf.border = true;
tf.selectable = false;
tf.background = true;
tf.name = StringUtil.substitute("a {0}", r);
tf.addEventListener(MouseEvent.CLICK, onClick);
addChild(tf);
algotflist.push(tf);
}
algoSprite.x = 680;
algoSprite.y = 40;
addChild(algoSprite);
for (r = 0; r < oplist.length; r++)
{
tf = new TextField;
tf.x = oplist[r][0];
tf.y = oplist[r][1];
tf.width = 50;
tf.height = 20;
tf.text = oplist[r][2];
tf.border = true;
tf.selectable = false;
tf.background = true;
algoSprite.addChild(tf);
}
}
private function drawWaveForm():void
{
var aawf:Array = new Array;
for (var op:int = 0; op < 5; op++)
{
aawf[op] = new Array(WIDTH);
}
// 波形の生成
for (var i:int = 0; i < WIDTH; i++)
{
sampling(i / SR);
for (op = 0; op < 5; op++)
{
aawf[op][i] = whlist[op];
}
}
for (op = 0; op < 5; op++)
{
var g:Graphics = wavesplist[op].graphics;
g.clear();
g.beginFill(BGCOLOR);
g.drawRect(0, 0, WIDTH, HEIGHT * 2);
g.endFill();
g.lineStyle(1);
g.moveTo(WIDTH, HEIGHT);
g.lineTo(0, HEIGHT);
g.lineStyle(1, 0xff0000);
var awf:Array = aawf[op];
for (i = 0; i < WIDTH; i++)
{
g.lineTo(i, HEIGHT - HEIGHT * awf[i]);
}
}
}
private function drawPlay():void
{
playtf.backgroundColor = switchColor(play);
}
private function drawMask():void
{
for (var r:int = 0; r < 4; r++)
{
masktflist[r].backgroundColor = switchColor(masklist[r]);
}
}
private function drawMultiple(r:int):void
{
for (var i:int = 0; i < 16; i++)
{
multflist[r][i].backgroundColor = switchColor(i == mullist[r]);
}
}
private function drawAlgorithm():void
{
for (var r:int = 0; r < 8; r++)
{
algotflist[r].backgroundColor = switchColor(r == algorithm);
}
var g:Graphics = algoSprite.graphics;
g.clear();
g.beginFill(BGCOLOR);
g.drawRect(0, 0, 300, 150);
g.endFill();
g.lineStyle(1, 0x0000ff);
for (var to:int = 0; to < 5; to++) // target op
{
var inp:int = algoinp[algorithm][to];
for (var io:int = 0; io < 4; io++) // input op
{
if (inp & (1 << io))
{
g.moveTo(oplist[io][0] + 25, oplist[io][1] + 10);
g.lineTo(oplist[to][0] + 25, oplist[to][1] + 10);
}
}
}
}
private function switchColor(b:Boolean):uint
{
return b ? 0xffc080 : 0xeeeeee;
}
private function onClick(e:MouseEvent):void
{
var arg:Array = e.target.name.split(" ");
var r:int;
switch (arg[0])
{
case "a":
algorithm = parseInt(arg[1]);
drawAlgorithm();
break;
case "m":
r = parseInt(arg[1]);
var i:int = parseInt(arg[2]);
mullist[r] = i;
drawMultiple(r);
break;
case "o":
r = parseInt(arg[1]);
masklist[r] = !masklist[r];
drawMask();
break;
case "p":
switchPlay();
drawPlay();
return;
default:
return;
}
drawWaveForm();
}
private function switchPlay():void
{
if (play)
{
if (soundChannel != null)
{
soundChannel.stop();
soundChannel = null;
}
play = false;
}
else
{
var st:SoundTransform = new SoundTransform;
st.volume = 0.2;
soundChannel = sound.play(0, 0, st);
play = true;
}
}
private function onSampleData(e:SampleDataEvent):void
{
for (var i:int = 0; i < 4096; i++)
{
var wh:Number = sampling((e.position + i) / SR);
e.data.writeFloat(wh);
e.data.writeFloat(wh);
}
}
private function sampling(t:Number):Number
{
var wh:Number;
// OP1-4
for (var op:int = 0; op < 4; op++)
{
if (masklist[op] == false)
{
whlist[op] = 0;
continue;
}
wh = 0;
var inp:int = algoinp[algorithm][op];
for (var io:int = 0; io < 4; io++) // input op
{
if (inp & (1 << io))
{
wh += whlist[io];
}
}
var mul:Number = mullist[op];
if (mul == 0) mul = 0.5;
whlist[op] = Math.sin(PI2 * mul * freq * t + wh);
}
// Output / Mixer
wh = 0;
var count:int = 0;
inp = algoinp[algorithm][4];
for (io = 0; io < 4; io++)
{
if (inp & (1 << io))
{
wh += whlist[io];
count++;
}
}
whlist[4] = wh / count;
return whlist[4];
}
}
}