text: Manipulating Sounds in AS3 With the Standing Wave 3 Library
  In this tutorial we will be exploring the AS3 sound manipulation library Standing Wave 3. We will create a sinewave piano, use a single MP3 to play many different pitches, make a chord and scale out of a single MP3, mix sounds together, and write the mixed sound to a ByteArray as .wav data.
  Step 1: Explaining Standing Wave 3
  The Standing Wave 3 library is a subset of the library that was used to create the very popular online music scoring application at noteflight.com. The library takes advantage of the dynamic sound generation that came along with Flash Player 10, and uses the newly created Alchemy extension to the Flash Player, which allows you to compile C++ code to run on the open source ActionScript Virtual Machine (AVM2).
  Step 2: Create New Flash Project
  Go to File > New and choose "ActionScript 3.0" with the following properties.
  - W:600
  - H:600
  - Background Color:#CCCCCC
  Save this file as "StandingWave.fla"
  Step 3: Create "Main.as"
  Go to File > New and choose "Actionscript 3.0 Class".
  Save this file as "Main.as" and set it as the Document Class.
  Step 4: Adding the Library
  You will need to grab a copy of the Standing Wave Library at github.
  Once you have extracted the .zip file, you will need to copy the com folder (which is located in the standingwave > sw3 > src directory) into your project directory.
  Next you have to add awave.swc, which is located in the standingwave > alchemy directory, to your project. Go to File > Actionscript Settings, then click on the "Library Path" tab to add the swc. If you're not sure how to do this see the tutorial on how to use an external library in your Flash projects.
  Step 5: Coding the Constructor
  Inside "Main.as" add the following code.
  package{ //Class extends MovieClip import flash.display.MovieClip; //Needed for our Buttons and Complete Events import flash.events.MouseEvent; import flash.events.Event; //Needed for standing Wave Library import flash.media.Sound; import com.noteflight.standingwave3.elements.*; import com.noteflight.standingwave3.filters.*; import com.noteflight.standingwave3.formats.*; import com.noteflight.standingwave3.generators.*; import com.noteflight.standingwave3.modulation.*; import com.noteflight.standingwave3.output.*; import com.noteflight.standingwave3.performance.*; import com.noteflight.standingwave3.sources.*; import com.noteflight.standingwave3.utils.*; public class Main extends MovieClip{ public function Main(){ } }//Close the class }//Close the package
  Here we import the classes we will need throughout the tutorial and set up our
  Main() constructor function.
  Step 6: Note Frequencies
  To be able to effectively take advantage of the Standing Wave library, we need a reference to note frequencies. You can find a nice chart on the website.
  Don't even worry about trying to memorize these, or having to constantly refer to this chart; we will create a nice "NoteUtils" class along the way that will reference all the notes shown in this chart.
  Step 7: Audio Sources
  Standing wave makes use of Audio Sources. These can be produced in a number of ways: by extracting sound from an sound file, using an existing array of values to construct a sound, or generating sound from mathematical functions at runtime.
  A good video showing some basic sound manipulation using flashes dynamic sound generation is this one on Lee Brimelow's GotoAndLearn.com website.
  Some of the Audio Sources available are:
  SineSource- allows you to generate sine waves
  LoopSource- allows you to loop another source.
  SamplerSource- provides a convenient way to perform complex sample wavetable playback functionality. It has flexible start and loop points, and accepts pitch modulations.
  All Audio Sources implement the
  IAudioSource Interface.
  Step 8: Interface for Playing a Sinewave
  Add two button components and a label to the stage. You can get to the component panel by going to Window > Components (alternatively just press CTRL+F7).
  Give the first button the instance name "sinewave_play_btn" and change the label property to "Play".
  Give the other button the instance name "sinewave_stop_btn" and change the label property to "Stop".
  Now change the label's text property to "Play/Stop Sinewave".
  Position the components as below.
  - play_sinewave_btn: X:20.00 Y:53.00
  - stop_sinewave_btn: X:136.00 Y:53.00
  - Play/Stop sinwave label X:80.00 Y:7.00
  Step 9: Playing a Sinewave
  Just under the line
  public class Main extends MovieClip add the following.
  public class Main extends MovieClip{ var sinewavePlayer:AudioPlayer = new AudioPlayer(); var sinewave:IAudioSource;
  The
  AudioPlayer class is what we use to play the sounds in Standing Wave, and the
  sinewave variable is an IAudioSource that we will feed into the player.
  Add the following to the
  Main() constructor.
  public function Main(){ addButtonListeners(); }
  This function will be used to add listeners to our buttons, which will allow us to play and stop the sinewave when they are clicked.
  Add the following underneath the
  Main() function.
  private function addButtonListeners():void{ sinewave_play_btn.addEventListener(MouseEvent.CLICK,playSinewave); sinewave_stop_btn.addEventListener(MouseEvent.CLICK,stopSinewave); }
  Here we add some Listeners that will call the "playSinewave" and "stopSinewave" functions when a user clicks on the buttons.
  Add the following underneath the
  addButtonListeners function.
  private function playSinewave(e:Event):void{ e.target.enabled = false; sinewave = new SineSource(new AudioDescriptor(),5,440,0.2); sinewavePlayer.addEventListener(Event.SOUND_COMPLETE,onPlaybackComplete); player.play(sinewave); }
  Here we disable the button, create a new SineSource (see below), add an
  Event.SOUND_COMPLETE listener that will be called when the sound finishes playing, and tell the player to play the sinewave.
  The SineSource takes as parameters an
  AudioDescriptor, which we will explain shortly, the amount of seconds you want the sinewave to play, the frequency of the sinewave, and the amplitude of the sinewave. You will want to keep the amplitude at 0.5 or below, putting it any higher can cause the audio to clip.
  Add the following below the
  playSinewave() function you added above.
  private function onPlaybackComplete(e:Event):void{ sinewave_play_btn.enabled = true; }
  This function is called when the sound finishes playing and it simply enables the
  sinewave_play_btn.
  Add the following below the
  doComplete() function you added above.
  private function stopSinewave(e:Event):void{ player.stop(sinewave); sinewave = null; }
  Here we stop the sinewave, set it to null, and enable the
  sinewave_play_btn.
  The AudioDescriptor describes the characteristics of an audio stream in terms of number of channels and sample rate. Every IAudioSource instance is associated with an AudioDescriptor that indicates what kind of audio data is available from it. Although we have not passed any parameters to it, you can pass two: the Rate, and the number of channels. Examine the AS Docs to learn more about it.
  You can now test the movie.
  Step 9: Explanation of the "NoteUtils" Class
  We are going to create a "NoteUtils" class, that will help us along. Having to constantly reference the chart I linked to above is no fun, and wastes time. This class will make use of public static const variables, so we will not even need to instantiate the class to use them.
  We will create the Notes shown in the aforementioned chart from C0 to D#8. Since we cannot use the "#"(sharp) sign in our variable names, we will use an "S" in its place - C#3 will be CS3, F#4 will be FS4, and so on.
  We could take our time and type all these variables in, but I have a better solution. By following a certain formula and using a for loop, we can create all these notes in one shot and just copy and paste them into the class.
  At the bottom of the chart I mentioned above you will see a link to the equations used to create the chart. By studying the equation we can come up with a formula to use in our for loop. We will create the class in the next step.
  Step 10: Creating the "NoteUtils" Class
  Go to File > New and choose "Actionscript File". Save this as "NoteUtils.as".
  Add the following to the "NoteUtils.as".
  package{ import flash.display.Sprite; public class NoteUtils extends Sprite{ public function NoteUtils(){ } } }
  Here we just set up our class to extend Sprite, and code the constructor function.
  We are going to use the timeline in our "StandingWave.fla" to generate code that defines the notes for this class, then copy this new code into our AS file, and once we are finished we will delete the code from the timeline.
  So.. select the first frame in the timeline.
  Then go to Window > Actions or just press F9. Next, enter the following code.
  var NoteArray:Array = ["C","CS","D","DS","E","F","FS","G","GS","A","AS","B"]; var sub:int = -1; for (var i:int = 0; i < 100; ++i){ var Notes = (16.35 * Math.pow(1.05946309,i)).toFixed(2); if(i%12 == 0){ sub++ } trace ("public static const "+NoteArray[i%12]+sub+":Number ="+Notes);
  We declare a
  NoteArray to hold all 12 notes that are available (remember the "S" stands for Sharp). We then create a
  sub variable, and set it to -1. The sub will be appended to the notes. We then code our for loop, using the formula from the link above.
  Because we are starting from "C0" we use 16.35 as the value of f0 from the formula. We also used AS3's
  toFixed(2) function to force each Note to a precision of 2 decimal places.
  Next we check whether
  i%12 == 0 - that is, whether it can be divided evenly by 12, the number of semitones in an octave - and if can we increment
  sub by 1. (Hopefully you can see why we started with -1 as the initial value of sub now).
  Finally, we use
  trace() to trace out each variable. The
  trace() may look a little cryptic so let me break it down.
  First we just trace "public static const" since we want our variables static and unchangeable. Next we add onto this
  NoteArray[i%12]+sub - the "i%12" forces the index to always be one of the indices of the NoteArray; for example if
  i were 16 then it would resolve to
  NoteArray[4]. Finally we tack on ":Number =" and the actual value of Notes.
  Go ahead and test the movie; you will see all the notes nicely formatted in the output window as so:
  public static const C0:Number =16.35 public static const CS0:Number =17.32 public static const D0:Number =18.35 public static const DS0:Number =19.44 .....
  You may notice that they are not dead on according to the chart, but I do not think being off by a small amount will matter much. You can always copy the values manually from the chart if you wish.
  Copy the lines from the output window and paste them into the "NoteUtils.as" you created in the step above just below the line
  public class NoteUtils extends Sprite.
  public class NoteUtils extends Sprite{ public static const C0:Number =16.35 public static const CS0:Number =17.32 public static const D0:Number =18.35 public static const DS0:Number =19.44 .....
  Now make sure you delete the code off the main timeline in the "StandingWave.fla".
  Step 11: Explanation of the Sinewave Piano
  We will be creating a sinewave piano whose notes will span from "C4" to "C5". We will use our newly created "NoteUtils" class to make a reference to the notes on the piano.
  Here is a preview:
  Step 12: Creating the Piano Keys
  Select the rectangle tool and make sure the following properties are set.
  - Stroke: Black
  - Fill: White
  Now drag a rectangle out on the stage, then use the selection tool to select both the fill and stroke.
  Next set the following properties on the rectangle.
  - W: 26.00
  - H: 106.00
  -
  Now making sure both the fill and stroke are still selected, right-click on the rectangle and choose "Convert to Symbol". Give it the name "WhiteKey" and make sure "Export for ActionScript" is checked of and the class name is "WhiteKey".
  Next select the rectangle tool and make sure the fill is set to black and there is no stroke color selected.
  Now drag a rectangle out on the stage, and use the selection tool to select it, then give it the following properties.
  - W: 18.00
  - H: 65.00
  Right click on the rectangle and choose "Convert to Symbol", give it the name "BlackKey" and make sure "Export for Actionscript" is checked and that the class name is "BlackKey".
  Step 13: Creating the Piano Key Classes
  Go to File > New and choose "Actionscript File", save this as "WhiteKey.as" and then enter the following code.
  package { import flash.display.Sprite; public class WhiteKey extends Sprite{ private var frequency:Number=0; public function WhiteKey() { } public function setFrequency(freq:Number):void{ this.frequency = freq; } public function getFrequency():Number{ return this.frequency; } } }
  Here we open our package and import the Sprite class.The
  frequency variable is used as the frequency of the Piano Key. If the piano key is "A4" then this would equal 440. We then have have getters and setters for this variable.
  Now go to File > New and choose "Actionscript File", and save this as "BlackKey.as" and enter the following code.
  package { import flash.display.Sprite; public class BlackKey extends Sprite{ private var frequency:Number; public function BlackKey() { } public function setFrequency(freq:Number):void{ this.frequency = freq; } public function getFrequency():Number{ return this.frequency; } } }
  This works the exact same way as the "WhiteKey" class.
  Step 14: Coding the Sinewave Piano
  Add the following variables, below the ones you already have.
  var keyboardPlayer:AudioPlayer = new AudioPlayer(); var pianoSinewave:IAudioSource; var whiteKeyFrequencies:Array = [NoteUtils.C4,NoteUtils.D4,NoteUtils.E4,NoteUtils.F4,NoteUtils.G4,NoteUtils.A4,NoteUtils.B4,NoteUtils.C5]; var blackKeyFrequencies:Array = [NoteUtils.CS4,NoteUtils.DS4,NoteUtils.FS4,NoteUtils.GS4,NoteUtils.AS4]; var blackKeyPositions:Array = [39,69,127,157,187];
  The
  keyboardPlayer will be the player for the keyboard. The
  pianoSinewave will be used to play the sinewave notes of the piano. The
  whiteKeyFrequencies and
  blackKeyFrequencies variables hold the corresponding frequecies of the piano key's by using our
  NoteUtils class. Finally, the
  blackKeyPositions are used to position the black keys of the piano.
  Add the following inside the
  Main() constructor.
  public function Main(){ addButtonListeners(); setupPianoKeyBoard(); }
  Next add the following code just below the
  stopSinewave() function.
  private function setupPianoKeyBoard():void{ var xPos:Number = 20.00; var yPos:Number = 120.00; for(var i=0;i<8;i++){ var whiteKey:WhiteKey = new WhiteKey(); whiteKey.setFrequency(whiteKeyFrequencies[i]); whiteKey.x = xPos; whiteKey.y = yPos; addChild(whiteKey); whiteKey.addEventListener(MouseEvent.MOUSE_DOWN,playPianoNote); whiteKey.addEventListener(MouseEvent.MOUSE_UP,stopPianoNote); xPos +=29; } for(var j=0;j<blackKeyPositions.length;j++){ var blackKey:BlackKey = new BlackKey(); blackKey.setFrequency(blackKeyFrequencies[j]); blackKey.x = blackKeyPositions[j]; blackKey.y = yPos; addChild(blackKey); blackKey.addEventListener(MouseEvent.MOUSE_DOWN,playPianoNote); blackKey.addEventListener(MouseEvent.MOUSE_UP,stopPianoNote); } }
  We first set up the
  xPos and
  yPos variables. These are used to position the piano keys on the stage. Next we run a for loop for the 8 White Keys, inside this loop we create a
  whiteKey, set it's frequency, position, and add it to the stage. Next we add two Event Listeners and increment the xPos variable so the key are staggered.
  We then run a for loop for the Black Keys, inside this for loop we do much the same as the for loop for the WhiteKeys.
  Step 15: Piano Key Listeners
  Add the following below the
  setupPianoKeyBoard() function.
  private function playPianoNote(e:Event):void{ pianoSinewave = new SineSource(new AudioDescriptor(),10,e.target.getFrequency()); player.play(pianoSinewave); } private function stopPianoNote(e:Event):void{ player.stop(); }
  In the
  playPianoNote() function we create a new
  pianoSinewave, with a length of 10 seconds, and call the
  getFrequency() function on the key that was pressed.
  The
  stopPianoNote() function simply tells the player to stop playing.
  Step 16: Using SoundSource
  Having examined how to use the SineSource we will now focus our attention on using SoundSource. SoundSource uses embedded MP3s or MP3s that you can load in at runtime.
  In the project files there is a file called "piano.mp3". Go to File > Import > Import To Library and choose this file.
  Go to the Library, right click on the MP3 and choose "Properties". On the "Options" tab make sure the compression is set to "MP3", that "convert stereo to mono" is unchecked, that "Bit Rate" is set to "128kbps", and that "Quality" is set to "fast".
  Next select the "ActionScript" tab, make sure "Export for Actionscript" is checked and that the "Class" is set to "Piano".
  Go to the components panel and drag two labels, a slider, a checkbox, and a button onto the stage. Give them the following properties:
  - First Label: X:42.00, Y:244.0, W:186.0, H:22.0, Text = "Using IAudio Source to play a sound"
  - Second Label: X:50, Y:280, Text ="Gain"
  - Slider: X:113.0, Y:285.00, Instance Name = "gain_slider"
  - CheckBox: X:88, Y:306.00, Instance Name = "echo_checkbox"
  - Button: X:93.00, Y:343.00, Instance Name = "piano_snd_btn"
  Step 17: Coding
  PlayPianoSound()
  The PlayPianoSound will be used to play the piano sound, with the gain set by the slider and optionally applying an echo by selecting the "Echo ON/OFF" checkbox.
  We need to a new variable, so add the following to the bottom of your variable declaration.
  var pianoSoundPlayer:AudioPlayer = new AudioPlayer(); var pianoSound:Sound = new Piano();
  Here the
  pianoSoundPlayer will be used to play the Piano Sound, and the
  pianoSound is a reference to the instance of piano.mp3 we create with a class of "Piano".
  Add the following beneath the
  stopPianoNote() function.
  private function playPianoSound(e:Event):void{ gain_slider.enabled = false; echo_checkbox.enabled = false; e.target.enabled = false; var pianoSource:IAudioSource = new SoundSource(pianoSound,new AudioDescriptor()); var pianoGain:IAudioSource = new GainFilter(pianoSource,gain_slider.value); var pianoEcho:IAudioSource = new EchoFilter(pianoGain,100,1,0.5); pianoSoundPlayer.addEventListener(Event.SOUND_COMPLETE,pianoSoundComplete); if(echo_checkbox.selected){ pianoSoundPlayer.play(pianoEcho); }else{ pianoSoundPlayer.play(pianoGain); } }
  We first disable the controls so the user cannot press them again until the sound is finished playing. Next create an new
  pianoSource as a
  SoundSource using the
  pianoSound we created above.
  Standing Wave has quite a few Filters available; to use them you create them as an
  IAudioSource and pass in another
  IAudioSource to which it will be applied. This allows you to "stack" the filters on top of one another.
  We first create a "Gain Filter", and pass the
  pianoSource to it, and use the
  gain_slider.value for the amount of gain. We then "stack" the
  pianoGain onto a new "Echo Filter", and add an
  Event.SOUND_COMPLETE to be called when the sound finishes playing.
  The "Echo Filter" takes, as its parameters: an
  IAudioSource, the time of the echo, the wet, and decay settings.
  Be sure to check out the other filters Standing Wave comes with. They are located in the com > noteflight > standingwave3 > filters directory.
  We check if the
  echo_checkbox is selected and if it is we play the
  pianoEcho source, otherwise we just play the
  pianoGain source.
  Add the following below the
  playPianoSound() we just created above.
  private function pianoSoundComplete(e:Event):void{ piano_snd_btn.enabled = true; gain_slider.enabled = true; echo_checkbox.enabled = true; }
  Here we simply enable the controls.
  Finally add the following inside); }
  Try it out:
  Step 18: Using the
  ResamplingFilter
  Standing Wav has a
  ResamplingFilter that allows you to resample an audio source to a new frequency. In this step we will use the resample filter to resample an mp3 of a piano that is A4 (440hz).
  In the download files there is a "piano2.mp3"; go to File > Import > Import to Library and import this MP3. Once you have it imported, go to the library and right click on the MP3. Go to the "ActionScript" tab and make sure "Export for ActionScript" is checked, then set the "Class" to "Piano2".
  Now at the bottom of your variable declarations, add the following
  var piano2Sound:Sound = new Piano2();
  All we are doing here is instantiating an instance of the "Piano2" sound.
  Next go to the Components panel, and drag a Button and ComboBox to the stage. (I am not including the Label here to save space.) Give the Button and ComboBox the following properties:
  - Button: X:150.00, Y:438.00, Label="Play", Instance Name ="resample_btn"
  - ComboBox: X:30, Y:438, Instance Name="resample_combo"
  Now we'll populate the ComboBox. We'll populate it with the frequencies from C4 to B6, and use the MP3 we imported in the step above with the ResamplingFilter to play each of these frequencies.
  Enter the following code beneath the
  pianoSoundComplete() function you added in the steps above.
  function populateComboBox():void{ var NoteArray:Array = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]; var FrequencyArray:Array = [NoteUtils.C4,NoteUtils.CS4,NoteUtils.D4,NoteUtils.DS4,NoteUtils.E4,NoteUtils.F4,NoteUtils.FS4,NoteUtils.G4,NoteUtils.GS4,NoteUtils.A4,NoteUtils.AS4,NoteUtils.B4, NoteUtils.C5,NoteUtils.CS5,NoteUtils.D5,NoteUtils.DS5,NoteUtils.E5,NoteUtils.F5,NoteUtils.FS5,NoteUtils.G4,NoteUtils.GS5,NoteUtils.A5,NoteUtils.AS5,NoteUtils.B5, NoteUtils.C6,NoteUtils.CS6,NoteUtils.D6,NoteUtils.DS6,NoteUtils.E6,NoteUtils.F6,NoteUtils.FS6,NoteUtils.G4,NoteUtils.GS6,NoteUtils.A6,NoteUtils.AS6,NoteUtils.B6]; var sub = 3; for(var i:int = 0;i<36;i++){ if(i % 12 == 0){ sub++; } resample_combo.addItem( { label:NoteArray[i%12]+sub.toString(), frequency:FrequencyArray[i] } ); } }
  Here we use a similiar method we used to create the "NoteUtils" class, toward the beginning of this tutorial. The
  NoteArray holds the notes that will be shown in the labels of the ComboBox. and the
  FrequencyArray holds the frequencies of the notes.
  In the for loop we check whether
  i%12 == 0; if so, we increment the
  sub variable. We then use
  addItem() to add the label and the frequency to each label in the ComboBox. The
  frequency part of
  addItem() acts like a dynamic variable for the ComboBox. When we choose, say, "E4" from the ComboBox then the
  frequency would be equal to NoteUtils.E4 from the
  FrequencyArray.
  Step 19: Playing the Resampled MP3
  Add the following beneath the
  populateComboBox() function you added in the step above.
  function playResample(e:Event):void{ var resampledSoundPlayer:AudioPlayer = new AudioPlayer(); var resampleFactor:* = (resample_combo.selectedItem.frequency/440).toFixed(3); var baseSound:IAudioSource = new SoundSource(piano2Sound,new AudioDescriptor()); var resampledSound:IAudioSource = new ResamplingFilter(baseSound,resampleFactor); resampledSoundPlayer.play(resampledSound); trace(resampleFactor); }
  We first set up an
  resampledAudioPlayer that will be used to play the sound. Next we set a
  resampleFactor variable that will be used as the "resampleFactor" within the
  ResamplingFilter. We type it as "*" which means any data type, because when we declare it it needs to use the
  toFixed() method which returns a String, but inside the
  ResamplingFilter it needs to be of type Number.
  Next we set our
  baseSound to the
  piano2Sound we created in the step above and set the
  resampledSound as a new
  ResamplingFilter, passing in the
  baseSound and the
  resampleFactor.
  The way we calculate the resample factor is to take the new frequency and divide it by the base frequency as you can see in the
  resampleFactor declaration above.
  You can see a chart that shows the differences between the notes on the phy.mtu.edu website.
  The last thing we need to do is add the EventListener to the button, so); }
  You can now test the movie and resample the MP3 to a wide variety of frequencies.
  Step 20: Playing a Chord
  One thing that has always been hard to accomplish in Flash, is to achieve perfect timing when playing multiple audio sources. If you wanted to play one sound after another, relying on
  SOUND_COMPLETE did not provide a consistent way to achieve this. Standing Wave has solved this problem with its Performance class. You can play multiple sounds at the exact same time and play sounds one after another with consistent timing.
  Go to Window > Components and drag a button onto the stage. Then give it the following properties.
  - X: 97.00
  - Y: 532.00
  - Label:"Play"
  - Instance Name = "resampleChord_btn"
  Now add the following code below the playResample() function you added in the steps above.
  function playChord(e:Event):void{ var baseSound:IAudioSource = new SoundSource(piano2Sound,new AudioDescriptor()); var C5Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.C5/440); var E5Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.E5/440); var G5Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.G5/440); var chordPerformance:ListPerformance = new ListPerformance(); chordPerformance.addSourceAt(0, C5Note); chordPerformance.addSourceAt(0, E5Note); chordPerformance.addSourceAt(0, G5Note); var chordSource:IAudioSource = new AudioPerformer(chordPerformance,new AudioDescriptor()); var chordPlayer:AudioPlayer = new AudioPlayer(); chordPlayer.play(chordSource); }
  Here we set up our
  baseSound like in the previous example. Then we set up the
  C5Note,
  E5Note, and
  G5Note variables using the ResamplingFilter. The notes of a C Major Chord are "C,E,G". We use our NoteUtils class to make it dead simple.
  Next we set up a
  ListPerformance variable named
  chordPerformance and use the
  addSourceAt() method to add the notes. The first parameter is the "position" you want the note added at. Since we want the sounds all playing at the same time we add all of them at position 0. Like arrays, the
  ListPerformance starts at 0.
  Lastly we create an
  IAudioSource as an
  AudioPerformer (passing in the
  chordPerformance), create an AudioPlay, and finally play the
  chordSource.
  All that is left to do is add the EventListener for the button.); }
  Now go ahead and test the movie.
  Step 21: Playing a Scale
  Having looked at how to play a chord with the resample filter and Performance, we will now play a scale. The code is nearly identical; all we are doing differently is adding more notes and (when we use the
  addSourceAt() method) offsetting the sounds by 1 each time.
  Go to Window > Components and drag a Button to the stage, then give it the following properties:
  - X:400
  - Y:48
  - Label:"Play"
  - Instance Name = "resampleScale_btn"
  Add the following beneath the
  playChord() function you added in the step above:
  function playScale(e:Event):void{ var baseSound:IAudioSource = new SoundSource(piano2Sound,new AudioDescriptor()); var C4Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.C4/440); var D4Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.D4/440); var E4Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.E4/440); var F4Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.F4/440); var G4Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.G4/440); var A4Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.A4/440); var B4Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.B4/440); var C5Note:IAudioSource = new ResamplingFilter(baseSound,NoteUtils.C5/440); var scalePerformance:ListPerformance = new ListPerformance(); scalePerformance.addSourceAt(0, C4Note); scalePerformance.addSourceAt(1, D4Note); scalePerformance.addSourceAt(2, E4Note); scalePerformance.addSourceAt(3, F4Note); scalePerformance.addSourceAt(4, G4Note); scalePerformance.addSourceAt(5, A4Note); scalePerformance.addSourceAt(6, B4Note); scalePerformance.addSourceAt(7, C5Note); var scaleSource:IAudioSource = new AudioPerformer(scalePerformance,new AudioDescriptor()); scalePlayer.addEventListener(Event.SOUND_COMPLETE,scaleComplete); var scalePlayer:AudioPlayer = new AudioPlayer(); scalePlayer.play(scaleSource); }
  The notes of a C major scale are "C,D,E,F,G,A,B,C"; once again our
  NoteUtils class makes this a breeze.
  We need to add the event listener for the button, so); }
  We also added an
  SOUND_COMPLETE event to the player so the user cannot press the button until the player is finished playing
  Add the following code below the
  playScale function you added above.
  private function scaleComplete(e:Event):void{ resampleScale_btn.enabled = true; }
  Here we simply enable the button. Try it out:
  Step 21: Loop Source
  Another type of Source is the Loop Source. This allows you to repeatedly loop a section of audio.
  Drag two buttons to the stage and give them the following properties.
  - Button1: X:340, Y:107, Label:"Play", Instance Name = "loopPlay_btn"
  - Button2: X:460, Y:107, Label:"Stop", Instance Name = "loopStop_btn"
  Add the following to the your variable declarations along with the other Audio Players:
  var loopPlayer:AudioPlayer = new AudioPlayer();
  Here we set up a new Audio Player. Nothing new here.
  private function playLoopSource(e:Event):void{ var length:Number = pianoSound.length * 44.1; var mySample:Sample = new Sample( new AudioDescriptor(44100, 2), length); mySample.extractSound(pianoSound, 0, length); var myLoop:LoopSource = new LoopSource(new AudioDescriptor(44100, 2), mySample); myLoop.firstFrame = 1; myLoop.startFrame = 1; myLoop.endFrame = myLoop.frameCount; loopPlayer.play(myLoop); }
  The first thing we do here is get the frame length of the audio. Since the sound was encoded at 44.1 khz we simply take the sounds length and multiply it by 44.1.
  We then set up a new Sample - we have not discussed this yet, but will do so in the next step. The sample takes as parameters an
  AudioDescriptor and the number of frames for the sample; here we use
  length since we want our sample to hold the same amount of frames as the source sound.
  We next use the sample's
  extractSound() method which extracts a Audio Source's sound into the sample. As parameters it takes: the source sound, the position within that sound to start extracting from, and the number of frames to extract. Since we want the whole sound we used 0 and
  length respectively for the latter two.
  After that we set up a LoopSource and pass in
  mySample; we set the
  firstFrame to 1, the
  startFrame to 1, and the
  endFrame to the
  myLoop.frameCount which returns the amount of frames. So essentially what we are doing is looping through the whole sample.
  Add the following beneath the
  playLoopSource function you added above.
  private function stopLoopSource(e:Event):void{ loopPlayer.stop(); }
  Here we simply stop the
  loopPlayer, otherwise we would have a never ending sound.
  Lastly we need to add the event listeners for our buttons.); }
  Go ahead and test the movie.
  Step 22: Samples
  We introduced Samples in the previous step. In Standing Wave, Samples are the heart of the library. If you are up on your math and DSP processing then samples are your playground.
  The class offers many methods to slice, dice, and re-arrange the Samples. We will not be getting too deep into this but be sure to check the AS Docs and example source code to learn more about what you can do with samples.
  In this step we will load an MP3 from the server and use
  extractSound() to extract the sound into the sample.
  Drag a button onto the stage and give it the following properties:
  - X:402
  - Y:182
  - Label:"Load"
  - Instance Name = "loadPlay_btn"
  Since we are loading a sound we need to import
  URLRequest, so enter the following at the bottom of your import statements:
  import flash.net.URLRequest;
  Next, add the following to the bottom of your variable declarations.
  var pianoSound3:Sound;
  Here we set up an
  Sound object to be used for the sound we will be loading in.
  Next add the following code below the
  stopLoopSource() function you added in the step above.
  private function loadSample(e:Event):void{ pianoSound3 = new Sound(new URLRequest("piano.mp3")); pianoSound3.addEventListener(Event.COMPLETE,soundLoaded); }
  Here we load a sound in and add an
  Event.COMPLETE for when the sound has finished loading.
  Add the following code below the function you just created:
  private function soundLoaded(e:Event):void{ loadPlay_btn.removeEventListener(MouseEvent.CLICK,loadSample); loadPlay_btn.label = "Play"; loadPlay_btn.addEventListener(MouseEvent.CLICK,playSample); }
  This function is called when the sound has finished loading. We remove the event listener for the
  loadSample() function, change the button's label, and add an event listener to the button.
  Add the following code below the function you just added:
  private function playSample(e:Event):void{ e.target.enabled = false; var samplePlayer:AudioPlayer = new AudioPlayer(); samplePlayer.addEventListener(Event.SOUND_COMPLETE,sampleComplete); var length:Number = pianoSound3.length * 44.1; var mySample = new Sample( new AudioDescriptor(44100, 2), length); mySample.extractSound(pianoSound3, 0, length); samplePlayer.play(mySample); }
  Here we disable the button, create a new
  AudioPlayer, add an event listener to the
  AudioPlayer, and use very much the same method as the step above; the only key difference is that we are doing this on a sound we have loaded from the server. Lastly we play the sound.
  Add the following below the function you created above:
  private function sampleComplete(e:Event):void{ loadPlay_btn.enabled = true; }
  Here we simply enable the button.
  Lastly, we need to add the Event Listener for the button, so); }
  You can now test the movie.
  Step 22: Resample a Sample
  One of the methods of the Sample Class allows you to resample a Sample. This method changes both the speed and pitch of the sample.
  Add a Button to the stage and give it the following properties:
  - X: 402
  - Y: 274
  - Label: "Play"
  - Instance Name = "resampleSample_btn"
  Next, add the following code beneath the
  sampleComplete() function you added in the step above.
  private function resampleSample(e:Event):void{ e.target.enabled = false; var resamplePlayer:AudioPlayer = new AudioPlayer; resamplePlayer.addEventListener(Event.SOUND_COMPLETE,resampleComplete); var length:Number = pianoSound.length * 44.1; var mySample = new Sample( new AudioDescriptor(44100, 2), length); mySample.extractSound(pianoSound, 0, length); var resampledSample:Sample = new Sample(new AudioDescriptor(44100,2),mySample.frameCount); resampledSample.resampleIn(mySample,2.0); resamplePlayer.play(resampledSample); }
  First, we disable the button, create an
  AudioPlayer, add an Event Listener to the
  AudioPlayer and once again use the same method as the previous steps to get the sound into the Sample - you should be used to this by now.
  The next thing we do is create an "empty" sample with the instance name
  resampledSample and set its length equal to
  mySample by using
  mySample.frameCount. We then call the
  resampleIn() method and pass the sample we want to resample and the speed. We used 2.0 as the speed in this example. Lastly we play the sample.
  Add the following code below the function you created above:
  private function resampleComplete(e:Event):void{ resampleSample_btn.enabled = true; }
  Here we simply enable the button.
  Last thing to do is add the event listener for the button.); }
  You can now test the movie.
  Step 23: Mixing Samples
  Another cool little method Sample offers is to mix one or more Samples together. We will be doing just that in this step.
  Add a button to the stage and give it the following properties.
  - X: 402
  - Y: 340
  - Label: "Play"
  - Instance Name: "mixSamples_btn"
  In the project files you will find a file named "drumbeat.mp3". Import this to the Library, then right-click it and choose "Properties"; on the "ActionScript" tab make sure "Export for ActionScript" is checked and that the "Class" is set to "Drumbeat".
  At the bottom of your variable declarations add the following:
  var drumBeat:Sound = new Drumbeat();
  Here we are simply creating an instance of the
  DrumBeat.
  Add the following code beneath the
  resampleComplete() function you added in the step above.
  private function mixSamples(e:Event):void{ e.target.enabled = false; var mixSamplePlayer:AudioPlayer = new AudioPlayer(); mixSamplePlayer.addEventListener(Event.SOUND_COMPLETE,mixSamplesComplete); var length:Number = pianoSound.length * 44.1; var mixSample1 = new Sample( new AudioDescriptor(44100, 2), length); mixSample1.extractSound(pianoSound, 0, length); var length2:Number = drumBeat.length * 44.1; var mixSample2 = new Sample(new AudioDescriptor(44100,2),length2) mixSample2.extractSound(drumBeat,0,length); mixSample1.mixIn(mixSample2,1.0); mixSamplePlayer.play(mixSample1); }
  Here we disable the button, create a new
  AudioPlayer, add an event listener to the
  AudioPlayer and use the same methods as before to create a sample and extract the sounds into the sample.
  We then mix
  mixSample2 into
  mixSample1 by calling the first Sample's
  mixIn() method. The first parameter is the Sample you want to mix in and the second parameter is the gain; here we put it at full gain. Lastly we play
  mixSample1 which now has the
  mixSample2 mixed in with it.
  Add the following code below the function you added above.
  private function mixSamplesComplete(e:Event):void{ mixSamples_btn.enabled = true; }
  Here we simply enable the button.
  You can now test the movie.
  Step 24: Bonus - Encoding a Sample
  In this bonus step we will use part of some code from SiON ROKUON
  on wonderfl.net to encode the Samples data as a .wav file, and then use
  FileReference to download it.
  A useful method of the
  Sample class is
  writeWavBytes() which writes the Samples data to a byte array as wav data. You can then encode that data.
  Enter the following code beneath the
  mixSamplesComplete() method you added in the step above:
  private function encodeSample(e:Event):void{ var length:Number = pianoSound.length * 44.1; var mixSample1 = new Sample( new AudioDescriptor(44100, 2), length); mixSample1.extractSound(pianoSound, 0, length); var _data:ByteArray = new ByteArray(); mixSample1.writeWavBytes(_data); var _wav:ByteArray = new ByteArray(); _wav.endian = Endian.LITTLE_ENDIAN; _wav.writeUTFBytes("RIFF"); var len : int = _data.length; _wav.writeInt(len + 36); _wav.writeUTFBytes("WAVE"); _wav.writeUTFBytes("fmt "); _wav.writeInt(16); _wav.writeShort(1); _wav.writeShort(2); _wav.writeInt(44100); _wav.writeInt(176400); _wav.writeShort(4); _wav.writeShort(16); _wav.writeUTFBytes("data"); _wav.writeInt(len); _data.position = 0; _wav.writeBytes(_data); var fr : FileReference = new FileReference(); fr.save( _wav, "mixed.wav"); }
  We once again extract a sound into the sample, then we setup a variable
  _data as a
  ByteArray, go through the encoding process,and pass the final
  _wav
  ByteArray to the
  FileReference save method.
  We will need to import the
  FileReference class,
  ByteArray, and
  Endian so enter the following to the bottom of your import statement.
  import flash.utils.ByteArray; import flash.net.FileReference; import flash.utils.Endian;
  Lastly we need to add a button and setup an EventListener for the button. Drag a button to the stage and give it the following properties:
  - X: 402
  - Y: 414
  - Label:"Encode"
  - Instance Name = "encode_btn"
  Now add the following to); mixSamples_btn.addEventListener(MouseEvent.CLICK,mixSamples); encode_btn.addEventListener(MouseEvent.CLICK,encodeSample); }
  You can now test the movie.
  Conclusion
  This tutorial gave an introduction to the Standing Wave Library. We barely even touched the surface of what is possible, however, so if you're interested in learning more about its capabilites be sure to dig into the AS Docs and source code. Finally make sure you check out NoteFlight.com; Standing Wave 3 is based on a subset of the Noteflight Score Editor's audio engine.
  