/**
* Copyright aobyrne ( http://wonderfl.net/user/aobyrne )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/hQVu
*/
package
{
import flash.display.Sprite;
/**
* ...
* @author sandcastls
*/
public class ComputeSpactrumTest extends Sprite
{
public function ComputeSpactrumTest()
{
addChild(new AbstractFrequencyAnalizer)
}
}
}
import com.bit101.components.CheckBox;
import com.bit101.components.HBox;
import com.bit101.components.HSlider;
import com.bit101.components.HUISlider;
import com.bit101.components.Label;
import com.bit101.components.TextArea;
import com.bit101.components.VBox;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.SampleDataEvent;
import flash.events.TimerEvent;
import flash.media.Sound;
import flash.media.SoundMixer;
import flash.utils.ByteArray;
import flash.utils.Timer;
class AbstractFrequencyAnalizer extends Sprite
{
public var frequency:Number = 0;
public var minFrequency:Number = 0;
public var maxFrequency:Number = 11025; // index/samples * sampleRate (256/1024 * 44100)
protected var logarithmic:Boolean = false;
protected var notes:Array=[];
protected var f:Number = 6.875;
private var sliderBar:HSlider;
private var frequencyField:Label;
protected var display:Shape;
private var sampleRatingInverse:Number;
private var marginx:Number;
private var labelNonNullIndexes:Label;
private var octaveFreqs:Array;
private var octavesAmount:Number;
private var chromaticScalesAmount:Number;
private var allOctaves:Array;
private var currentFrequency:Number;
private var count:uint;
private var octaveIndex:int=-1;
private var isNonIndexPrinting:Boolean;
private var textArea:TextArea;
private var visWidth:Number;
private var visHeight:Number;
private var visY:Number;
public function AbstractFrequencyAnalizer()
{
if (stage)
{
init(null)
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
private function init(e:Event):void
{
marginx = 5;
visWidth = 465 - marginx * 2;
visHeight = 465 - marginx * 2;
visY = 250;
removeEventListener(Event.ADDED_TO_STAGE, init);
// setup
display = new Shape();
addChild(display);
var vBox:VBox = new VBox(this, 10, 10);
frequencyField = new Label(vBox, 0, 0, "frequencyField");
sliderBar = new HSlider(this, marginx, visY+10, mouseMoveHandler);
sliderBar.visible = false;
sliderBar.setSize(visWidth, sliderBar.height);
var sound:Sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, sampleDataHandler);
sampleRatingInverse = 1 / 44100;
sound.play();
sliderBar.value = translate(frequency, minFrequency, maxFrequency, sliderBar.minimum, sliderBar.maximum);
frequencyField.text = frequency.toString();
textArea = new TextArea(this, marginx, sliderBar.y+20 );
textArea.setSize(visWidth, 465-textArea.y-10);
setFrequencyLabels();
updateNotes();
labelNonNullIndexes = new Label(vBox, 0, 0);
chromaticScalesAmount = 12;
octavesAmount = 11;
var p:Number = Math.pow(2, 1 / chromaticScalesAmount);
var thfr:Number = 1;
thfr = 440;
var semitonesForA:Number = 10;
for (var k:int = 0; k < semitonesForA; k++)
{
thfr /= p;
}
trace( "thfr : " + thfr );
var thFreqForCentralC:Number = thfr;
var octavesUnderCentral:Number = 5;
for (var l:int = 0; l < octavesUnderCentral; l++)
{
thFreqForCentralC *= 0.5;
}
trace( "thFreqForCentralC : " + thFreqForCentralC );
thfr = thFreqForCentralC;
allOctaves = [];
for (var i:int = 0; i < octavesAmount; i++)
{
allOctaves[i] = [];
octaveFreqs = allOctaves[i];
for (var j:int = 0; j < chromaticScalesAmount; j++)
{
thfr *= p;
octaveFreqs[j] = thfr;
trace( "thfr : " + thfr );
}
trace('--------------------');
}
var aol:uint = allOctaves.length;
while (aol--)
{
var array:Array = allOctaves[aol] as Array;
trace( "array : " + array.length );
}
//new CheckBox(vBox, 0, 0, 'logarithmic', onLogarithmic);
var timer:Timer = new Timer(100, octavesAmount * chromaticScalesAmount);
timer.addEventListener(TimerEvent.TIMER, onRunTest);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTestComplete);
timer.start();
frequency = allOctaves[0][0];
updateStats();
addEventListener(Event.ENTER_FRAME, loop);
}
private function onTestComplete(e:TimerEvent):void
{
//isNonIndexPrinting =
sliderBar.visible = true;
}
private function onRunTest(e:TimerEvent):void
{
var timer:Timer = e.target as Timer;
var noteIndex:Number = count % chromaticScalesAmount;
if (noteIndex == 0) octaveIndex++;
trace( "pair : " +octaveIndex+','+ noteIndex );
frequency = allOctaves[octaveIndex][noteIndex] as Number;
updateStats();
trace( "frequency : " + frequency.toFixed(4) );
//if (noteIndex == chromaticScalesAmount - 1)
count++;
isNonIndexPrinting = true;
}
private function onLogarithmic(e:Event):void
{
logarithmic = CheckBox(e.target).selected;
}
protected function setFrequencyLabels():void
{
isNonIndexPrinting = false;
}
private function sampleDataHandler(event:SampleDataEvent):void {
var sample:Number;
var pre:Number = 2 * Math.PI * sampleRatingInverse * frequency;
for (var i:int = 0; i < 4096; i++)
{
sample = Math.sin((i+event.position) * pre)*0.1;
event.data.writeFloat(sample);
event.data.writeFloat(sample);
}
}
private function mouseMoveHandler(event:Event):void {
// var sliderWidth:Number = sliderBar.width - sliderHandle.width;
// sliderHandle.x = Math.max(sliderBar.x, Math.min(sliderBar.x + sliderWidth, root.mouseX));
updateFrequency();
updateStats();
}
protected function updateFrequency():void {
// var sliderWidth:Number = sliderBar.width - sliderHandle.width;
if(logarithmic) {
frequency = translateLinearToLog(sliderBar.value, sliderBar.minimum, sliderBar.maximum, minFrequency, maxFrequency);
} else {
frequency = translate(sliderBar.value, sliderBar.minimum, sliderBar.maximum, minFrequency, maxFrequency);
}
}
//private function trackNative(myRythm:SimpleRhythm):void
private function loop(e:Event):void
{
var rf:Number;
var amplitude:Number;
var bytes:ByteArray = new ByteArray();
SoundMixer.computeSpectrum(bytes, true, 0);
display.graphics.clear();
display.graphics.lineStyle(0, 0x999999);
display.graphics.moveTo(marginx, 200);
//pixels per unit
var ppuX:Number = visWidth / 256;
var ppuY:Number = 160;
var nonNullIndexes:Array = [];
var array:Array = [];
for (var i:uint = 0; i < 256; ++i)
{
rf = bytes.readFloat();
if (rf > 0)
{
nonNullIndexes[nonNullIndexes.length] = i;
array[array.length] = rf;
}
amplitude = visY - (rf * ppuY);
display.graphics.lineTo( marginx + (i*ppuX), amplitude);
}
var aMax:Number = arrayMax(array);
if (isNonIndexPrinting)
{
isNonIndexPrinting = false;
labelNonNullIndexes.text = String(nonNullIndexes )
textArea.textField.appendText(int(frequency).toString()+':'+aMax.toFixed(4)+': '+nonNullIndexes + '\n');
textArea.textField.scrollV = textArea.textField.numLines;
}
}
private function onSlide(e:Event):void
{
}
public function updateNotes():void {
trace( "AbstractFrequencyAnalizer.updateNotes" );
trace( "sliderBar.x : " + sliderBar.x );
trace( "sliderBar.x + sliderBar.width : " + (sliderBar.x + sliderBar.width) );
trace( "sliderBar.width : " + sliderBar.width );
for( var i:String in notes ) trace( "key : " + i + ", value : " + notes[ i ] );
for each(var note:Object in notes) {
trace( "note : " + note );
if(logarithmic) {
note.field.x = translateLogToLinear(note.frequency, minFrequency, maxFrequency, sliderBar.x, sliderBar.x+sliderBar.width);
} else {
note.field.x = translate(note.frequency, minFrequency, maxFrequency, sliderBar.x, sliderBar.x + sliderBar.width);
}
note.field.x += 8; // offset for rotation
note.field.y = sliderBar.y + 7;
note.field.rotation = 45/(Math.PI/180);
}
}
private function arrayMax(input:Array):Number
{
var i:Array = input;
var il:uint = i.length;
var output:Number = 0;
for (var j:int = 0; j < il; j++)
{
output=Math.max(output,i[j])
}
return output;
}
private function updateStats():void {
//var percent:Number = (sliderHandle.x - sliderBar.x)/(sliderBar.width - sliderHandle.width);
frequencyField.text = (Math.round(frequency)).toString() + " Hz";
//percentField.text = (Math.round(percent*1000)/10).toString() + "%";
} // utility
public function translate(value:Number, minimum:Number, maximum:Number, minRange:Number, maxRange:Number):Number {
var percent:Number = (value-minimum)/(maximum-minimum);
return (maxRange - minRange)*percent + minRange;
}
public function translateLinearToLog(value:Number, minimum:Number, maximum:Number, minLog:Number, maxLog:Number):Number {
var peak:Number = Math.log(maxLog-minLog)/Math.log(2);
var percent:Number = (value-minimum)/(maximum-minimum);
return Math.pow(2, percent*peak) + minLog;
}
public function translateLogToLinear(value:Number, minLog:Number, maxLog:Number, minimum:Number, maximum:Number):Number {
var percent:Number = Math.log(value-minLog)/Math.log(maxLog-minLog);
return (maximum-minimum)*percent + minimum;
}
}