I spent the last couple weeks working on a project involving sound. Unfortunatly I can’t show it yet, but my goal was to play a bunch of musical notes at the same time in a especific interval. The first thing I tried to do was load a lot of samples and play then when I needed, but I got a slow performance with that. So my only solution was to dig out Google and Andre’s Michelle lab to know how to work with dynamic sound.
Well, I’m still learning, but I think that a lot of people would like to work with this and have no idea where to start, so I hope this post be usefull to you.
First thing we need to have in mind is that a sound is a wave, and this wave can have diferent shapes depending on the sound we are hearing.

Now imagine that this wave is formed by connected points. Each point represents a position of the wave in a especific time.
*move your mouse horizontally to chance the shape of the wave
OK, now let’s call this points samples, and say that they can change their values from -1 to 1.
Basicly this is how sound works in flash. But there is a few things we need to know about quality. A better quality of sound deppend on the number of samples playied in a second of sound, and the precision of the floating point. The number os samples playied in a second is called sample rate, flash works with a sample rate of 44100 samples per second. That mean that each second of sound contains 44100 floating points. Each sample have a 64 bit precision, 32 bit for the left channel and 32 bit for the right channel.
Now let’s bring this to flash. Remember that we are using Flash player 10.
First we create a Sound instance, a SoundChannel instance, add a listener to the sound and play it at the sound channel.
package { import flash.display.Sprite; import flash.events.SampleDataEvent; import flash.media.Sound; import flash.media.SoundChannel; public class Main extends Sprite { private var sound:Sound; private var channel:SoundChannel; public function Main():void{ sound = new Sound(); sound.addEventListener(SampleDataEvent.SAMPLE_DATA, writeData); channel = sound.play(); } private function writeData(e:SampleDataEvent):void{ } } }
The event that we will be listening is dispatched before the sound is played and request the sound data that compunds this range of sound. You can provide from 2048 through 8192 samples. Higher this number is, better is the performance, but higher is the latency. If you provide fewer than 2048 samples (per call to the sampleData event listener), the application stops after playing the remaining samples.
Now let’s fill our sound data with random samples. Each sample with a value from -1 to 1.
private function writeData(e:SampleDataEvent):void{ for(var i:Number = 0; i<8192; i++){ //Left Channel e.data.writeFloat(Math.random()*2-1); //RightChannel e.data.writeFloat(Math.random()*2-1); } }
It makes nothing but noise. To make some decent sound we need to create a wave shape that makes some sense. There is some basics wave shapes the we can extract some sound of.

We will use a sine wave to generate a A4 musical note. The frequency of this note is 440.000 Hz, it means that our wave complete 440 cycles per second.

This is a 1Hz sine wave
And this is a 2Hz sine wave
*Humans can hear between 20 to 20,000 hertz
If we know that each second contains 44100 samples and a A4 note completes 440 cycles per second, each sample well be a 440/44100 cycle step. A cycle is 360 degrees, or Math.PI*2 radians since flash works with radians when calculates sine. Converting this to flash we have the following:
private var phase:Number = 0; private var step:Number = Math.PI*2 * 440/44100; private function writeData(e:SampleDataEvent):void{ for(var i:Number = 0; i<8192; i++){ //Left Channel e.data.writeFloat(Math.sin(phase)); //RightChannel e.data.writeFloat(Math.sin(phase)); phase += step; } }
OK, now we can hear something.
Check the result here
If you want to play different notes you can try this formula where de lowest note is A2.
phaseStep = 110.0*Math.pow( 2, octave + semiTone / 12 )/44100;
Let’s try create a major A4 chord.
We need 3 notes to do this, an A4, a C#4 and a E4.
private var A4:Number = 110.0*Math.pow( 2, 4 + 0 / 12 )/44100; private var Csharp4:Number = 110.0*Math.pow( 2, 4 + 4 / 12 )/44100; private var E4:Number = 110.0*Math.pow( 2, 4 + 7 / 12 )/44100;
and we need a phase for each note
private var phaseA4:Number = 0; private var phaseCsharp4:Number = 0; private var phaseE4:Number = 0;
Then we add each value to compound the chord
private function writeData(e:SampleDataEvent):void{ for(var i:Number = 0; i<8192; i++){ var amplitudeA4:Number = Math.sin(phaseA4); var amplitudeCsharp4:Number = Math.sin(phaseCsharp4); var amplitudeE4:Number = Math.sin(phaseE4); phaseA4 += A4; phaseCsharp4 += Csharp4; phaseE4 += E4; e.data.writeFloat(amplitudeA4+amplitudeCsharp4+amplitudeE4); e.data.writeFloat(amplitudeA4+amplitudeCsharp4+amplitudeE4); } }
When we need to merge two or more sounds, we just add each value to get the full amplitude of the sample, the problem is that when we write a value that is over 1 or below -1, we distort the sound.
Check this
In this case we solve the problem by dividing the full value by 3, sinse we have 3 notes.
private function writeData(e:SampleDataEvent):void{ for(var i:Number = 0; i<8192; i++){ var amplitudeA4:Number = Math.sin(phaseA4); var amplitudeCsharp4:Number = Math.sin(phaseCsharp4); var amplitudeE4:Number = Math.sin(phaseE4); phaseA4 += A4; phaseCsharp4 += Csharp4; phaseE4 += E4; e.data.writeFloat((amplitudeA4+amplitudeCsharp4+amplitudeE4)/3); e.data.writeFloat((amplitudeA4+amplitudeCsharp4+amplitudeE4)/3); } }
Now it sounds much more pleasant.
Get the source here
We can have a lot of fun with this, but we can do a lot more using pre-recorded samples and manipulating samples to create effects.
Wow man, awesome post. congrats!!
[]s!
great post, now i think i understand. thanks very much!
But please could you explain one more thing:
phaseStep = 110.0*Math.pow( 2, octave + semiTone / 12 )/44100;
would be nice, thanks.
This is a formula to get the phaseStep of different notes. Every musical note is part of an Octave and every octave is compound by 12 semi tunes (A, A#, B, C, C#, D, D#, E, F, F#, G and G#).
Check this reference
Frequencies of Musical Notes
Each row represent a semi tune frequency. When you set the base frenquency as 110.00 Hz, it means that the fisrt octave is 2 and the first semiTune will be an A, so if you passe octave = 0 and semiTune = 0, you will get an A2. If you pass octave = 2 and semiTune = 4, you will get a C4 because it is 2 octaves above and 4 semi tunes above A2.
If you change the base frequency, every note will follow it. For instance, if you set the base frequency as 261.63 the first octave will be 4 and the first semi tune will be C, you will get a middle C4:
phaseStep = 261.63*Math.pow( 2, octave + semiTone / 12 )/44100;
phaseStep = 261.63*Math.pow( 2, 0 + 0 / 12 )/44100; //C4
phaseStep = 261.63*Math.pow( 2, 0 + 1 / 12 )/44100; //C#4
phaseStep = 261.63*Math.pow( 2, 0 + 2 / 12 )/44100; //D4
phaseStep = 261.63*Math.pow( 2, 1 + 0 / 12 )/44100; //C5
phaseStep = 261.63*Math.pow( 2, 1 + 0 / 12 )/44100; //C6
I don’t know the logic behind this formula, but I know that it works ;)
Hope this is more clear to you.
Thanks for the comment
Ok, very interesting. thank you!
good one…
Great tutorial. Exactly what I was looking for. Thanks!
Very nice tutorial… :)
script work nice on my machine, thanx a lot
greetings form germany
this might help on using power^n to shift notes – http://www.phy.mtu.edu/~suits/NoteFreqCalcs.html
a = 2^(n/12) which means there are “12 half steps” between octaves. (example, you will count 12 white and black keys between middle C and high C, etc)