In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

FUCK YEAH RADIO!!!1

Get Adobe Flash player
by makc3d 01 Jul 2011
package {
	import flash.display.*;
	import flash.events.*;
	import flash.media.*;
	import flash.net.*;
	import flash.text.*;
	import flash.utils.*;

	/**
	 * I wrote this code almost two years ago, but I never knew that
	 * Sound.extract() bypasses crossdomain check! FFT FTW!
	 * 
	 * Preceeding FFT implementations (that I didn't know of at the time):
	 * http://stephan.acidcats.nl/blog/2009/03/01/spectral-analysis-source-files/
	 * http://rest-term.com/archives/1345/
	 * 
	 * Since then there were several other AS3 FFT versions
	 * published, including here, at wonderfl.net
	 */
	public class FFTTest extends Sprite {

		// random stations I don't actually listen to :)
		// http://dir.xiph.org/by_format/MP3 for more...
		private var stations:Array = [
			"http://209.208.14.51:8001/pure_party",
			"http://streaming101.radionomy.com:80/Radio-Mozart",
			"http://rs35.stream24.org:80/stream",
			"http://stream-1.ssatr.ch:80/rsc/mp3",
			"http://demovibes.de:8000/necta192.mp3",
			"http://217.146.71.24:80/dfm.mp3",
			"http://87.104.236.199:80/SR"
		];

		private var info:TextField;
		private var sound:Sound;
		private var channel:SoundChannel;
		private var bytes:ByteArray;
		private var samples:Array;
		private var fft:FastFourierTransform;

		public function FFTTest () {
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;

			// add info text field
			info = new TextField;
			info.autoSize = TextFieldAutoSize.LEFT;
			info.text = "Frequencies in 0 to 5KHz range";
			addChild (info);

			bytes = new ByteArray; samples = new Array; fft = new FastFourierTransform;
			addEventListener (Event.ENTER_FRAME, enterFrameHandler);

			// play safe
			for (var i:int = 0; i < 1024; i++) samples [i] = 0;

			// start the madness :)
			changeStation (); setInterval (changeStation, 20000);
		}

		private function changeStation ():void {
			var station:String = stations.shift ();
			stations.push (station);

			if (channel) channel.stop ();
			sound = new Sound;
			sound.load (new URLRequest (station));
			channel = sound.play ();
		}

		private function enterFrameHandler (event:Event):void {
			// get bytes of 1024 samples
			bytes.position = 0;
			if (sound.extract (bytes, 1024, channel.position * 44.1) < 1024) {
				// ??
				//return;
			}

			// get samples of left channel
			bytes.position = 0;
			while (bytes.bytesAvailable > 0) {
				samples [int (bytes.position / 8)] = bytes.readFloat (); bytes.readFloat ();
			}

			// analyze samples
			fft.analyze (samples);

			// fft.magnitudes contain full spectrum, we want 1st 5KHz
			var limitHz:Number = 5000;
			var i:int, n:int = fft.magnitudes.length * limitHz / (44100 / 2), w:int = 465 / n;

			// draw spectrum
			graphics.clear ();
			graphics.lineStyle ();
			graphics.beginFill (0);
			for (i = 0; i < n; i++) {
				graphics.drawRect (w*i, 50, w, 400 * fft.magnitudes [i]);
			}
			graphics.endFill ();

			// draw 1KHz ticks
			var ticksStep:Number = 1000;
			graphics.lineStyle (0);
			for (i = 0; i < limitHz / ticksStep + 1; i++) {
				graphics.moveTo (w * (ticksStep / limitHz * n * i), 50);
				graphics.lineTo (w * (ticksStep / limitHz * n * i), 45);
			}
		}
	}
}

/**
* Port of java FFT class.
* @author Dr Iain A Robin iain@xunil.uklinux.net
* @see http://www.dsptutor.freeuk.com/analyser/SpectrumAnalyser.html
*/
class FastFourierTransform {

	/**
	 * Magnitudes (corresponding frequency ranges from 0 to half of sampling frequency).
	 */
	public var magnitudes:Array = [];

	/**
	 * Analyzes samples and fills <code>magnitudes</code> array.
	 * @param	samples Array of numbers to analyze (length must be power of 2).
	 */
	public function analyze (samples:Array):void {
		// minimal sanity check
		if ((samples == null) || (samples.length < 2)) {
			magnitudes.length = 0; return;
		}
		// find power of 2 not exceeding samles length
		var n:int = 2; while (n * 2 <= samples.length) n *= 2;
		// transform samples
		var n2:int = n >> 1;
		nu = int (Math.log (n) * Math.LOG2E);
		var nu1:int = nu - 1;
		var tr:Number, ti:Number, p:Number, arg:Number, c:Number, s:Number;
		var i:int, k:int = 0;
		for (i = 0; i < n; i++) {
			xre [i] = samples [i]; xim [i] = 0.0;
		}

		for (var l:int = 1; l <= nu; l++) {
			while (k < n) {
				for (i = 1; i <= n2; i++) {
					p = bitrev (k >> nu1);
					arg = 2 * Math.PI * p / n;
					c = Math.cos (arg);
					s = Math.sin (arg);
					tr = xre [k + n2] * c + xim [k + n2] * s;
					ti = xim [k + n2] * c - xre [k + n2] * s;
					xre [k + n2] = xre [k] - tr;
					xim [k + n2] = xim [k] - ti;
					xre [k] += tr;
					xim [k] += ti;
					k++;
				}
				k += n2;
			}
			k = 0;
			nu1--;
			n2 = n2 >> 1;
		}

		k = 0;
		var r:int;
		while (k < n) {
			r = bitrev (k);
			if (r > k) {
				tr = xre [k];
				ti = xim [k];
				xre [k] = xre [r];
				xim [k] = xim [r];
				xre [r] = tr;
				xim [r] = ti;
			}
			k++;
		}

		n2 = n >> 1;
		var n2i:Number = 2 / n, xr:Number, xi:Number;
		
		for (i = 0; i < n2; i++) {
			xr = xre [i]; xi = xim [i];
			magnitudes [i] = Math.sqrt (xr * xr + xi * xi) * n2i;
		}
		magnitudes [0] *= 0.5;
		magnitudes.length = n2;
	}

	private var xre:Array = [];
	private var xim:Array = [];

	private var nu:int;
	private function bitrev (j:int):int {
		var j2:int;
		var j1:int = j;
		var k:int = 0;
		for (var i:int = 1; i <= nu; i++) {
			j2 = j1 >> 1;
			k = 2 * k + j1 - 2 * j2;
			j1 = j2;
		}
		return k;
	}

}