Skip to content

Instantly share code, notes, and snippets.

@koyachi
Created May 7, 2010 23:16
Show Gist options
  • Save koyachi/394133 to your computer and use it in GitHub Desktop.
Save koyachi/394133 to your computer and use it in GitHub Desktop.
// 2010-05-08 koyachi
// Frequency selected sound energy algorithm 1
// http://www.gamedev.net/reference/programming/features/beatdetection/
package {
import flash.display.*;
import flash.text.*;
import flash.net.*;
import flash.media.*;
import flash.events.*;
import flash.utils.*;
public class Sketch20100506 extends Sprite {
private var tf:TextField;
private var textFormat:TextFormat;
private var sound:Sound = new Sound();
private var playSound:Sound = new Sound();
private var sprite:Sprite = new Sprite();
private var samplesL:Array = [];
private var samplesR:Array = [];
private var energyHistory:Array = [];
private var beatDetected:Boolean = false;
[SWF(background=0xFFFFFF,width=800,height=600,frameRate=30)]
public function Sketch20100506() {
// var url:URLRequest = new URLRequest('./renai_circulation.mp3');
var url:URLRequest = new URLRequest('./f.x.n.c..mp3.ab160.mp3');
sound.load(url);
sound.addEventListener(Event.COMPLETE, onLoaded);
tf = new TextField();
tf.width = 800;
tf.height = 600;
tf.text = '2010-05-06, hello.';
textFormat = new TextFormat();
textFormat.size = 8;
tf.defaultTextFormat = textFormat;
addChild(tf);
addChild(sprite);
addEventListener(Event.ENTER_FRAME, processSamples);
}
public function onLoaded(event:Event):void {
playSound.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound);
playSound.play();
}
public function processSound(event:SampleDataEvent):void {
var resultBuffer:ByteArray = new ByteArray();
var sourceBuffer:ByteArray = new ByteArray();
var len:Number = 4096;
var samples:Number = sound.extract(sourceBuffer, len);
var str:String = samples + '.\nhohoho\n';
sourceBuffer.position = 0;
samplesL = [];
samplesR = [];
var energy:Number = 0;
var count:uint=0;
while (sourceBuffer.bytesAvailable > 0) {
count++;
var l:Number = sourceBuffer.readFloat();
var r:Number = sourceBuffer.readFloat();
samplesL.push(l);
samplesR.push(r);
resultBuffer.writeFloat(l);
resultBuffer.writeFloat(r);
energy += l*l + r*r;
// change pitch
// if (sourceBuffer.bytesAvailable > 0) {
// sourceBuffer.position += 4;
// }
}
event.data.writeBytes(resultBuffer);
var optimizedE:Number = 0.0;
for(var i:uint=0; i < energyHistory.length; i++) {
// 2乗だとほとんど検出しない
//optimizedE += energyHistory[i] * energyHistory[i];
optimizedE += energyHistory[i];
}
optimizedE *= (1.0 / 43);
// beatDetected = isBeat(energy, optimizedE);
var v:Number = 0;
for(i=0; i < energyHistory.length; i++) {
v += energyHistory[i] - optimizedE;
}
v *= (1.0 / 43);
beatDetected = isBeat2(energy, optimizedE, v);
energyHistory.push(energy);
if (energyHistory.length > (44032 / 1024)) { // 43
energyHistory.shift();
}
str = [str, count,energy, optimizedE, (beatDetected ? 'BEAT' : '...'), ''].join('\n');
str += energyHistory.map(function(eh:Number, index:int, list:Array):String{return '[' + eh + ']'}).join('\n');
tf.text = str;
}
public function isBeat(currentEnergy:Number, optimizedE:Number):Boolean {
var C:Number = 1.3;
// var C:Number = 1.0;
return (currentEnergy > C * optimizedE) ? true : false;
}
public function isBeat2(currentEnergy:Number, optimizedE:Number, v:Number):Boolean {
var C:Number = (-0.0025714 * v) + 1.5142857;
return (currentEnergy > C * optimizedE) ? true : false;
}
public function processSamples(event:Event):void {
var g:Graphics = sprite.graphics;
g.clear();
var w:uint = 800;
var h:uint = 600;
var prev_lx:uint = 0;
var prev_ly:uint = h/2;
var cur_lx:uint = 0;
var cur_ly:uint = 0;
/*
var prev_rx:uint = 0;
var prev_ry:uint = h/2;
var cur_rx:uint = 0;
var cur_ry:uint = 0;
*/
if (beatDetected) {
g.lineStyle(2, 0x0000ff);
}
else {
g.lineStyle(1, 0x8080ff);
}
g.moveTo(prev_lx, prev_ly);
for (var i:uint=0; i < samplesL.length; i++) {
// g.lineStyle(1, 0xff0000ff, 1.0);
// g.moveTo(prev_lx, prev_ly);
cur_lx = w * i / samplesL.length;
cur_ly = samplesL[i] * (h / 2) + (h / 2);
// g.lineStyle(1, 0xff0000ff, 1.0);
g.lineTo(cur_lx, cur_ly);
// prev_lx = cur_lx;
// prev_ly = cur_ly;
/*
g.lineStyle(1, 0x00ff00ff, 1.0);
g.moveTo(prev_rx, prev_ry);
cur_rx = w * i / samplesR.length;
cur_ry = samplesR[i] * (h / 2) + (h / 2);
g.lineStyle(1, 0xff0000ff, 1.0);
g.lineTo(cur_rx, cur_ry);
prev_rx = cur_rx;
prev_ry = cur_ry;
*/
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment