Aurora membrane sound visualizer

This gnarly effect is sort of a semi-unintentional byproduct of my previous experiment.

Some of the same rules and techniques still apply: the main driving element is an animated perlinNoise map, but this time it’s used to supply pixel-displacement data.
Along with some basic sound-analysis and bitmapData effects it creates a pretty interesting end-result that in my mind is now officially stuck with the vaguely cyberpunk-inspired moniker “Aurora membrane”:

By the way, the suffocatingly sinister track is by Gök.

I have gone through at least a dozen different iterations of this effect, with various ways to filter, dampen, amplify or shuffle around the audiovisual data that drives the look, but ended up liking this unsettling, twitchy version the most.

Well, without further ado please feel free to dive right into the source.
Yes, that’s right: the source. Have fun kids, and stay in school! ;)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// AURORA MEMBRANE (C) edvardtoth.com
 
package {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BitmapDataChannel;
	import flash.display.PixelSnapping;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageQuality;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.filters.BlurFilter;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.net.URLRequest;
	import flash.utils.getTimer;
 
	[SWF(width=500,height=500,frameRate=30,backgroundColor=0x000000)]
	public class AuroraMembrane extends Sprite
	{
		private const SIZE:int = 500;			// size of the canvas
		private const NOISESIZE:int = 100;		// size of the noise map
		private const RATIO:Number = SIZE / NOISESIZE;  // ratio to accurately map the noise on the canvas
		private const OCTAVES:int = 3;			// number of perlin noise octaves
		private const SPEED:Number = 0.05;		// speed value used to animate the perlin noise
 
		private var noiseMap:BitmapData;
		private var canvasBitmapData:BitmapData;
		private var canvas:Bitmap;
 
		private var canvasBlur:BlurFilter;
		private var canvasFade:ColorMatrixFilter;
 
		private var clipRect:Rectangle;
		private var point:Point;
 
		private var sound:Sound;
		private var channel:SoundChannel;
		private var leftMagnitude:Number;
		private var rightMagnitude:Number;
 
		private var soundAvailable:Boolean = true;
 
		public function AuroraMembrane()
		{
			// setup stage properties
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.quality = StageQuality.MEDIUM;
			stage.align = StageAlign.TOP_LEFT;
 
			// create matrix for the ColorMatrixFilter used to fade out the continuously overdrawn bitmap
			var canvasFadeMatrix:Array = new Array();
 
			canvasFadeMatrix = canvasFadeMatrix.concat([1, 0, 0, 0, 0]); 	// red
			canvasFadeMatrix = canvasFadeMatrix.concat([0, 1, 0, 0, 0]); 	// green
			canvasFadeMatrix = canvasFadeMatrix.concat([0, 0, 1, 0, 0]); 	// blue
			canvasFadeMatrix = canvasFadeMatrix.concat([0, 0, 0, 0.99, 0]); // alpha
 
			canvasFade = new ColorMatrixFilter (canvasFadeMatrix);
			canvasBlur = new BlurFilter (2, 32, 1); // Y values is much larger than X to achieve vertical streaking
 
			clipRect = new Rectangle (0, 0, SIZE, SIZE);
			point = new Point (0, 0);
 
			noiseMap = new BitmapData (NOISESIZE, NOISESIZE, false, 0x000000);
 
			canvasBitmapData = new BitmapData(SIZE, SIZE, false, 0x000000);
			canvas = new Bitmap(canvasBitmapData, PixelSnapping.AUTO, false);
			addChild(canvas);
 
			// load sound and handle potential stream error
			// effect should still be presentable even if sound cannot be loaded
			sound = new Sound(new URLRequest ("your soundfile location here"));
			sound.addEventListener(IOErrorEvent.IO_ERROR, function ():void{soundAvailable = false;});
 
			channel = sound.play();
 
			addEventListener (Event.ENTER_FRAME, updateFrame, false, 0, true);
		}
 
		private function updateFrame(event:Event):void
		{
			// get peak information from sound, or default to 1 if sound was not available to load
			if (soundAvailable == true) {
				leftMagnitude = channel.leftPeak;
				rightMagnitude = channel.rightPeak;
			} else {
				leftMagnitude = 1;
				rightMagnitude = 1;
			}
 
			var offsets:Array = [];
			var offset:Number = -(getTimer() * SPEED);
 
			for(var i:uint = 0; i < OCTAVES; i++) {
 
				// offsets are used for animating the various octaves of the perlin noise map
				offsets.push(new Point(0, offset/(i+1)));
			}
 
			// render the noiseMap
			noiseMap.perlinNoise(NOISESIZE, NOISESIZE, OCTAVES, Math.random(), false, false, BitmapDataChannel.RED |BitmapDataChannel.GREEN | BitmapDataChannel.BLUE , false, offsets);
 
			// apply fading and blurring to the existing contents of the canvas
			canvasBitmapData.applyFilter (canvasBitmapData, clipRect, point, canvasBlur);
			canvasBitmapData.applyFilter (canvasBitmapData, clipRect, point, canvasFade);
 
			for (var y:int = 0; y < NOISESIZE; y++)
			{
				for (var x:int = 0; x < NOISESIZE; x++)
				{
					// separate R,G,B values extracted from the noiseMap using bitwise operators
					var pixelColor:uint = noiseMap.getPixel(x, y);
					var r:int = pixelColor >> 16 & 0xFF;
					var g:int = pixelColor >> 8 & 0xFF;
					var b:int = pixelColor & 0xFF;
 
					// calculate coordinates for displaced pixels
					// the perlin noise map information drives the direction of the displacement, 
					// and the sound values drive the magnitude
					var vX:int = x * RATIO + (g / 0xff - 0.25) * (leftMagnitude * SIZE);
					var vY:int = y * RATIO + (b / 0xff - 0.25) * (rightMagnitude * SIZE);
 
					// don't render out-of-bounds pixels
					if (vY < 0 || vY >= SIZE || vX < 0 || vX >= SIZE) {
					 continue;
					}
 
					// render the displaced pixel with the right color value
					canvasBitmapData.setPixel(vX, vY, pixelColor);
				}
			}
		}
 
 
	}
}
2 Responses to Aurora membrane sound visualizer
  1. antonio brandao
    August 20, 2010 | 4:55 am

    fkin great stuff. the music kicks ass too

  2. Nuajan
    August 26, 2010 | 8:19 am

    Really cool effect! Also awesame track!
    Thx and keep it on.

Leave a Reply

Headway Themes — The Drag & Drop WordPress Theme