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

forked from: Ode To Joy (Sound Generation fork)

Just experimenting with sound generation to learn how it works. Nothing to see here really
Currently plays Ode To Joy

Key:
the note numbers are MIDI notes
A0 (440hz) = note #69
Middle C (C0) = note #60

- Billy
Get Adobe Flash player
by lfoundation 30 Nov 2009
    Embed
// forked from Billy's Ode To Joy (Sound Generation fork)
// forked from seagirl's Dynamic Sound Generation

/*
Just experimenting with sound generation to learn how it works. Nothing to see here really
Currently plays Ode To Joy

Key:
    the note numbers are MIDI notes
    A0 (440hz) = note #69
    Middle C (C0) = note #60
    
- Billy
*/

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;

	[SWF(backgroundColor="#ABCDEF")]
	
	public class DSG extends Sprite
	{
		public function DSG()
		{
			super();
			
			init();
		}
		
		private var timer:Timer;
		
                private var songOffset:Number = 0;
                
                //songs
                private var odeToJoy:Array = [44, 54, 55, 47, 47, 65, 64, 62, 60, 60, 62, 64, 64, 62, 62, 0, 0, 0, 0, 0];
                
                //The song you want to play. Copy an array.
                private var song:Array = odeToJoy;

		private function init():void
		{			
			timer = new Timer(500);
			timer.addEventListener(TimerEvent.TIMER, timerHandler);
			timer.start();
		}

                private function playSong():void {
                        if (songOffset >= song.length - 1) {
                            songOffset = 0;
                        }
                        
                        var noteNumber:int = song[songOffset];
                        new Tone(noteNumber, .5, 8, 1, 1, 5, 1).start();
                        
                        songOffset++;
                }
		
		private function timerHandler(event:TimerEvent):void
		{
			playSong();
		}
		
	}
}

import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;

import flash.events.EventDispatcher;
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.utils.ByteArray;

class Tone extends EventDispatcher
{
	public static const SAMPLING_RATE:Number = 44100;
	public static const BUFFER_SIZE:int = 8192;
		
	public static const UNIT:int = 10;
	
	public function Tone(noteNumber:uint, length:Number, volume:Number, attack:Number, decay:Number, sustain:Number, release:Number)
	{	
		this.frequency = noteNumber2frequency(noteNumber);
		this.length = length;
		this.volume = volume;
		this.attack = attack;
		this.decay = decay;
		this.sustain = sustain;
		this.release = release;
		
		check();
		initializeVelocity();
	}
	
	private var sound:Sound;
	
	private var phase:Number = 0;
	private var amplify:Number = 0;
	
	private var state:int = 1; // 1: Attack, 2: Decay, 3: Release
	
	private var frequency:Number;
	private var length:Number;
	private var volume:Number;
	private var attack:Number;
	private var decay:Number;
	private var sustain:Number;
	private var release:Number;
	
	private var v1:Number;
	private var v2:Number;
	private var v3:Number;
		
	private function check():void
	{
		if (attack + decay + release != UNIT)
		{
			 attack = 0;
			 decay = 5;
			 release = 5;
		}
			
		if (volume > UNIT)
			volume = UNIT;
		
		if (volume < 0)
			volume = 0;
			
		if (sustain > UNIT)
			sustain = UNIT;
			
		if (sustain < 0)
			sustain = 0;
	}
	
	private function initializeVelocity():void
	{			
		v1 = volume / (SAMPLING_RATE * length * attack / UNIT);
		v2 = (volume - sustain) / (SAMPLING_RATE * length * decay / UNIT);
		v3 = sustain / (SAMPLING_RATE * length * release / UNIT);
	}
	
	private function updateAmplify():void
	{
		if (state == 1)
		{
			amplify += v1;

			if (amplify >= volume)
			{
				amplify = volume;
				state = 2;
			}
		}
		else if (state == 2)
		{
			amplify -= v2;
			
			if (volume < sustain)
			{
				if (amplify >= sustain)
				{
					amplify = sustain;
					state = 3;
				}
			}
			else
			{
				if (amplify <= sustain)
				{
					amplify = sustain;
					state = 3;
				}
			}	
		}
		else if (state == 3)
		{
			amplify -= v3;
			
			if (amplify <= 0)
			{
				amplify = 0;
				
				stop();
			}
		}
	}
	
	public function start():void
	{					
		sound = new Sound();
		sound.addEventListener(SampleDataEvent.SAMPLE_DATA, soundSampleDataHandler);
		sound.play();
	}
	
	public function stop():void
	{
		sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, soundSampleDataHandler);
		dispatchEvent(new Event(Event.COMPLETE));
	}
	
	private function soundSampleDataHandler(event:SampleDataEvent):void
	{	
		var bytes:ByteArray = new ByteArray();
		
		for (var i:int = 0; i < BUFFER_SIZE; ++i)
		{
			phase += frequency / SAMPLING_RATE;  
			
			var phaseAngle:Number = phase * Math.PI * 2;
			var sample:Number = Math.sin(phaseAngle) * amplify / UNIT;
			
			sample *= 0.2;
			
			bytes.writeFloat(sample);
			bytes.writeFloat(sample);
			
			updateAmplify();
		}
		
		event.data.writeBytes(bytes);
	}
	
}


function noteNumber2frequency(value:uint):Number
{
        //Clamp to valid values
	if (value > 127)
		value = 127;
	
	return 440 * Math.pow(2, (value - 69) / 12);
}